Skip to content

Commit

Permalink
Merge pull request #994 from UC-Davis-molecular-computing/992-adding-…
Browse files Browse the repository at this point in the history
…keyboard-shortcuts-for-selection-variants

fixes #992: adding keyboard shortcuts for select mode change
  • Loading branch information
dave-doty authored Sep 19, 2024
2 parents 995263b + 945ff2c commit e0b988a
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 191 deletions.
193 changes: 71 additions & 122 deletions lib/src/state/select_mode.dart
Original file line number Diff line number Diff line change
Expand Up @@ -92,170 +92,119 @@ class SelectModeChoice extends EnumClass {
switch (this) {
case end_5p_strand:
return '''\
5' strand: Allows one to select the 5'
end (square) of a whole strand. If many
5' ends are selected, then one can
add a 5' modification to all of them
by right-clicking and selecting "add
modification". This will add only to
the type of modification picked. For
example, if both 5' and 3' ends are
selected, and a 5' modification is
added, then only the 5' ends are
5' strand: Allows one to select the 5' end (square) of a whole strand. If many
5' ends are selected, then one can add a 5' modification to all of them
by right-clicking and selecting "add modification". This will add only to
the type of modification picked. For example, if both 5' and 3' ends are
selected, and a 5' modification is added, then only the 5' ends are
modified.''';
case end_3p_strand:
return '''\
3' strand: Allows one to select the 3'
end (triangle) of a whole strand. If many
3' ends are selected, then one can
add a 3' modification to all of them
by right-clicking and selecting "add
modification". This will add only to
the type of modification picked. For
example, if both 5' and 3' ends are
selected, and a 3' modification is
added, then only the 3' ends are
3' strand: Allows one to select the 3' end (triangle) of a whole strand. If
many 3' ends are selected, then one can add a 3' modification to all of them
by right-clicking and selecting "add modification". This will add only to
the type of modification picked. For example, if both 5' and 3' ends are
selected, and a 3' modification is added, then only the 3' ends are
modified.''';
case end_5p_domain:
return '''\
5' domain: Each strand is composed of
one or more bound domains, defined to
be a portion of a strand that exists on
a single helix. A 5'/3' end of a bound
domain that is not the 5'/3' end of the
whole strand is one of these. They are
not normally visible, but when these
select modes are enabled, they become
visible on mouseover and can be
selected and dragged. Deleting a 5'/3'
end of a bound domain deletes the whole
bound domain. Ends can be moved, but
unlike strands and domains, they can
only be moved back and forth along their
5' domain: Each strand is composed of one or more bound domains, defined to
be a portion of a strand that exists on a single helix. A 5'/3' end of a bound
domain that is not the 5'/3' end of the whole strand is one of these. They are
not normally visible, but when these select modes are enabled, they become
visible on mouseover and can be selected and dragged. Deleting a 5'/3'
end of a bound domain deletes the whole bound domain. Ends can be moved, but
unlike strands and domains, they can only be moved back and forth along their
current helix.''';
case end_3p_domain:
return '''\
3' domain: Each strand is composed of
one or more bound domains, defined to
be a portion of a strand that exists on
a single helix. A 5'/3' end of a bound
domain that is not the 5'/3' end of the
whole strand is one of these. They are
not normally visible, but when these
select modes are enabled, they become
visible on mouseover and can be
selected and dragged. Deleting a 5'/3'
end of a bound domain deletes the whole
bound domain. Ends can be moved, but
unlike strands and domains, they can
only be moved back and forth along their
3' domain: Each strand is composed of one or more bound domains, defined to
be a portion of a strand that exists on a single helix. A 5'/3' end of a bound
domain that is not the 5'/3' end of the whole strand is one of these. They are
not normally visible, but when these select modes are enabled, they become
visible on mouseover and can be selected and dragged. Deleting a 5'/3'
end of a bound domain deletes the whole bound domain. Ends can be moved, but
unlike strands and domains, they can only be moved back and forth along their
current helix.''';
case domain:
return '''\
domain: A single bound domain can be
selected. Groups of domains can be
moved, but only if they are all in the
same helix group. (Though they can be
moved to a different helix group.)''';
domain: A single bound domain can be selected. Groups of domains can be
moved, but only if they are all in the same helix group. (Though they can be
moved to a different helix group.)
[Alt+O or Alt+D (Alt+D has another behavior in Chrome that pops up a window)]''';
case crossover:
return '''\
crossover: Two consecutive bound
domains on a strand can be joined by a
crossover, which consists of no DNA
bases (Technically bound domains do not
have to be bound to another strand, but
the idea is that generally in a
finished design, most of the bound
domains will actually be bound to
crossover: Two consecutive bound domains on a strand can be joined by a
crossover, which consists of no DNA bases (Technically bound domains do not
have to be bound to another strand, but the idea is that generally in a
finished design, most of the bound domains will actually be bound to
another.)
If many crossovers/loopouts are
selected, all the crossovers can be
converted to loopouts (or vice versa)
by right-clicking on one of them and
picking "convert to loopout" (or
"change loopout length" if a loopout;
changing to length 0 converts it to a
crossover).''';
If many crossovers/loopouts are selected, all the crossovers can be
converted to loopouts (or vice versa) by right-clicking on one of them and
picking "convert to loopout" (or "change loopout length" if a loopout;
changing to length 0 converts it to a crossover).
[Alt+C]''';
case loopout:
return '''\
loopout: Two consecutive bound domains
on a strand can be joined by a loopout,
which is a single-stranded portion of
the strand with one or more DNA bases.
(Technically bound domains do not have
to be bound to another strand, but the
idea is that generally in a finished
design, most of the bound domains will
loopout: Two consecutive bound domains on a strand can be joined by a loopout,
which is a single-stranded portion of the strand with one or more DNA bases.
(Technically bound domains do not have to be bound to another strand, but the
idea is that generally in a finished design, most of the bound domains will
actually be bound to another.)
If many crossovers/loopouts are
selected, all the crossovers can be
converted to loopouts (or vice versa)
by right-clicking on one of them and
picking "convert to loopout" (or
"change loopout length" if a loopout;
changing to length 0 converts it to a
crossover).''';
If many crossovers/loopouts are selected, all the crossovers can be
converted to loopouts (or vice versa) by right-clicking on one of them and
picking "convert to loopout" (or "change loopout length" if a loopout;
changing to length 0 converts it to a crossover).
[Alt+L]''';
case extension_:
return '''\
extension: An extension is a single-stranded
portion of a strand that is not on a
Helix (like a domain) and does not connect
two domains. It is like a loopout but on
the end of a strand, useful for modeling
toeholds for DNA strand displacement,
for instance.''';
extension: An extension is a single-stranded portion of a strand that is not on a
Helix (like a domain) and does not connect two domains. It is like a loopout but on
the end of a strand, useful for modeling toeholds for DNA strand displacement,
for instance.
[Alt+X]''';
case deletion:
return '''\
deletion: Deletions can be selected and
deleted in batch by pressing the Delete key.''';
deletion: Deletions can be selected and deleted in batch by pressing the Delete key.''';
case insertion:
return '''\
insertion: Insertions can be selected
and deleted in batch by pressing the
Delete key. Also, one can change the
length of all selected insertions by
right-clicking on one of them and
selecting the option to change
insertion length.''';
insertion: Insertions can be selected and deleted in batch by pressing the
Delete key. Also, one can change the length of all selected insertions by
right-clicking on one of them and selecting the option to change
insertion length.
[Alt+I]''';
case modification:
return '''\
modification: If many modifications are
selected, they can be deleted at once
by pressing the Delete key (or
right-clicking and selecting "remove
modification"). Those of a similar type
(5', 3', or internal) can be modified
in batch by right-clicking on one of
them and selecting "edit
modification".''';
modification: If many modifications are selected, they can be deleted at once
by pressing the Delete key (or right-clicking and selecting "remove
modification"). Those of a similar type (5', 3', or internal) can be modified
in batch by right-clicking on one of them and selecting "edit modification".
[Alt+M]''';
case strand:
return '''\
strand: The whole strand can be selected.
Groups of strands can be copy/pasted or
moved, but only if they are all in the
same helix group. (Though they can be
copied/moved to a different helix group.)''';
strand: The whole strand can be selected. Groups of strands can be copy/pasted or
moved, but only if they are all in the same helix group. (Though they can be
copied/moved to a different helix group.)
[Alt+S]''';
case scaffold:
return '''\
scaffold: This option allows one to
select scaffold strands. The option is
scaffold: This option allows one to select scaffold strands. The option is
not shown in a non-origami design.''';
case staple:
return '''\
staple: All non-scaffold strands are
called staples. This option allows one
to select staples. The option is not
shown in a non-origami design.''';
staple: All non-scaffold strands are called staples. This option allows one
to select staples. The option is not shown in a non-origami design.''';
}
return '';
}

static String get all_ends_image_file => 'images/select_mode_icons/allends.svg';

static String get all_ends_tooltip => '''all ends: Selects all of 5' strand, 3'
strand, 5' domain, 3' domain.''';
strand, 5' domain, 3' domain.
[Alt+E]''';

String css_selector() {
switch (this) {
Expand Down
27 changes: 27 additions & 0 deletions lib/src/view/design.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import '../state/address.dart';
import '../state/dna_ends_move.dart';
import '../state/edit_mode.dart';
import '../state/helix.dart';
import '../state/select_mode.dart';
import '../state/strand_creation.dart';
import '../state/strands_move.dart';

Expand Down Expand Up @@ -637,6 +638,32 @@ class DesignViewComponent {
// Alt+Shift+A for Select all with same
ev.preventDefault();
app.disable_keyboard_shortcuts_while(ask_for_select_all_with_same_as_selected);
} else if ((app.state.ui_state.edit_modes.contains(EditModeChoice.select) ||
app.state.ui_state.edit_modes.contains(EditModeChoice.rope_select) &&
ev.altKey &&
!(ev.ctrlKey || ev.metaKey))) {
// Alt+? for select modes
ev.preventDefault(); // for some reason this is not stopping Alt+D,
// so we also let the user type Alt+O since Alt+D has a special meaning in Chrome
if (key == KeyCode.S) {
app.dispatch(actions.SelectModeToggle(SelectModeChoice.strand));
} else if (key == KeyCode.O || key == KeyCode.D) {
app.dispatch(actions.SelectModeToggle(SelectModeChoice.domain));
} else if (key == KeyCode.E) {
app.dispatch(actions.SelectModesAdd(modes: SelectModeChoice.ends));
} else if (key == KeyCode.C) {
app.dispatch(actions.SelectModeToggle(SelectModeChoice.crossover));
} else if (key == KeyCode.L) {
app.dispatch(actions.SelectModeToggle(SelectModeChoice.loopout));
} else if (key == KeyCode.X) {
app.dispatch(actions.SelectModeToggle(SelectModeChoice.extension_));
} else if (key == KeyCode.I) {
app.dispatch(actions.SelectModeToggle(SelectModeChoice.insertion));
} else if (key == KeyCode.N) {
app.dispatch(actions.SelectModeToggle(SelectModeChoice.deletion));
} else if (key == KeyCode.M) {
app.dispatch(actions.SelectModeToggle(SelectModeChoice.modification));
}
}

if (key == EditModeChoice.pencil.key_code()) {
Expand Down
69 changes: 0 additions & 69 deletions lib/src/view/menu.dart
Original file line number Diff line number Diff line change
Expand Up @@ -48,75 +48,6 @@ UiFactory<MenuProps> ConnectedMenu = connect<AppState, MenuProps>(
forwardRef: true,
)(Menu);

/*
mapStateToProps: (AppState state) {
return (Menu()
..selected_ends = state.ui_state.selectables_store.selected_dna_ends
..geometry = state.maybe_design?.geometry
..no_grid_is_none = state.maybe_design == null
? false
: state.design.groups.values.every((group) => group.grid != Grid.none)
..show_oxview = state.ui_state.show_oxview
..show_dna = state.ui_state.show_dna
..base_pair_display_type = state.ui_state.base_pair_display_type
..show_strand_names = state.ui_state.show_strand_names
..show_strand_labels = state.ui_state.show_strand_labels
..show_domain_names = state.ui_state.show_domain_names
..show_domain_labels = state.ui_state.show_domain_labels
..strand_name_font_size = state.ui_state.strand_name_font_size
..strand_label_font_size = state.ui_state.strand_label_font_size
..domain_name_font_size = state.ui_state.domain_name_font_size
..domain_label_font_size = state.ui_state.domain_label_font_size
..show_modifications = state.ui_state.show_modifications
..show_mismatches = state.ui_state.show_mismatches
..show_domain_name_mismatches = state.ui_state.show_domain_name_mismatches
..show_unpaired_insertion_deletions = state.ui_state.show_unpaired_insertion_deletions
..strand_paste_keep_color = state.ui_state.strand_paste_keep_color
..zoom_speed = state.ui_state.zoom_speed
..autofit = state.ui_state.autofit
..only_display_selected_helices = state.ui_state.only_display_selected_helices
..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
..example_designs = state.ui_state.example_designs
..design_has_insertions_or_deletions = state.maybe_design?.has_insertions_or_deletions == true
..undo_stack_empty = state.undo_redo.undo_stack.isEmpty
..redo_stack_empty = state.undo_redo.redo_stack.isEmpty
..enable_copy = app.state.ui_state.selectables_store.selected_strands.isNotEmpty
..modification_font_size = state.ui_state.modification_font_size
..major_tick_offset_font_size = state.ui_state.major_tick_offset_font_size
..major_tick_width_font_size = state.ui_state.major_tick_width_font_size
..modification_display_connector = state.ui_state.modification_display_connector
..display_of_major_ticks_offsets = state.ui_state.display_base_offsets_of_major_ticks
..display_base_offsets_of_major_ticks_only_first_helix =
state.ui_state.display_base_offsets_of_major_ticks_only_first_helix
..display_major_tick_widths = state.ui_state.display_major_tick_widths
..display_major_tick_widths_all_helices = state.ui_state.display_major_tick_widths_all_helices
..invert_y = state.ui_state.invert_y
..dynamically_update_helices = state.ui_state.dynamically_update_helices
..show_helix_circles_main_view = state.ui_state.show_helix_circles_main_view
..show_helix_components_main_view = state.ui_state.show_helix_components_main_view
..warn_on_exit_if_unsaved = state.ui_state.warn_on_exit_if_unsaved
..show_grid_coordinates_side_view = state.ui_state.show_grid_coordinates_side_view
..show_helices_axis_arrows = state.ui_state.show_helices_axis_arrows
..show_loopout_extension_length = state.ui_state.show_loopout_extension_length
..export_svg_text_separately = state.ui_state.export_svg_text_separately
..show_slice_bar = state.ui_state.show_slice_bar
..show_mouseover_data = state.ui_state.show_mouseover_data
..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
..local_storage_design_choice = state.ui_state.local_storage_design_choice
..clear_helix_selection_when_loading_new_design =
state.ui_state.clear_helix_selection_when_loading_new_design
..default_crossover_type_scaffold_for_setting_helix_rolls =
state.ui_state.default_crossover_type_scaffold_for_setting_helix_rolls
..default_crossover_type_staple_for_setting_helix_rolls =
state.ui_state.default_crossover_type_staple_for_setting_helix_rolls
..selection_box_intersection = state.ui_state.selection_box_intersection
..ox_export_only_selected_strands = state.ui_state.ox_export_only_selected_strands
..undo_redo = state.undo_redo);
*/

UiFactory<MenuProps> Menu = _$Menu;

mixin MenuProps on UiProps {
Expand Down

0 comments on commit e0b988a

Please sign in to comment.