mirror of
https://github.com/enso-org/enso.git
synced 2024-11-12 17:54:09 +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
|
||||
selected from the dropdown, the necessary module imports are inserted,
|
||||
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
|
||||
quickly understand each button's function.
|
||||
- [File associations are created on Windows and macOS][6077]. This allows
|
||||
@ -189,6 +191,7 @@
|
||||
[4047]: https://github.com/enso-org/enso/pull/4047
|
||||
[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/6130
|
||||
[6035]: https://github.com/enso-org/enso/pull/6035
|
||||
[6097]: https://github.com/enso-org/enso/pull/6097
|
||||
|
||||
|
30
Cargo.lock
generated
30
Cargo.lock
generated
@ -1613,6 +1613,18 @@ dependencies = [
|
||||
"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]]
|
||||
name = "debug-scene-icons"
|
||||
version = "0.1.0"
|
||||
@ -1635,6 +1647,7 @@ dependencies = [
|
||||
"ensogl-hardcoded-theme",
|
||||
"ensogl-text-msdf",
|
||||
"ide-view",
|
||||
"ide-view-execution-mode-selector",
|
||||
"parser",
|
||||
"span-tree",
|
||||
"uuid 0.8.2",
|
||||
@ -2096,6 +2109,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"debug-scene-component-list-panel-view",
|
||||
"debug-scene-documentation",
|
||||
"debug-scene-execution-mode-dropdown",
|
||||
"debug-scene-icons",
|
||||
"debug-scene-interface",
|
||||
"debug-scene-text-grid-visualization",
|
||||
@ -4273,6 +4287,7 @@ dependencies = [
|
||||
"ensogl-text-msdf",
|
||||
"ide-view-component-browser",
|
||||
"ide-view-documentation",
|
||||
"ide-view-execution-mode-selector",
|
||||
"ide-view-graph-editor",
|
||||
"js-sys",
|
||||
"multi-map",
|
||||
@ -4386,6 +4401,20 @@ dependencies = [
|
||||
"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]]
|
||||
name = "ide-view-graph-editor"
|
||||
version = "0.1.0"
|
||||
@ -4406,6 +4435,7 @@ dependencies = [
|
||||
"ensogl-hardcoded-theme",
|
||||
"ensogl-text-msdf",
|
||||
"failure",
|
||||
"ide-view-execution-mode-selector",
|
||||
"indexmap",
|
||||
"js-sys",
|
||||
"nalgebra",
|
||||
|
@ -379,10 +379,20 @@ impl Project {
|
||||
let graph_controller = self.model.graph_controller.clone_ref();
|
||||
|
||||
self.init_analytics()
|
||||
.init_execution_modes()
|
||||
.setup_notification_handler()
|
||||
.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 {
|
||||
let network = &self.network;
|
||||
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-hardcoded-theme = { path = "../../../lib/rust/ensogl/app/theme/hardcoded" }
|
||||
ide-view-component-browser = { path = "component-browser" }
|
||||
ide-view-execution-mode-selector = { path = "execution-mode-selector" }
|
||||
ide-view-documentation = { path = "documentation" }
|
||||
ide-view-graph-editor = { path = "graph-editor" }
|
||||
span-tree = { path = "../language/span-tree" }
|
||||
|
@ -14,6 +14,7 @@ debug-scene-icons = { path = "icons" }
|
||||
debug-scene-interface = { path = "interface" }
|
||||
debug-scene-text-grid-visualization = { path = "text-grid-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.
|
||||
[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]
|
||||
ast = { path = "../../../language/ast/impl" }
|
||||
parser = { path = "../../../language/parser" }
|
||||
enso-frp = { path = "../../../../../lib/rust/frp" }
|
||||
ensogl = { path = "../../../../../lib/rust/ensogl" }
|
||||
ensogl-hardcoded-theme = { path = "../../../../../lib/rust/ensogl/app/theme/hardcoded" }
|
||||
ensogl-text-msdf = { path = "../../../../../lib/rust/ensogl/component/text/src/font/msdf" }
|
||||
ide-view = { path = "../.." }
|
||||
ide-view-execution-mode-selector = { path = "../../execution-mode-selector" }
|
||||
parser = { path = "../../../language/parser" }
|
||||
span-tree = { path = "../../../language/span-tree" }
|
||||
uuid = { version = "0.8", features = ["v4", "wasm-bindgen"] }
|
||||
wasm-bindgen = { workspace = true }
|
||||
|
@ -254,6 +254,14 @@ fn init(app: &Application) {
|
||||
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 mut was_rendered = 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_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_interface as interface;
|
||||
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-text-msdf = { path = "../../../../lib/rust/ensogl/component/text/src/font/msdf" }
|
||||
failure = { workspace = true }
|
||||
ide-view-execution-mode-selector = { path = "../execution-mode-selector" }
|
||||
indexmap = "1.9.2"
|
||||
js-sys = { workspace = true }
|
||||
nalgebra = { workspace = true }
|
||||
|
@ -51,8 +51,9 @@ pub const HEIGHT: f32 = VERTICAL_MARGIN
|
||||
+ VERTICAL_MARGIN;
|
||||
|
||||
// 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 gap_width = default();
|
||||
|
||||
scene.layers.panel.add(&background);
|
||||
scene.layers.panel_background.add(&background);
|
||||
|
||||
Self {
|
||||
display_object,
|
||||
@ -267,6 +268,8 @@ impl BreadcrumbsModel {
|
||||
|
||||
self.project_name.set_x(gap_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 background_width = width + 2.0 * BACKGROUND_PADDING;
|
||||
|
@ -4,7 +4,8 @@
|
||||
//!
|
||||
//! 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
|
||||
//! values.
|
||||
//! values. It should also be refactored to use `drop_down_menu` from `ensogl_components` instead
|
||||
//! of the old list view.
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
@ -60,7 +61,9 @@ struct Model {
|
||||
impl Model {
|
||||
pub fn new(app: &Application, registry: visualization::Registry) -> Self {
|
||||
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);
|
||||
selection_menu.set_label_layer(&app.display.default_scene.layers.above_nodes_text);
|
||||
Self { selection_menu, registry }
|
||||
}
|
||||
|
||||
|
@ -76,6 +76,7 @@ use ensogl_component::text;
|
||||
use ensogl_component::text::buffer::selection::Selection;
|
||||
use ensogl_component::tooltip::Tooltip;
|
||||
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 =
|
||||
-MACOS_TRAFFIC_LIGHTS_SIDE_OFFSET - MACOS_TRAFFIC_LIGHTS_CONTENT_HEIGHT / 2.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 {
|
||||
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 {
|
||||
MACOS_TRAFFIC_LIGHTS_CONTENT_WIDTH + MACOS_TRAFFIC_LIGHTS_SIDE_OFFSET
|
||||
} else {
|
||||
0.0
|
||||
TOP_BAR_ITEM_MARGIN
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// =================
|
||||
// === SharedVec ===
|
||||
// =================
|
||||
@ -650,6 +652,9 @@ ensogl::define_endpoints_2! {
|
||||
/// Drop an edge that is being dragged.
|
||||
drop_dragged_edge (),
|
||||
|
||||
/// Set the execution modes available to the graph.
|
||||
set_available_execution_modes (Rc<Vec<execution_mode_selector::ExecutionMode>>),
|
||||
|
||||
}
|
||||
|
||||
Output {
|
||||
@ -749,6 +754,11 @@ ensogl::define_endpoints_2! {
|
||||
default_x_gap_between_nodes (f32),
|
||||
default_y_gap_between_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 (),
|
||||
}
|
||||
}
|
||||
|
||||
@ -1752,24 +1762,25 @@ impl GraphEditorModelWithNetwork {
|
||||
#[derive(Debug, Clone, CloneRef)]
|
||||
#[allow(missing_docs)] // FIXME[everyone] Public-facing API should be documented.
|
||||
pub struct GraphEditorModel {
|
||||
pub display_object: display::object::Instance,
|
||||
pub app: Application,
|
||||
pub breadcrumbs: component::Breadcrumbs,
|
||||
pub cursor: cursor::Cursor,
|
||||
pub nodes: Nodes,
|
||||
pub edges: Edges,
|
||||
pub vis_registry: visualization::Registry,
|
||||
pub drop_manager: ensogl_drop_manager::Manager,
|
||||
pub navigator: Navigator,
|
||||
pub add_node_button: Rc<component::add_node_button::AddNodeButton>,
|
||||
tooltip: Tooltip,
|
||||
touch_state: TouchState,
|
||||
visualisations: Visualisations,
|
||||
frp: Frp,
|
||||
profiling_statuses: profiling::Statuses,
|
||||
profiling_button: component::profiling::Button,
|
||||
styles_frp: StyleWatchFrp,
|
||||
selection_controller: selection::Controller,
|
||||
pub display_object: display::object::Instance,
|
||||
pub app: Application,
|
||||
pub breadcrumbs: component::Breadcrumbs,
|
||||
pub cursor: cursor::Cursor,
|
||||
pub nodes: Nodes,
|
||||
pub edges: Edges,
|
||||
pub vis_registry: visualization::Registry,
|
||||
pub drop_manager: ensogl_drop_manager::Manager,
|
||||
pub navigator: Navigator,
|
||||
pub add_node_button: Rc<component::add_node_button::AddNodeButton>,
|
||||
tooltip: Tooltip,
|
||||
touch_state: TouchState,
|
||||
visualisations: Visualisations,
|
||||
frp: Frp,
|
||||
profiling_statuses: profiling::Statuses,
|
||||
profiling_button: component::profiling::Button,
|
||||
styles_frp: StyleWatchFrp,
|
||||
selection_controller: selection::Controller,
|
||||
execution_mode_selector: execution_mode_selector::ExecutionModeSelector,
|
||||
}
|
||||
|
||||
|
||||
@ -1787,6 +1798,8 @@ impl GraphEditorModel {
|
||||
let visualisations = default();
|
||||
let touch_state = TouchState::new(network, &scene.mouse.frp_deprecated);
|
||||
let breadcrumbs = component::Breadcrumbs::new(app.clone_ref());
|
||||
let execution_mode_selector = execution_mode_selector::ExecutionModeSelector::new(app);
|
||||
|
||||
let app = app.clone_ref();
|
||||
let frp = frp.clone_ref();
|
||||
let navigator = Navigator::new(scene, &scene.camera());
|
||||
@ -1824,17 +1837,19 @@ impl GraphEditorModel {
|
||||
add_node_button,
|
||||
styles_frp,
|
||||
selection_controller,
|
||||
execution_mode_selector,
|
||||
}
|
||||
.init()
|
||||
}
|
||||
|
||||
fn init(self) -> Self {
|
||||
self.add_child(&self.breadcrumbs);
|
||||
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_y(y_offset);
|
||||
self.breadcrumbs.gap_width(traffic_lights_gap_width());
|
||||
|
||||
self.scene().add_child(&self.tooltip);
|
||||
self.add_child(&self.profiling_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 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 ===
|
||||
// ========================
|
||||
@ -2778,17 +2787,9 @@ fn new_graph_editor(app: &Application) -> GraphEditor {
|
||||
// ===================
|
||||
|
||||
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 ===
|
||||
|
||||
eval_ inputs.debug_push_breadcrumb(model.breadcrumbs.debug_push_breadcrumb.emit(None));
|
||||
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());
|
||||
|
||||
|
||||
// ================================
|
||||
// === 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 ===
|
||||
|
@ -41,6 +41,7 @@ pub mod window_control_buttons;
|
||||
|
||||
pub use ide_view_component_browser as component_browser;
|
||||
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 welcome_screen;
|
||||
|
||||
|
@ -10,6 +10,7 @@ use enso_frp as frp;
|
||||
use ensogl::application;
|
||||
use ensogl::application::Application;
|
||||
use ensogl::display;
|
||||
use ensogl::display::shape::StyleWatchFrp;
|
||||
use std::rc::Rc;
|
||||
|
||||
|
||||
@ -130,10 +131,18 @@ impl View {
|
||||
let model = Model::new(app);
|
||||
let frp = Frp::new();
|
||||
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
|
||||
init <- source::<()>();
|
||||
|
||||
eval_ frp.switch_view_to_project(model.switch_view_to_project());
|
||||
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 }
|
||||
}
|
||||
|
||||
|
@ -442,6 +442,7 @@ define_themes! { [light:0, dark:1]
|
||||
}
|
||||
}
|
||||
status_bar {
|
||||
offset_y = -30.0, -30.0;
|
||||
text = text, text;
|
||||
background = graph_editor::node::background , graph_editor::node::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);
|
||||
}
|
||||
}
|
||||
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 {
|
||||
list_view {
|
||||
|
@ -75,6 +75,7 @@ pub mod chooser_hover_area {
|
||||
use super::*;
|
||||
|
||||
ensogl_core::shape! {
|
||||
above = [arrow];
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
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 ===
|
||||
@ -100,6 +120,8 @@ ensogl_core::define_endpoints! {
|
||||
hide_selection_menu (),
|
||||
set_selected (Option<list_view::entry::Id>),
|
||||
set_menu_offset_y (f32),
|
||||
set_menu_alignment (Alignment),
|
||||
set_label_alignment (Alignment),
|
||||
}
|
||||
Output {
|
||||
menu_visible (bool),
|
||||
@ -123,8 +145,8 @@ pub type Entry = list_view::entry::Label;
|
||||
struct Model {
|
||||
display_object: display::object::Instance,
|
||||
|
||||
icon: arrow::View,
|
||||
icon_overlay: chooser_hover_area::View,
|
||||
icon: arrow::View,
|
||||
click_overlay: chooser_hover_area::View,
|
||||
|
||||
label: text::Text,
|
||||
selection_menu: list_view::ListView<Entry>,
|
||||
@ -137,17 +159,17 @@ impl Model {
|
||||
fn new(app: &Application) -> Self {
|
||||
let display_object = display::object::Instance::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 label = app.new_view::<text::Text>();
|
||||
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 {
|
||||
self.add_child(&self.icon);
|
||||
self.add_child(&self.icon_overlay);
|
||||
self.add_child(&self.click_overlay);
|
||||
self.add_child(&self.label);
|
||||
// Clear default parent and hide again.
|
||||
self.show_selection_menu();
|
||||
@ -249,7 +271,6 @@ impl DropDownMenu {
|
||||
|
||||
let menu_height = DEPRECATED_Animation::<f32>::new(network);
|
||||
|
||||
|
||||
eval menu_height.value ([model](height) {
|
||||
model.selection_menu.frp.resize.emit(Vector2::new(MENU_WIDTH,*height));
|
||||
if *height <= 0.0 {
|
||||
@ -264,27 +285,42 @@ impl DropDownMenu {
|
||||
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);
|
||||
eval resize_menu (((menu_size,icon_size,menu_offset_y)) {
|
||||
resize_menu <- all(model.selection_menu.size,frp.input.set_icon_size,
|
||||
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.
|
||||
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.
|
||||
let offfset_y = -menu_size.x/2.0+icon_size.x/2.0-list_view::SHADOW_PX/2.0;
|
||||
model.selection_menu.set_x(offfset_y);
|
||||
let x_offset = match alignment {
|
||||
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);
|
||||
eval label_position (((text_width,icon_size)) {
|
||||
model.label.set_x(-text_width-icon_size.x/2.0);
|
||||
label_position <- all(model.label.frp.width,frp.input.set_icon_size,model.label.frp.height,
|
||||
frp.input.set_label_alignment);
|
||||
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.
|
||||
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);
|
||||
eval overlay_size ([model]((text_width,icon_size)) {
|
||||
let size = Vector2::new(text_width + icon_size.x,icon_size.y);
|
||||
model.icon_overlay.set_size(size);
|
||||
model.icon_overlay.set_x(-text_width/2.0);
|
||||
overlay_size <- all(
|
||||
model.label.frp.width,
|
||||
model.label.frp.height,
|
||||
frp.input.set_icon_size,
|
||||
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 ===
|
||||
|
||||
icon_hovered <- source::<bool>();
|
||||
eval_ model.icon_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_over ( icon_hovered.emit(true) );
|
||||
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_out <+ model.icon_overlay.events_deprecated.mouse_out;
|
||||
frp.source.icon_mouse_over <+ model.click_overlay.events_deprecated.mouse_over;
|
||||
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) ;
|
||||
|
||||
eval visibility_on_mouse_down ([show_menu,hide_menu](is_visible){
|
||||
@ -384,6 +420,28 @@ impl DropDownMenu {
|
||||
|
||||
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 {
|
||||
|
@ -240,7 +240,7 @@ impl<E: Entry> Model<E> {
|
||||
self.entries.set_x(-view.size.x / 2.0 + entry_padding);
|
||||
self.background.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);
|
||||
}
|
||||
|
||||
|
@ -494,6 +494,15 @@ impl Rgba {
|
||||
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.
|
||||
pub fn into_linear(self) -> LinearRgba {
|
||||
self.into()
|
||||
|
@ -601,6 +601,7 @@ pub struct HardcodedLayers {
|
||||
pub above_nodes_text: Layer,
|
||||
/// Layer containing all panels with fixed position (not moving with the panned scene)
|
||||
/// like status bar, breadcrumbs or similar.
|
||||
pub panel_background: Layer,
|
||||
pub panel: Layer,
|
||||
pub panel_text: Layer,
|
||||
pub node_searcher: Layer,
|
||||
@ -640,6 +641,7 @@ impl HardcodedLayers {
|
||||
let label = root.create_sublayer("label");
|
||||
let above_nodes = root.create_sublayer("above_nodes");
|
||||
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_text = root.create_sublayer_with_camera("panel_text", &panel_cam);
|
||||
let node_searcher = root.create_sublayer_with_camera("node_searcher", &node_searcher_cam);
|
||||
@ -662,6 +664,7 @@ impl HardcodedLayers {
|
||||
label,
|
||||
above_nodes,
|
||||
above_nodes_text,
|
||||
panel_background,
|
||||
panel,
|
||||
panel_text,
|
||||
node_searcher,
|
||||
|
@ -21,7 +21,8 @@ pub use shape::Shape;
|
||||
// === Shape ===
|
||||
// =============
|
||||
|
||||
mod shape {
|
||||
/// Shape definition.
|
||||
pub mod shape {
|
||||
use super::*;
|
||||
crate::shape! {
|
||||
(
|
||||
|
Loading…
Reference in New Issue
Block a user