Skip to content

Commit

Permalink
Component Group View with static header and without icons (#3373)
Browse files Browse the repository at this point in the history
Add an initial version of the visual component for displaying the Component Group View. The component contains a header (for displaying the Group Name) and a list of labels (for displaying the component names).

https://www.pivotaltracker.com/story/show/181724889


#### Visuals

A screenshot from a debug scene demonstrating the component:

<img width="251" alt="Screenshot 2022-04-13 at 20 07 56" src="https://user-images.githubusercontent.com/273837/163243304-21c3ad78-4813-4368-b3bb-844d979da699.png">



Screenshots from other debug scenes (`list_view` and `text_area`), demonstrating that the other components still display correctly:

<img width="202" alt="Screenshot 2022-04-13 at 20 08 56" src="https://user-images.githubusercontent.com/273837/163243428-de9dc1c7-5a9f-45e0-9325-db60cece9768.png">


<img width="403" alt="Screenshot 2022-04-13 at 20 08 48" src="https://user-images.githubusercontent.com/273837/163243432-895061d9-5bd9-4349-8679-eb63b0f6724d.png">


A screenshot of the Node Searcher's list, showing that long entries in a ListView are now truncated, and an ellipsis character is added in place of removed characters:


<img width="651" alt="Screenshot 2022-04-13 at 20 10 16" src="https://user-images.githubusercontent.com/273837/163243664-5b671969-7aa0-4bef-8fd2-825602d85848.png">

# Important Notes
- Adding support for the text truncation feature in `ListView` required some changes in the`list_view::Entry`-related APIs.
- An embedded font was added (DejaVuSans-Bold) for use in the Component Group View debug scene, and 5 unused embedded fonts were removed.
  • Loading branch information
akavel authored Apr 14, 2022
1 parent 0ea5dc2 commit e75df61
Show file tree
Hide file tree
Showing 22 changed files with 664 additions and 40 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

#### Visual Environment

- [Long names on the Node Searcher's list are truncated.][3373] The part of the
name that doesn't fit in the Searcher's window is replaced with an ellipsis
character ("…").
- [Magnet Alignment algorithm is used while placing new nodes][3366]. When we
find an available free space for a new node, the node gets aligned with the
surrounding nodes horizontally and vertically. This helps to preserve a nice
Expand Down Expand Up @@ -154,6 +157,7 @@
[3349]: https://github.com/enso-org/enso/pull/3349
[3361]: https://github.com/enso-org/enso/pull/3361
[3364]: https://github.com/enso-org/enso/pull/3364
[3373]: https://github.com/enso-org/enso/pull/3373
[3377]: https://github.com/enso-org/enso/pull/3377
[3366]: https://github.com/enso-org/enso/pull/3366
[3379]: https://github.com/enso-org/enso/pull/3379
Expand Down
27 changes: 26 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions app/gui/view/component-browser/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "ide-view-component-browser"
version = "0.1.0"
authors = ["Enso Team <[email protected]>"]
edition = "2021"

[lib]
crate-type = ["cdylib", "rlib"]

[dependencies]
ide-view-component-group = { path = "component-group" }
17 changes: 17 additions & 0 deletions app/gui/view/component-browser/component-group/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[package]
name = "ide-view-component-group"
version = "0.1.0"
authors = ["Enso Team <[email protected]>"]
edition = "2021"

[lib]
crate-type = ["cdylib", "rlib"]

[dependencies]
enso-frp = { version = "0.1.0", path = "../../../../../lib/rust/frp" }
ensogl-core = { version = "0.1.0", path = "../../../../../lib/rust/ensogl/core" }
ensogl-gui-component = { version = "0.1.0", path = "../../../../../lib/rust/ensogl/component/gui" }
ensogl-hardcoded-theme = { version = "0.1.0", path = "../../../../../lib/rust/ensogl/app/theme/hardcoded" }
ensogl-list-view = { version = "0.1.0", path = "../../../../../lib/rust/ensogl/component/list-view" }
ensogl-text = { version = "0.1.0", path = "../../../../../lib/rust/ensogl/component/text" }

250 changes: 250 additions & 0 deletions app/gui/view/component-browser/component-group/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@
//! This module defines a widget for displaying a list of entries of a component group and the name
//! of the component group.
//!
//! The widget is defined by the [`View`].
//!
//! To learn more about component groups, see the [Component Browser Design
//! Document](https://github.com/enso-org/design/blob/e6cffec2dd6d16688164f04a4ef0d9dff998c3e7/epics/component-browser/design.md).
// === Standard Linter Configuration ===
#![deny(non_ascii_idents)]
#![warn(unsafe_code)]
// === 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_core::prelude::*;

use enso_frp as frp;
use ensogl_core::application::Application;
use ensogl_core::data::color::Rgba;
use ensogl_core::display;
use ensogl_core::display::shape::*;
use ensogl_gui_component::component;
use ensogl_hardcoded_theme::application::component_browser::component_group as theme;
use ensogl_list_view as list_view;
use ensogl_text as text;



// =================
// === Constants ===
// =================

const HEADER_FONT: &str = "DejaVuSans-Bold";



// ==========================
// === Shapes Definitions ===
// ==========================


// === Background ===

/// The background of the [`View`].
pub mod background {
use super::*;

ensogl_core::define_shape_system! {
below = [list_view::background];
(style:Style, color:Vector4) {
let sprite_width: Var<Pixels> = "input_size.x".into();
let sprite_height: Var<Pixels> = "input_size.y".into();
let color = Var::<Rgba>::from(color);
// TODO[MC,WD]: We should use Plane here, but it has a bug - renders wrong color. See:
// https://github.com/enso-org/enso/pull/3373#discussion_r849054476
let shape = Rect((&sprite_width, &sprite_height)).fill(color);
shape.into()
}
}
}



// =======================
// === Header Geometry ===
// =======================

#[derive(Debug, Copy, Clone, Default)]
struct HeaderGeometry {
height: f32,
padding_left: f32,
padding_right: f32,
padding_bottom: f32,
}

impl HeaderGeometry {
fn from_style(style: &StyleWatchFrp, network: &frp::Network) -> frp::Sampler<Self> {
let height = style.get_number(theme::header::height);
let padding_left = style.get_number(theme::header::padding::left);
let padding_right = style.get_number(theme::header::padding::right);
let padding_bottom = style.get_number(theme::header::padding::bottom);

frp::extend! { network
init <- source_();
theme <- all_with5(&init,&height,&padding_left,&padding_right,&padding_bottom,
|_,&height,&padding_left,&padding_right,&padding_bottom|
Self{height,padding_left,padding_right,padding_bottom}
);
theme_sampler <- theme.sampler();
}
init.emit(());
theme_sampler
}
}



// ===========
// === FRP ===
// ===========

ensogl_core::define_endpoints_2! {
Input {
set_header(String),
set_entries(list_view::entry::AnyModelProvider<list_view::entry::Label>),
set_background_color(Rgba),
set_size(Vector2),
}
Output {}
}

impl component::Frp<Model> for Frp {
fn init(api: &Self::Private, _app: &Application, model: &Model, style: &StyleWatchFrp) {
let network = &api.network;
let input = &api.input;
let header_text_size = style.get_number(theme::header::text::size);
frp::extend! { network

// === Geometry ===

let header_geometry = HeaderGeometry::from_style(style, network);
size_and_header_geometry <- all(&input.set_size, &header_geometry);
eval size_and_header_geometry(((size, hdr_geom)) model.resize(*size, *hdr_geom));


// === Header ===

init <- source_();
header_text_size <- all(&header_text_size, &init)._0();
model.header.set_default_text_size <+ header_text_size.map(|v| text::Size(*v));
_set_header <- input.set_header.map2(&size_and_header_geometry, f!(
(text, (size, hdr_geom)) {
model.header_text.replace(text.clone());
model.update_header_width(*size, *hdr_geom);
})
);
eval input.set_background_color((c)
model.background.color.set(c.into()));


// === Entries ===

model.entries.set_background_color(HOVER_COLOR);
model.entries.show_background_shadow(false);
model.entries.set_background_corners_radius(0.0);
model.entries.set_background_color <+ input.set_background_color;
model.entries.set_entries <+ input.set_entries;
}
init.emit(());
}
}



// =============
// === Model ===
// =============

/// The Model of the [`View`] component.
#[derive(Clone, CloneRef, Debug)]
pub struct Model {
display_object: display::object::Instance,
header: text::Area,
header_text: Rc<RefCell<String>>,
background: background::View,
entries: list_view::ListView<list_view::entry::Label>,
}

impl display::Object for Model {
fn display_object(&self) -> &display::object::Instance {
&self.display_object
}
}

impl component::Model for Model {
fn label() -> &'static str {
"ComponentGroup"
}

fn new(app: &Application, logger: &Logger) -> Self {
let header_text = default();
let display_object = display::object::Instance::new(&logger);
let background = background::View::new(&logger);
let header = text::Area::new(app);
let entries = list_view::ListView::new(app);
display_object.add_child(&background);
display_object.add_child(&header);
display_object.add_child(&entries);

header.set_font(HEADER_FONT);
let label_layer = &app.display.default_scene.layers.label;
header.add_to_scene_layer(label_layer);

Model { display_object, header, header_text, background, entries }
}
}

impl Model {
fn resize(&self, size: Vector2, header_geometry: HeaderGeometry) {
// === Background ===

self.background.size.set(size);


// === Header Text ===

let header_padding_left = header_geometry.padding_left;
let header_text_x = -size.x / 2.0 + header_padding_left;
let header_text_height = self.header.height.value();
let header_padding_bottom = header_geometry.padding_bottom;
let header_height = header_geometry.height;
let header_bottom_y = size.y / 2.0 - header_height;
let header_text_y = header_bottom_y + header_text_height + header_padding_bottom;
self.header.set_position_xy(Vector2(header_text_x, header_text_y));
self.update_header_width(size, header_geometry);


// === Entries ===

self.entries.resize(size - Vector2(0.0, header_height));
self.entries.set_position_y(-header_height / 2.0);
}

fn update_header_width(&self, size: Vector2, header_geometry: HeaderGeometry) {
let header_padding_left = header_geometry.padding_left;
let header_padding_right = header_geometry.padding_right;
let max_text_width = size.x - header_padding_left - header_padding_right;
self.header.set_content_truncated(self.header_text.borrow().clone(), max_text_width);
}
}



// ============
// === View ===
// ============

/// A widget for displaying the entries and name of a component group.
///
/// The widget is rendered as a header label, a list of entries below it, and a colored background.
///
/// To learn more about component groups, see the [Component Browser Design
/// Document](https://github.com/enso-org/design/blob/e6cffec2dd6d16688164f04a4ef0d9dff998c3e7/epics/component-browser/design.md).
pub type View = component::ComponentView<Model, Frp>;
19 changes: 19 additions & 0 deletions app/gui/view/component-browser/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// === Standard Linter Configuration ===
#![deny(non_ascii_idents)]
#![warn(unsafe_code)]
// === 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)]


// ==============
// === Export ===
// ==============

pub use ide_view_component_group as component_group;

1 change: 1 addition & 0 deletions app/gui/view/debug_scene/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ edition = "2021"
crate-type = ["cdylib", "rlib"]

[dependencies]
debug-scene-component-group = { path = "component-group" }
debug-scene-interface = { path = "interface" }
debug-scene-visualization = { path = "visualization" }
17 changes: 17 additions & 0 deletions app/gui/view/debug_scene/component-group/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[package]
name = "debug-scene-component-group"
version = "0.1.0"
authors = ["Enso Team <[email protected]>"]
edition = "2021"

[lib]
crate-type = ["cdylib", "rlib"]

[dependencies]
enso-frp = { path = "../../../../../lib/rust/frp" }
ensogl-core = { path = "../../../../../lib/rust/ensogl/core" }
ensogl-hardcoded-theme = { path = "../../../../../lib/rust/ensogl/app/theme/hardcoded" }
ensogl-list-view = { path = "../../../../../lib/rust/ensogl/component/list-view" }
ensogl-text-msdf-sys = { path = "../../../../../lib/rust/ensogl/component/text/msdf-sys" }
ide-view-component-group = { path = "../../component-browser/component-group" }
wasm-bindgen = { version = "0.2.78", features = ["nightly"] }
Loading

0 comments on commit e75df61

Please sign in to comment.