Debug Mode for Graph Editor (#3264)

This commit is contained in:
Ilya Bogdanov 2022-02-14 13:19:08 +03:00 committed by GitHub
parent 585afd83ce
commit 03e105d42e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 280 additions and 8 deletions

View File

@ -2,6 +2,9 @@
#### Visual Environment
- [Debug Mode for Graph Editor can be activated/deactivated using a
shortcut.][3264] It allows access to a set of restricted features. See
[debug-shortcuts].
- [New nodes can be created by dragging and dropping a connection on the
scene.][3231]
- [Node connections can be dropped by pressing the Esc key while dragging
@ -36,6 +39,8 @@
`Table.use_first_row_as_names` operations][3249]
- [Implemented `Text.at` and `Text.is_digit` methods][3269]
[debug-shortcuts]:
https://github.com/enso-org/enso/blob/develop/app/gui/docs/product/shortcuts.md#debug
[3153]: https://github.com/enso-org/enso/pull/3153
[3166]: https://github.com/enso-org/enso/pull/3166
[3181]: https://github.com/enso-org/enso/pull/3181
@ -51,6 +56,7 @@
[3250]: https://github.com/enso-org/enso/pull/3250
[3256]: https://github.com/enso-org/enso/pull/3256
[3249]: https://github.com/enso-org/enso/pull/3249
[3264]: https://github.com/enso-org/enso/pull/3264
[3269]: https://github.com/enso-org/enso/pull/3269
#### Enso Compiler

View File

@ -120,6 +120,7 @@ broken and require further investigation.
| 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. |
| <kbd>ctrl</kbd> + <kbd>alt</kbd> + <kbd>0 - 10</kbd> | Switch between debug rendering modes (0 is the normal mode). |

View File

@ -485,6 +485,9 @@ ensogl::define_endpoints! {
// === Debug ===
/// Enable or disable debug-only features.
set_debug_mode(bool),
/// Push a hardcoded breadcrumb without notifying the controller.
debug_push_breadcrumb(),
/// Pop a breadcrumb without notifying the controller.
@ -542,6 +545,9 @@ ensogl::define_endpoints! {
}
Output {
// === Debug Mode ===
debug_mode (bool),
// === Edge ===
@ -3374,6 +3380,16 @@ fn new_graph_editor(app: &Application) -> GraphEditor {
frp.source.default_y_gap_between_nodes.emit(default_y_gap.value());
frp.source.min_x_spacing_for_new_nodes.emit(min_x_spacing.value());
// ==================
// === Debug Mode ===
// ==================
frp::extend! { network
out.source.debug_mode <+ frp.set_debug_mode;
}
// Init defaults
frp.edit_mode_off.emit(());

View File

@ -0,0 +1,206 @@
//! Text message on top of the screen that signals about enabling/disabling Debug Mode of Graph
//! Editor.
use crate::prelude::*;
use enso_frp as frp;
use ensogl::animation::delayed::DelayedAnimation;
use ensogl::application::Application;
use ensogl::display;
use ensogl::display::scene::Scene;
use ensogl::display::shape::*;
use ensogl::Animation;
use ensogl_component::label::Label;
// =================
// === Constants ===
// =================
/// Mitigate limitations of constant strings concatenation.
macro_rules! define_debug_mode_shortcut {
($shortcut:literal) => {
/// A keyboard shortcut used to enable/disable Debug Mode.
pub const DEBUG_MODE_SHORTCUT: &str = $shortcut;
const DEBUG_MODE_ENABLED: &str =
concat!("Debug Mode enabled. To disable, press `", $shortcut, "`.");
};
}
define_debug_mode_shortcut!("ctrl shift d");
const DEBUG_MODE_DISABLED: &str = "Debug Mode disabled.";
const LABEL_VISIBILITY_DELAY_MS: f32 = 3_000.0;
const LABEL_PADDING_TOP: f32 = 50.0;
// ==================
// === PopupLabel ===
// ==================
/// Text label that disappears after a predefined delay.
#[derive(Debug, Clone, CloneRef)]
struct PopupLabel {
label: Label,
network: frp::Network,
delay_animation: DelayedAnimation,
show: frp::Source<String>,
}
impl display::Object for PopupLabel {
fn display_object(&self) -> &display::object::Instance<Scene> {
self.label.display_object()
}
}
impl PopupLabel {
/// Constructor.
pub fn new(app: &Application) -> Self {
let network = frp::Network::new("PopupLabel");
let label = Label::new(app);
label.set_opacity(0.0);
let background_layer = &app.display.scene().layers.panel;
let text_layer = &app.display.scene().layers.panel_text;
label.set_layers(background_layer, text_layer);
let opacity_animation = Animation::new(&network);
network.store(&opacity_animation);
let delay_animation = DelayedAnimation::new(&network);
delay_animation.set_delay(0.0);
delay_animation.set_duration(0.0);
network.store(&delay_animation);
frp::extend! { network
show <- source::<String>();
eval show ([label, delay_animation](text) {
label.set_content(text);
delay_animation.reset();
delay_animation.start();
});
opacity_animation.target <+ show.constant(1.0);
opacity_animation.target <+ delay_animation.on_end.constant(0.0);
label.set_opacity <+ opacity_animation.value;
}
Self { label, network, show, delay_animation }
}
/// Set a delay in milliseconds after which the label will disappear.
pub fn set_delay(&self, delay: f32) {
self.delay_animation.set_delay(delay);
}
}
// =============
// === Model ===
// =============
#[derive(Debug, Clone, CloneRef)]
struct Model {
display_object: display::object::Instance,
label: PopupLabel,
logger: Logger,
}
impl Model {
/// Constructor.
pub fn new(app: &Application) -> Self {
let logger = Logger::new("DebugModePopup");
let display_object = display::object::Instance::new(&logger);
let label = PopupLabel::new(app);
label.set_delay(LABEL_VISIBILITY_DELAY_MS);
display_object.add_child(&label);
Self { display_object, label, logger }
}
/// Show "Debug Mode enabled" label.
pub fn show_enabled_label(&self) {
self.label.show.emit(String::from(DEBUG_MODE_ENABLED));
}
/// Show "Debug Mode disabled" label.
pub fn show_disabled_label(&self) {
self.label.show.emit(String::from(DEBUG_MODE_DISABLED));
}
/// Return the height of the label.
pub fn label_height(&self) -> f32 {
self.label.label.size.value().y
}
}
// ===========
// === FRP ===
// ===========
ensogl::define_endpoints! {
Input {
// Debug Mode was enabled.
enabled(),
// Debug Mode was disabled.
disabled(),
}
Output {}
}
// ============
// === View ===
// ============
/// Text message on top of the screen that signals about enabling/disabling Debug Mode of Graph
/// Editor.
#[derive(Debug, Clone, CloneRef)]
pub struct View {
frp: Frp,
model: Model,
}
impl View {
/// Constructor.
pub fn new(app: &Application) -> Self {
let frp = Frp::new();
let model = Model::new(app);
let network = &frp.network;
frp::extend! { network
init <- source_();
let shape = app.display.scene().shape();
_eval <- all_with(shape, &init, f!([model](scene_size, _init) {
let half_height = scene_size.height / 2.0;
let label_height = model.label_height();
let pos_y = half_height - LABEL_PADDING_TOP - label_height / 2.0;
model.display_object.set_position_y(pos_y);
}));
eval_ frp.enabled(model.show_enabled_label());
eval_ frp.disabled(model.show_disabled_label());
}
init.emit(());
Self { frp, model }
}
}
impl display::Object for View {
fn display_object(&self) -> &display::object::Instance<Scene> {
&self.model.display_object
}
}
impl Deref for View {
type Target = Frp;
fn deref(&self) -> &Self::Target {
&self.frp
}
}

View File

@ -26,6 +26,7 @@
#[allow(clippy::option_map_unit_fn)]
pub mod code_editor;
pub mod debug_mode_popup;
pub mod documentation;
pub mod open_dialog;
pub mod project;

View File

@ -3,6 +3,8 @@
use crate::prelude::*;
use crate::code_editor;
use crate::debug_mode_popup;
use crate::debug_mode_popup::DEBUG_MODE_SHORTCUT;
use crate::graph_editor::component::node;
use crate::graph_editor::component::node::Expression;
use crate::graph_editor::component::visualization;
@ -92,6 +94,10 @@ ensogl::define_endpoints! {
show_prompt(),
/// Disable the prompt. It will be hidden if currently visible.
disable_prompt(),
// Enable Debug Mode of Graph Editor.
enable_debug_mode(),
// Disable Debug Mode of Graph Editor.
disable_debug_mode(),
}
Output {
@ -106,6 +112,7 @@ ensogl::define_endpoints! {
style (Theme),
fullscreen_visualization_shown (bool),
drop_files_enabled (bool),
debug_mode (bool),
}
}
@ -153,6 +160,7 @@ struct Model {
prompt_background: prompt_background::View,
prompt: ensogl_text::Area,
open_dialog: Rc<OpenDialog>,
debug_mode_popup: debug_mode_popup::View,
}
impl Model {
@ -166,6 +174,7 @@ impl Model {
let fullscreen_vis = default();
let prompt_background = prompt_background::View::new(&logger);
let prompt = ensogl_text::Area::new(app);
let debug_mode_popup = debug_mode_popup::View::new(app);
let window_control_buttons = ARGS.is_in_cloud.unwrap_or_default().as_some_from(|| {
let window_control_buttons = app.new_view::<crate::window_control_buttons::View>();
display_object.add_child(&window_control_buttons);
@ -174,6 +183,7 @@ impl Model {
});
let window_control_buttons = Immutable(window_control_buttons);
let open_dialog = Rc::new(OpenDialog::new(app));
prompt_background.add_child(&prompt);
prompt.set_content("Press the tab key to search for components.");
scene.layers.panel.add_exclusive(&prompt_background);
@ -184,6 +194,7 @@ impl Model {
display_object.add_child(&code_editor);
display_object.add_child(&searcher);
display_object.add_child(&prompt_background);
display_object.add_child(&debug_mode_popup);
display_object.remove_child(&searcher);
let app = app.clone_ref();
@ -200,6 +211,7 @@ impl Model {
prompt_background,
prompt,
open_dialog,
debug_mode_popup,
}
}
@ -625,6 +637,14 @@ impl View {
frp.source.drop_files_enabled <+ init.constant(true);
frp.source.drop_files_enabled <+ frp.open_dialog_shown.map(|v| !v);
// === Debug Mode ===
frp.source.debug_mode <+ bool(&frp.disable_debug_mode, &frp.enable_debug_mode);
graph.set_debug_mode <+ frp.source.debug_mode;
model.debug_mode_popup.enabled <+ frp.enable_debug_mode;
model.debug_mode_popup.disabled <+ frp.disable_debug_mode;
}
init.emit(());
std::mem::forget(prompt_visibility);
@ -697,6 +717,8 @@ impl application::View for View {
(Press, "", "cmd s", "save_module"),
(Press, "", "cmd z", "undo"),
(Press, "", "cmd y", "redo"),
(Press, "!debug_mode", DEBUG_MODE_SHORTCUT, "enable_debug_mode"),
(Press, "debug_mode", DEBUG_MODE_SHORTCUT, "disable_debug_mode"),
])
.iter()
.map(|(a, b, c, d)| Self::self_shortcut_when(*a, *c, *d, *b))

View File

@ -18,6 +18,7 @@ use enso_frp as frp;
use ensogl_core::application::Application;
use ensogl_core::data::color;
use ensogl_core::display;
use ensogl_core::display::scene::Layer;
use ensogl_core::display::shape::*;
use ensogl_shadow as shadow;
use ensogl_text as text;
@ -91,25 +92,29 @@ impl Model {
let label = app.new_view::<text::Area>();
let background = background::View::new(&logger);
// FIXME[MM/WD]: Depth sorting of labels to in front of everything else in the scene.
// Temporary solution. The depth management needs to allow defining relative position of
// the text and background and let the whole component to be set to am an arbitrary layer.
label.remove_from_scene_layer(&scene.layers.main);
label.add_to_scene_layer(&scene.layers.tooltip_text);
scene.layers.tooltip.add_exclusive(&background);
display_object.add_child(&background);
display_object.add_child(&label);
let style = StyleWatch::new(&app.display.scene().style_sheet);
Model { background, label, display_object, style }
let model = Model { background, label, display_object, style };
model.set_layers(&scene.layers.tooltip, &scene.layers.tooltip_text);
model
}
pub fn height(&self) -> f32 {
self.style.get_number(theme::height)
}
/// Set scene layers for background and text respectively.
pub fn set_layers(&self, background_layer: &Layer, text_layer: &Layer) {
// FIXME[MM/WD]: Depth sorting of labels to in front of everything else in the scene.
// Temporary solution. The depth management needs to allow defining relative position of
// the text and background and let the whole component to be set to am an arbitrary layer.
background_layer.add_exclusive(&self.background);
self.label.add_to_scene_layer(text_layer);
}
fn set_width(&self, width: f32) -> Vector2 {
let padding_outer = self.style.get_number(theme::padding_outer);
let padding_inner_x = self.style.get_number(theme::padding_inner_x);
@ -166,6 +171,13 @@ impl Label {
Label { model, frp }.init()
}
/// Set layers for Label's background and text respectively. This is needed because
/// `text::Area` uses its own `add_to_scene_layer` method instead of utilizing more common
/// [`Layer::add_exclusive`].
pub fn set_layers(&self, background_layer: &Layer, text_layer: &Layer) {
self.model.set_layers(background_layer, text_layer);
}
fn init(self) -> Self {
let frp = &self.frp;
let network = &frp.network;
@ -183,6 +195,14 @@ impl Label {
}
}
impl Deref for Label {
type Target = Frp;
fn deref(&self) -> &Self::Target {
&self.frp
}
}
impl display::Object for Label {
fn display_object(&self) -> &display::object::Instance {
&self.model.display_object