Skip to content

Commit

Permalink
Forbid edits in read-only mode (#6342)
Browse files Browse the repository at this point in the history
Closes #6182 

Implements read-only mode for relevant components of the IDE.

- [x]  Project Name renaming
- [x]  Nodes editing
- [x]  Editing code in the code editor
- [x]  Creating nodes
- [x]  Removing nodes
- [x]  Entering and leaving nodes
- [x]  Creating, dropping, and changing connections between nodes
- [x]  Buttons on nodes (except for visualization toggle button)
- [x]  Widgets on nodes


https://user-images.githubusercontent.com/6566674/232824737-bdd6f676-b20d-4218-af7d-4373e00cbe3e.mp4
  • Loading branch information
vitvakatu authored Apr 24, 2023
1 parent 22f820f commit 719bd8c
Show file tree
Hide file tree
Showing 15 changed files with 149 additions and 39 deletions.
3 changes: 2 additions & 1 deletion app/gui/docs/product/shortcuts.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ broken and require further investigation.
#### Debug

| Shortcut | Action |
| ------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------ |
| ------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------ | ---------------------- |
| <kbd>ctrl</kbd> + <kbd>shift</kbd> + <kbd>d</kbd> | Toggle Debug Mode. All actions below are only possible when it is activated. |
| <kbd>ctrl</kbd> + <kbd>alt</kbd> + <kbd>shift</kbd> + <kbd>i</kbd> | Open the developer console. |
| <kbd>ctrl</kbd> + <kbd>alt</kbd> + <kbd>shift</kbd> + <kbd>r</kbd> | Reload the visual interface. |
Expand All @@ -134,3 +134,4 @@ broken and require further investigation.
| <kbd>ctrl</kbd> + <kbd>shift</kbd> + <kbd>enter</kbd> | Push a hardcoded breadcrumb without navigating. |
| <kbd>ctrl</kbd> + <kbd>shift</kbd> + <kbd>arrow up</kbd> | Pop a breadcrumb without navigating. |
| <kbd>cmd</kbd> + <kbd>i</kbd> | Reload visualizations. To see the effect in the currently shown visualizations, you need to switch to another and switch back. |
| <kbd>ctrl</kbd> + <kbd>shift</kbd> + <kbd>b</kbd> | | Toggle read-only mode. |
13 changes: 8 additions & 5 deletions app/gui/src/presenter/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,10 +199,13 @@ impl Model {
self.ide_controller.set_component_browser_private_entries_visibility(!visibility);
}

fn toggle_read_only(&self) {
let read_only = self.controller.model.read_only();
self.controller.model.set_read_only(!read_only);
info!("New read only state: {}.", self.controller.model.read_only());
/// Toggle the read-only mode, return the new state.
fn toggle_read_only(&self) -> bool {
let current_state = self.controller.model.read_only();
let new_state = !current_state;
self.controller.model.set_read_only(new_state);
info!("New read only state: {}.", new_state);
new_state
}

fn restore_project_snapshot(&self) {
Expand Down Expand Up @@ -381,7 +384,7 @@ impl Project {

eval_ view.execution_context_restart(model.execution_context_restart());

eval_ view.toggle_read_only(model.toggle_read_only());
view.set_read_only <+ view.toggle_read_only.map(f_!(model.toggle_read_only()));
}

let graph_controller = self.model.graph_controller.clone_ref();
Expand Down
9 changes: 9 additions & 0 deletions app/gui/view/graph-editor/src/component/breadcrumbs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ ensogl::define_endpoints! {
gap_width (f32),
/// Set whether the project was changed since the last snapshot save.
set_project_changed(bool),
/// Set read-only mode for this component.
set_read_only(bool),
}
Output {
/// Signalizes when a new breadcrumb is pushed.
Expand All @@ -124,6 +126,8 @@ ensogl::define_endpoints! {
project_name_hovered (bool),
/// Indicates whether the project name was clicked.
project_mouse_down (),
/// Indicates if the read-only mode is enabled.
read_only(bool),
}
}

Expand Down Expand Up @@ -521,6 +525,11 @@ impl Breadcrumbs {

frp.source.pointer_style <+ model.project_name.frp.output.pointer_style;


// === Read-only mode ===

frp.source.read_only <+ frp.input.set_read_only;
model.project_name.set_read_only <+ frp.input.set_read_only;
}

Self { model, frp }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ ensogl::define_endpoints_2! {
ide_text_edit_mode (bool),
/// Set whether the project was changed since the last snapshot save.
set_project_changed(bool),
/// Set the read-only mode for this component.
set_read_only(bool),
}

Output {
Expand All @@ -88,6 +90,7 @@ ensogl::define_endpoints_2! {
edit_mode (bool),
selected (bool),
is_hovered (bool),
read_only (bool),
}
}

Expand Down Expand Up @@ -265,6 +268,10 @@ impl ProjectName {
let input = &frp.private.input;
let output = &frp.private.output;
frp::extend! { network
// === Read-only mode ===

output.read_only <+ input.set_read_only;


// === Mouse IO ===

Expand Down Expand Up @@ -402,9 +409,9 @@ impl View for ProjectName {
fn default_shortcuts() -> Vec<shortcut::Shortcut> {
use shortcut::ActionType::*;
[
(Press, "", "enter", "commit"),
(Press, "!read_only", "enter", "commit"),
(Release, "", "escape", "cancel_editing"),
(DoublePress, "is_hovered", "left-mouse-button", "start_editing"),
(DoublePress, "is_hovered & !read_only", "left-mouse-button", "start_editing"),
]
.iter()
.map(|(a, b, c, d)| Self::self_shortcut_when(*a, *c, *d, *b))
Expand Down
7 changes: 7 additions & 0 deletions app/gui/view/graph-editor/src/component/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,7 @@ ensogl::define_endpoints_2! {
/// Indicate whether on hover the quick action icons should appear.
show_quick_action_bar_on_hover (bool),
set_execution_environment (ExecutionEnvironment),
set_read_only (bool),
}
Output {
/// Press event. Emitted when user clicks on non-active part of the node, like its
Expand Down Expand Up @@ -827,6 +828,12 @@ impl Node {
model.vcs_indicator.set_visibility <+ input.set_view_mode.map(|&mode| {
!matches!(mode,view::Mode::Profiling {..})
});


// === Read-only mode ===

action_bar.set_read_only <+ input.set_read_only;
model.input.set_read_only <+ input.set_read_only;
}


Expand Down
17 changes: 17 additions & 0 deletions app/gui/view/graph-editor/src/component/node/action_bar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ ensogl::define_endpoints! {
set_action_context_switch_state (Option<bool>),
show_on_hover (bool),
set_execution_environment (ExecutionEnvironment),
/// Set the read-only mode for the buttons.
set_read_only (bool),
}

Output {
Expand Down Expand Up @@ -129,6 +131,12 @@ impl Icons {
self.skip.frp.set_visibility(visible);
}

fn set_read_only(&self, read_only: bool) {
self.context_switch.set_read_only(read_only);
self.freeze.frp.set_read_only(read_only);
self.skip.frp.set_read_only(read_only);
}

fn set_color_scheme(&self, color_scheme: &toggle_button::ColorScheme) {
self.visibility.frp.set_color_scheme(color_scheme);
self.context_switch.set_color_scheme(color_scheme);
Expand Down Expand Up @@ -207,6 +215,11 @@ impl ContextSwitchButton {
self.enable_button.set_visibility(visible);
}

fn set_read_only(&self, read_only: bool) {
self.disable_button.set_read_only(read_only);
self.enable_button.set_read_only(read_only);
}

fn set_color_scheme(&self, color_scheme: &toggle_button::ColorScheme) {
self.disable_button.set_color_scheme(color_scheme);
self.enable_button.set_color_scheme(color_scheme);
Expand Down Expand Up @@ -375,6 +388,10 @@ impl ActionBar {
let model = &self.model;

frp::extend! { network
// === Read-only mode ===

eval frp.set_read_only((read_only) model.icons.set_read_only(*read_only));


// === Input Processing ===

Expand Down
3 changes: 3 additions & 0 deletions app/gui/view/graph-editor/src/component/node/input/area.rs
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,7 @@ impl Model {
}));
area_frp.source.on_port_code_update <+ code_update;
area_frp.source.request_import <+ widget.request_import;
widget.set_read_only <+ area_frp.set_read_only;
}
}

Expand Down Expand Up @@ -936,6 +937,8 @@ ensogl::define_endpoints! {
set_view_mode (view::Mode),
set_profiling_status (profiling::Status),

/// Set read-only mode for input ports.
set_read_only (bool),
}

Output {
Expand Down
16 changes: 13 additions & 3 deletions app/gui/view/graph-editor/src/component/node/input/widget.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ ensogl::define_endpoints_2! {
set_current_value (Option<ImString>),
set_focused (bool),
set_visible (bool),
set_read_only (bool),
}
Output {
value_changed(Option<ImString>),
Expand Down Expand Up @@ -148,6 +149,7 @@ pub struct SampledFrp {
set_focused: frp::Sampler<bool>,
out_value_changed: frp::Any<Option<ImString>>,
out_request_import: frp::Any<ImString>,
set_read_only: frp::Sampler<bool>,
}


Expand Down Expand Up @@ -193,9 +195,17 @@ impl View {
set_current_value <- input.set_current_value.sampler();
set_visible <- input.set_visible.sampler();
set_focused <- input.set_focused.sampler();
set_read_only <- input.set_read_only.sampler();
let out_value_changed = frp.private.output.value_changed.clone_ref();
let out_request_import = frp.private.output.request_import.clone_ref();
let sampled_frp = SampledFrp { set_current_value, set_visible, set_focused, out_value_changed, out_request_import };
let sampled_frp = SampledFrp {
set_current_value,
set_visible,
set_focused,
out_value_changed,
out_request_import,
set_read_only
};

eval widget_data([model, sampled_frp]((meta, node_data)) {
model.set_widget_data(&sampled_frp, meta, node_data);
Expand Down Expand Up @@ -415,8 +425,8 @@ impl SingleChoiceModel {
let dropdown = Rc::new(RefCell::new(dropdown));

frp::extend! { network
let dot_clicked = activation_shape.events_deprecated.mouse_down_primary.clone_ref();
toggle_focus <- dot_clicked.map(f!([display_object](()) !display_object.is_focused()));
clicked <- activation_shape.events_deprecated.mouse_down_primary.gate_not(&frp.set_read_only);
toggle_focus <- clicked.map(f!([display_object](()) !display_object.is_focused()));
set_focused <- any(toggle_focus, frp.set_focused);
eval set_focused([display_object](focus) match focus {
true => display_object.focus(),
Expand Down
70 changes: 51 additions & 19 deletions app/gui/view/graph-editor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,11 @@ ensogl::define_endpoints_2! {
space_for_window_buttons (Vector2<f32>),


// === Read-only mode ===

set_read_only(bool),


// === Node Selection ===

/// Node press event
Expand Down Expand Up @@ -662,6 +667,11 @@ ensogl::define_endpoints_2! {

debug_mode (bool),


// === Read-only mode ===

read_only (bool),

// === Edge ===

has_detached_edge (bool),
Expand Down Expand Up @@ -1702,6 +1712,11 @@ impl GraphEditorModelWithNetwork {
node.set_view_mode <+ self.model.frp.view_mode;


// === Read-only mode ===

node.set_read_only <+ self.model.frp.set_read_only;


// === Profiling ===

let profiling_min_duration = &self.model.profiling_statuses.min_duration;
Expand Down Expand Up @@ -2659,15 +2674,15 @@ impl application::View for GraphEditor {
fn default_shortcuts() -> Vec<application::shortcut::Shortcut> {
use shortcut::ActionType::*;
[
(Press, "!node_editing", "tab", "start_node_creation"),
(Press, "!node_editing", "enter", "start_node_creation"),
(Press, "!node_editing & !read_only", "tab", "start_node_creation"),
(Press, "!node_editing & !read_only", "enter", "start_node_creation"),
// === Drag ===
(Press, "", "left-mouse-button", "node_press"),
(Release, "", "left-mouse-button", "node_release"),
(Press, "!node_editing", "backspace", "remove_selected_nodes"),
(Press, "!node_editing", "delete", "remove_selected_nodes"),
(Press, "!node_editing & !read_only", "backspace", "remove_selected_nodes"),
(Press, "!node_editing & !read_only", "delete", "remove_selected_nodes"),
(Press, "has_detached_edge", "escape", "drop_dragged_edge"),
(Press, "", "cmd g", "collapse_selected_nodes"),
(Press, "!read_only", "cmd g", "collapse_selected_nodes"),
// === Visualization ===
(Press, "!node_editing", "space", "press_visualization_visibility"),
(DoublePress, "!node_editing", "space", "double_press_visualization_visibility"),
Expand All @@ -2694,17 +2709,17 @@ impl application::View for GraphEditor {
"ctrl space",
"cycle_visualization_for_selected_node",
),
(DoublePress, "", "left-mouse-button", "enter_hovered_node"),
(DoublePress, "", "left-mouse-button", "start_node_creation_from_port"),
(Press, "", "right-mouse-button", "start_node_creation_from_port"),
(Press, "!node_editing", "cmd enter", "enter_selected_node"),
(Press, "", "alt enter", "exit_node"),
(DoublePress, "!read_only", "left-mouse-button", "enter_hovered_node"),
(DoublePress, "!read_only", "left-mouse-button", "start_node_creation_from_port"),
(Press, "!read_only", "right-mouse-button", "start_node_creation_from_port"),
(Press, "!node_editing & !read_only", "cmd enter", "enter_selected_node"),
(Press, "!read_only", "alt enter", "exit_node"),
// === Node Editing ===
(Press, "", "cmd", "edit_mode_on"),
(Release, "", "cmd", "edit_mode_off"),
(Press, "", "cmd left-mouse-button", "edit_mode_on"),
(Release, "", "cmd left-mouse-button", "edit_mode_off"),
(Press, "node_editing", "cmd enter", "stop_editing"),
(Press, "!read_only", "cmd", "edit_mode_on"),
(Release, "!read_only", "cmd", "edit_mode_off"),
(Press, "!read_only", "cmd left-mouse-button", "edit_mode_on"),
(Release, "!read_only", "cmd left-mouse-button", "edit_mode_off"),
(Press, "node_editing & !read_only", "cmd enter", "stop_editing"),
// === Profiling Mode ===
(Press, "", "cmd p", "toggle_profiling_mode"),
// === Debug ===
Expand Down Expand Up @@ -2761,6 +2776,23 @@ fn new_graph_editor(app: &Application) -> GraphEditor {
let out = &frp.private.output;
let selection_controller = &model.selection_controller;



// ======================
// === Read-only mode ===
// ======================

frp::extend! { network
out.read_only <+ inputs.set_read_only;
model.breadcrumbs.set_read_only <+ inputs.set_read_only;

// Drop the currently dragged edge if read-only mode is enabled.
read_only_enabled <- inputs.set_read_only.on_true();
inputs.drop_dragged_edge <+ read_only_enabled;
}



// ========================
// === Scene Navigation ===
// ========================
Expand Down Expand Up @@ -2928,7 +2960,7 @@ fn new_graph_editor(app: &Application) -> GraphEditor {
}
});
edge_click <- map2(&edge_mouse_down,&cursor_pos_in_scene,|edge_id,pos|(*edge_id,*pos));
valid_edge_disconnect_click <- edge_click.gate_not(&has_detached_edge);
valid_edge_disconnect_click <- edge_click.gate_not(&has_detached_edge).gate_not(&inputs.set_read_only);

edge_is_source_click <- valid_edge_disconnect_click.map(f!([model]((edge_id,pos)) {
if let Some(edge) = model.edges.get_cloned_ref(edge_id){
Expand Down Expand Up @@ -2963,8 +2995,8 @@ fn new_graph_editor(app: &Application) -> GraphEditor {
attach_all_edge_inputs <- any (port_input_mouse_up, inputs.press_node_input, inputs.set_detached_edge_targets);
attach_all_edge_outputs <- any (port_output_mouse_up, inputs.press_node_output, inputs.set_detached_edge_sources);

create_edge_from_output <- node_output_touch.down.gate_not(&has_detached_edge_on_output_down);
create_edge_from_input <- node_input_touch.down.map(|value| value.clone());
create_edge_from_output <- node_output_touch.down.gate_not(&has_detached_edge_on_output_down).gate_not(&inputs.set_read_only);
create_edge_from_input <- node_input_touch.down.map(|value| value.clone()).gate_not(&inputs.set_read_only);

on_new_edge <- any(&output_down,&input_down);
let selection_mode = selection::get_mode(network,inputs);
Expand Down Expand Up @@ -3043,7 +3075,7 @@ fn new_graph_editor(app: &Application) -> GraphEditor {
// === Adding Node ===

frp::extend! { network
let node_added_with_button = model.add_node_button.clicked.clone_ref();
node_added_with_button <- model.add_node_button.clicked.gate_not(&inputs.set_read_only);

input_start_node_creation_from_port <- inputs.hover_node_output.sample(
&inputs.start_node_creation_from_port);
Expand Down
Loading

0 comments on commit 719bd8c

Please sign in to comment.