Skip to content

Commit

Permalink
Merge pull request #966 from UC-Davis-molecular-computing/897-option-…
Browse files Browse the repository at this point in the history
…to-display-grey-rectangle

#897 option to display rectangle
  • Loading branch information
rayzhuca committed Mar 15, 2024
2 parents f4a80f4 + f842e25 commit 6dc78a6
Show file tree
Hide file tree
Showing 12 changed files with 244 additions and 12 deletions.
16 changes: 16 additions & 0 deletions lib/src/actions/actions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4011,6 +4011,22 @@ abstract class ExampleDesignsLoad
static Serializer<ExampleDesignsLoad> get serializer => _$exampleDesignsLoadSerializer;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// pair lines display

abstract class BasePairTypeSet
with BuiltJsonSerializable
implements Action, Built<BasePairTypeSet, BasePairTypeSetBuilder> {
int get selected_idx;

/************************ begin BuiltValue boilerplate ************************/
factory BasePairTypeSet({int selected_idx}) = _$BasePairTypeSet._;

BasePairTypeSet._();

static Serializer<BasePairTypeSet> get serializer => _$basePairTypeSetSerializer;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// change helix position

Expand Down
1 change: 1 addition & 0 deletions lib/src/constants.dart
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,7 @@ const css_selector_scaffold = 'scaffold';
const css_selector_staple = 'staple';
const css_selector_domain = 'domain-line';
const css_selector_base_pair_line = 'base-pair-line';
const css_selector_base_pair_rect = 'base-pair-rect';
const css_selector_extension = 'extension-line';
const css_selector_crossover = 'crossover-curve';
const css_selector_crossover_same_helix = 'crossover-curve-same-helix';
Expand Down
3 changes: 2 additions & 1 deletion lib/src/middleware/export_svg.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'package:built_collection/built_collection.dart';
import 'package:over_react/over_react.dart';
import 'package:redux/redux.dart';
import 'package:scadnano/src/middleware/system_clipboard.dart';
import 'package:scadnano/src/state/base_pair_display_type.dart';
import 'package:scadnano/src/state/strand.dart';
import 'package:scadnano/src/view/design_main_dna_sequence.dart';

Expand Down Expand Up @@ -80,7 +81,7 @@ export_svg_middleware(Store<AppState> store, dynamic action, NextDispatcher next
List<Element> get_selected_svg_elements(AppState state) {
BuiltSet<Strand> selected_strands = state.ui_state.selectables_store.selected_strands;
List<Element> selected_elts = [];
if (app.state.ui_state.show_base_pair_lines) {
if (app.state.ui_state.base_pair_display_type != BasePairDisplayType.none) {
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);
Expand Down
6 changes: 6 additions & 0 deletions lib/src/reducers/app_ui_state_reducer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -451,6 +456,7 @@ AppUIStateStorables app_ui_state_storable_local_reducer(AppUIStateStorables stor
..display_base_offsets_of_major_ticks_only_first_helix = TypedReducer<bool, actions.SetDisplayBaseOffsetsOfMajorTicksOnlyFirstHelix>(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<bool, actions.SetDisplayMajorTickWidths>(display_major_tick_widths_reducer)(storables.display_major_tick_widths, action)
..display_major_tick_widths_all_helices = TypedReducer<bool, actions.SetDisplayMajorTickWidthsAllHelices>(display_major_tick_widths_all_helices_reducer)(storables.display_major_tick_widths_all_helices, action)
..base_pair_display_type = TypedReducer<BasePairDisplayType, actions.BasePairTypeSet>(base_pair_type_idx_reducer)(storables.base_pair_display_type, action)
..show_base_pair_lines = TypedReducer<bool, actions.ShowBasePairLinesSet>(show_base_pair_lines_reducer)(storables.show_base_pair_lines, action)
..show_base_pair_lines_with_mismatches = TypedReducer<bool, actions.ShowBasePairLinesWithMismatchesSet>(show_base_pair_lines_with_mismatches_reducer)(storables.show_base_pair_lines_with_mismatches, action)
..export_svg_text_separately = TypedReducer<bool, actions.ExportSvgTextSeparatelySet>(export_svg_text_separately_reducer)(storables.export_svg_text_separately, action)
Expand Down
3 changes: 3 additions & 0 deletions lib/src/serializers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -137,6 +138,7 @@ part 'serializers.g.dart';
SelectionBoxRemove,
SelectionRope,
Line,
BasePairDisplayType,
SelectionRopeCreate,
SelectionRopeMouseMove,
SelectionRopeAddPoint,
Expand Down Expand Up @@ -316,6 +318,7 @@ part 'serializers.g.dart';
StrandPasteKeepColorSet,
ExampleDesigns,
ExampleDesignsLoad,
BasePairTypeSet,
HelixPositionSet,
HelixGridPositionSet,
InlineInsertionsDeletions,
Expand Down
3 changes: 3 additions & 0 deletions lib/src/state/app_ui_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -162,6 +163,8 @@ abstract class AppUIState with BuiltJsonSerializable implements Built<AppUIState

bool get show_domain_labels => 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;
Expand Down
4 changes: 4 additions & 0 deletions lib/src/state/app_ui_state_storables.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
66 changes: 66 additions & 0 deletions lib/src/state/base_pair_display_type.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
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<BasePairDisplayType> 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<BasePairDisplayType> types = const [none, lines, rectangle].toBuiltList();

static BuiltSet<BasePairDisplayType> get values => _$values;

static BasePairDisplayType valueOf(String name) => _$valueOf(name);

String to_json() => name;

int toIndex() {
switch (this) {
case none:
return 0;
case lines:
return 1;
case rectangle:
return 2;
}
return 0;
}

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}"');
}
}
1 change: 1 addition & 0 deletions lib/src/state/dialog.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
16 changes: 15 additions & 1 deletion lib/src/view/design_main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ import 'package:built_collection/built_collection.dart';
import 'package:over_react/over_react.dart';
import 'package:over_react/over_react_redux.dart';
import 'package:react/react_client/react_interop.dart';
import 'package:scadnano/src/state/base_pair_display_type.dart';
import 'package:scadnano/src/view/design_main_unpaired_insertion_deletions.dart';
import 'package:scadnano/src/view/design_main_slice_bar.dart';
import 'package:scadnano/src/view/potential_extensions_view.dart';

import '../state/selection_rope.dart';
import 'design_main_base_pair_rectangle.dart';
import 'design_main_domains_moving.dart';
import 'selection_rope_view.dart';
import '../actions/actions.dart' as actions;
Expand Down Expand Up @@ -65,6 +67,7 @@ UiFactory<DesignMainProps> ConnectedDesignMain = connect<AppState, DesignMainPro
..show_domain_name_mismatches = state.ui_state.show_domain_name_mismatches
..show_unpaired_insertion_deletions = state.ui_state.show_unpaired_insertion_deletions
..show_dna = state.ui_state.show_dna
..base_pair_display_type = state.ui_state.base_pair_display_type
..show_base_pair_lines = state.ui_state.show_base_pair_lines
..show_base_pair_lines_with_mismatches = state.ui_state.show_base_pair_lines_with_mismatches
..show_domain_names = state.ui_state.show_domain_names
Expand Down Expand Up @@ -110,6 +113,7 @@ mixin DesignMainPropsMixin on UiProps {
bool show_domain_name_mismatches;
bool show_unpaired_insertion_deletions;
bool show_dna;
BasePairDisplayType base_pair_display_type;
bool show_base_pair_lines;
bool show_base_pair_lines_with_mismatches;
bool show_domain_names;
Expand Down Expand Up @@ -210,7 +214,7 @@ class DesignMainComponent extends UiComponent2<DesignMainProps> {
.map((helix_idx, svg_position) => MapEntry(helix_idx, svg_position.y))
..key = 'unpaired-insertion-deletions')(),

if (props.show_base_pair_lines)
if (props.base_pair_display_type == BasePairDisplayType.lines)
(DesignMainBasePairLines()
..with_mismatches = props.show_base_pair_lines_with_mismatches
..design = props.design
Expand All @@ -220,6 +224,16 @@ class DesignMainComponent extends UiComponent2<DesignMainProps> {
.map((helix_idx, svg_position) => MapEntry(helix_idx, svg_position.y))
..key = 'base-pair-lines')(),

if (props.base_pair_display_type == BasePairDisplayType.rectangle)
(DesignMainBasePairRectangle()
..with_mismatches = props.show_base_pair_lines_with_mismatches
..design = props.design
..only_display_selected_helices = props.only_display_selected_helices
..side_selected_helix_idxs = props.side_selected_helix_idxs
..helix_idx_to_svg_position_y_map = props.helix_idx_to_svg_position_map
.map((helix_idx, svg_position) => MapEntry(helix_idx, svg_position.y))
..key = 'base-pair-rectangle')(),

(ConnectedDesignMainStrands()..key = 'strands')(),

// after strands so can click when crossover overlaps potential crossover
Expand Down
99 changes: 99 additions & 0 deletions lib/src/view/design_main_base_pair_rectangle.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
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';

import '../state/design.dart';
import '../state/strand.dart';
import '../state/domain.dart';
import 'pure_component.dart';
import 'design_main_warning_star.dart';
import '../util.dart' as util;
import '../constants.dart' as constants;

part 'design_main_base_pair_rectangle.over_react.g.dart';

UiFactory<DesignMainBasePairRectangleProps> DesignMainBasePairRectangle = _$DesignMainBasePairRectangle;

mixin DesignMainBasePairRectangleProps on UiProps {
bool with_mismatches;
Design design;
bool only_display_selected_helices;
BuiltSet<int> side_selected_helix_idxs;
BuiltMap<int, num> helix_idx_to_svg_position_y_map;
}

class DesignMainBasePairRectangleComponent extends UiComponent2<DesignMainBasePairRectangleProps>
with PureComponent {
@override
render() {
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(BuiltSet<Strand> strands) {
List<ReactElement> base_pair_lines_components = [];
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)) {
var helix = props.design.helices[helix_idx];
HelixGroup group = props.design.groups[helix.group];
String transform_str = group.transform_str(props.design.geometry);

// code below draws one line for each base pair, should render somewhat slowly
// however, this makes it easier to associate base pair lines to individual strands,
// convenient when exporting SVG
List<ReactElement> helix_components = [];
int last_offset = -2;
var last_svg_forward_pos = null;
for (int offset in base_pairs[helix_idx]) {
var svg_position_y = props.helix_idx_to_svg_position_y_map[helix_idx];
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_ele = null;

if (offset - last_offset == 1) {
base_pair_ele = (Dom.rect()
..id = 'base_pair-${helix_idx}-${offset}'
..x = last_svg_forward_pos.x - 0.5
..y = base_svg_forward_pos.y
..width = base_svg_reverse_pos.x - last_svg_forward_pos.x + 0.8
..height = base_svg_reverse_pos.y - base_svg_forward_pos.y
..className = constants.css_selector_base_pair_rect
..fill = 'grey'
..key = 'base-pair-rect-H${helix_idx}-${offset}')();
} else {
base_pair_ele = (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
..y2 = base_svg_reverse_pos.y
..className = constants.css_selector_base_pair_line
..stroke = 'grey'
..key = 'base-pair-line-H${helix_idx}-${offset}')();
}

helix_components.add(base_pair_ele);
last_offset = offset;
last_svg_forward_pos = base_svg_forward_pos;
}
var helix_dom_group = (Dom.g()
..transform = transform_str
..className = 'base-pair-lines-components-in-helix'
..key = 'base-pair-lines-components-in-helix-H${helix_idx}')(helix_components);
base_pair_lines_components.add(helix_dom_group);
}
}

return base_pair_lines_components;
}
}
Loading

0 comments on commit 6dc78a6

Please sign in to comment.