mirror of
https://github.com/enso-org/enso.git
synced 2024-12-23 21:12:44 +03:00
A drop-down that allows changing the execution mode. (#6130)
Implements https://github.com/enso-org/enso/issues/5931. https://user-images.githubusercontent.com/1428930/228532453-2032b376-1aa5-4140-8331-be37e4e675d4.mp4 # Important Notes Not functional yet, as it needs integration with the engine.
This commit is contained in:
parent
e5a96b9782
commit
64043323e8
@ -126,6 +126,8 @@
|
|||||||
shortened labels for entries with long module paths. When an option is
|
shortened labels for entries with long module paths. When an option is
|
||||||
selected from the dropdown, the necessary module imports are inserted,
|
selected from the dropdown, the necessary module imports are inserted,
|
||||||
eliminating the need for fully qualified names.
|
eliminating the need for fully qualified names.
|
||||||
|
- [The IDE now has a new UI element for selecting the execution mode of the
|
||||||
|
project][6130].
|
||||||
- [Added tooltips to icon buttons][6035] for improved usability. Users can now
|
- [Added tooltips to icon buttons][6035] for improved usability. Users can now
|
||||||
quickly understand each button's function.
|
quickly understand each button's function.
|
||||||
- [File associations are created on Windows and macOS][6077]. This allows
|
- [File associations are created on Windows and macOS][6077]. This allows
|
||||||
@ -189,6 +191,7 @@
|
|||||||
[4047]: https://github.com/enso-org/enso/pull/4047
|
[4047]: https://github.com/enso-org/enso/pull/4047
|
||||||
[4003]: https://github.com/enso-org/enso/pull/4003
|
[4003]: https://github.com/enso-org/enso/pull/4003
|
||||||
[5895]: https://github.com/enso-org/enso/pull/5895
|
[5895]: https://github.com/enso-org/enso/pull/5895
|
||||||
|
[5895]: https://github.com/enso-org/enso/pull/6130
|
||||||
[6035]: https://github.com/enso-org/enso/pull/6035
|
[6035]: https://github.com/enso-org/enso/pull/6035
|
||||||
[6097]: https://github.com/enso-org/enso/pull/6097
|
[6097]: https://github.com/enso-org/enso/pull/6097
|
||||||
|
|
||||||
|
30
Cargo.lock
generated
30
Cargo.lock
generated
@ -1613,6 +1613,18 @@ dependencies = [
|
|||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "debug-scene-execution-mode-dropdown"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"ensogl",
|
||||||
|
"ensogl-drop-down-menu",
|
||||||
|
"ensogl-hardcoded-theme",
|
||||||
|
"ensogl-list-view",
|
||||||
|
"ensogl-text-msdf",
|
||||||
|
"ide-view-execution-mode-selector",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "debug-scene-icons"
|
name = "debug-scene-icons"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@ -1635,6 +1647,7 @@ dependencies = [
|
|||||||
"ensogl-hardcoded-theme",
|
"ensogl-hardcoded-theme",
|
||||||
"ensogl-text-msdf",
|
"ensogl-text-msdf",
|
||||||
"ide-view",
|
"ide-view",
|
||||||
|
"ide-view-execution-mode-selector",
|
||||||
"parser",
|
"parser",
|
||||||
"span-tree",
|
"span-tree",
|
||||||
"uuid 0.8.2",
|
"uuid 0.8.2",
|
||||||
@ -2096,6 +2109,7 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"debug-scene-component-list-panel-view",
|
"debug-scene-component-list-panel-view",
|
||||||
"debug-scene-documentation",
|
"debug-scene-documentation",
|
||||||
|
"debug-scene-execution-mode-dropdown",
|
||||||
"debug-scene-icons",
|
"debug-scene-icons",
|
||||||
"debug-scene-interface",
|
"debug-scene-interface",
|
||||||
"debug-scene-text-grid-visualization",
|
"debug-scene-text-grid-visualization",
|
||||||
@ -4273,6 +4287,7 @@ dependencies = [
|
|||||||
"ensogl-text-msdf",
|
"ensogl-text-msdf",
|
||||||
"ide-view-component-browser",
|
"ide-view-component-browser",
|
||||||
"ide-view-documentation",
|
"ide-view-documentation",
|
||||||
|
"ide-view-execution-mode-selector",
|
||||||
"ide-view-graph-editor",
|
"ide-view-graph-editor",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"multi-map",
|
"multi-map",
|
||||||
@ -4386,6 +4401,20 @@ dependencies = [
|
|||||||
"web-sys",
|
"web-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ide-view-execution-mode-selector"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"enso-frp",
|
||||||
|
"enso-prelude",
|
||||||
|
"ensogl",
|
||||||
|
"ensogl-derive-theme",
|
||||||
|
"ensogl-drop-down-menu",
|
||||||
|
"ensogl-gui-component",
|
||||||
|
"ensogl-hardcoded-theme",
|
||||||
|
"ensogl-list-view",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ide-view-graph-editor"
|
name = "ide-view-graph-editor"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@ -4406,6 +4435,7 @@ dependencies = [
|
|||||||
"ensogl-hardcoded-theme",
|
"ensogl-hardcoded-theme",
|
||||||
"ensogl-text-msdf",
|
"ensogl-text-msdf",
|
||||||
"failure",
|
"failure",
|
||||||
|
"ide-view-execution-mode-selector",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"nalgebra",
|
"nalgebra",
|
||||||
|
@ -379,10 +379,20 @@ impl Project {
|
|||||||
let graph_controller = self.model.graph_controller.clone_ref();
|
let graph_controller = self.model.graph_controller.clone_ref();
|
||||||
|
|
||||||
self.init_analytics()
|
self.init_analytics()
|
||||||
|
.init_execution_modes()
|
||||||
.setup_notification_handler()
|
.setup_notification_handler()
|
||||||
.attach_frp_to_values_computed_notifications(graph_controller, values_computed)
|
.attach_frp_to_values_computed_notifications(graph_controller, values_computed)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Initialises execution modes. Currently a dummy implementqation to be replaced during
|
||||||
|
/// implementation of #5930.
|
||||||
|
fn init_execution_modes(self) -> Self {
|
||||||
|
let graph = &self.model.view.graph();
|
||||||
|
let entries = Rc::new(vec!["development".to_string(), "production".to_string()]);
|
||||||
|
graph.set_available_execution_modes(entries);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
fn init_analytics(self) -> Self {
|
fn init_analytics(self) -> Self {
|
||||||
let network = &self.network;
|
let network = &self.network;
|
||||||
let project = &self.model.view;
|
let project = &self.model.view;
|
||||||
|
@ -23,6 +23,7 @@ ensogl-text = { path = "../../../lib/rust/ensogl/component/text" }
|
|||||||
ensogl-text-msdf = { path = "../../../lib/rust/ensogl/component/text/src/font/msdf" }
|
ensogl-text-msdf = { path = "../../../lib/rust/ensogl/component/text/src/font/msdf" }
|
||||||
ensogl-hardcoded-theme = { path = "../../../lib/rust/ensogl/app/theme/hardcoded" }
|
ensogl-hardcoded-theme = { path = "../../../lib/rust/ensogl/app/theme/hardcoded" }
|
||||||
ide-view-component-browser = { path = "component-browser" }
|
ide-view-component-browser = { path = "component-browser" }
|
||||||
|
ide-view-execution-mode-selector = { path = "execution-mode-selector" }
|
||||||
ide-view-documentation = { path = "documentation" }
|
ide-view-documentation = { path = "documentation" }
|
||||||
ide-view-graph-editor = { path = "graph-editor" }
|
ide-view-graph-editor = { path = "graph-editor" }
|
||||||
span-tree = { path = "../language/span-tree" }
|
span-tree = { path = "../language/span-tree" }
|
||||||
|
@ -14,6 +14,7 @@ debug-scene-icons = { path = "icons" }
|
|||||||
debug-scene-interface = { path = "interface" }
|
debug-scene-interface = { path = "interface" }
|
||||||
debug-scene-text-grid-visualization = { path = "text-grid-visualization" }
|
debug-scene-text-grid-visualization = { path = "text-grid-visualization" }
|
||||||
debug-scene-visualization = { path = "visualization" }
|
debug-scene-visualization = { path = "visualization" }
|
||||||
|
debug-scene-execution-mode-dropdown = { path = "execution-mode-dropdown" }
|
||||||
|
|
||||||
# Stop wasm-pack from running wasm-opt, because we run it from our build scripts in order to customize options.
|
# Stop wasm-pack from running wasm-opt, because we run it from our build scripts in order to customize options.
|
||||||
[package.metadata.wasm-pack.profile.release]
|
[package.metadata.wasm-pack.profile.release]
|
||||||
|
16
app/gui/view/examples/execution-mode-dropdown/Cargo.toml
Normal file
16
app/gui/view/examples/execution-mode-dropdown/Cargo.toml
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
[package]
|
||||||
|
name = "debug-scene-execution-mode-dropdown"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Enso Team <contact@enso.org>"]
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
crate-type = ["cdylib", "rlib"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
ensogl = { path = "../../../../../lib/rust/ensogl" }
|
||||||
|
ensogl-drop-down-menu = { path = "../../../../../lib/rust/ensogl/component/drop-down-menu" }
|
||||||
|
ensogl-list-view = { path = "../../../../../lib/rust/ensogl/component/list-view" }
|
||||||
|
ensogl-hardcoded-theme = { path = "../../../../../lib/rust/ensogl/app/theme/hardcoded" }
|
||||||
|
ensogl-text-msdf = { path = "../../../../../lib/rust/ensogl/component/text/src/font/msdf" }
|
||||||
|
ide-view-execution-mode-selector = { path = "../../execution-mode-selector" }
|
66
app/gui/view/examples/execution-mode-dropdown/src/lib.rs
Normal file
66
app/gui/view/examples/execution-mode-dropdown/src/lib.rs
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
//! This is a visualization example scene which creates a sinusoidal graph.
|
||||||
|
|
||||||
|
// === Standard Linter Configuration ===
|
||||||
|
#![deny(non_ascii_idents)]
|
||||||
|
#![warn(unsafe_code)]
|
||||||
|
#![allow(clippy::bool_to_int_with_if)]
|
||||||
|
#![allow(clippy::let_and_return)]
|
||||||
|
// === Non-Standard Linter Configuration ===
|
||||||
|
#![warn(missing_copy_implementations)]
|
||||||
|
#![warn(missing_debug_implementations)]
|
||||||
|
#![warn(missing_docs)]
|
||||||
|
#![warn(trivial_casts)]
|
||||||
|
#![warn(trivial_numeric_casts)]
|
||||||
|
#![warn(unused_import_braces)]
|
||||||
|
#![warn(unused_qualifications)]
|
||||||
|
|
||||||
|
use ensogl::prelude::*;
|
||||||
|
|
||||||
|
use ensogl::animation;
|
||||||
|
use ensogl::application::Application;
|
||||||
|
use ensogl_text_msdf::run_once_initialized;
|
||||||
|
use ide_view_execution_mode_selector as execution_mode_selector;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// ======================
|
||||||
|
// === Initialisation ===
|
||||||
|
// ======================
|
||||||
|
|
||||||
|
fn make_entries() -> execution_mode_selector::ExecutionModes {
|
||||||
|
Rc::new(vec!["development".to_string(), "production".to_string()])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init(app: &Application) {
|
||||||
|
let app = app.clone_ref();
|
||||||
|
let world = &app.display;
|
||||||
|
let _scene = &world.default_scene;
|
||||||
|
|
||||||
|
let execution_mode_selector = execution_mode_selector::ExecutionModeSelector::new(&app);
|
||||||
|
world.add_child(&execution_mode_selector);
|
||||||
|
execution_mode_selector.set_available_execution_modes(make_entries());
|
||||||
|
|
||||||
|
world
|
||||||
|
.on
|
||||||
|
.before_frame
|
||||||
|
.add(move |_time_info: animation::TimeInfo| {
|
||||||
|
let _keep_alive = &execution_mode_selector;
|
||||||
|
})
|
||||||
|
.forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ===================
|
||||||
|
// === Entry Point ===
|
||||||
|
// ===================
|
||||||
|
|
||||||
|
/// Entry point for the demo scene.
|
||||||
|
#[entry_point]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn main() {
|
||||||
|
run_once_initialized(|| {
|
||||||
|
let app = Application::new("root");
|
||||||
|
init(&app);
|
||||||
|
mem::forget(app);
|
||||||
|
});
|
||||||
|
}
|
@ -9,12 +9,13 @@ crate-type = ["cdylib", "rlib"]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ast = { path = "../../../language/ast/impl" }
|
ast = { path = "../../../language/ast/impl" }
|
||||||
parser = { path = "../../../language/parser" }
|
|
||||||
enso-frp = { path = "../../../../../lib/rust/frp" }
|
enso-frp = { path = "../../../../../lib/rust/frp" }
|
||||||
ensogl = { path = "../../../../../lib/rust/ensogl" }
|
ensogl = { path = "../../../../../lib/rust/ensogl" }
|
||||||
ensogl-hardcoded-theme = { path = "../../../../../lib/rust/ensogl/app/theme/hardcoded" }
|
ensogl-hardcoded-theme = { path = "../../../../../lib/rust/ensogl/app/theme/hardcoded" }
|
||||||
ensogl-text-msdf = { path = "../../../../../lib/rust/ensogl/component/text/src/font/msdf" }
|
ensogl-text-msdf = { path = "../../../../../lib/rust/ensogl/component/text/src/font/msdf" }
|
||||||
ide-view = { path = "../.." }
|
ide-view = { path = "../.." }
|
||||||
|
ide-view-execution-mode-selector = { path = "../../execution-mode-selector" }
|
||||||
|
parser = { path = "../../../language/parser" }
|
||||||
span-tree = { path = "../../../language/span-tree" }
|
span-tree = { path = "../../../language/span-tree" }
|
||||||
uuid = { version = "0.8", features = ["v4", "wasm-bindgen"] }
|
uuid = { version = "0.8", features = ["v4", "wasm-bindgen"] }
|
||||||
wasm-bindgen = { workspace = true }
|
wasm-bindgen = { workspace = true }
|
||||||
|
@ -254,6 +254,14 @@ fn init(app: &Application) {
|
|||||||
graph_editor.set_node_profiling_status(node3_id, node3_status);
|
graph_editor.set_node_profiling_status(node3_id, node3_status);
|
||||||
|
|
||||||
|
|
||||||
|
// === Execution Modes ===
|
||||||
|
|
||||||
|
graph_editor
|
||||||
|
.set_available_execution_modes(vec!["development".to_string(), "production".to_string()]);
|
||||||
|
|
||||||
|
|
||||||
|
// === Rendering ===
|
||||||
|
|
||||||
// let tgt_type = dummy_type_generator.get_dummy_type();
|
// let tgt_type = dummy_type_generator.get_dummy_type();
|
||||||
let mut was_rendered = false;
|
let mut was_rendered = false;
|
||||||
let mut loader_hidden = false;
|
let mut loader_hidden = false;
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
pub use debug_scene_component_list_panel_view as new_component_list_panel_view;
|
pub use debug_scene_component_list_panel_view as new_component_list_panel_view;
|
||||||
pub use debug_scene_documentation as documentation;
|
pub use debug_scene_documentation as documentation;
|
||||||
|
pub use debug_scene_execution_mode_dropdown as execution_mode_dropdown;
|
||||||
pub use debug_scene_icons as icons;
|
pub use debug_scene_icons as icons;
|
||||||
pub use debug_scene_interface as interface;
|
pub use debug_scene_interface as interface;
|
||||||
pub use debug_scene_text_grid_visualization as text_grid_visualization;
|
pub use debug_scene_text_grid_visualization as text_grid_visualization;
|
||||||
|
18
app/gui/view/execution-mode-selector/Cargo.toml
Normal file
18
app/gui/view/execution-mode-selector/Cargo.toml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
[package]
|
||||||
|
name = "ide-view-execution-mode-selector"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Enso Team <contact@enso.org>"]
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
crate-type = ["cdylib", "rlib"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
enso-frp = { path = "../../../../lib/rust/frp" }
|
||||||
|
enso-prelude = { path = "../../../../lib/rust/prelude" }
|
||||||
|
ensogl = { path = "../../../../lib/rust/ensogl" }
|
||||||
|
ensogl-derive-theme = { path = "../../../../lib/rust/ensogl/app/theme/derive" }
|
||||||
|
ensogl-drop-down-menu = { path = "../../../../lib/rust/ensogl/component/drop-down-menu" }
|
||||||
|
ensogl-gui-component = { path = "../../../../lib/rust/ensogl/component/gui" }
|
||||||
|
ensogl-hardcoded-theme = { path = "../../../../lib/rust/ensogl/app/theme/hardcoded" }
|
||||||
|
ensogl-list-view = { path = "../../../../lib/rust/ensogl/component/list-view" }
|
274
app/gui/view/execution-mode-selector/src/lib.rs
Normal file
274
app/gui/view/execution-mode-selector/src/lib.rs
Normal file
@ -0,0 +1,274 @@
|
|||||||
|
//! UI component that allows selecting a execution mode.
|
||||||
|
|
||||||
|
#![recursion_limit = "512"]
|
||||||
|
// === Features ===
|
||||||
|
#![feature(option_result_contains)]
|
||||||
|
#![feature(trait_alias)]
|
||||||
|
// === Standard Linter Configuration ===
|
||||||
|
#![deny(non_ascii_idents)]
|
||||||
|
#![warn(unsafe_code)]
|
||||||
|
#![allow(clippy::bool_to_int_with_if)]
|
||||||
|
#![allow(clippy::let_and_return)]
|
||||||
|
// === Non-Standard Linter Configuration ===
|
||||||
|
#![warn(missing_copy_implementations)]
|
||||||
|
#![warn(missing_debug_implementations)]
|
||||||
|
#![warn(missing_docs)]
|
||||||
|
#![warn(trivial_casts)]
|
||||||
|
#![warn(trivial_numeric_casts)]
|
||||||
|
#![warn(unused_import_braces)]
|
||||||
|
#![warn(unused_qualifications)]
|
||||||
|
|
||||||
|
use enso_prelude::*;
|
||||||
|
use ensogl::prelude::*;
|
||||||
|
|
||||||
|
use enso_frp as frp;
|
||||||
|
use ensogl::application::Application;
|
||||||
|
use ensogl::data::color::Rgba;
|
||||||
|
use ensogl::display;
|
||||||
|
use ensogl::display::camera::Camera2d;
|
||||||
|
use ensogl::display::shape::StyleWatchFrp;
|
||||||
|
use ensogl_derive_theme::FromTheme;
|
||||||
|
use ensogl_gui_component::component;
|
||||||
|
use ensogl_hardcoded_theme::graph_editor::execution_mode_selector as theme;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// =============
|
||||||
|
// === Style ===
|
||||||
|
// ==============
|
||||||
|
|
||||||
|
/// Theme specification for the execution mode selector.
|
||||||
|
#[derive(Debug, Clone, Copy, Default, FromTheme)]
|
||||||
|
#[base_path = "ensogl_hardcoded_theme::graph_editor::execution_mode_selector"]
|
||||||
|
pub struct Style {
|
||||||
|
play_button_size: f32,
|
||||||
|
play_button_offset: f32,
|
||||||
|
play_button_padding: f32,
|
||||||
|
divider_offset: f32,
|
||||||
|
divider_padding: f32,
|
||||||
|
dropdown_width: f32,
|
||||||
|
height: f32,
|
||||||
|
background: Rgba,
|
||||||
|
divider: Rgba,
|
||||||
|
menu_offset: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Style {
|
||||||
|
fn overall_width(&self) -> f32 {
|
||||||
|
self.dropdown_width
|
||||||
|
+ 2.0 * self.divider_padding
|
||||||
|
+ self.play_button_size
|
||||||
|
+ self.play_button_padding
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ==============
|
||||||
|
// === Shapes ===
|
||||||
|
// ==============
|
||||||
|
|
||||||
|
mod play_icon {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
use std::f32::consts::PI;
|
||||||
|
ensogl::shape! {
|
||||||
|
above = [display::shape::compound::rectangle::shape];
|
||||||
|
(style:Style) {
|
||||||
|
let triangle_size = style.get_number(theme::play_button_size);
|
||||||
|
let color = style.get_color(theme::triangle);
|
||||||
|
let triangle = Triangle(triangle_size, triangle_size).rotate((PI/2.0).radians());
|
||||||
|
let triangle = triangle.fill(color);
|
||||||
|
let bg_size = Var::canvas_size();
|
||||||
|
let bg = Rect(bg_size).fill(INVISIBLE_HOVER_COLOR);
|
||||||
|
(bg + triangle).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===========
|
||||||
|
// === FRP ===
|
||||||
|
// ===========
|
||||||
|
|
||||||
|
/// An identifier of a execution mode.
|
||||||
|
pub type ExecutionMode = String;
|
||||||
|
/// A list of execution modes.
|
||||||
|
pub type ExecutionModes = Rc<Vec<ExecutionMode>>;
|
||||||
|
|
||||||
|
ensogl::define_endpoints_2! {
|
||||||
|
Input {
|
||||||
|
set_available_execution_modes (ExecutionModes),
|
||||||
|
}
|
||||||
|
Output {
|
||||||
|
selected_execution_mode (ExecutionMode),
|
||||||
|
play_press(),
|
||||||
|
size (Vector2),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// =============
|
||||||
|
// === Model ===
|
||||||
|
// =============
|
||||||
|
|
||||||
|
/// The model of the execution mode selector.
|
||||||
|
#[derive(Debug, Clone, CloneRef)]
|
||||||
|
pub struct Model {
|
||||||
|
/// Main root object for the execution mode selector exposed for external positioning.
|
||||||
|
display_object: display::object::Instance,
|
||||||
|
/// Inner root that will be used for positioning the execution mode selector relative to the
|
||||||
|
/// window
|
||||||
|
inner_root: display::object::Instance,
|
||||||
|
background: display::shape::compound::rectangle::Rectangle,
|
||||||
|
divider: display::shape::compound::rectangle::Rectangle,
|
||||||
|
play_icon: play_icon::View,
|
||||||
|
dropdown: ensogl_drop_down_menu::DropDownMenu,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Model {
|
||||||
|
fn update_dropdown_style(&self, style: &Style) {
|
||||||
|
self.dropdown.set_menu_offset_y(style.menu_offset);
|
||||||
|
self.dropdown.set_x(style.overall_width() / 2.0 - style.divider_offset);
|
||||||
|
self.dropdown.set_label_color(Rgba::white());
|
||||||
|
self.dropdown.set_icon_size(Vector2::new(1.0, 1.0));
|
||||||
|
self.dropdown.set_menu_alignment(ensogl_drop_down_menu::Alignment::Right);
|
||||||
|
self.dropdown.set_label_alignment(ensogl_drop_down_menu::Alignment::Left);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_background_style(&self, style: &Style) {
|
||||||
|
let width = style.overall_width();
|
||||||
|
let Style { height, background, .. } = *style;
|
||||||
|
let size = Vector2::new(width, height);
|
||||||
|
self.background.set_size(size);
|
||||||
|
self.background.set_xy(-size / 2.0);
|
||||||
|
self.background.set_corner_radius(height / 2.0);
|
||||||
|
self.background.set_color(background);
|
||||||
|
|
||||||
|
self.divider.set_size(Vector2::new(1.0, height));
|
||||||
|
self.divider.set_xy(Vector2::new(width / 2.0 - style.divider_offset, -height / 2.0));
|
||||||
|
self.divider.set_color(style.divider);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_play_icon_style(&self, style: &Style) {
|
||||||
|
let width = style.overall_width();
|
||||||
|
let size = Vector2::new(style.play_button_size + style.play_button_padding, style.height);
|
||||||
|
self.play_icon.set_size(size);
|
||||||
|
self.play_icon.set_x(width / 2.0 - style.play_button_offset - size.x / 2.0);
|
||||||
|
self.play_icon.set_y(-size.y / 2.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_position(&self, style: &Style, camera: &Camera2d) {
|
||||||
|
let screen = camera.screen();
|
||||||
|
let x = -screen.width / 2.0 + style.overall_width() / 2.0;
|
||||||
|
let y = screen.height / 2.0 - style.height / 2.0;
|
||||||
|
self.inner_root.set_x(x.round());
|
||||||
|
self.inner_root.set_y(y.round());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_entries(&self, entries: Rc<Vec<ExecutionMode>>) {
|
||||||
|
let provider = ensogl_list_view::entry::AnyModelProvider::from(entries.clone_ref());
|
||||||
|
self.dropdown.set_entries(provider);
|
||||||
|
self.dropdown.set_selected(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl display::Object for Model {
|
||||||
|
fn display_object(&self) -> &display::object::Instance {
|
||||||
|
&self.display_object
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// =============================
|
||||||
|
// === ExecutionModeDropdown ===
|
||||||
|
// =============================
|
||||||
|
|
||||||
|
impl component::Model for Model {
|
||||||
|
fn label() -> &'static str {
|
||||||
|
"ExecutionModeDropdown"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new(app: &Application) -> Self {
|
||||||
|
let scene = &app.display.default_scene;
|
||||||
|
|
||||||
|
let display_object = display::object::Instance::new();
|
||||||
|
let inner_root = display::object::Instance::new();
|
||||||
|
let background = default();
|
||||||
|
let divider = default();
|
||||||
|
let play_icon = play_icon::View::new();
|
||||||
|
let dropdown = ensogl_drop_down_menu::DropDownMenu::new(app);
|
||||||
|
|
||||||
|
display_object.add_child(&inner_root);
|
||||||
|
inner_root.add_child(&dropdown);
|
||||||
|
inner_root.add_child(&play_icon);
|
||||||
|
inner_root.add_child(&background);
|
||||||
|
inner_root.add_child(÷r);
|
||||||
|
|
||||||
|
scene.layers.panel.add(&inner_root);
|
||||||
|
scene.layers.panel.add(&dropdown);
|
||||||
|
scene.layers.panel.add(÷r);
|
||||||
|
|
||||||
|
dropdown.set_label_layer(&scene.layers.panel_text);
|
||||||
|
dropdown.restore_shape_constraints(app);
|
||||||
|
|
||||||
|
|
||||||
|
Self { display_object, background, play_icon, dropdown, inner_root, divider }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl component::Frp<Model> for Frp {
|
||||||
|
fn init(
|
||||||
|
network: &enso_frp::Network,
|
||||||
|
frp: &<Self as ensogl::application::frp::API>::Private,
|
||||||
|
app: &Application,
|
||||||
|
model: &Model,
|
||||||
|
style_watch: &StyleWatchFrp,
|
||||||
|
) {
|
||||||
|
let scene = &app.display.default_scene;
|
||||||
|
let camera = scene.camera();
|
||||||
|
let dropdown = &model.dropdown;
|
||||||
|
let play_icon = &model.play_icon;
|
||||||
|
let input = &frp.input;
|
||||||
|
let output = &frp.output;
|
||||||
|
|
||||||
|
let style = Style::from_theme(network, style_watch);
|
||||||
|
let style_update = style.update;
|
||||||
|
|
||||||
|
frp::extend! { network
|
||||||
|
|
||||||
|
// == Layout ==
|
||||||
|
|
||||||
|
let camera_changed = scene.frp.camera_changed.clone_ref();
|
||||||
|
update_position <- all(camera_changed, style_update)._1();
|
||||||
|
eval update_position ([model, camera] (style){
|
||||||
|
model.update_position(style, &camera);
|
||||||
|
});
|
||||||
|
|
||||||
|
eval style_update((style) {
|
||||||
|
model.update_dropdown_style(style);
|
||||||
|
model.update_background_style(style);
|
||||||
|
model.update_play_icon_style(style);
|
||||||
|
});
|
||||||
|
|
||||||
|
// == Inputs ==
|
||||||
|
|
||||||
|
eval input.set_available_execution_modes ((entries) model.set_entries(entries.clone()));
|
||||||
|
|
||||||
|
selected_id <- dropdown.frp.chosen_entry.unwrap();
|
||||||
|
selection <- all(input.set_available_execution_modes, selected_id);
|
||||||
|
selected_entry <- selection.map(|(entries, entry_id)| entries[*entry_id].clone());
|
||||||
|
output.selected_execution_mode <+ selected_entry;
|
||||||
|
|
||||||
|
// == Outputs ==
|
||||||
|
|
||||||
|
output.play_press <+ play_icon.events_deprecated.mouse_down.constant(());
|
||||||
|
output.size <+ style_update.map(|style| {
|
||||||
|
Vector2::new(style.overall_width(),style.height)
|
||||||
|
}).on_change();
|
||||||
|
}
|
||||||
|
style.init.emit(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ExecutionModeSelector is a component that allows the user to select the execution mode of the
|
||||||
|
/// graph.
|
||||||
|
pub type ExecutionModeSelector = component::ComponentView<Model, Frp>;
|
@ -24,6 +24,7 @@ ensogl-drop-manager = { path = "../../../../lib/rust/ensogl/component/drop-manag
|
|||||||
ensogl-hardcoded-theme = { path = "../../../../lib/rust/ensogl/app/theme/hardcoded" }
|
ensogl-hardcoded-theme = { path = "../../../../lib/rust/ensogl/app/theme/hardcoded" }
|
||||||
ensogl-text-msdf = { path = "../../../../lib/rust/ensogl/component/text/src/font/msdf" }
|
ensogl-text-msdf = { path = "../../../../lib/rust/ensogl/component/text/src/font/msdf" }
|
||||||
failure = { workspace = true }
|
failure = { workspace = true }
|
||||||
|
ide-view-execution-mode-selector = { path = "../execution-mode-selector" }
|
||||||
indexmap = "1.9.2"
|
indexmap = "1.9.2"
|
||||||
js-sys = { workspace = true }
|
js-sys = { workspace = true }
|
||||||
nalgebra = { workspace = true }
|
nalgebra = { workspace = true }
|
||||||
|
@ -51,8 +51,9 @@ pub const HEIGHT: f32 = VERTICAL_MARGIN
|
|||||||
+ VERTICAL_MARGIN;
|
+ VERTICAL_MARGIN;
|
||||||
|
|
||||||
// This should be as large as the shadow around the background.
|
// This should be as large as the shadow around the background.
|
||||||
const MAGIC_SHADOW_MARGIN: f32 = 40.0;
|
const MAGIC_SHADOW_MARGIN: f32 = 25.0;
|
||||||
|
/// Text offset to make the text appear more centered.
|
||||||
|
const TEXT_Y_OFFSET: f32 = 2.0;
|
||||||
|
|
||||||
|
|
||||||
// ========================
|
// ========================
|
||||||
@ -207,7 +208,7 @@ impl BreadcrumbsModel {
|
|||||||
let background = background::View::new();
|
let background = background::View::new();
|
||||||
let gap_width = default();
|
let gap_width = default();
|
||||||
|
|
||||||
scene.layers.panel.add(&background);
|
scene.layers.panel_background.add(&background);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
display_object,
|
display_object,
|
||||||
@ -267,6 +268,8 @@ impl BreadcrumbsModel {
|
|||||||
|
|
||||||
self.project_name.set_x(gap_width);
|
self.project_name.set_x(gap_width);
|
||||||
self.breadcrumbs_container.set_x(gap_width + project_name_width);
|
self.breadcrumbs_container.set_x(gap_width + project_name_width);
|
||||||
|
self.project_name.set_y(TEXT_Y_OFFSET);
|
||||||
|
self.breadcrumbs_container.set_y(TEXT_Y_OFFSET);
|
||||||
|
|
||||||
let width = gap_width + project_name_width + self.breadcrumbs_container_width();
|
let width = gap_width + project_name_width + self.breadcrumbs_container_width();
|
||||||
let background_width = width + 2.0 * BACKGROUND_PADDING;
|
let background_width = width + 2.0 * BACKGROUND_PADDING;
|
||||||
|
@ -4,7 +4,8 @@
|
|||||||
//!
|
//!
|
||||||
//! TODO: If similar things are needed elsewhere, refactor this to a
|
//! TODO: If similar things are needed elsewhere, refactor this to a
|
||||||
//! Chooser<T:Eq+Display> (or similar) which would represent a `DropDownMenu` for specific owned
|
//! Chooser<T:Eq+Display> (or similar) which would represent a `DropDownMenu` for specific owned
|
||||||
//! values.
|
//! values. It should also be refactored to use `drop_down_menu` from `ensogl_components` instead
|
||||||
|
//! of the old list view.
|
||||||
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
@ -60,7 +61,9 @@ struct Model {
|
|||||||
impl Model {
|
impl Model {
|
||||||
pub fn new(app: &Application, registry: visualization::Registry) -> Self {
|
pub fn new(app: &Application, registry: visualization::Registry) -> Self {
|
||||||
let selection_menu = drop_down_menu::DropDownMenu::new(app);
|
let selection_menu = drop_down_menu::DropDownMenu::new(app);
|
||||||
|
selection_menu.set_label_alignment(drop_down_menu::Alignment::Right);
|
||||||
app.display.default_scene.layers.above_nodes.add(&selection_menu);
|
app.display.default_scene.layers.above_nodes.add(&selection_menu);
|
||||||
|
selection_menu.set_label_layer(&app.display.default_scene.layers.above_nodes_text);
|
||||||
Self { selection_menu, registry }
|
Self { selection_menu, registry }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,6 +76,7 @@ use ensogl_component::text;
|
|||||||
use ensogl_component::text::buffer::selection::Selection;
|
use ensogl_component::text::buffer::selection::Selection;
|
||||||
use ensogl_component::tooltip::Tooltip;
|
use ensogl_component::tooltip::Tooltip;
|
||||||
use ensogl_hardcoded_theme as theme;
|
use ensogl_hardcoded_theme as theme;
|
||||||
|
use ide_view_execution_mode_selector as execution_mode_selector;
|
||||||
|
|
||||||
|
|
||||||
// ===============
|
// ===============
|
||||||
@ -109,6 +110,8 @@ const MACOS_TRAFFIC_LIGHTS_SIDE_OFFSET: f32 = 13.0;
|
|||||||
const MACOS_TRAFFIC_LIGHTS_VERTICAL_CENTER: f32 =
|
const MACOS_TRAFFIC_LIGHTS_VERTICAL_CENTER: f32 =
|
||||||
-MACOS_TRAFFIC_LIGHTS_SIDE_OFFSET - MACOS_TRAFFIC_LIGHTS_CONTENT_HEIGHT / 2.0;
|
-MACOS_TRAFFIC_LIGHTS_SIDE_OFFSET - MACOS_TRAFFIC_LIGHTS_CONTENT_HEIGHT / 2.0;
|
||||||
const MAX_ZOOM: f32 = 1.0;
|
const MAX_ZOOM: f32 = 1.0;
|
||||||
|
/// Space between items in the top bar.
|
||||||
|
const TOP_BAR_ITEM_MARGIN: f32 = 10.0;
|
||||||
|
|
||||||
fn traffic_lights_gap_width() -> f32 {
|
fn traffic_lights_gap_width() -> f32 {
|
||||||
let platform_str = ARGS.groups.startup.options.platform.value.as_str();
|
let platform_str = ARGS.groups.startup.options.platform.value.as_str();
|
||||||
@ -117,12 +120,11 @@ fn traffic_lights_gap_width() -> f32 {
|
|||||||
if is_macos && !ARGS.groups.window.options.frame.value {
|
if is_macos && !ARGS.groups.window.options.frame.value {
|
||||||
MACOS_TRAFFIC_LIGHTS_CONTENT_WIDTH + MACOS_TRAFFIC_LIGHTS_SIDE_OFFSET
|
MACOS_TRAFFIC_LIGHTS_CONTENT_WIDTH + MACOS_TRAFFIC_LIGHTS_SIDE_OFFSET
|
||||||
} else {
|
} else {
|
||||||
0.0
|
TOP_BAR_ITEM_MARGIN
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// =================
|
// =================
|
||||||
// === SharedVec ===
|
// === SharedVec ===
|
||||||
// =================
|
// =================
|
||||||
@ -650,6 +652,9 @@ ensogl::define_endpoints_2! {
|
|||||||
/// Drop an edge that is being dragged.
|
/// Drop an edge that is being dragged.
|
||||||
drop_dragged_edge (),
|
drop_dragged_edge (),
|
||||||
|
|
||||||
|
/// Set the execution modes available to the graph.
|
||||||
|
set_available_execution_modes (Rc<Vec<execution_mode_selector::ExecutionMode>>),
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Output {
|
Output {
|
||||||
@ -749,6 +754,11 @@ ensogl::define_endpoints_2! {
|
|||||||
default_x_gap_between_nodes (f32),
|
default_x_gap_between_nodes (f32),
|
||||||
default_y_gap_between_nodes (f32),
|
default_y_gap_between_nodes (f32),
|
||||||
min_x_spacing_for_new_nodes (f32),
|
min_x_spacing_for_new_nodes (f32),
|
||||||
|
|
||||||
|
/// The selected execution mode.
|
||||||
|
execution_mode (execution_mode_selector::ExecutionMode),
|
||||||
|
/// A press of the execution mode selector play button.
|
||||||
|
execution_mode_play_button_pressed (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1770,6 +1780,7 @@ pub struct GraphEditorModel {
|
|||||||
profiling_button: component::profiling::Button,
|
profiling_button: component::profiling::Button,
|
||||||
styles_frp: StyleWatchFrp,
|
styles_frp: StyleWatchFrp,
|
||||||
selection_controller: selection::Controller,
|
selection_controller: selection::Controller,
|
||||||
|
execution_mode_selector: execution_mode_selector::ExecutionModeSelector,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1787,6 +1798,8 @@ impl GraphEditorModel {
|
|||||||
let visualisations = default();
|
let visualisations = default();
|
||||||
let touch_state = TouchState::new(network, &scene.mouse.frp_deprecated);
|
let touch_state = TouchState::new(network, &scene.mouse.frp_deprecated);
|
||||||
let breadcrumbs = component::Breadcrumbs::new(app.clone_ref());
|
let breadcrumbs = component::Breadcrumbs::new(app.clone_ref());
|
||||||
|
let execution_mode_selector = execution_mode_selector::ExecutionModeSelector::new(app);
|
||||||
|
|
||||||
let app = app.clone_ref();
|
let app = app.clone_ref();
|
||||||
let frp = frp.clone_ref();
|
let frp = frp.clone_ref();
|
||||||
let navigator = Navigator::new(scene, &scene.camera());
|
let navigator = Navigator::new(scene, &scene.camera());
|
||||||
@ -1824,17 +1837,19 @@ impl GraphEditorModel {
|
|||||||
add_node_button,
|
add_node_button,
|
||||||
styles_frp,
|
styles_frp,
|
||||||
selection_controller,
|
selection_controller,
|
||||||
|
execution_mode_selector,
|
||||||
}
|
}
|
||||||
.init()
|
.init()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init(self) -> Self {
|
fn init(self) -> Self {
|
||||||
self.add_child(&self.breadcrumbs);
|
|
||||||
let x_offset = MACOS_TRAFFIC_LIGHTS_SIDE_OFFSET;
|
let x_offset = MACOS_TRAFFIC_LIGHTS_SIDE_OFFSET;
|
||||||
let y_offset = MACOS_TRAFFIC_LIGHTS_VERTICAL_CENTER + component::breadcrumbs::HEIGHT / 2.0;
|
|
||||||
|
self.add_child(&self.execution_mode_selector);
|
||||||
|
|
||||||
|
self.add_child(&self.breadcrumbs);
|
||||||
self.breadcrumbs.set_x(x_offset);
|
self.breadcrumbs.set_x(x_offset);
|
||||||
self.breadcrumbs.set_y(y_offset);
|
|
||||||
self.breadcrumbs.gap_width(traffic_lights_gap_width());
|
|
||||||
self.scene().add_child(&self.tooltip);
|
self.scene().add_child(&self.tooltip);
|
||||||
self.add_child(&self.profiling_button);
|
self.add_child(&self.profiling_button);
|
||||||
self.add_child(&*self.add_node_button);
|
self.add_child(&*self.add_node_button);
|
||||||
@ -2746,12 +2761,6 @@ fn new_graph_editor(app: &Application) -> GraphEditor {
|
|||||||
let out = &frp.private.output;
|
let out = &frp.private.output;
|
||||||
let selection_controller = &model.selection_controller;
|
let selection_controller = &model.selection_controller;
|
||||||
|
|
||||||
// FIXME : StyleWatch is unsuitable here, as it was designed as an internal tool for shape
|
|
||||||
// system (#795)
|
|
||||||
let styles = StyleWatch::new(&scene.style_sheet);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ========================
|
// ========================
|
||||||
// === Scene Navigation ===
|
// === Scene Navigation ===
|
||||||
// ========================
|
// ========================
|
||||||
@ -2778,17 +2787,9 @@ fn new_graph_editor(app: &Application) -> GraphEditor {
|
|||||||
// ===================
|
// ===================
|
||||||
|
|
||||||
frp::extend! { network
|
frp::extend! { network
|
||||||
// === Layout ===
|
|
||||||
eval inputs.space_for_window_buttons([model](size) {
|
|
||||||
// The breadcrumbs apply their own spacing next to the gap, so we need to omit padding.
|
|
||||||
let width = size.x;
|
|
||||||
let path = theme::application::window_control_buttons::padding::right;
|
|
||||||
let right_padding = styles.get_number(path);
|
|
||||||
model.breadcrumbs.gap_width.emit(width - right_padding)
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
// === Debugging ===
|
// === Debugging ===
|
||||||
|
|
||||||
eval_ inputs.debug_push_breadcrumb(model.breadcrumbs.debug_push_breadcrumb.emit(None));
|
eval_ inputs.debug_push_breadcrumb(model.breadcrumbs.debug_push_breadcrumb.emit(None));
|
||||||
eval_ inputs.debug_pop_breadcrumb (model.breadcrumbs.debug_pop_breadcrumb.emit(()));
|
eval_ inputs.debug_pop_breadcrumb (model.breadcrumbs.debug_pop_breadcrumb.emit(()));
|
||||||
}
|
}
|
||||||
@ -3875,6 +3876,35 @@ fn new_graph_editor(app: &Application) -> GraphEditor {
|
|||||||
frp.private.output.min_x_spacing_for_new_nodes.emit(min_x_spacing.value());
|
frp.private.output.min_x_spacing_for_new_nodes.emit(min_x_spacing.value());
|
||||||
|
|
||||||
|
|
||||||
|
// ================================
|
||||||
|
// === Execution Mode Selection ===
|
||||||
|
// ================================
|
||||||
|
|
||||||
|
let execution_mode_selector = &model.execution_mode_selector;
|
||||||
|
frp::extend! { network
|
||||||
|
|
||||||
|
execution_mode_selector.set_available_execution_modes <+ frp.set_available_execution_modes;
|
||||||
|
out.execution_mode <+ execution_mode_selector.selected_execution_mode;
|
||||||
|
out.execution_mode_play_button_pressed <+ execution_mode_selector.play_press;
|
||||||
|
|
||||||
|
// === Layout ===
|
||||||
|
init <- source::<()>();
|
||||||
|
size_update <- all(init,execution_mode_selector.size,inputs.space_for_window_buttons);
|
||||||
|
eval size_update ([model]((_,size,gap_size)) {
|
||||||
|
let y_offset = MACOS_TRAFFIC_LIGHTS_VERTICAL_CENTER;
|
||||||
|
let traffic_light_width = traffic_lights_gap_width();
|
||||||
|
|
||||||
|
let execution_mode_selector_x = gap_size.x + traffic_light_width;
|
||||||
|
model.execution_mode_selector.set_x(execution_mode_selector_x);
|
||||||
|
let breadcrumb_gap_width = execution_mode_selector_x + size.x + TOP_BAR_ITEM_MARGIN;
|
||||||
|
model.breadcrumbs.gap_width(breadcrumb_gap_width);
|
||||||
|
|
||||||
|
model.execution_mode_selector.set_y(y_offset + size.y / 2.0);
|
||||||
|
model.breadcrumbs.set_y(y_offset + component::breadcrumbs::HEIGHT / 2.0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
init.emit(());
|
||||||
|
|
||||||
|
|
||||||
// ==================
|
// ==================
|
||||||
// === Debug Mode ===
|
// === Debug Mode ===
|
||||||
|
@ -41,6 +41,7 @@ pub mod window_control_buttons;
|
|||||||
|
|
||||||
pub use ide_view_component_browser as component_browser;
|
pub use ide_view_component_browser as component_browser;
|
||||||
pub use ide_view_documentation as documentation;
|
pub use ide_view_documentation as documentation;
|
||||||
|
pub use ide_view_execution_mode_selector as execution_mode_selector;
|
||||||
pub use ide_view_graph_editor as graph_editor;
|
pub use ide_view_graph_editor as graph_editor;
|
||||||
pub use welcome_screen;
|
pub use welcome_screen;
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ use enso_frp as frp;
|
|||||||
use ensogl::application;
|
use ensogl::application;
|
||||||
use ensogl::application::Application;
|
use ensogl::application::Application;
|
||||||
use ensogl::display;
|
use ensogl::display;
|
||||||
|
use ensogl::display::shape::StyleWatchFrp;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
|
||||||
@ -130,10 +131,18 @@ impl View {
|
|||||||
let model = Model::new(app);
|
let model = Model::new(app);
|
||||||
let frp = Frp::new();
|
let frp = Frp::new();
|
||||||
let network = &frp.network;
|
let network = &frp.network;
|
||||||
|
let style = StyleWatchFrp::new(&app.display.default_scene.style_sheet);
|
||||||
|
let offset_y = style.get_number(ensogl_hardcoded_theme::application::status_bar::offset_y);
|
||||||
|
|
||||||
frp::extend! { network
|
frp::extend! { network
|
||||||
|
init <- source::<()>();
|
||||||
|
|
||||||
eval_ frp.switch_view_to_project(model.switch_view_to_project());
|
eval_ frp.switch_view_to_project(model.switch_view_to_project());
|
||||||
eval_ frp.switch_view_to_welcome_screen(model.switch_view_to_welcome_screen());
|
eval_ frp.switch_view_to_welcome_screen(model.switch_view_to_welcome_screen());
|
||||||
|
offset_y <- all(&init,&offset_y)._1();
|
||||||
|
eval offset_y ((offset_y) model.status_bar.set_y(*offset_y));
|
||||||
}
|
}
|
||||||
|
init.emit(());
|
||||||
Self { model, frp }
|
Self { model, frp }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -442,6 +442,7 @@ define_themes! { [light:0, dark:1]
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
status_bar {
|
status_bar {
|
||||||
|
offset_y = -30.0, -30.0;
|
||||||
text = text, text;
|
text = text, text;
|
||||||
background = graph_editor::node::background , graph_editor::node::background;
|
background = graph_editor::node::background , graph_editor::node::background;
|
||||||
background {
|
background {
|
||||||
@ -653,6 +654,19 @@ define_themes! { [light:0, dark:1]
|
|||||||
color = Rgba(0.0, 0.451, 0.859, 1.0), Rgba(0.0, 0.451, 0.859, 1.0);
|
color = Rgba(0.0, 0.451, 0.859, 1.0), Rgba(0.0, 0.451, 0.859, 1.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
execution_mode_selector {
|
||||||
|
background = Rgb::from_base_255(100.0, 181.0, 38.0), Rgb::from_base_255(100.0, 181.0, 38.0);
|
||||||
|
divider = Rgba::black_with_alpha(0.12), Rgba::black_with_alpha(0.12);
|
||||||
|
triangle = Rgba::white_with_alpha(0.75), Rgba::white_with_alpha(0.75);
|
||||||
|
play_button_size = 10.0, 10.0;
|
||||||
|
play_button_offset = 15.0, 15.0;
|
||||||
|
play_button_padding = 10.0, 10.0;
|
||||||
|
divider_offset = 32.5, 32.5;
|
||||||
|
divider_padding = 10.0, 10.0;
|
||||||
|
dropdown_width = 95.0, 95.0;
|
||||||
|
height = 24.0, 24.0;
|
||||||
|
menu_offset = 20.0, 20.0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
widget {
|
widget {
|
||||||
list_view {
|
list_view {
|
||||||
|
@ -75,6 +75,7 @@ pub mod chooser_hover_area {
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
ensogl_core::shape! {
|
ensogl_core::shape! {
|
||||||
|
above = [arrow];
|
||||||
alignment = center;
|
alignment = center;
|
||||||
(style: Style) {
|
(style: Style) {
|
||||||
let width : Var<Pixels> = "input_size.x".into();
|
let width : Var<Pixels> = "input_size.x".into();
|
||||||
@ -87,6 +88,25 @@ pub mod chooser_hover_area {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// =================
|
||||||
|
// === Alignment ===
|
||||||
|
// =================
|
||||||
|
|
||||||
|
/// Indicates the alignment of the selection menu.
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub enum Alignment {
|
||||||
|
/// Align the menu to the left side of the selection menu.
|
||||||
|
Left,
|
||||||
|
/// Align the menu to the right side of the selection menu.
|
||||||
|
Right,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Alignment {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Left
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ===========
|
// ===========
|
||||||
// === FRP ===
|
// === FRP ===
|
||||||
@ -100,6 +120,8 @@ ensogl_core::define_endpoints! {
|
|||||||
hide_selection_menu (),
|
hide_selection_menu (),
|
||||||
set_selected (Option<list_view::entry::Id>),
|
set_selected (Option<list_view::entry::Id>),
|
||||||
set_menu_offset_y (f32),
|
set_menu_offset_y (f32),
|
||||||
|
set_menu_alignment (Alignment),
|
||||||
|
set_label_alignment (Alignment),
|
||||||
}
|
}
|
||||||
Output {
|
Output {
|
||||||
menu_visible (bool),
|
menu_visible (bool),
|
||||||
@ -124,7 +146,7 @@ struct Model {
|
|||||||
display_object: display::object::Instance,
|
display_object: display::object::Instance,
|
||||||
|
|
||||||
icon: arrow::View,
|
icon: arrow::View,
|
||||||
icon_overlay: chooser_hover_area::View,
|
click_overlay: chooser_hover_area::View,
|
||||||
|
|
||||||
label: text::Text,
|
label: text::Text,
|
||||||
selection_menu: list_view::ListView<Entry>,
|
selection_menu: list_view::ListView<Entry>,
|
||||||
@ -137,17 +159,17 @@ impl Model {
|
|||||||
fn new(app: &Application) -> Self {
|
fn new(app: &Application) -> Self {
|
||||||
let display_object = display::object::Instance::new();
|
let display_object = display::object::Instance::new();
|
||||||
let icon = arrow::View::new();
|
let icon = arrow::View::new();
|
||||||
let icon_overlay = chooser_hover_area::View::new();
|
let click_overlay = chooser_hover_area::View::new();
|
||||||
let selection_menu = list_view::ListView::new(app);
|
let selection_menu = list_view::ListView::new(app);
|
||||||
let label = app.new_view::<text::Text>();
|
let label = app.new_view::<text::Text>();
|
||||||
let content = default();
|
let content = default();
|
||||||
|
|
||||||
Self { display_object, icon, icon_overlay, label, selection_menu, content }.init()
|
Self { display_object, icon, click_overlay, label, selection_menu, content }.init()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init(self) -> Self {
|
fn init(self) -> Self {
|
||||||
self.add_child(&self.icon);
|
self.add_child(&self.icon);
|
||||||
self.add_child(&self.icon_overlay);
|
self.add_child(&self.click_overlay);
|
||||||
self.add_child(&self.label);
|
self.add_child(&self.label);
|
||||||
// Clear default parent and hide again.
|
// Clear default parent and hide again.
|
||||||
self.show_selection_menu();
|
self.show_selection_menu();
|
||||||
@ -249,7 +271,6 @@ impl DropDownMenu {
|
|||||||
|
|
||||||
let menu_height = DEPRECATED_Animation::<f32>::new(network);
|
let menu_height = DEPRECATED_Animation::<f32>::new(network);
|
||||||
|
|
||||||
|
|
||||||
eval menu_height.value ([model](height) {
|
eval menu_height.value ([model](height) {
|
||||||
model.selection_menu.frp.resize.emit(Vector2::new(MENU_WIDTH,*height));
|
model.selection_menu.frp.resize.emit(Vector2::new(MENU_WIDTH,*height));
|
||||||
if *height <= 0.0 {
|
if *height <= 0.0 {
|
||||||
@ -264,27 +285,42 @@ impl DropDownMenu {
|
|||||||
model.icon.set_size(size-2.0*padding);
|
model.icon.set_size(size-2.0*padding);
|
||||||
});
|
});
|
||||||
|
|
||||||
resize_menu <- all(model.selection_menu.size,frp.input.set_icon_size,frp.input.set_menu_offset_y);
|
resize_menu <- all(model.selection_menu.size,frp.input.set_icon_size,
|
||||||
eval resize_menu (((menu_size,icon_size,menu_offset_y)) {
|
frp.input.set_menu_offset_y,frp.input.set_menu_alignment);
|
||||||
|
eval resize_menu (((menu_size,icon_size,menu_offset_y,alignment)) {
|
||||||
// Align the top of the menu to the bottom of the icon.
|
// Align the top of the menu to the bottom of the icon.
|
||||||
model.selection_menu.set_y(-menu_size.y/2.0-icon_size.y/2.0-menu_offset_y);
|
model.selection_menu.set_y(-menu_size.y/2.0-icon_size.y/2.0-menu_offset_y);
|
||||||
// Align the right of the menu to the right of the icon.
|
// Align the right of the menu to the right of the icon.
|
||||||
let offfset_y = -menu_size.x/2.0+icon_size.x/2.0-list_view::SHADOW_PX/2.0;
|
let x_offset = match alignment {
|
||||||
model.selection_menu.set_x(offfset_y);
|
Alignment::Left => -menu_size.x/2.0+icon_size.x/2.0-list_view::SHADOW_PX/2.0,
|
||||||
|
Alignment::Right => 0.0,
|
||||||
|
};
|
||||||
|
model.selection_menu.set_x(x_offset);
|
||||||
});
|
});
|
||||||
|
|
||||||
label_position <- all(model.label.frp.width,frp.input.set_icon_size);
|
label_position <- all(model.label.frp.width,frp.input.set_icon_size,model.label.frp.height,
|
||||||
eval label_position (((text_width,icon_size)) {
|
frp.input.set_label_alignment);
|
||||||
model.label.set_x(-text_width-icon_size.x/2.0);
|
eval label_position ([model]((text_width,icon_size,text_height,alignment)) {
|
||||||
|
let base_offset = match alignment {
|
||||||
|
Alignment::Left => -MENU_WIDTH/2.0+icon_size.x/2.0,
|
||||||
|
Alignment::Right => -text_width-icon_size.x/2.0,
|
||||||
|
};
|
||||||
|
model.label.set_x(base_offset);
|
||||||
// Adjust for text offset, so this appears more centered.
|
// Adjust for text offset, so this appears more centered.
|
||||||
model.label.set_y(0.25 * icon_size.y);
|
model.label.set_y(0.5 * text_height);
|
||||||
});
|
});
|
||||||
|
|
||||||
overlay_size <- all(model.label.frp.width,frp.input.set_icon_size);
|
overlay_size <- all(
|
||||||
eval overlay_size ([model]((text_width,icon_size)) {
|
model.label.frp.width,
|
||||||
let size = Vector2::new(text_width + icon_size.x,icon_size.y);
|
model.label.frp.height,
|
||||||
model.icon_overlay.set_size(size);
|
frp.input.set_icon_size,
|
||||||
model.icon_overlay.set_x(-text_width/2.0);
|
frp.input.set_icon_padding);
|
||||||
|
eval overlay_size ([model]((text_width,text_height,icon_size,icon_padding)) {
|
||||||
|
let height = icon_size.y.max(*text_height);
|
||||||
|
let width = text_width + icon_size.x + icon_padding.x;
|
||||||
|
let size = Vector2::new(width,height);
|
||||||
|
model.click_overlay.set_size(size);
|
||||||
|
model.click_overlay.set_x(-width/2.0 + icon_size.x/2.0 - icon_padding.x);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@ -349,14 +385,14 @@ impl DropDownMenu {
|
|||||||
// === Menu Toggle Through Mouse Interaction ===
|
// === Menu Toggle Through Mouse Interaction ===
|
||||||
|
|
||||||
icon_hovered <- source::<bool>();
|
icon_hovered <- source::<bool>();
|
||||||
eval_ model.icon_overlay.events_deprecated.mouse_over ( icon_hovered.emit(true) );
|
eval_ model.click_overlay.events_deprecated.mouse_over ( icon_hovered.emit(true) );
|
||||||
eval_ model.icon_overlay.events_deprecated.mouse_out ( icon_hovered.emit(false) );
|
eval_ model.click_overlay.events_deprecated.mouse_out ( icon_hovered.emit(false) );
|
||||||
|
|
||||||
frp.source.icon_mouse_over <+ model.icon_overlay.events_deprecated.mouse_over;
|
frp.source.icon_mouse_over <+ model.click_overlay.events_deprecated.mouse_over;
|
||||||
frp.source.icon_mouse_out <+ model.icon_overlay.events_deprecated.mouse_out;
|
frp.source.icon_mouse_out <+ model.click_overlay.events_deprecated.mouse_out;
|
||||||
|
|
||||||
|
|
||||||
let icon_mouse_down = model.icon_overlay.events_deprecated.mouse_down_primary.clone_ref();
|
let icon_mouse_down = model.click_overlay.events_deprecated.mouse_down_primary.clone_ref();
|
||||||
visibility_on_mouse_down <- frp.source.menu_visible.sample(&icon_mouse_down) ;
|
visibility_on_mouse_down <- frp.source.menu_visible.sample(&icon_mouse_down) ;
|
||||||
|
|
||||||
eval visibility_on_mouse_down ([show_menu,hide_menu](is_visible){
|
eval visibility_on_mouse_down ([show_menu,hide_menu](is_visible){
|
||||||
@ -384,6 +420,28 @@ impl DropDownMenu {
|
|||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the label of the dropdown menu.
|
||||||
|
pub fn set_label_color(&self, color: color::Rgba) {
|
||||||
|
self.model.label.set_property_default(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the layer of all text labels.
|
||||||
|
pub fn set_label_layer(&self, layer: &display::scene::Layer) {
|
||||||
|
self.model.selection_menu.set_label_layer(layer);
|
||||||
|
self.model.label.add_to_scene_layer(layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the correct order for the shapes. To be sued after moving the component to a different
|
||||||
|
/// layer. Workaround for #6241.
|
||||||
|
pub fn restore_shape_constraints(&self, app: &Application) {
|
||||||
|
let scene = &app.display.default_scene;
|
||||||
|
shapes_order_dependencies! {
|
||||||
|
scene => {
|
||||||
|
arrow -> chooser_hover_area;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl display::Object for DropDownMenu {
|
impl display::Object for DropDownMenu {
|
||||||
|
@ -240,7 +240,7 @@ impl<E: Entry> Model<E> {
|
|||||||
self.entries.set_x(-view.size.x / 2.0 + entry_padding);
|
self.entries.set_x(-view.size.x / 2.0 + entry_padding);
|
||||||
self.background.set_size(view.size + padding + shadow + margin);
|
self.background.set_size(view.size + padding + shadow + margin);
|
||||||
self.overlay.set_size(view.size + padding + shadow + margin);
|
self.overlay.set_size(view.size + padding + shadow + margin);
|
||||||
self.scrolled_area.set_y(view.size.y / 2.0 - view.position_y);
|
self.scrolled_area.set_y(view.size.y / 2.0 - view.position_y + SHAPE_MARGIN / 2.0);
|
||||||
self.entries.update_entries(visible_entries, entry_width, style_prefix);
|
self.entries.update_entries(visible_entries, entry_width, style_prefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -494,6 +494,15 @@ impl Rgba {
|
|||||||
Self::new(0.0, 0.0, 0.0, 0.0)
|
Self::new(0.0, 0.0, 0.0, 0.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Constructor.
|
||||||
|
pub fn black_with_alpha(alpha: f32) -> Self {
|
||||||
|
Self::new(0.0, 0.0, 0.0, alpha)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Constructor.
|
||||||
|
pub fn white_with_alpha(alpha: f32) -> Self {
|
||||||
|
Self::new(1.0, 1.0, 1.0, alpha)
|
||||||
|
}
|
||||||
/// Convert the color to `LinearRgba` representation.
|
/// Convert the color to `LinearRgba` representation.
|
||||||
pub fn into_linear(self) -> LinearRgba {
|
pub fn into_linear(self) -> LinearRgba {
|
||||||
self.into()
|
self.into()
|
||||||
|
@ -601,6 +601,7 @@ pub struct HardcodedLayers {
|
|||||||
pub above_nodes_text: Layer,
|
pub above_nodes_text: Layer,
|
||||||
/// Layer containing all panels with fixed position (not moving with the panned scene)
|
/// Layer containing all panels with fixed position (not moving with the panned scene)
|
||||||
/// like status bar, breadcrumbs or similar.
|
/// like status bar, breadcrumbs or similar.
|
||||||
|
pub panel_background: Layer,
|
||||||
pub panel: Layer,
|
pub panel: Layer,
|
||||||
pub panel_text: Layer,
|
pub panel_text: Layer,
|
||||||
pub node_searcher: Layer,
|
pub node_searcher: Layer,
|
||||||
@ -640,6 +641,7 @@ impl HardcodedLayers {
|
|||||||
let label = root.create_sublayer("label");
|
let label = root.create_sublayer("label");
|
||||||
let above_nodes = root.create_sublayer("above_nodes");
|
let above_nodes = root.create_sublayer("above_nodes");
|
||||||
let above_nodes_text = root.create_sublayer("above_nodes_text");
|
let above_nodes_text = root.create_sublayer("above_nodes_text");
|
||||||
|
let panel_background = root.create_sublayer_with_camera("panel_background", &panel_cam);
|
||||||
let panel = root.create_sublayer_with_camera("panel", &panel_cam);
|
let panel = root.create_sublayer_with_camera("panel", &panel_cam);
|
||||||
let panel_text = root.create_sublayer_with_camera("panel_text", &panel_cam);
|
let panel_text = root.create_sublayer_with_camera("panel_text", &panel_cam);
|
||||||
let node_searcher = root.create_sublayer_with_camera("node_searcher", &node_searcher_cam);
|
let node_searcher = root.create_sublayer_with_camera("node_searcher", &node_searcher_cam);
|
||||||
@ -662,6 +664,7 @@ impl HardcodedLayers {
|
|||||||
label,
|
label,
|
||||||
above_nodes,
|
above_nodes,
|
||||||
above_nodes_text,
|
above_nodes_text,
|
||||||
|
panel_background,
|
||||||
panel,
|
panel,
|
||||||
panel_text,
|
panel_text,
|
||||||
node_searcher,
|
node_searcher,
|
||||||
|
@ -21,7 +21,8 @@ pub use shape::Shape;
|
|||||||
// === Shape ===
|
// === Shape ===
|
||||||
// =============
|
// =============
|
||||||
|
|
||||||
mod shape {
|
/// Shape definition.
|
||||||
|
pub mod shape {
|
||||||
use super::*;
|
use super::*;
|
||||||
crate::shape! {
|
crate::shape! {
|
||||||
(
|
(
|
||||||
|
Loading…
Reference in New Issue
Block a user