mirror of
https://github.com/enso-org/enso.git
synced 2024-12-23 21:12:44 +03:00
Debug Mode for Graph Editor (#3264)
This commit is contained in:
parent
585afd83ce
commit
03e105d42e
@ -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
|
||||
|
@ -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). |
|
||||
|
@ -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(());
|
||||
|
||||
|
206
app/gui/view/src/debug_mode_popup.rs
Normal file
206
app/gui/view/src/debug_mode_popup.rs
Normal 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
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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))
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user