diff --git a/gui/src/rust/Cargo.lock b/gui/src/rust/Cargo.lock index f2974f2d5ea..4458c14eebd 100644 --- a/gui/src/rust/Cargo.lock +++ b/gui/src/rust/Cargo.lock @@ -1258,6 +1258,7 @@ dependencies = [ "bimap 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "console_error_panic_hook 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "data 0.1.0", + "enso-callback 0.1.0", "enso-frp 0.1.0", "enso-prelude 0.1.0", "enso-protocol 0.1.0", diff --git a/gui/src/rust/ensogl/src/display/scene.rs b/gui/src/rust/ensogl/src/display/scene.rs index 2bd4cb396c0..aafeb2aa057 100644 --- a/gui/src/rust/ensogl/src/display/scene.rs +++ b/gui/src/rust/ensogl/src/display/scene.rs @@ -33,7 +33,6 @@ use crate::system::web::StyleSetter; use crate::system::web; use crate::display::shape::ShapeSystemInstance; use crate::display::shape::system::ShapeSystemOf; -use crate::display::layout::Alignment; use display::style::data::DataMatch; use enso_frp as frp; diff --git a/gui/src/rust/ide/Cargo.toml b/gui/src/rust/ide/Cargo.toml index 4ac9fc3dd60..b4e2db32414 100644 --- a/gui/src/rust/ide/Cargo.toml +++ b/gui/src/rust/ide/Cargo.toml @@ -8,6 +8,7 @@ edition = "2018" crate-type = ["cdylib", "rlib"] [dependencies] +enso-callback = { version = "0.1.0" , path = "../lib/callback" } ensogl = { version = "0.1.0" , path = "../ensogl" } ensogl-core-msdf-sys = { version = "0.1.0" , path = "../ensogl/msdf-sys" } ensogl-system-web = { version = "0.1.0" , path = "../lib/system/web" } diff --git a/gui/src/rust/ide/src/view/layout.rs b/gui/src/rust/ide/src/view/layout.rs index 1975f65f59c..60c475333fd 100644 --- a/gui/src/rust/ide/src/view/layout.rs +++ b/gui/src/rust/ide/src/view/layout.rs @@ -9,10 +9,12 @@ use crate::view::text_editor::TextEditor; use crate::view::node_editor::NodeEditor; use crate::view::node_searcher::NodeSearcher; +use enso_callback as callback; use enso_frp::io::keyboard; use ensogl::application::Application; use ensogl::display::shape::text::glyph::font; use ensogl::display::traits::*; +use ensogl::display::Uniform; use ensogl::display::world::World; use nalgebra::Vector2; use nalgebra::zero; @@ -30,11 +32,15 @@ shared! { ViewLayout /// Initial implementation of ViewLayout with a TextEditor and NodeEditor. #[derive(Debug)] pub struct ViewLayoutData { - text_editor : TextEditor, - node_editor : NodeEditor, - node_searcher : NodeSearcher, - size : Vector2, - logger : Logger + text_editor : TextEditor, + node_editor : NodeEditor, + node_searcher : NodeSearcher, + size : Vector2, + logger : Logger, + /// FIXME[dg]: This is a provisional code. Getting the mouse position from Uniform is bad. Mouse + /// position should be retrieved from the frp network instead. + mouse_position : Uniform>, + node_searcher_show_action : Option } impl { @@ -96,25 +102,38 @@ impl ViewLayout { , visualization_controller : controller::Visualization , fonts : &mut font::Registry ) -> FallibleResult { - let logger = logger.sub("ViewLayout"); - let world = &application.display; - let text_editor = TextEditor::new(&logger,world,text_controller,kb_actions,fonts); - let graph = graph_controller.graph.clone_ref(); - let node_searcher = NodeSearcher::new(world,&logger,graph,fonts); - let graph_controller = graph_controller.clone_ref(); - let node_editor = NodeEditor::new + let logger = logger.sub("ViewLayout"); + let world = &application.display; + let text_editor = TextEditor::new(&logger,world,text_controller,kb_actions,fonts); + let graph = graph_controller.graph.clone_ref(); + let node_editor = NodeEditor::new (&logger,application,graph_controller,visualization_controller).await?; + let node_searcher = NodeSearcher::new(world,&logger,node_editor.clone_ref(),graph,fonts); world.add_child(&text_editor.display_object()); world.add_child(&node_editor); world.add_child(&node_searcher); - let size = zero(); - let data = ViewLayoutData {text_editor,node_editor,node_searcher,size,logger}; + let size = zero(); + let mouse_position = world.scene().mouse.position.clone_ref(); + let node_searcher_show_action = None; + let data = ViewLayoutData{text_editor,node_editor,node_searcher,size,logger,mouse_position, + node_searcher_show_action}; let rc = Rc::new(RefCell::new(data)); Ok(Self {rc}.init(world,kb_actions)) } - fn init_keyboard(self, _keyboard_actions:&mut keyboard::Actions) -> Self { + fn init_keyboard(self, keyboard_actions:&mut keyboard::Actions) -> Self { // TODO[ao] add here some useful staff (quitting project for example) + let layout = self.rc.clone_ref(); + let keys = &[keyboard::Key::Tab]; + let node_searcher_show_action = keyboard_actions.add_action(keys, move || { + let mut layout = layout.borrow_mut(); + let position = layout.mouse_position.get(); + //TODO[dg]: Test it when graph scene panning is working. + let node_searcher_position = Vector3::new(position.x as f32,position.y as f32,0.0); + layout.node_searcher.set_position(node_searcher_position); + layout.node_searcher.show(); + }); + self.rc.borrow_mut().node_searcher_show_action = Some(node_searcher_show_action); self } diff --git a/gui/src/rust/ide/src/view/node_searcher.rs b/gui/src/rust/ide/src/view/node_searcher.rs index 7cf46e4b0f6..179438cf40a 100644 --- a/gui/src/rust/ide/src/view/node_searcher.rs +++ b/gui/src/rust/ide/src/view/node_searcher.rs @@ -3,7 +3,12 @@ use crate::prelude::*; -use crate::controller::graph::{NewNodeInfo, LocationHint}; +use crate::controller::graph::LocationHint; +use crate::controller::graph::NewNodeInfo; +use crate::model::module::NodeMetadata; +use crate::model::module::Position; +use crate::view::node_editor::NodeEditor; + use ensogl::data::color; use ensogl::display::shape::text::glyph::font; use ensogl::display::shape::text::text_field::TextField; @@ -13,9 +18,10 @@ use ensogl::display; use ensogl::traits::*; -#[derive(Clone,Debug)] +#[derive(Clone,Debug,CloneRef)] pub struct NodeSearcher { display_object : display::object::Instance, + node_editor : NodeEditor, text_field : TextField, controller : controller::graph::Handle, logger : Logger, @@ -23,7 +29,11 @@ pub struct NodeSearcher { impl NodeSearcher { pub fn new - (world:&World, logger:&Logger, controller:controller::graph::Handle, fonts:&mut font::Registry) + ( world : &World + , logger : &Logger + , node_editor : NodeEditor + , controller : controller::graph::Handle + , fonts : &mut font::Registry) -> Self { let scene = world.scene(); let camera = scene.camera(); @@ -31,40 +41,54 @@ impl NodeSearcher { let logger = logger.sub("NodeSearcher"); let display_object = display::object::Instance::new(&logger); let properties = TextFieldProperties { - font : fonts.get_or_load_embedded_font("DejaVuSansMono").unwrap(), - text_size : 16.0, - base_color : color::Rgba::new(1.0, 1.0, 1.0, 0.7), - size : Vector2::new(screen.width,16.0), + font : fonts.get_or_load_embedded_font("DejaVuSansMono").unwrap(), + text_size : 16.0, + base_color : color::Rgba::new(1.0, 1.0, 1.0, 0.7), + size : Vector2::new(screen.width,16.0), }; - let text_field = TextField::new(world,properties); + let text_field = TextField::new(world,properties); display_object.add_child(&text_field.display_object()); - let searcher = NodeSearcher{ display_object,text_field,controller,logger}; + let searcher = NodeSearcher{node_editor,display_object,text_field,controller,logger}; searcher.initialize() } fn initialize(self) -> Self { - let text_field_weak = self.text_field.downgrade(); - let controller = self.controller.clone(); + let mut node_searcher = self.clone_ref(); self.text_field.set_text_edit_callback(move |change| { // If the text edit callback is called, the TextEdit must be still alive. - let text_field = text_field_weak.upgrade().unwrap(); - let field_content = text_field.get_content(); + let field_content = node_searcher.text_field.get_content(); let expression = field_content.split('\n').next().unwrap(); if change.inserted == "\n" { - let metadata = default(); + let position = node_searcher.display_object.position(); + let position = position - node_searcher.node_editor.position(); + let position = Some(Position{vector:Vector2::new(position.x,position.y)}); + let metadata = Some(NodeMetadata{position}); let id = None; let location_hint = LocationHint::End; let expression = expression.to_string(); let new_node = NewNodeInfo { expression,metadata,id,location_hint }; - controller.add_node(new_node); - text_field.clear_content(); + node_searcher.controller.add_node(new_node); + node_searcher.hide(); } else { // Keep only one line. - text_field.set_content(expression); + node_searcher.text_field.set_content(expression); } }); self } + + /// Show NodeSearcher if it is invisible. + pub fn show(&mut self) { + self.display_object.add_child(&self.text_field.display_object()); + self.text_field.clear_content(); + self.text_field.set_focus(); + } + + /// Hide NodeSearcher if it is visible. + pub fn hide(&mut self) { + self.text_field.clear_content(); + self.display_object.remove_child(&self.text_field.display_object()); + } } impl display::Object for NodeSearcher {