Original commit: 3c8b4b37ad
This commit is contained in:
Michael Mauderer 2021-02-12 12:38:06 +00:00 committed by GitHub
parent 6229013e87
commit 0b4bf473d1
6 changed files with 274 additions and 2 deletions

View File

@ -36,12 +36,14 @@ read the notes of the `Enso 2.0.0-alpha.1` release.
- [Added the ability to reposition visualisations.][1096] There is now an icon in the visualization
action bar that allows dragging the visualization. Once the visualization has been moved, there
appears another icon that will reset the position to the original position.
- [There is now an API to show VCS status for node][1160].
- [A shortcut for reloading visualization files.][1190] The visible visualizations must be switched
to another and switched back to see the effect.
[1096]: https://github.com/enso-org/ide/pull/1172
[1098]: https://github.com/enso-org/ide/pull/1098
[1181]: https://github.com/enso-org/ide/pull/1181
[1160]: https://github.com/enso-org/ide/pull/1160
[1190]: https://github.com/enso-org/ide/pull/1190
<br/>

View File

@ -199,6 +199,11 @@ define_themes! { [light:0, dark:1]
hovered = Lcha(0.0,0.0,0.0,0.45) , Lcha(1.0,0.0,0.0,0.7);
}
}
vcs {
unchanged = Lcha::transparent(), Lcha::transparent();
added = Lcha::green(0.8,1.0), Lcha::green(0.8,1.0);
edited = Lcha::yellow(0.9,1.0), Lcha::yellow(0.9,1.0);
}
}
visualization {
background = Lcha(0.98,0.014,0.18,1.0) , Lcha(0.2,0.014,0.18,1.0);

View File

@ -10,6 +10,8 @@ pub mod input;
pub mod output;
#[deny(missing_docs)]
pub mod error;
#[deny(missing_docs)]
pub mod vcs;
pub use expression::Expression;
pub use error::Error;
@ -246,8 +248,9 @@ ensogl::define_endpoints! {
/// Set the expression USAGE type. This is not the definition type, which can be set with
/// `set_expression` instead. In case the usage type is set to None, ports still may be
/// colored if the definition type was present.
set_expression_usage_type (Crumbs,Option<Type>),
set_expression_usage_type (Crumbs,Option<Type>),
set_output_expression_visibility (bool),
set_vcs_status (Option<vcs::Status>),
}
Output {
/// Press event. Emitted when user clicks on non-active part of the node, like its
@ -350,6 +353,7 @@ pub struct NodeModel {
pub output : output::Area,
pub visualization : visualization::Container,
pub action_bar : action_bar::ActionBar,
pub vcs_indicator : vcs::StatusIndicator,
}
impl NodeModel {
@ -381,12 +385,14 @@ impl NodeModel {
let main_area = shape::View::new(&main_logger);
let drag_area = drag_area::View::new(&drag_logger);
let error_text = app.new_view::<text::Area>();
let vcs_indicator = vcs::StatusIndicator::new(app);
let display_object = display::object::Instance::new(&logger);
display_object.add_child(&drag_area);
display_object.add_child(&main_area);
display_object.add_child(&error_indicator);
display_object.add_child(&error_text);
display_object.add_child(&vcs_indicator);
error_text.set_default_color.emit(color::Rgba::red());
error_text.set_default_text_size(TextSize::from(TEXT_SIZE));
@ -411,7 +417,7 @@ impl NodeModel {
let app = app.clone_ref();
Self {app,display_object,logger,main_area,drag_area,output,input,visualization,action_bar,
error_indicator,error_text}.init()
error_indicator,error_text,vcs_indicator}.init()
}
pub fn get_crumbs_by_id(&self, id:ast::Id) -> Option<Crumbs> {
@ -452,10 +458,13 @@ impl NodeModel {
self.main_area.size.set(padded_size);
self.drag_area.size.set(padded_size);
self.error_indicator.size.set(padded_size);
self.vcs_indicator.set_size(padded_size);
self.main_area.mod_position(|t| t.x = width/2.0);
self.drag_area.mod_position(|t| t.x = width/2.0);
self.error_indicator.set_position_x(width/2.0);
self.vcs_indicator.set_position_x(width/2.0);
self.error_text.set_position_y(height + TEXT_SIZE);
self.error_text.set_position_x(CORNER_RADIUS);
@ -584,6 +593,10 @@ impl Node {
eval bg_color_anim.value ((c)
model.main_area.bg_color.set(color::Rgba::from(c).into())
);
// === VCS Handling ===
model.vcs_indicator.frp.set_status <+ frp.set_vcs_status;
}
frp.set_error.emit(None);

View File

@ -0,0 +1,200 @@
//! Functionality related to visualising the version control system status of a node.
use crate::component::node as node;
use crate::prelude::*;
use enso_frp as frp;
use ensogl::application::Application;
use ensogl::data::color;
use ensogl::display::shape::*;
use ensogl::display;
// ==============
// === Status ===
// ==============
/// The version control system status of a node.
#[derive(Debug,Copy,Clone)]
#[allow(missing_docs)]
pub enum Status {
Unchanged,
Added,
Edited,
}
impl Status {
fn get_highlight_color_from_style(self, style:&StyleWatch) -> color::Lcha {
match self {
Status::Unchanged => style.get_color(ensogl_theme::graph_editor::node::vcs::unchanged),
Status::Added => style.get_color(ensogl_theme::graph_editor::node::vcs::added),
Status::Edited => style.get_color(ensogl_theme::graph_editor::node::vcs::edited),
}
}
}
impl Default for Status {
fn default() -> Self {
Status::Unchanged
}
}
// =======================
// === Indicator Shape ===
// =======================
/// Shape used in the status indicator. Appears as a colored border surrounding the node.
mod status_indicator_shape {
use super::*;
const INDICATOR_WIDTH_OUTER : f32 = 15.0;
const INDICATOR_WIDTH_INNER : f32 = 10.0;
ensogl::define_shape_system! {
(style:Style,color_rgba:Vector4<f32>) {
let width = Var::<Pixels>::from("input_size.x");
let height = Var::<Pixels>::from("input_size.y");
let width = width - node::PADDING.px() * 2.0;
let height = height - node::PADDING.px() * 2.0;
let radius = node::RADIUS.px();
let base = Rect((&width,&height)).corners_radius(&radius);
let outer = base.grow(INDICATOR_WIDTH_OUTER.px());
let inner = base.grow(INDICATOR_WIDTH_INNER.px());
(outer-inner).fill(color_rgba).into()
}
}
}
// ==============================
// === Status Indicator Model ===
// ==============================
/// Internal data of `StatusIndicator`.
#[derive(Clone,CloneRef,Debug)]
struct StatusIndicatorModel {
shape : status_indicator_shape::View,
root : display::object::Instance,
}
impl StatusIndicatorModel {
fn new(logger: &Logger) -> Self {
let shape = status_indicator_shape::View::new(logger);
let root = display::object::Instance::new(&logger);
root.add_child(&shape);
StatusIndicatorModel{shape, root}
}
fn hide(&self) {
self.shape.unset_parent();
}
fn show(&self) {
self.root.add_child(&self.shape);
}
fn set_visibility(&self, visibility:bool) {
if visibility {
self.show()
} else {
self.hide()
}
}
}
impl display::Object for StatusIndicatorModel {
fn display_object(&self) -> &display::object::Instance {
&self.root
}
}
// =======================
// === StatusIndicator ===
// =======================
ensogl::define_endpoints! {
Input {
set_status (Option<Status>),
set_size (Vector2),
set_visibility (bool),
}
Output {
status (Option<Status>),
}
}
#[derive(Clone,CloneRef,Debug)]
#[allow(missing_docs)]
pub struct StatusIndicator {
model : Rc<StatusIndicatorModel>,
pub frp : Frp,
}
impl StatusIndicator {
/// Constructor.
pub fn new(app:&Application) -> Self {
let logger = Logger::new("status_indicator");
let model = Rc::new(StatusIndicatorModel::new(&logger));
let frp = Frp::new();
Self {frp,model}.init_frp(app)
}
fn init_frp(self, app:&Application) -> Self {
let frp = &self.frp;
let model = &self.model;
let network = &frp.network;
let indicator_color = color::Animation::new(network);
// FIXME : StyleWatch is unsuitable here, as it was designed as an internal tool for shape
// system (#795)
let styles = StyleWatch::new(&app.display.scene().style_sheet);
frp::extend! { network
frp.source.status <+ frp.input.set_status;
status_color <- frp.set_status.unwrap().map(f!([styles](status)
status.get_highlight_color_from_style(&styles)
));
indicator_color.target <+ status_color;
eval indicator_color.value ((c)
model.shape.color_rgba.set(color::Rgba::from(c).into())
);
eval frp.input.set_size ((size)
model.shape.size.set(*size);
);
has_status <- frp.status.map(|status| status.is_some());
visible <- and(&frp.input.set_visibility,&has_status);
eval visible ([model](visible) model.set_visibility(*visible));
};
frp.set_status.emit(None);
frp.set_visibility.emit(true);
self
}
}
impl display::Object for StatusIndicator {
fn display_object(&self) -> &display::object::Instance {
&self.model.display_object()
}
}
impl Deref for StatusIndicator {
type Target = Frp;
fn deref(&self) -> &Self::Target {
&self.frp
}
}

View File

@ -408,6 +408,11 @@ ensogl::define_endpoints! {
debug_set_test_visualization_data_for_selected_node(),
// === VCS Status ===
set_node_vcs_status ((NodeId,Option<node::vcs::Status>)),
set_detached_edge_targets (EdgeEndpoint),
set_detached_edge_sources (EdgeEndpoint),
set_edge_source ((EdgeId,EdgeEndpoint)),
@ -2794,6 +2799,16 @@ fn new_graph_editor(app:&Application) -> GraphEditor {
// ================
// === Node VCS ===
// ================
eval inputs.set_node_vcs_status(((node_id,status))
model.with_node(*node_id, |node| node.set_vcs_status.emit(status))
);
// ==================
// === Edge Binds ===
// ==================

View File

@ -130,6 +130,29 @@ fn init(app:&Application) {
graph_editor.frp.connect_nodes.emit((src,tgt));
// === VCS ===
let dummy_node_added_id = graph_editor.add_node();
let dummy_node_edited_id = graph_editor.add_node();
let dummy_node_unchanged_id = graph_editor.add_node();
graph_editor.frp.set_node_position.emit((dummy_node_added_id,Vector2(-450.0,50.0)));
graph_editor.frp.set_node_position.emit((dummy_node_edited_id,Vector2(-450.0,125.0)));
graph_editor.frp.set_node_position.emit((dummy_node_unchanged_id,Vector2(-450.0,200.0)));
let dummy_node_added_expr = expression_mock_string("This node was added.");
let dummy_node_edited_expr = expression_mock_string("This node was edited.");
let dummy_node_unchanged_expr = expression_mock_string("This node was not changed.");
graph_editor.frp.set_node_expression.emit((dummy_node_added_id,dummy_node_added_expr));
graph_editor.frp.set_node_expression.emit((dummy_node_edited_id,dummy_node_edited_expr));
graph_editor.frp.set_node_expression.emit((dummy_node_unchanged_id,dummy_node_unchanged_expr));
graph_editor.frp.set_node_vcs_status.emit((dummy_node_added_id,Some(vcs::Status::Edited)));
graph_editor.frp.set_node_vcs_status.emit((dummy_node_edited_id,Some(vcs::Status::Added)));
graph_editor.frp.set_node_vcs_status.emit((dummy_node_unchanged_id,Some(vcs::Status::Unchanged)));
// === Types (Port Coloring) ===
let mut dummy_type_generator = DummyTypeGenerator::default();
@ -215,6 +238,7 @@ fn init(app:&Application) {
// =============
use crate::graph_editor::component::node::Expression;
use crate::graph_editor::component::node::vcs;
use ast::crumbs::*;
use ast::crumbs::PatternMatchCrumb::*;
@ -223,6 +247,19 @@ use ensogl_text_msdf_sys::run_once_initialized;
use span_tree::traits::*;
pub fn expression_mock_string(label:&str) -> Expression {
let pattern = Some(label.to_string());
let code = format!("\"{}\"", label);
let parser = Parser::new_or_panic();
let parameters = vec![];
let ast = parser.parse_line(&code).unwrap();
let invocation_info = span_tree::generate::context::CalledMethodInfo {parameters};
let ctx = span_tree::generate::MockContext::new_single(ast.id.unwrap(),invocation_info);
let output_span_tree = span_tree::SpanTree::default();
let input_span_tree = span_tree::SpanTree::new(&ast,&ctx).unwrap();
Expression {pattern,code,input_span_tree,output_span_tree}
}
pub fn expression_mock() -> Expression {
let pattern = Some("var1".to_string());
let code = "[1,2,3]".to_string();