This repository has been archived by the owner on Dec 28, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 34
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Implement tooltips that show the type of an output port on hover.
- Loading branch information
1 parent
6a3845e
commit 5b28468
Showing
18 changed files
with
761 additions
and
152 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,198 @@ | ||
//! Text label component. Appears as text with background. | ||
use crate::prelude::*; | ||
|
||
use enso_frp as frp; | ||
use enso_frp; | ||
use ensogl_core::application::Application; | ||
use ensogl_core::data::color; | ||
use ensogl_core::display::shape::*; | ||
use ensogl_core::display::traits::*; | ||
use ensogl_core::display; | ||
use ensogl_text as text; | ||
|
||
|
||
// ========================== | ||
// === Shapes Definitions === | ||
// ========================== | ||
|
||
|
||
// === Constants === | ||
|
||
const TEXT_OFFSET : f32 = 10.0; | ||
const TEXT_SIZE : f32 = 12.0; | ||
const HEIGHT : f32 = TEXT_SIZE * 3.0; | ||
const PADDING : f32 = 15.0; | ||
const SHADOW_SIZE : f32 = 10.0; | ||
|
||
|
||
// === Background === | ||
|
||
mod background { | ||
use super::*; | ||
|
||
ensogl_core::define_shape_system! { | ||
(style:Style,bg_color:Vector4) { | ||
use ensogl_theme::graph_editor::node as node_theme; | ||
|
||
let width = Var::<Pixels>::from("input_size.x"); | ||
let height = Var::<Pixels>::from("input_size.y"); | ||
let width = width - PADDING.px() * 2.0; | ||
let height = height - PADDING.px() * 2.0; | ||
let radius = &height / 2.0; | ||
let shape = Rect((&width,&height)).corners_radius(&radius); | ||
let shape = shape.fill(Var::<color::Rgba>::from(bg_color.clone())); | ||
|
||
|
||
// === Shadow === | ||
let alpha = Var::<f32>::from(format!("({0}.w)",bg_color)); | ||
let border_size_f = 16.0; | ||
let shadow_size = SHADOW_SIZE.px(); | ||
let shadow_width = &width + &shadow_size * 2.0; | ||
let shadow_height = &height + &shadow_size * 2.0; | ||
let shadow_radius = &shadow_height / 2.0; | ||
let shadow = Rect((shadow_width,shadow_height)).corners_radius(shadow_radius); | ||
let base_color = color::Rgba::from(style.get_color(node_theme::shadow)); | ||
let base_color = Var::<color::Rgba>::from(base_color); | ||
let base_color = base_color.multiply_alpha(&alpha); | ||
let fading_color = color::Rgba::from(style.get_color(node_theme::shadow::fading)); | ||
let fading_color = Var::<color::Rgba>::from(fading_color); | ||
let fading_color = fading_color.multiply_alpha(&alpha); | ||
let exponent = style.get_number_or(node_theme::shadow::exponent,2.0); | ||
let shadow_color = color::LinearGradient::new() | ||
.add(0.0,fading_color.into_linear()) | ||
.add(1.0,base_color.into_linear()); | ||
let shadow_color = color::SdfSampler::new(shadow_color) | ||
.max_distance(border_size_f) | ||
.slope(color::Slope::Exponent(exponent)); | ||
let shadow = shadow.fill(shadow_color); | ||
|
||
(shadow+shape).into() | ||
} | ||
} | ||
} | ||
|
||
|
||
|
||
// =========== | ||
// === FRP === | ||
// =========== | ||
|
||
ensogl_core::define_endpoints! { | ||
Input { | ||
set_content(String), | ||
set_opacity(f32) | ||
} | ||
Output { | ||
size (Vector2) | ||
} | ||
} | ||
|
||
|
||
|
||
// ============= | ||
// === Model === | ||
// ============= | ||
|
||
#[derive(Clone,Debug)] | ||
struct Model { | ||
background : background::View, | ||
label : text::Area, | ||
display_object : display::object::Instance, | ||
app : Application | ||
} | ||
|
||
impl Model { | ||
fn new(app: Application) -> Self { | ||
let app = app.clone_ref(); | ||
let scene = app.display.scene(); | ||
let logger = Logger::new("TextLabel"); | ||
let display_object = display::object::Instance::new(&logger); | ||
let label = app.new_view::<text::Area>(); | ||
let background = background::View::new(&logger); | ||
display_object.add_child(&background); | ||
display_object.add_child(&label); | ||
|
||
// Depth sorting of labels to in front of the background. | ||
label.remove_from_scene_layer_DEPRECATED(&scene.layers.main); | ||
label.add_to_scene_layer_DEPRECATED(&scene.layers.label); | ||
|
||
Model { label, display_object, background, app } | ||
} | ||
|
||
pub fn height(&self) -> f32 { | ||
HEIGHT | ||
} | ||
|
||
fn set_width(&self, width:f32) -> Vector2 { | ||
let height = self.height(); | ||
let size = Vector2(width*1.25,height); | ||
let padded_size = size + Vector2(PADDING,PADDING) * 2.0; | ||
self.background.size.set(padded_size); | ||
let text_origin = Vector2(PADDING / 2.0 + TEXT_OFFSET - size.x/2.0,TEXT_SIZE/2.0); | ||
self.label.set_position_xy(text_origin); | ||
padded_size | ||
} | ||
|
||
fn set_content(&self, t:&str) -> Vector2 { | ||
self.label.set_content(t); | ||
self.set_width(self.label.width.value()) | ||
} | ||
|
||
fn set_opacity(&self, value:f32) { | ||
let style = StyleWatch::new(&self.app.display.scene().style_sheet); | ||
let text_color_path = ensogl_theme::graph_editor::node::text; | ||
let text_color = style.get_color_dim(text_color_path).multiply_alpha(value); | ||
let text_color = color::Rgba::from(text_color); | ||
self.label.frp.set_color_all.emit(text_color); | ||
self.label.frp.set_default_color.emit(text_color); | ||
|
||
let bg_color_path = ensogl_theme::graph_editor::node::background; | ||
let bg_color = style.get_color_dim(bg_color_path).multiply_alpha(value); | ||
let bg_color = color::Rgba::from(bg_color); | ||
self.background.bg_color.set(bg_color.into()) | ||
} | ||
} | ||
|
||
|
||
|
||
// ============================ | ||
// === Text Label Component === | ||
// ============================ | ||
|
||
#[allow(missing_docs)] | ||
#[derive(Clone,CloneRef,Debug)] | ||
pub struct TextLabel { | ||
model : Rc<Model>, | ||
pub frp : Rc<Frp>, | ||
} | ||
|
||
|
||
impl TextLabel { | ||
/// Constructor. | ||
pub fn new(app:Application) -> Self { | ||
let frp = Rc::new(Frp::new()); | ||
let model = Rc::new(Model::new(app.clone_ref())); | ||
TextLabel {frp,model}.init() | ||
} | ||
|
||
fn init(self) -> Self { | ||
let frp = &self.frp; | ||
let network = &frp.network; | ||
let model = &self.model; | ||
|
||
frp::extend! { network | ||
frp.source.size <+ frp.set_content.map(f!((t) | ||
model.set_content(t) | ||
)); | ||
|
||
eval frp.set_opacity((value) model.set_opacity(*value)); | ||
} | ||
|
||
self | ||
} | ||
} | ||
|
||
impl display::Object for TextLabel { | ||
fn display_object(&self) -> &display::object::Instance { &self.model.display_object } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
116 changes: 116 additions & 0 deletions
116
src/rust/ensogl/lib/core/src/animation/frp/animation/hysteretic.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
//! Animation that has a delayed onset.\ | ||
use crate::prelude::*; | ||
|
||
use crate::Animation; | ||
use crate::Easing; | ||
|
||
use enso_frp as frp; | ||
|
||
|
||
|
||
// =========== | ||
// === Frp === | ||
// =========== | ||
|
||
crate::define_endpoints! { | ||
Input { | ||
/// Trigger start of animation towards start state (0.0). Will be delayed by onset time. | ||
to_start(), | ||
/// Trigger start of animation towards end state (1.0). Will be delayed by onset time. | ||
to_end(), | ||
} | ||
Output { | ||
/// Represents the numeric state of the animation in the range 0..1. | ||
value(f32), | ||
/// Triggered when the state reaches 1.0. | ||
on_end(), | ||
/// Triggered when the state reaches 0.0. | ||
on_start(), | ||
} | ||
} | ||
|
||
|
||
|
||
// =========================== | ||
// === HystereticAnimation === | ||
// =========================== | ||
|
||
/// Animation that has a delayed onset. | ||
/// | ||
/// The basic idea behind this animation is, that it changes between two states: of (0.0) and on | ||
/// (1.0), but only after a delay (`st`/`et` start delay, end delay). If the animation gets | ||
/// canceled before the delay has passed, nothing happens, and the delay resets. | ||
/// | ||
/// | ||
/// This can be used to hide state changes that are only happening for a short duration. For example | ||
/// consider a UI element that is shown when hovering ofer an icon. When only moving the mouse | ||
/// cursor past the icon we want to avoid the pop-up appearing and disappearing right away. The | ||
/// `HystereticAnimation` allows this by setting a `start_delay_duration` long enough to avoid | ||
/// triggering during the time it takes to move past the icon. Thus, when the cursor moves past the | ||
/// icon nothing is visible to the user, but if the mosque cursor stays on the icon longer than | ||
/// `start_delay_duration`, the animation starts, and the pop-up becomes visible. In reverse, when | ||
/// moving the cursor between multiple icons, the pop-up should not permanently start and disappear | ||
/// and re-appear. Thus setting a `end_delay_duration` will avoid the pop-up from disappearing, if | ||
/// the time the cursor is between icons is less than the `end_delay_duration`. Instead, the hiding | ||
/// will only start iof the cursos has left any icon triggering the pop-up for longer than the | ||
/// `end_delay_duration`. | ||
/// | ||
#[derive(CloneRef,Debug,Shrinkwrap)] | ||
pub struct HystereticAnimation { | ||
/// Public FRP Api. | ||
pub frp : FrpEndpoints, | ||
} | ||
|
||
impl HystereticAnimation { | ||
/// Constructor. | ||
pub fn new(network:&frp::Network, start_delay_duration:f32, end_delay_duration:f32) -> Self { | ||
let frp = Frp::extend(network); | ||
|
||
let start_delay = Easing::new(network); | ||
let end_delay = Easing::new(network); | ||
start_delay.set_duration(start_delay_duration); | ||
end_delay.set_duration(end_delay_duration); | ||
|
||
let transition = Animation::<f32>::new(network); | ||
|
||
frp::extend! { network | ||
|
||
during_transition <- any_mut(); | ||
|
||
on_end <- frp.to_end.constant(()); | ||
on_end_while_active <- on_end.gate(&during_transition); | ||
on_end_while_inactive <- on_end.gate_not(&during_transition); | ||
|
||
on_start <- frp.to_start.constant(()); | ||
on_start_while_active <- on_start.gate(&during_transition); | ||
on_start_while_inactive <- on_start.gate_not(&during_transition); | ||
|
||
start_delay.target <+ on_start_while_inactive.constant(1.0); | ||
end_delay.target <+ on_end_while_inactive.constant(1.0); | ||
|
||
start_delay.stop_and_rewind <+ on_end.constant(0.0); | ||
end_delay.stop_and_rewind <+ on_start.constant(0.0); | ||
|
||
offset_start <- end_delay.on_end.map(|t| t.is_normal()).on_true(); | ||
onset_start <- start_delay.on_end.map(|t| t.is_normal()).on_true(); | ||
|
||
onset_end <- transition.value.map(|t| (t - 1.0).abs() < std::f32::EPSILON).on_true(); | ||
offset_end <- transition.value.map(|t| t.abs() < std::f32::EPSILON).on_true(); | ||
|
||
transition.target <+ onset_start.constant(1.0); | ||
transition.target <+ offset_start.constant(0.0); | ||
transition.target <+ on_end_while_active.constant(0.0); | ||
transition.target <+ on_start_while_active.constant(1.0); | ||
|
||
during_transition <+ bool(&onset_end,&onset_start); | ||
during_transition <+ bool(&offset_end,&offset_start); | ||
|
||
frp.source.value <+ transition.value; | ||
frp.source.on_end <+ onset_end; | ||
frp.source.on_start <+ offset_end; | ||
} | ||
|
||
HystereticAnimation{frp} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.