Introduce new focus APIs, and use for CB (#7167)

Introduce new APIs for managing focus and using focus to inform delivery of keyboard events.

Use new APIs to implement the following behavior:

Focus:
- If the component browser is opened, its initial state is *focused*.
- If the node input area's text component is clicked, the component browser's state becomes *blurred*.
- If a click occurs anywhere in the component browser, the component browser's state becomes *focused*.

Event dispatch:
- When the component browser is in the *focused* state, it handles certain keyboard events (chiefly, arrow keys).
- If the component browser handles an event, the event is not received by other components.
- If an event occurs that the component browser doesn't handle, the node input area's text component receives the event.

[vokoscreenNG-2023-06-29_10-55-00.webm](https://github.com/enso-org/enso/assets/1047859/f1d9d07c-8c32-4482-ba32-15b6e4e20ae7)

# Important Notes
Changes to display object interface:
- **`display::Object` can now be derived.**
- Introduce display object *focus receiver* concept. Many components, when receiving focus, should actually be focused indirectly by focusing a descendant.
- For example, when the CB Panel receives focus, its descendant at `self.model().grid.model().grid` should be focused, because that's the underlying Grid View, which has its own event handlers. By allowing each level of the hierarchy to define a `focus_receiver`, focus can reach the right object without the CB panel having to know structural details of its descendants.
- When delegating to a field's `display::Object` implementation, the derived implementation uses the child's `focus_receiver`, which will normally be the correct behavior.

**Changes to `shortcut` API**:
- New `View::focused_shortcuts()` is a focus-aware alternative to `View::default_shortcuts()` (which should now only be used for global shortcuts, i.e. shortcuts that don't depend on whether the component is focused). It's based on the *Keyboard Event* API (see below), so events propagate up the focus hierarchy until a shortcut is executed and `stop_propagation()` is called; this allows sensible resolution of event targets when more than one component is capable of handling the same keypress.

Keypress dataflow overview:
DOM -> KeyboardManager -> FrpKeyboard -> KeyboardEvents -> Shortcut.

Low-level keyboard changes to support Focus:
- New `KeyboardManager`: Attaches DOM event handlers the same way as `MouseManager`.
- New *Keyboard Event* API: `on_event::<KeyDown>()`. Events propagate up the focus hierarchy. This API is used for low-level keyboard listeners such a `Text`, which may need complex logic to determine whether a key is handled (rather than having a closed set of bindings, which can be handled by `shortcut`).
- FRP keyboard: Now attaches to the `KeyboardManager` API. It now serves primarily to produce Keyboard Events (it still performs the role of making `KeyUp` events saner in a couple different ways). The FRP keyboard can also be used directly as a global keyboard, for such things as reacting to modifier state.

Misc:
- Updated the workspace `syn` to version 2. Crates still depending on legacy `syn` now do so through the workspace-level `syn_1` alias.
This commit is contained in:
Kaz Wesley 2023-07-26 15:13:48 -07:00 committed by GitHub
parent b288ccaa64
commit 828d160c56
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
142 changed files with 2206 additions and 1732 deletions

16
Cargo.lock generated
View File

@ -2272,7 +2272,7 @@ dependencies = [
"Inflector",
"proc-macro2",
"quote",
"syn 1.0.107",
"syn 2.0.15",
]
[[package]]
@ -2473,7 +2473,7 @@ dependencies = [
"Inflector",
"proc-macro2",
"quote",
"syn 1.0.107",
"syn 2.0.15",
]
[[package]]
@ -2674,6 +2674,7 @@ dependencies = [
"enso-shortcuts",
"enso-types",
"enso-web",
"ensogl-derive",
"ensogl-text-embedded-fonts",
"enum_dispatch",
"failure",
@ -2696,6 +2697,15 @@ dependencies = [
"web-sys",
]
[[package]]
name = "ensogl-derive"
version = "0.1.0"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.15",
]
[[package]]
name = "ensogl-derive-theme"
version = "0.1.0"
@ -4243,7 +4253,7 @@ dependencies = [
"sha2",
"strum",
"symlink",
"syn 1.0.107",
"syn 2.0.15",
"sysinfo",
"tar",
"tempfile",

View File

@ -125,7 +125,15 @@ matches = { version = "0.1" }
console_error_panic_hook = { version = "0.1.6" }
reqwest = { version = "0.11.5" }
proc-macro2 = { version = "1.0.50" }
syn = { version = "1.0", features = [
syn = { version = "2.0", features = [
"full",
"extra-traits",
"printing",
"parsing",
"visit",
"visit-mut",
] }
syn_1 = { package = "syn", version = "1.0", features = [
"full",
"extra-traits",
"printing",

View File

@ -72,17 +72,17 @@ impl Ide {
let network = &self.network;
let scene = &self.ensogl_app.display.default_scene;
let mouse = &scene.mouse.frp_deprecated;
let keyboard = &scene.keyboard.frp;
let keyboard = &scene.global_keyboard.frp;
enso_frp::extend! { network
on_log_sent <- source::<()>();
mouse_moved <- mouse.position.constant(()).profile();
any_mouse_press <- any(mouse.up,mouse.down).constant(()).profile();
any_mouse_event <- any(any_mouse_press,mouse_moved,mouse.wheel).profile();
any_keyboard_event <- any(keyboard.down,keyboard.up).constant(()).profile();
any_input_event <- any(any_mouse_event,any_keyboard_event).profile();
on_log_sent <- source::<()>();
mouse_moved <- mouse.position.constant(()).profile();
any_mouse_press <- any(mouse.up, mouse.down).constant(()).profile();
any_mouse_event <- any(any_mouse_press, mouse_moved, mouse.wheel).profile();
any_keyboard_event <- keyboard.any_event.profile();
any_input_event <- any(any_mouse_event, any_keyboard_event).profile();
// True if any input event was captured since the last "alive" log sending.
input_event_received <- bool(&on_log_sent,&any_input_event).profile().sampler();
input_event_received <- bool(&on_log_sent, &any_input_event).profile().sampler();
}
async move {
loop {

View File

@ -148,7 +148,7 @@ enum State {
/// representation for each entry in the grid view. For efficiency, text label and icons are
/// allocated once the entry is created.
#[allow(missing_docs)]
#[derive(Clone, Debug)]
#[derive(Clone, Debug, display::Object)]
pub struct EntryData {
display_object: display::object::Instance,
text: text::Text,
@ -280,9 +280,10 @@ pub struct Params {
// === Entry ===
/// A Breadcrumbs entry.
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
pub struct Entry {
frp: EntryFrp<Self>,
#[display_object]
data: Rc<EntryData>,
}
@ -375,9 +376,3 @@ impl ensogl_grid_view::Entry for Entry {
&self.frp
}
}
impl display::Object for Entry {
fn display_object(&self) -> &display::object::Instance {
&self.data.display_object
}
}

View File

@ -144,7 +144,7 @@ impl Layers {
// =============
/// A breadcrumbs model.
#[derive(Debug, Clone, CloneRef)]
#[derive(Debug, Clone, CloneRef, display::Object)]
pub struct Model {
display_object: display::object::Instance,
grid: GridView,
@ -427,9 +427,8 @@ ensogl_core::define_endpoints_2! {
/// === Widget ===
/// ==============
#[derive(Debug, Clone, CloneRef, Deref)]
#[derive(Debug, Clone, CloneRef, Deref, display::Object)]
pub struct Breadcrumbs {
#[deref]
widget: Widget<Model, Frp>,
}
@ -437,7 +436,6 @@ impl Breadcrumbs {
/// Constructor.
pub fn new(app: &Application) -> Self {
let model = Rc::new(Model::new(app));
let display_object = model.display_object.clone_ref();
let frp = Frp::new();
let network = frp.network();
let input = &frp.private().input;
@ -473,7 +471,7 @@ impl Breadcrumbs {
}
init.emit(());
let widget = Widget::new(app, frp, model, display_object);
let widget = Widget::new(app, frp, model);
Self { widget }
}
@ -492,7 +490,7 @@ impl ensogl_core::application::View for Breadcrumbs {
Self::new(app)
}
fn default_shortcuts() -> Vec<Shortcut> {
fn global_shortcuts() -> Vec<Shortcut> {
use ensogl_core::application::shortcut::ActionType::*;
[(Press, "shift enter", "move_up"), (Press, "ctrl shift enter", "move_down")]
.iter()
@ -506,9 +504,3 @@ impl FrpNetworkProvider for Breadcrumbs {
self.widget.frp().network()
}
}
impl display::Object for Breadcrumbs {
fn display_object(&self) -> &display::object::Instance {
self.widget.display_object()
}
}

View File

@ -139,7 +139,7 @@ pub struct Params {
// === Data ===
/// The data of Component Browser Entry [`View`], passed to its FRP nodes.
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
pub struct Data {
display_object: display::object::Instance,
label: text::Text,
@ -215,9 +215,10 @@ impl Data {
/// The entries (except [local scope entries](`Kind::LocalScopeEntry`) have width equal to the
/// column width declared in [`Style`]. Making grid column broader can create a nice vertical gaps
/// between columns. The horizontal gaps are left by the header entries (having a bit lower height).
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
pub struct View {
frp: grid_view::entry::EntryFrp<Self>,
#[display_object]
data: Data,
}
@ -287,9 +288,3 @@ impl grid_view::Entry for View {
&self.frp
}
}
impl display::Object for View {
fn display_object(&self) -> &display::object::Instance {
&self.data.display_object
}
}

View File

@ -118,6 +118,7 @@ ensogl_core::define_endpoints_2! {
accept_suggestion(),
/// Accept current input as expression, ignoring any active suggestion.
accept_current_input_expression(),
focus(),
}
Output {
active(Option<EntryId>),
@ -193,9 +194,10 @@ impl Style {
// === Model ===
/// A [Model](component::Model) of [Component List Panel Grid View](View).
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
pub struct Model {
display_object: display::object::Instance,
#[focus_receiver]
grid: Grid,
grid_layer: Layer,
selection_layer: Layer,
@ -421,15 +423,6 @@ impl Model {
}
// === display::Object Implementation ===
impl display::Object for Model {
fn display_object(&self) -> &display::object::Instance {
&self.display_object
}
}
// =================
// === FRP Logic ===
@ -455,6 +448,7 @@ impl component::Frp<Model> for Frp {
let colors = entry::style::Colors::from_theme(network, style_frp);
let selection_colors = entry::style::SelectionColors::from_theme(network, style_frp);
frp::extend! { network
// === Active and Hovered Entry ===
grid.select_entry <+ grid.entry_hovered;
@ -541,10 +535,12 @@ impl component::Frp<Model> for Frp {
grid_scroll_frp.set_content_height <+ grid.content_size.map(|c| c.y);
// === Focus propagation ===
// === Focus ===
// The underlying grid should handle keyboard events only when any element is active.
grid.deprecated_set_focus <+ out.focused && out.is_active;
eval_ input.focus (model.focus());
let focused = model.on_event::<ensogl_core::event::FocusIn>();
let defocused = model.on_event::<ensogl_core::event::FocusOut>();
grid.disable_selection <+ bool(&focused, &defocused);
}
grid.resize_grid(0, COLUMN_COUNT);
@ -562,9 +558,8 @@ impl component::Frp<Model> for Frp {
// underlying Grid View.
(Press, "!is_active", "enter", "accept_current_input_expression"),
(Press, "", "cmd enter", "accept_current_input_expression"),
(Press, "", "cmd up", "jump_group_up"),
(Press, "", "cmd down", "jump_group_down"),
(Press, "!is_active", "up", "select_first_entry"),
(Press, "!is_active", "up", "focus"),
]
.iter()
.map(|(a, b, c, d)| View::self_shortcut_when(*a, *c, *d, *b))

View File

@ -49,6 +49,7 @@ use ensogl_core::display::shape::*;
use enso_frp as frp;
use ensogl_core::application::frp::API;
use ensogl_core::application::Application;
use ensogl_core::control::io::mouse;
use ensogl_core::data::bounding_box::BoundingBox;
use ensogl_core::data::color;
use ensogl_core::define_endpoints_2;
@ -232,10 +233,11 @@ pub mod background {
/// The Model of Select Component.
#[allow(missing_docs)]
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
pub struct Model {
display_object: display::object::Instance,
background: background::View,
#[focus_receiver]
pub grid: grid::View,
pub breadcrumbs: breadcrumbs::Breadcrumbs,
}
@ -291,12 +293,6 @@ impl Model {
}
}
impl display::Object for Model {
fn display_object(&self) -> &display::object::Instance {
&self.display_object
}
}
impl component::Model for Model {
fn label() -> &'static str {
"ComponentBrowserPanel"
@ -363,10 +359,11 @@ impl component::Frp<Model> for Frp {
model.is_hovered(pos, style)
})).gate(&is_visible).on_change();
output.is_hovered <+ is_hovered;
// TODO[ib] Temporary solution for focus, we grab keyboard events if the
// component browser is visible. The proper implementation is tracked in
// https://www.pivotaltracker.com/story/show/180872763
model.grid.deprecated_set_focus <+ is_visible;
let mouse_down = model.on_event::<mouse::Down>();
eval_ mouse_down (model.focus());
eval_ input.show (model.focus());
eval_ input.hide (model.blur());
}
panel_style.init.emit(());

View File

@ -1,8 +1,6 @@
//! A crate with Component Browser View.
//!
//! Currently, this crate gathers the related panels. The Component Browser View itself is defined
//! in `ide_view` crate, because the Documentation panel is used by old node searcher as well, and
//! we need to avoid crates' circular dependencies.
//! Currently, this crate gathers the related panels.
#![recursion_limit = "256"]
// === Standard Linter Configuration ===
@ -44,7 +42,7 @@ pub use ide_view_component_list_panel_breadcrumbs as breadcrumbs;
/// The Model of Component Browser View.
#[allow(missing_docs)]
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
pub struct Model {
display_object: display::object::Instance,
pub list: component_list_panel::View,
@ -105,12 +103,6 @@ impl Model {
}
}
impl display::Object for Model {
fn display_object(&self) -> &display::object::Instance {
&self.display_object
}
}
ensogl::define_endpoints_2! {
Input {
show(),

View File

@ -81,7 +81,7 @@ pub struct Style {
/// Model of Native visualization that generates documentation for given Enso code and embeds
/// it in a HTML container.
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
#[allow(missing_docs)]
pub struct Model {
outer_dom: DomSymbol,
@ -259,10 +259,11 @@ ensogl::define_endpoints! {
/// however we're unable to summarize methods and atoms of types.
///
/// The default format is the docstring.
#[derive(Clone, CloneRef, Debug, Deref)]
#[derive(Clone, CloneRef, Debug, Deref, display::Object)]
#[allow(missing_docs)]
pub struct View {
#[deref]
#[display_object]
pub model: Model,
pub visualization_frp: visualization::instance::Frp,
pub frp: Frp,
@ -378,9 +379,3 @@ impl From<View> for visualization::Instance {
Self::new(&t, &t.visualization_frp, &t.frp.network, Some(t.model.outer_dom.clone_ref()))
}
}
impl display::Object for View {
fn display_object(&self) -> &display::object::Instance {
&self.model.display_object
}
}

View File

@ -104,7 +104,7 @@ ensogl::define_endpoints_2! {
// =============
/// The model of the execution environment selector.
#[derive(Debug, Clone, CloneRef)]
#[derive(Debug, Clone, CloneRef, display::Object)]
pub struct Model {
/// Main root object for the execution environment selector exposed for external positioning.
display_object: display::object::Instance,
@ -168,12 +168,6 @@ impl Model {
}
}
impl display::Object for Model {
fn display_object(&self) -> &display::object::Instance {
&self.display_object
}
}
// ====================================

View File

@ -91,7 +91,7 @@ ensogl::define_endpoints_2! {
// === Model ===
// =============
#[derive(Debug, Clone, CloneRef)]
#[derive(Debug, Clone, CloneRef, display::Object)]
pub struct Model {
display_object: display::object::Instance,
play_icon: play_icon::View,
@ -120,12 +120,6 @@ impl Model {
}
}
impl display::Object for Model {
fn display_object(&self) -> &display::object::Instance {
&self.display_object
}
}
// ===================

View File

@ -91,7 +91,7 @@ ensogl::define_endpoints_2! {
// === Model ===
// =============
#[derive(Debug, Clone, CloneRef)]
#[derive(Debug, Clone, CloneRef, display::Object)]
pub struct Model {
display_object: display::object::Instance,
play_icon: play_icon::View,
@ -120,12 +120,6 @@ impl Model {
}
}
impl display::Object for Model {
fn display_object(&self) -> &display::object::Instance {
&self.display_object
}
}
// ===================

View File

@ -40,14 +40,14 @@ pub mod shape {
// ========================
/// Sample implementation of a Bubble Chart.
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
#[allow(missing_docs)]
pub struct BubbleChartModel {
pub display_object: display::object::Instance,
pub scene: Scene,
signature: Signature,
views: Rc<RefCell<Vec<shape::View>>>,
size: Rc<Cell<Vector2>>,
display_object: display::object::Instance,
pub scene: Scene,
signature: Signature,
views: Rc<RefCell<Vec<shape::View>>>,
size: Rc<Cell<Vector2>>,
}
impl BubbleChartModel {
@ -81,10 +81,11 @@ impl BubbleChartModel {
// ===================
/// Sample implementation of a Bubble Chart.
#[derive(Debug, Deref)]
#[derive(Debug, Deref, display::Object)]
#[allow(missing_docs)]
pub struct BubbleChart {
#[deref]
#[display_object]
model: BubbleChartModel,
network: frp::Network,
frp: visualization::instance::Frp,
@ -135,9 +136,3 @@ impl From<BubbleChart> for Instance {
Self::new(&t, &t.frp, &t.network, None)
}
}
impl display::Object for BubbleChart {
fn display_object(&self) -> &display::object::Instance {
self.model.display_object.display_object()
}
}

View File

@ -80,10 +80,11 @@ pub struct Input {
// =============
/// Sample visualization that renders the given data as text. Useful for debugging and testing.
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
#[allow(missing_docs)]
pub struct Error {
pub frp: visualization::instance::Frp,
#[display_object]
model: Model,
network: frp::Network,
}
@ -152,9 +153,10 @@ impl Error {
}
}
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
#[allow(missing_docs)]
pub struct Model {
#[display_object]
dom: DomSymbol,
size: Rc<Cell<Vector2>>,
// FIXME : StyleWatch is unsuitable here, as it was designed as an internal tool for shape
@ -263,9 +265,3 @@ impl From<Error> for Instance {
Self::new(&t, &t.frp, &t.network, Some(t.model.dom.clone_ref()))
}
}
impl display::Object for Error {
fn display_object(&self) -> &display::object::Instance {
self.model.dom.display_object()
}
}

View File

@ -87,12 +87,12 @@ pub struct GridWindow {
// === Model ===
// =============
#[derive(Debug)]
#[derive(Debug, display::Object)]
#[allow(missing_docs)]
pub struct Model<T> {
app: Application,
size: Rc<Cell<Vector2>>,
root: display::object::Instance,
display_object: display::object::Instance,
// Note that we are using a simple `GridView` and our own scrollbar, instead of the
// `scrollable::GridView` to avoid adding `ScrollAreas` to the scene, as the clipping they
// provide though the `mask::View` is not free in terms of performance (they add a draw call
@ -108,7 +108,7 @@ pub struct Model<T> {
impl<T: 'static> Model<T> {
/// Constructor.
fn new(app: Application) -> Self {
let root = display::object::Instance::new();
let display_object = display::object::Instance::new();
let clipping_div = web::document.create_div_or_panic();
let clipping_div = DomSymbol::new(&clipping_div);
let dom_entry_root = web::document.create_div_or_panic();
@ -116,7 +116,7 @@ impl<T: 'static> Model<T> {
let text_provider = default();
let text_grid: GridView<grid_view_entry::Entry> = GridView::new(&app);
root.add_child(&text_grid);
display_object.add_child(&text_grid);
let scroll_bar_horizontal = Scrollbar::new(&app);
let scroll_bar_vertical = Scrollbar::new(&app);
@ -129,7 +129,7 @@ impl<T: 'static> Model<T> {
dom_entry_root,
scroll_bar_horizontal,
scroll_bar_vertical,
root,
display_object,
text_provider,
}
.init()
@ -148,7 +148,7 @@ impl<T: 'static> Model<T> {
self.clipping_div.set_style_or_warn("overflow", "hidden");
self.clipping_div.set_style_or_warn("z-index", "2");
scene.dom.layers.back.manage(&self.clipping_div);
self.root.add_child(&self.clipping_div);
self.display_object.add_child(&self.clipping_div);
// The `dom_entry_root` is a container for the elements and its position is not managed
// through the display object hierarchy to a avoid issues with mixing the DOM and EnsoGL
@ -159,8 +159,8 @@ impl<T: 'static> Model<T> {
}
fn init_scrollbars(&self) {
self.root.add_child(&self.scroll_bar_horizontal);
self.root.add_child(&self.scroll_bar_vertical);
self.display_object.add_child(&self.scroll_bar_horizontal);
self.display_object.add_child(&self.scroll_bar_vertical);
self.scroll_bar_vertical.set_rotation_z(-90.0_f32.to_radians());
}
@ -198,10 +198,11 @@ impl<T: TextProvider> Model<T> {
// ================
/// Sample visualization that renders the given data as text. Useful for debugging and testing.
#[derive(Debug, Deref)]
#[derive(Debug, Deref, display::Object)]
#[allow(missing_docs)]
pub struct TextGrid<T> {
#[deref]
#[display_object]
model: Rc<Model<T>>,
pub frp: visualization::instance::Frp,
network: frp::Network,
@ -411,12 +412,6 @@ impl<T> From<TextGrid<T>> for visualization::Instance {
}
}
impl<T> display::Object for TextGrid<T> {
fn display_object(&self) -> &display::object::Instance {
&self.root
}
}
// ========================

View File

@ -48,10 +48,11 @@ pub struct Params {
/// display object for compatibility with `GridView`. The `dummy_root` is not used for
/// displaying anything, all that is visible is the `text` element, which is updates through
/// the FRP.
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
pub struct Entry {
// Needed to provide a dummy display object for the `display::Object` trait. Not used, as the
// text element is created as HTML Element and positioned manually in `set_position_and_size`.
#[display_object]
dummy_root: display::object::Instance,
text: Rc<web::HtmlDivElement>,
frp: Rc<EntryFrp<Self>>,
@ -87,12 +88,6 @@ impl Entry {
}
}
impl display::Object for Entry {
fn display_object(&self) -> &display::object::Instance {
&self.dummy_root
}
}
impl grid_view::Entry for Entry {
type Model = Model;
type Params = Params;

View File

@ -80,9 +80,10 @@ type View = ensogl_component::button::View<shape::Shape>;
///
/// This is a button with + icon, which sticks to the left-bottom corner of the scene. It exposes
/// the FRP of EnsoGL Button Component, including the main "click" event.
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
pub struct AddNodeButton {
network: frp::Network,
#[display_object]
view: View,
style_watch: StyleWatchFrp,
}
@ -134,9 +135,3 @@ impl AddNodeButton {
view.set_y(y.round());
}
}
impl display::Object for AddNodeButton {
fn display_object(&self) -> &display::object::Instance {
self.view.display_object()
}
}

View File

@ -0,0 +1,525 @@
//! This module provides a clickable view for a single breadcrumb.
use crate::prelude::*;
use ensogl::display::shape::*;
use crate::component::breadcrumbs;
use crate::component::breadcrumbs::project_name::LINE_HEIGHT;
use crate::MethodPointer;
use super::GLYPH_WIDTH;
use super::HORIZONTAL_MARGIN;
use super::TEXT_SIZE;
use enso_frp as frp;
use ensogl::application::Application;
use ensogl::data::color;
use ensogl::display;
use ensogl::display::object::ObjectOps;
use ensogl::DEPRECATED_Animation;
use ensogl_component::text;
use ensogl_hardcoded_theme as theme;
use nalgebra::Vector2;
use std::f32::consts::PI;
// =================
// === Constants ===
// =================
/// Breadcrumb vertical margin.
pub const VERTICAL_MARGIN: f32 = 0.0;
/// Breadcrumb left margin.
pub const LEFT_MARGIN: f32 = 0.0;
/// Breadcrumb right margin.
pub const RIGHT_MARGIN: f32 = 0.0;
const ICON_LEFT_MARGIN: f32 = 0.0;
const ICON_RIGHT_MARGIN: f32 = HORIZONTAL_MARGIN;
const ICON_RADIUS: f32 = 6.0;
const ICON_SIZE: f32 = ICON_RADIUS * 2.0;
const ICON_RING_WIDTH: f32 = 1.5;
const ICON_ARROW_SIZE: f32 = 4.0;
const SEPARATOR_SIZE: f32 = 6.0;
/// Breadcrumb padding.
pub const PADDING: f32 = 1.0;
const SEPARATOR_MARGIN: f32 = 10.0;
// ==================
// === Background ===
// ==================
/// A transparent "background" of single breadcrumb, set for capturing mouse events.
pub mod background {
use super::*;
ensogl::shape! {
alignment = center;
(style: Style) {
let bg_color = color::Rgba::new(0.0,0.0,0.0,0.000_001);
Plane().fill(bg_color).into()
}
}
}
// ============
// === Icon ===
// ============
mod icon {
use super::*;
ensogl::shape! {
pointer_events = false;
alignment = center;
(style: Style, red: f32, green: f32, blue: f32, alpha: f32) {
let outer_circle = Circle((ICON_RADIUS).px());
let inner_circle = Circle((ICON_RADIUS - ICON_RING_WIDTH).px());
let ring = outer_circle - inner_circle;
let size = ICON_ARROW_SIZE;
let arrow = Triangle(size.px(),size.px()).rotate((PI/2.0).radians());
let arrow = arrow.translate_x(0.5.px());
let shape = ring + arrow;
let color = format!("vec4({red},{green},{blue},{alpha})");
let color : Var<color::Rgba> = color.into();
shape.fill(color).into()
}
}
}
// =================
// === Separator ===
// =================
mod separator {
use super::*;
ensogl::shape! {
pointer_events = false;
alignment = center;
(style: Style, red: f32, green: f32, blue: f32, alpha: f32) {
let size = SEPARATOR_SIZE;
let angle = PI/2.0;
let triangle = Triangle(size.px(),size.px()).rotate(angle.radians());
let color = format!("vec4({red},{green},{blue},{alpha})");
let color : Var<color::Rgba> = color.into();
triangle.fill(color).into()
}
}
}
// ========================
// === RelativePosition ===
// ========================
/// The position of this breadcrumb relative to the selected breadcrumb. We use this to determine
/// the color.
#[derive(Debug, Clone, Copy)]
enum RelativePosition {
Left,
Right,
}
// ==================
// === Animations ===
// ==================
/// ProjectName's animations handlers.
#[derive(Debug, Clone, CloneRef)]
pub struct Animations {
color: DEPRECATED_Animation<Vector4<f32>>,
separator_color: DEPRECATED_Animation<Vector4<f32>>,
fade_in: DEPRECATED_Animation<f32>,
}
impl Animations {
/// Constructor.
pub fn new(network: &frp::Network) -> Self {
let color = DEPRECATED_Animation::new(network);
let fade_in = DEPRECATED_Animation::new(network);
let separator_color = DEPRECATED_Animation::new(network);
Self { color, separator_color, fade_in }
}
}
// =================
// === FrpInputs ===
// =================
/// Breadcrumb frp network inputs.
#[derive(Debug, Clone, CloneRef)]
pub struct FrpInputs {
/// Select the breadcrumb, triggering the selection animation.
pub select: frp::Source,
/// Select the breadcrumb, triggering the deselection animation, using the (self,new)
/// breadcrumb indices to determine if the breadcrumb is on the left or on the right of the
/// newly selected breadcrumb.
pub deselect: frp::Source<(usize, usize)>,
/// Triggers the fade in animation, which only makes sense during the breadcrumb creation.
pub fade_in: frp::Source,
}
impl FrpInputs {
/// Constructor.
pub fn new(network: &frp::Network) -> Self {
frp::extend! {network
select <- source();
deselect <- source();
fade_in <- source();
}
Self { select, deselect, fade_in }
}
}
// ==================
// === FrpOutputs ===
// ==================
/// Breadcrumb frp network outputs.
#[derive(Debug, Clone, CloneRef)]
pub struct FrpOutputs {
/// Signalizes that the breadcrumb was clicked.
pub clicked: frp::Source,
/// Signalizes that the breadcrumb's size changed.
pub size: frp::Source<Vector2<f32>>,
/// Signalizes the breadcrumb's selection state.
pub selected: frp::Source<bool>,
/// Used to check if the breadcrumb is selected.
pub is_selected: frp::Sampler<bool>,
}
impl FrpOutputs {
/// Constructor.
pub fn new(network: &frp::Network) -> Self {
frp::extend! { network
clicked <- source();
size <- source();
selected <- source();
is_selected <- selected.sampler();
}
Self { clicked, size, selected, is_selected }
}
}
// ===========
// === Frp ===
// ===========
/// A breadcrumb frp structure with its endpoints and network representation.
#[derive(Debug, Clone, CloneRef)]
#[allow(missing_docs)]
pub struct Frp {
pub inputs: FrpInputs,
pub outputs: FrpOutputs,
pub network: frp::Network,
}
impl Deref for Frp {
type Target = FrpInputs;
fn deref(&self) -> &Self::Target {
&self.inputs
}
}
impl Default for Frp {
fn default() -> Self {
Self::new()
}
}
impl Frp {
/// Constructor.
pub fn new() -> Self {
let network = frp::Network::new("breadcrumbs");
let inputs = FrpInputs::new(&network);
let outputs = FrpOutputs::new(&network);
Self { inputs, outputs, network }
}
}
// ======================
// === BreadcrumbInfo ===
// ======================
/// Breadcrumb information such as name and expression ID.
#[derive(Debug)]
#[allow(missing_docs)]
pub struct BreadcrumbInfo {
pub method_pointer: MethodPointer,
pub expression_id: ast::Id,
}
// =======================
// === BreadcrumbModel ===
// =======================
/// Breadcrumbs model.
#[derive(Debug, Clone, CloneRef, display::Object)]
pub struct BreadcrumbModel {
display_object: display::object::Instance,
view: background::View,
separator: separator::View,
icon: icon::View,
label: text::Text,
animations: Animations,
style: StyleWatch,
/// Breadcrumb information such as name and expression ID.
pub info: Rc<BreadcrumbInfo>,
relative_position: Rc<Cell<Option<RelativePosition>>>,
outputs: FrpOutputs,
}
impl BreadcrumbModel {
/// Constructor.
#[profile(Detail)]
pub fn new(
app: &Application,
frp: &Frp,
method_pointer: &MethodPointer,
expression_id: &ast::Id,
) -> Self {
let scene = &app.display.default_scene;
let display_object = display::object::Instance::new();
let view = background::View::new();
let icon = icon::View::new();
let separator = separator::View::new();
let label = app.new_view::<text::Text>();
let expression_id = *expression_id;
let method_pointer = method_pointer.clone();
let info = Rc::new(BreadcrumbInfo { method_pointer, expression_id });
let animations = Animations::new(&frp.network);
let relative_position = default();
let outputs = frp.outputs.clone_ref();
ensogl::shapes_order_dependencies! {
scene => {
background -> icon;
background -> separator;
}
}
scene.layers.panel.add(&view);
scene.layers.panel.add(&icon);
scene.layers.panel.add(&separator);
scene.layers.main.remove(&label);
label.add_to_scene_layer(&scene.layers.panel_text);
// FIXME : StyleWatch is unsuitable here, as it was designed as an internal tool for shape
// system (#795)
let style = StyleWatch::new(&scene.style_sheet);
Self {
display_object,
view,
separator,
icon,
label,
animations,
style,
info,
relative_position,
outputs,
}
.init()
}
fn init(self) -> Self {
self.add_child(&self.view);
self.view.add_child(&self.separator);
self.separator.add_child(&self.icon);
self.icon.add_child(&self.label);
let styles = &self.style;
let full_color = styles.get_color(theme::graph_editor::breadcrumbs::full);
let transparent_color = styles.get_color(theme::graph_editor::breadcrumbs::transparent);
let color = if self.is_selected() { full_color } else { transparent_color };
self.label.set_property_default(color);
self.label.set_property_default(text::formatting::Size::from(TEXT_SIZE));
self.label.set_single_line_mode(true);
self.label.set_x(ICON_RADIUS + ICON_RIGHT_MARGIN);
self.label.set_y(TEXT_SIZE / 2.0);
self.label.set_content(&self.info.method_pointer.name);
let width = self.width();
let height = self.height();
let offset = SEPARATOR_MARGIN + SEPARATOR_SIZE / 2.0;
self.view.set_size(Vector2::new(width, height));
self.fade_in(0.0);
let separator_size = (SEPARATOR_SIZE + PADDING * 2.0).max(0.0);
let icon_size = (ICON_SIZE + PADDING * 2.0).max(0.0);
self.separator.set_size(Vector2::new(separator_size, separator_size));
self.separator.set_x((offset - width / 2.0).round());
self.icon.set_size(Vector2::new(icon_size, icon_size));
let x_position = offset + PADDING + ICON_SIZE / 2.0 + LEFT_MARGIN + ICON_LEFT_MARGIN;
self.icon.set_x(x_position.round());
self
}
fn label_width(&self) -> f32 {
self.info.method_pointer.name.len() as f32 * GLYPH_WIDTH
}
/// Get the width of the view.
pub fn width(&self) -> f32 {
let separator_width = SEPARATOR_MARGIN * 2.0 + SEPARATOR_SIZE;
let icon_width = ICON_LEFT_MARGIN + ICON_SIZE + ICON_RIGHT_MARGIN;
let label_width = self.label_width();
let margin_and_padding = LEFT_MARGIN + RIGHT_MARGIN + PADDING * 2.0;
let width = separator_width + icon_width + label_width + margin_and_padding;
width.ceil()
}
/// Get the height of the view.
pub fn height(&self) -> f32 {
LINE_HEIGHT + breadcrumbs::VERTICAL_MARGIN * 2.0
}
fn fade_in(&self, value: f32) {
let width = self.width();
let height = self.height();
let x_position = width * value / 2.0;
let y_position = -height / 2.0 - VERTICAL_MARGIN - PADDING;
self.view.set_position(Vector3(x_position.round(), y_position.round(), 0.0));
}
fn set_color(&self, value: Vector4<f32>) {
let color = color::Rgba::from(value);
self.label.set_property(.., color);
self.icon.red.set(color.red);
self.icon.green.set(color.green);
self.icon.blue.set(color.blue);
self.icon.alpha.set(color.alpha);
}
fn set_separator_color(&self, value: Vector4<f32>) {
let color = color::Rgba::from(value);
self.separator.red.set(color.red);
self.separator.green.set(color.green);
self.separator.blue.set(color.blue);
self.separator.alpha.set(color.alpha);
}
fn select(&self) {
let styles = &self.style;
let selected_color = styles.get_color(theme::graph_editor::breadcrumbs::selected);
let left_deselected = styles.get_color(theme::graph_editor::breadcrumbs::deselected::left);
self.animations.color.set_target_value(selected_color.into());
self.animations.separator_color.set_target_value(left_deselected.into());
}
fn deselect(&self, old: usize, new: usize) {
let left = RelativePosition::Left;
let right = RelativePosition::Right;
self.relative_position
.set((new > old).as_option().map(|_| Some(left)).unwrap_or(Some(right)));
let color = self.deselected_color().into();
self.animations.color.set_target_value(color);
self.animations.separator_color.set_target_value(color);
}
fn deselected_color(&self) -> color::Rgba {
let styles = &self.style;
let selected_color = styles.get_color(theme::graph_editor::breadcrumbs::selected);
let left_deselected = styles.get_color(theme::graph_editor::breadcrumbs::deselected::left);
let right_deselected =
styles.get_color(theme::graph_editor::breadcrumbs::deselected::right);
match self.relative_position.get() {
Some(RelativePosition::Right) => right_deselected,
Some(RelativePosition::Left) => left_deselected,
None => selected_color,
}
}
fn is_selected(&self) -> bool {
self.outputs.is_selected.value()
}
}
// ==================
// === Breadcrumb ===
// ==================
/// The breadcrumb's view which displays its name and exposes mouse press interactions.
#[derive(Debug, Clone, CloneRef, Deref, display::Object)]
#[allow(missing_docs)]
pub struct Breadcrumb {
#[deref]
#[display_object]
model: Rc<BreadcrumbModel>,
pub frp: Frp,
}
impl Breadcrumb {
/// Constructor.
pub fn new(app: &Application, method_pointer: &MethodPointer, expression_id: &ast::Id) -> Self {
let frp = Frp::new();
let model = Rc::new(BreadcrumbModel::new(app, &frp, method_pointer, expression_id));
let network = &frp.network;
let scene = &app.display.default_scene;
// FIXME : StyleWatch is unsuitable here, as it was designed as an internal tool for shape
// system (#795)
let styles = StyleWatch::new(&scene.style_sheet);
let hover_color = styles.get_color(theme::graph_editor::breadcrumbs::hover);
frp::extend! { network
eval_ frp.fade_in(model.animations.fade_in.set_target_value(1.0));
eval_ frp.select({
model.outputs.selected.emit(true);
model.select();
});
eval frp.deselect(((old,new)) {
model.outputs.selected.emit(false);
model.deselect(*old,*new);
});
not_selected <- frp.outputs.selected.map(|selected| !selected);
mouse_over_if_not_selected <- model.view.events_deprecated.mouse_over.gate(&not_selected);
mouse_out_if_not_selected <- model.view.events_deprecated.mouse_out.gate(&not_selected);
eval_ mouse_over_if_not_selected(
model.animations.color.set_target_value(hover_color.into())
);
eval_ mouse_out_if_not_selected(
model.animations.color.set_target_value(model.deselected_color().into())
);
eval_ model.view.events_deprecated.mouse_down_primary(frp.outputs.clicked.emit(()));
}
// === Animations ===
frp::extend! {network
eval model.animations.fade_in.value((value) model.fade_in(*value));
eval model.animations.color.value((value) model.set_color(*value));
eval model.animations.separator_color.value((value) model.set_separator_color(*value));
}
Self { model, frp }
}
}

View File

@ -67,19 +67,14 @@ define_endpoints_2! {
// ============
/// Edge definition.
#[derive(AsRef, Clone, CloneRef, Debug, Deref)]
#[derive(Clone, CloneRef, Debug, Deref, display::Object)]
pub struct Edge {
#[deref]
frp: Frp,
#[display_object]
model: Rc<EdgeModel>,
}
impl AsRef<Edge> for Edge {
fn as_ref(&self) -> &Self {
self
}
}
impl Edge {
/// Constructor.
#[profile(Detail)]
@ -153,12 +148,6 @@ impl Edge {
}
}
impl display::Object for Edge {
fn display_object(&self) -> &display::object::Instance {
&self.model.display_object
}
}
// =================
@ -166,7 +155,7 @@ impl display::Object for Edge {
// =================
/// Internal data of `Edge`
#[derive(Debug)]
#[derive(Debug, display::Object)]
struct EdgeModel {
/// The parent display object of all the edge's parts.
display_object: display::object::Instance,
@ -327,12 +316,6 @@ impl EdgeModel {
// === Trait implementations ===
impl display::Object for EdgeModel {
fn display_object(&self) -> &display::object::Instance {
&self.display_object
}
}
impl ShapeParent for EdgeModel {
fn scene(&self) -> &Scene {
&self.scene

View File

@ -102,8 +102,9 @@ pub type Comment = ImString;
// ==============
/// A node's background area and selection.
#[derive(Debug, Clone, CloneRef)]
#[derive(Debug, Clone, CloneRef, display::Object)]
pub struct Background {
#[display_object]
shape: Rectangle,
inset: Immutable<f32>,
selection_color: Immutable<color::Rgba>,
@ -140,12 +141,6 @@ impl Background {
}
}
impl display::Object for Background {
fn display_object(&self) -> &display::object::Instance {
self.shape.display_object()
}
}
// =======================
@ -331,7 +326,7 @@ ensogl::define_endpoints_2! {
/// emitted back to the right node).
///
/// Currently, the solution "C" (nearest to optimal) is implemented here.
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
#[allow(missing_docs)]
pub struct Node {
widget: gui::Widget<NodeModel, Frp>,
@ -358,7 +353,7 @@ impl Deref for Node {
}
/// Internal data of `Node`
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
#[allow(missing_docs)]
pub struct NodeModel {
// Required for switching the node to a different layer
@ -638,9 +633,13 @@ impl Node {
let background_press = model.background.on_event::<mouse::Down>();
let input_press = model.input.on_event::<mouse::Down>();
input_as_background_press <- input_press.gate(&input.set_edit_ready_mode);
// When editing, clicks focus the `Text` component and set the cursor position.
background_as_input_press <- background_press.gate(&model.input.editing);
model.input.mouse_down <+_ background_as_input_press;
background_press <- background_press.gate_not(&model.input.editing);
any_background_press <- any(&background_press, &input_as_background_press);
any_primary_press <- any_background_press.filter(mouse::event::is_primary);
out.background_press <+ any_primary_press.constant(());
out.background_press <+_ any_primary_press;
// === Selection ===
@ -920,8 +919,7 @@ impl Node {
frp.set_disabled.emit(false);
frp.show_quick_action_bar_on_hover.emit(true);
let display_object = model.display_object.clone_ref();
let widget = gui::Widget::new(app, frp, model, display_object);
let widget = gui::Widget::new(app, frp, model);
Node { widget }
}
@ -947,11 +945,6 @@ impl Node {
}
}
impl display::Object for Node {
fn display_object(&self) -> &display::object::Instance {
self.deref().display_object()
}
}
// === Positioning ===

View File

@ -92,7 +92,7 @@ ensogl::define_endpoints! {
// === Action Bar Icons ===
// ========================
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
struct Icons {
display_object: display::object::Instance,
visibility: ToggleButton<icon::visibility::Shape>,
@ -131,12 +131,6 @@ impl Icons {
}
}
impl display::Object for Icons {
fn display_object(&self) -> &display::object::Instance {
&self.display_object
}
}
fn labeled_button<Icon: ColorableShape>(app: &Application, label: &str) -> ToggleButton<Icon> {
let tooltip_style = tooltip::Style::set_label(label.to_owned());
ToggleButton::new(app, tooltip_style)
@ -151,7 +145,7 @@ fn labeled_button<Icon: ColorableShape>(app: &Application, label: &str) -> Toggl
/// A button to enable/disable the output context for a particular node. It holds two buttons
/// internally for each shape, but only one is shown at a time, based on the execution environment
/// which sets the global permission for the output context.
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
struct ContextSwitchButton {
globally_enabled: Rc<Cell<bool>>,
disable_button: ToggleButton<icon::disable_output_context::Shape>,
@ -212,19 +206,13 @@ impl ContextSwitchButton {
}
}
impl display::Object for ContextSwitchButton {
fn display_object(&self) -> &display::object::Instance {
&self.display_object
}
}
// ========================
// === Action Bar Model ===
// ========================
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
struct Model {
display_object: display::object::Instance,
hover_area: Rectangle,
@ -327,12 +315,6 @@ impl Model {
}
}
impl display::Object for Model {
fn display_object(&self) -> &display::object::Instance {
&self.display_object
}
}
// ==================
@ -348,20 +330,15 @@ impl display::Object for Model {
/// | <icon1> <icon2> <icon3> |
/// \ ----------------------------- /
/// ```
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, Deref, display::Object)]
#[allow(missing_docs)]
pub struct ActionBar {
#[deref]
pub frp: Frp,
#[display_object]
model: Rc<Model>,
}
impl Deref for ActionBar {
type Target = Frp;
fn deref(&self) -> &Self::Target {
&self.frp
}
}
impl ActionBar {
/// Constructor.
pub fn new(app: &Application) -> Self {
@ -463,12 +440,6 @@ impl ActionBar {
}
}
impl display::Object for ActionBar {
fn display_object(&self) -> &display::object::Instance {
self.model.display_object()
}
}
// ============

View File

@ -75,8 +75,9 @@ const BORDER_RADIUS: f32 = 14.0;
// === Container ===
/// The container containing just the error visualization and background.
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, Deref, display::Object)]
pub struct Container {
#[deref]
visualization: error_visualization::Error,
scene: Scene,
// TODO : We added a HTML background to the `View`, because "shape" background was
@ -86,14 +87,6 @@ pub struct Container {
display_object: display::object::Instance,
}
impl Deref for Container {
type Target = error_visualization::Error;
fn deref(&self) -> &Self::Target {
&self.visualization
}
}
impl Container {
/// Constructor of error container.
pub fn new(app: &Application) -> Self {
@ -143,9 +136,3 @@ impl Container {
layer.apply_for_html_component(&self.scene, &self.background_dom);
}
}
impl display::Object for Container {
fn display_object(&self) -> &display::object::Instance {
&self.display_object
}
}

View File

@ -161,7 +161,7 @@ impl From<node::Expression> for Expression {
// =============
/// Internal model of the port area.
#[derive(Debug)]
#[derive(Debug, display::Object)]
pub struct Model {
display_object: display::object::Instance,
edit_mode_label: text::Text,
@ -216,12 +216,13 @@ impl Model {
self.display_object.remove_child(&self.widget_tree);
self.show_edit_mode_label();
self.edit_mode_label.set_cursor_at_mouse_position();
// [`ensogl_text`] has not been ported to the new focus API yet.
self.edit_mode_label.deprecated_focus();
} else {
self.hide_edit_mode_label();
self.display_object.add_child(&self.widget_tree);
self.edit_mode_label.set_content("");
}
self.edit_mode_label.deprecated_set_focus(edit_mode_active);
}
/// A workaround to fix the cursor position calculation when clicking into the node.
@ -253,9 +254,6 @@ impl Model {
let text_color = self.styles.get_color(theme::graph_editor::node::text);
self.edit_mode_label.set_single_line_mode(true);
app.commands.set_command_enabled(&self.edit_mode_label, "cursor_move_up", false);
app.commands.set_command_enabled(&self.edit_mode_label, "cursor_move_down", false);
app.commands.set_command_enabled(
&self.edit_mode_label,
"add_cursor_at_mouse_position",
@ -420,6 +418,10 @@ ensogl::define_endpoints! {
/// `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 (ast::Id,Option<Type>),
/// Signal a mouse click in the input area. The click position will be determined by the
/// current pointer position, and the cursor position will be updated in the text area.
mouse_down (),
}
Output {
@ -458,20 +460,15 @@ ensogl::define_endpoints! {
/// ## Origin
/// Please note that the origin of the node is on its left side, centered vertically. To learn more
/// about this design decision, please read the docs for the [`node::Node`].
#[derive(Clone, Deref, CloneRef, Debug)]
#[derive(Clone, Deref, CloneRef, Debug, display::Object)]
pub struct Area {
#[allow(missing_docs)]
#[deref]
pub frp: Frp,
#[display_object]
pub(crate) model: Rc<Model>,
}
impl display::Object for Area {
fn display_object(&self) -> &display::object::Instance {
&self.model.display_object
}
}
impl Area {
/// Constructor.
#[profile(Debug)]

View File

@ -108,11 +108,12 @@ impl PortLayers {
/// Node of a widget tree that can be a source of an edge. Displays a visual representation of the
/// connection below the widget, and handles mouse hover and click events when an edge is dragged.
#[derive(Debug)]
#[derive(Debug, display::Object)]
pub struct Port {
/// Drop source must be kept at the top of the struct, so it will be dropped first.
_on_cleanup: frp::DropSource,
port_id: frp::Source<PortId>,
#[display_object]
port_root: display::object::Instance,
widget_root: display::object::Instance,
widget: DynWidget,
@ -128,7 +129,7 @@ impl Port {
/// display object, and its layout size will be used to determine the port's size.
pub fn new(widget: DynWidget, app: &Application, frp: &WidgetsFrp) -> Self {
let port_root = display::object::Instance::new_named("Port");
let widget_root = widget.root_object().clone_ref();
let widget_root = widget.display_object().clone_ref();
let port_shape = PortShape::new();
let hover_shape = HoverShape::new();
port_shape.set_corner_radius_max().set_pointer_events(false);
@ -234,7 +235,7 @@ impl Port {
}
fn update_root(&mut self) {
let new_root = self.widget.root_object();
let new_root = self.widget.display_object();
if new_root != &self.widget_root {
self.port_root.remove_child(&self.widget_root);
self.port_root.add_child(new_root);
@ -289,9 +290,3 @@ impl Port {
&self.hover_shape
}
}
impl display::Object for Port {
fn display_object(&self) -> &display::object::Instance {
self.port_root.display_object()
}
}

View File

@ -143,7 +143,7 @@ pub struct OverrideKey {
/// Common trait for constructing and reconfiguring all widget variants. See "Widget Lifecycle"
/// section of the module documentation for more details.
pub trait SpanWidget {
pub trait SpanWidget: display::Object {
/// Configuration associated with specific widget variant.
type Config: Debug + Clone + PartialEq;
/// Score how well a widget kind matches current [`ConfigContext`], e.g. checking if the span
@ -156,8 +156,6 @@ pub trait SpanWidget {
/// automatically derived configuration. It is not called for widgets that have a configuration
/// provided externally or by a parent widget.
fn default_config(ctx: &ConfigContext) -> Configuration<Self::Config>;
/// Root display object of a widget. It is returned to the parent widget for positioning.
fn root_object(&self) -> &display::object::Instance;
/// Create a new widget with given configuration.
fn new(config: &Self::Config, ctx: &ConfigContext) -> Self;
/// Update configuration for existing widget.
@ -281,13 +279,6 @@ macro_rules! define_widget_modules(
)*
impl DynWidget {
#[allow(missing_docs)]
pub fn root_object(&self) -> &display::object::Instance {
match self {
$(DynWidget::$name(inner) => inner.root_object(),)*
}
}
fn new(config: &DynConfig, ctx: &ConfigContext) -> Self {
match config {
$(DynConfig::$name(config) => DynWidget::$name(SpanWidget::new(config, ctx)),)*
@ -315,6 +306,20 @@ macro_rules! define_widget_modules(
}
}
}
impl display::Object for DynWidget {
fn display_object(&self) -> &display::object::Instance {
match self {
$(DynWidget::$name(inner) => inner.display_object(),)*
}
}
fn focus_receiver(&self) -> &display::object::Instance {
match self {
$(DynWidget::$name(inner) => inner.focus_receiver(),)*
}
}
}
};
);
@ -515,20 +520,15 @@ pub struct TransferRequest {
/// The node widget tree view. Contains all widgets created from the node's span tree, as well as
/// all input ports of a node. The tree is initialized to empty state, waiting for first
/// `rebuild_tree` call to build appropriate view hierarchy.
#[derive(Debug, Deref, Clone, CloneRef)]
#[derive(Debug, Deref, Clone, CloneRef, display::Object)]
pub struct Tree {
#[deref]
frp: Frp,
widgets_frp: WidgetsFrp,
#[display_object]
model: Rc<TreeModel>,
}
impl display::Object for Tree {
fn display_object(&self) -> &display::object::Instance {
&self.model.display_object
}
}
impl Tree {
/// Create a new node widget. The widget is initialized to empty state, waiting for first
/// `rebuild_tree` call to build appropriate view hierarchy.
@ -713,7 +713,14 @@ impl display::Object for TreeNode {
fn display_object(&self) -> &display::object::Instance {
match self {
TreeNode::Port(port) => port.display_object(),
TreeNode::Widget(widget) => widget.root_object(),
TreeNode::Widget(widget) => widget.display_object(),
}
}
fn focus_receiver(&self) -> &display::object::Instance {
match self {
TreeNode::Port(port) => port.focus_receiver(),
TreeNode::Widget(widget) => widget.focus_receiver(),
}
}
}
@ -757,7 +764,7 @@ pub struct EdgeData {
// === TreeModel ===
// =================
#[derive(Debug)]
#[derive(Debug, display::Object)]
struct TreeModel {
app: Application,
display_object: display::object::Instance,

View File

@ -4,6 +4,7 @@
use crate::component::node::input::widget::prelude::*;
use crate::prelude::*;
use ensogl::display;
use ensogl::display::object;
@ -29,7 +30,7 @@ pub type CollectedChildren = SmallVec<[object::Instance; 4]>;
pub struct Config;
/// Hierarchy widget. This widget expands each child of its span tree into a new widget.
#[derive(Clone, Debug)]
#[derive(Clone, Debug, display::Object)]
pub struct Widget {
display_object: object::Instance,
}
@ -49,10 +50,6 @@ impl SpanWidget for Widget {
Configuration::maybe_with_port(default(), has_port)
}
fn root_object(&self) -> &object::Instance {
&self.display_object
}
fn new(_: &Config, _: &ConfigContext) -> Self {
let display_object = object::Instance::new_named("widget::Hierarchy");
display_object.use_auto_layout();

View File

@ -8,6 +8,7 @@
use crate::component::node::input::widget::prelude::*;
use crate::prelude::*;
use ensogl::display;
use ensogl::display::object;
@ -22,7 +23,7 @@ pub struct Config;
/// Insertion point widget. Displays nothing when not connected.
#[derive(Clone, Debug)]
#[derive(Clone, Debug, display::Object)]
pub struct Widget {
root: object::Instance,
}
@ -38,10 +39,6 @@ impl SpanWidget for Widget {
Configuration::inert(default())
}
fn root_object(&self) -> &object::Instance {
&self.root
}
fn new(_: &Config, _: &ConfigContext) -> Self {
let root = object::Instance::new_named("widget::InsertionPoint");
root.set_size(Vector2::<f32>::zero());

View File

@ -6,6 +6,7 @@ use crate::prelude::*;
use crate::component::node::input::area::TEXT_SIZE;
use ensogl::data::color;
use ensogl::display;
use ensogl::display::object;
use ensogl::display::shape::StyleWatch;
use ensogl_component::text;
@ -30,9 +31,10 @@ ensogl::define_endpoints_2! {
}
/// Label widget. Always displays the span tree node's expression as text.
#[derive(Clone, Debug)]
#[derive(Clone, Debug, display::Object)]
pub struct Widget {
frp: Frp,
#[display_object]
root: object::Instance,
#[allow(dead_code)]
label: text::Text,
@ -51,10 +53,6 @@ impl SpanWidget for Widget {
Configuration::maybe_with_port(default(), has_port)
}
fn root_object(&self) -> &object::Instance {
&self.root
}
fn new(_: &Config, ctx: &ConfigContext) -> Self {
// Embed the label in a vertically centered fixed height container, so that the label's
// baseline is properly aligned to center and lines up with other labels in the line.

View File

@ -39,7 +39,7 @@ const INSERTION_OFFSET: f32 = ITEMS_GAP * 0.5;
// === Element ===
// ===============
#[derive(Debug)]
#[derive(Debug, display::Object)]
struct Element {
display_object: object::Instance,
content: object::Instance,
@ -75,7 +75,7 @@ enum ElementIdentity {
FullIdentity(WidgetIdentity),
}
#[derive(Clone, CloneRef)]
#[derive(Clone, CloneRef, display::Object)]
struct ListItem {
child_id: Immutable<WidgetIdentity>,
element_id: Immutable<ElementIdentity>,
@ -110,12 +110,6 @@ impl ListItem {
}
}
impl display::Object for ListItem {
fn display_object(&self) -> &object::Instance {
&self.display_object
}
}
impl Element {
fn new() -> Self {
let display_object = object::Instance::new_named("Element");
@ -137,14 +131,8 @@ impl Element {
}
}
impl display::Object for Element {
fn display_object(&self) -> &object::Instance {
&self.display_object
}
}
/// A model for the vector editor widget.
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
pub struct Widget {
display_object: object::Instance,
network: frp::Network,
@ -639,10 +627,6 @@ impl SpanWidget for Widget {
Configuration::always(Config { item_widget: None, item_default })
}
fn root_object(&self) -> &object::Instance {
&self.display_object
}
fn new(_: &Config, ctx: &ConfigContext) -> Self {
let display_object = object::Instance::new_named("widget::ListEditor");
let model = Model::new(ctx, &display_object);

View File

@ -107,7 +107,7 @@ ensogl::define_endpoints_2! {
/// A widget for selecting a single value from a list of available options. The options can be
/// provided as a static list of strings from argument `tag_values`, or as a dynamic expression.
#[derive(Debug)]
#[derive(Debug, display::Object)]
#[allow(dead_code)]
pub struct Widget {
config_frp: Frp,
@ -137,10 +137,6 @@ impl SpanWidget for Widget {
Configuration::always(default_config)
}
fn root_object(&self) -> &display::object::Instance {
&self.display_object
}
fn new(_: &Config, ctx: &ConfigContext) -> Self {
let app = ctx.app();
// ╭─display_object────────────────────╮

View File

@ -132,7 +132,7 @@ ensogl::define_endpoints! {
}
/// Internal model of the port area.
#[derive(Debug)]
#[derive(Debug, display::Object)]
pub struct Model {
app: Application,
display_object: display::object::Instance,
@ -348,11 +348,12 @@ impl Model {
/// ## Origin
/// Please note that the origin of the node is on its left side, centered vertically. To learn more
/// about this design decision, please read the docs for the [`node::Node`].
#[derive(Clone, CloneRef, Debug, Deref)]
#[derive(Clone, CloneRef, Debug, Deref, display::Object)]
#[allow(missing_docs)]
pub struct Area {
#[deref]
pub frp: Frp,
#[display_object]
pub model: Rc<Model>,
}
@ -450,9 +451,3 @@ impl Area {
self.model.expression.borrow().whole_expr_id
}
}
impl display::Object for Area {
fn display_object(&self) -> &display::object::Instance {
&self.model.display_object
}
}

View File

@ -415,6 +415,13 @@ impl display::Object for PortShapeView {
Self::Multi(view) => view.display_object(),
}
}
fn focus_receiver(&self) -> &display::object::Instance {
match self {
Self::Single(view) => view.focus_receiver(),
Self::Multi(view) => view.focus_receiver(),
}
}
}

View File

@ -177,30 +177,23 @@ ensogl::define_endpoints! {
/// The color of the label will reflect the status and be determined by [`Status::display_color`].
/// The necessary theme will be taken from the application's style sheet. The origin of the label,
/// as a `display::Object` should be placed on the node's center.
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, Deref, display::Object)]
pub struct ProfilingLabel {
root: display::object::Instance,
label: text::Text,
frp: Frp,
styles: StyleWatchFrp,
}
impl Deref for ProfilingLabel {
type Target = Frp;
fn deref(&self) -> &Self::Target {
&self.frp
}
display_object: display::object::Instance,
label: text::Text,
#[deref]
frp: Frp,
styles: StyleWatchFrp,
}
impl ProfilingLabel {
/// Constructs a `ProfilingLabel` for the given application.
pub fn new(app: &Application) -> Self {
let scene = &app.display.default_scene;
let root = display::object::Instance::new();
let display_object = display::object::Instance::new();
let label = text::Text::new(app);
root.add_child(&label);
display_object.add_child(&label);
label.set_y(crate::component::node::input::area::TEXT_SIZE / 2.0);
scene.layers.main.remove(&label);
label.add_to_scene_layer(&scene.layers.label);
@ -244,7 +237,7 @@ impl ProfilingLabel {
label.set_content <+ frp.set_status.map(|status| status.to_im_string());
}
ProfilingLabel { root, label, frp, styles }
ProfilingLabel { display_object, label, frp, styles }
}
/// Set a scene layer for text rendering.
@ -252,9 +245,3 @@ impl ProfilingLabel {
self.label.add_to_scene_layer(layer);
}
}
impl display::Object for ProfilingLabel {
fn display_object(&self) -> &display::object::Instance {
&self.root
}
}

View File

@ -83,18 +83,18 @@ mod status_indicator_shape {
// ==============================
/// Internal data of `StatusIndicator`.
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
struct StatusIndicatorModel {
shape: status_indicator_shape::View,
root: display::object::Instance,
shape: status_indicator_shape::View,
display_object: display::object::Instance,
}
impl StatusIndicatorModel {
fn new() -> Self {
let shape = status_indicator_shape::View::new();
let root = display::object::Instance::new();
root.add_child(&shape);
StatusIndicatorModel { shape, root }
let display_object = display::object::Instance::new();
display_object.add_child(&shape);
StatusIndicatorModel { shape, display_object }
}
fn hide(&self) {
@ -102,7 +102,7 @@ impl StatusIndicatorModel {
}
fn show(&self) {
self.root.add_child(&self.shape);
self.display_object.add_child(&self.shape);
}
fn set_visibility(&self, visibility: bool) {
@ -114,12 +114,6 @@ impl StatusIndicatorModel {
}
}
impl display::Object for StatusIndicatorModel {
fn display_object(&self) -> &display::object::Instance {
&self.root
}
}
// =======================
@ -137,10 +131,12 @@ ensogl::define_endpoints! {
}
}
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, Deref, display::Object)]
#[allow(missing_docs)]
pub struct StatusIndicator {
#[display_object]
model: Rc<StatusIndicatorModel>,
#[deref]
pub frp: Frp,
}
@ -188,16 +184,3 @@ impl StatusIndicator {
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

@ -127,21 +127,15 @@ ensogl::define_endpoints! {
/// A toggle button that can be used to toggle the graph editor's view mode. It positions itself in
/// the upper right corner of the scene.
#[derive(Debug, Clone, CloneRef)]
#[derive(Debug, Clone, CloneRef, Deref, display::Object)]
pub struct Button {
#[deref]
frp: Frp,
#[display_object]
button: ToggleButton<icon::Shape>,
styles: StyleWatchFrp,
}
impl Deref for Button {
type Target = Frp;
fn deref(&self) -> &Self::Target {
&self.frp
}
}
impl Button {
/// Constructs a new button for toggling the editor's view mode.
pub fn new(app: &Application) -> Button {
@ -200,9 +194,3 @@ impl Button {
Button { frp, button, styles }
}
}
impl display::Object for Button {
fn display_object(&self) -> &display::object::Instance {
self.button.display_object()
}
}

View File

@ -160,7 +160,7 @@ ensogl::define_endpoints_2! {
/// View of the visualization container.
///
/// Container has its origin in the top left corner.
#[derive(Debug)]
#[derive(Debug, display::Object)]
#[allow(missing_docs)]
pub struct View {
display_object: display::object::Instance,
@ -278,12 +278,6 @@ impl View {
}
}
impl display::Object for View {
fn display_object(&self) -> &display::object::Instance {
&self.display_object
}
}
// ======================
@ -291,7 +285,7 @@ impl display::Object for View {
// ======================
/// Internal data of a `Container`.
#[derive(Debug)]
#[derive(Debug, display::Object)]
#[allow(missing_docs)]
pub struct ContainerModel {
display_object: display::object::Instance,
@ -534,12 +528,6 @@ impl ContainerModel {
}
}
impl display::Object for ContainerModel {
fn display_object(&self) -> &display::object::Instance {
&self.display_object
}
}
// =================
@ -551,10 +539,11 @@ impl display::Object for ContainerModel {
/// Container that wraps a `visualization::Instance` for rendering and interaction in the GUI.
///
/// The API to interact with the visualization is exposed through the `Frp`.
#[derive(Clone, CloneRef, Debug, Derivative, Deref)]
#[derive(Clone, CloneRef, Debug, Deref, display::Object)]
#[allow(missing_docs)]
pub struct Container {
#[deref]
#[display_object]
pub model: Rc<ContainerModel>,
pub frp: Frp,
}
@ -832,9 +821,3 @@ impl Container {
&self.model.fullscreen_view
}
}
impl display::Object for Container {
fn display_object(&self) -> &display::object::Instance {
&self.model.display_object
}
}

View File

@ -160,7 +160,7 @@ mod pin_icon {
}
}
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
struct Icons {
display_object: display::object::Instance,
icon_root: display::object::Instance,
@ -217,12 +217,6 @@ impl Icons {
}
}
impl display::Object for Icons {
fn display_object(&self) -> &display::object::Instance {
&self.display_object
}
}
// ===========
@ -254,7 +248,7 @@ ensogl::define_endpoints! {
// === Action Bar Model ===
// ========================
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
struct Model {
hover_area: hover_area::View,
visualization_chooser: VisualizationChooser,
@ -320,12 +314,6 @@ impl Model {
}
}
impl display::Object for Model {
fn display_object(&self) -> &display::object::Instance {
&self.display_object
}
}
// ==================
@ -343,9 +331,10 @@ impl display::Object for Model {
/// |--------------------------------|
/// ```
#[allow(missing_docs)]
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
pub struct ActionBar {
pub frp: Frp,
#[display_object]
model: Rc<Model>,
}
@ -438,9 +427,3 @@ impl ActionBar {
&self.model.visualization_chooser
}
}
impl display::Object for ActionBar {
fn display_object(&self) -> &display::object::Instance {
self.model.display_object()
}
}

View File

@ -17,7 +17,7 @@ use ensogl::system::web;
// ======================
/// View of the visualization container meant to be used in fullscreen mode.
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
#[allow(missing_docs)]
pub struct Panel {
display_object: display::object::Instance,
@ -56,9 +56,3 @@ impl Panel {
Self { display_object, background_dom }
}
}
impl display::Object for Panel {
fn display_object(&self) -> &display::object::Instance {
&self.display_object
}
}

View File

@ -52,8 +52,9 @@ ensogl::define_endpoints! {
// === Model ===
// =============
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
struct Model {
#[display_object]
selection_menu: drop_down_menu::DropDownMenu,
registry: visualization::Registry,
}
@ -74,12 +75,6 @@ impl Model {
}
}
impl display::Object for Model {
fn display_object(&self) -> &display::object::Instance {
self.selection_menu.display_object()
}
}
// ============================
@ -88,9 +83,10 @@ impl display::Object for Model {
/// UI entity that shows a button that opens a list of visualizations that can be selected from.
#[allow(missing_docs)]
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
pub struct VisualizationChooser {
pub frp: Frp,
#[display_object]
model: Model,
}
@ -167,9 +163,3 @@ impl VisualizationChooser {
self
}
}
impl display::Object for VisualizationChooser {
fn display_object(&self) -> &display::object::Instance {
self.model.display_object()
}
}

View File

@ -81,10 +81,11 @@ type PreprocessorCallbackCell = Rc<RefCell<Option<Box<dyn PreprocessorCallback>>
/// `JsVisualizationGeneric` allows the use of arbitrary javascript to create visualizations. It
/// takes function definitions as strings and proved those functions with data.
#[derive(Clone, CloneRef, Derivative)]
#[derive(Clone, CloneRef, Derivative, display::Object)]
#[derivative(Debug)]
#[allow(missing_docs)]
pub struct InstanceModel {
#[display_object]
pub root_node: DomSymbol,
on_data_received: Rc<Option<web::Function>>,
set_size: Rc<Option<web::Function>>,
@ -255,10 +256,11 @@ impl InstanceModel {
// ================
/// Sample visualization that renders the given data as text. Useful for debugging and testing.
#[derive(Clone, CloneRef, Debug, Deref)]
#[derive(Clone, CloneRef, Debug, Deref, display::Object)]
#[allow(missing_docs)]
pub struct Instance {
#[deref]
#[display_object]
model: InstanceModel,
frp: visualization::instance::Frp,
network: frp::Network,
@ -315,12 +317,6 @@ impl From<Instance> for visualization::Instance {
}
}
impl display::Object for Instance {
fn display_object(&self) -> &display::object::Instance {
self.model.root_node.display_object()
}
}
// === Utils ===

View File

@ -200,10 +200,11 @@ impl Frp {
// ================
/// Abstraction for any visualization instance.
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, Deref, display::Object)]
#[allow(missing_docs)]
pub struct Instance {
display_object: display::object::Instance,
#[deref]
pub frp: Frp,
network: frp::Network,
root_dom: Immutable<Option<DomSymbol>>,
@ -235,16 +236,3 @@ impl Instance {
self.root_dom.deref()
}
}
impl Deref for Instance {
type Target = Frp;
fn deref(&self) -> &Self::Target {
&self.frp
}
}
impl display::Object for Instance {
fn display_object(&self) -> &display::object::Instance {
&self.display_object
}
}

View File

@ -732,10 +732,11 @@ impl FrpNetworkProvider for GraphEditor {
// === Node ===
// ============
#[derive(Clone, CloneRef, Debug, Deref)]
#[derive(Clone, CloneRef, Debug, Deref, display::Object)]
#[allow(missing_docs)] // FIXME[everyone] Public-facing API should be documented.
pub struct Node {
#[deref]
#[display_object]
pub view: component::Node,
in_edges: SharedHashSet<EdgeId>,
out_edges: SharedHashSet<EdgeId>,
@ -774,12 +775,6 @@ impl Node {
}
}
impl display::Object for Node {
fn display_object(&self) -> &display::object::Instance {
self.view.display_object()
}
}
impl Display for NodeId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Display::fmt(&self.0, f)
@ -792,10 +787,11 @@ impl Display for NodeId {
// === Edge ===
// ============
#[derive(Debug, Deref)]
#[derive(Debug, Deref, display::Object)]
#[allow(missing_docs)] // FIXME[everyone] Public-facing API should be documented.
struct Edge {
#[deref]
#[display_object]
view: component::Edge,
color: color::Lcha,
source: Option<EdgeEndpoint>,
@ -889,12 +885,6 @@ impl Edge {
}
}
impl display::Object for Edge {
fn display_object(&self) -> &display::object::Instance {
self.view.display_object()
}
}
impl Display for EdgeId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Display::fmt(&self.0, f)
@ -1787,7 +1777,7 @@ impl GraphEditorModel {
// === GraphEditorModel ===
// ========================
#[derive(Debug)]
#[derive(Debug, display::Object)]
#[allow(missing_docs)] // FIXME[everyone] Public-facing API should be documented.
pub struct GraphEditorModel {
pub display_object: display::object::Instance,
@ -2274,13 +2264,6 @@ fn some_if_negative(x: f32) -> Option<f32> {
}
// === Display object ===
impl display::Object for GraphEditorModel {
fn display_object(&self) -> &display::object::Instance {
&self.display_object
}
}
// ============================
// === FRP internal signals ===
@ -2347,8 +2330,9 @@ struct EdgeInteractionFrp {
/// the graph and allows the user to interact with it. It manages the views of all nodes and edges
/// on the scene.
#[allow(missing_docs)]
#[derive(Debug, Clone, CloneRef, Deref)]
#[derive(Debug, Clone, CloneRef, Deref, display::Object)]
pub struct GraphEditor {
#[display_object]
pub model: Rc<GraphEditorModel>,
#[deref]
pub frp: Frp,
@ -2785,7 +2769,7 @@ impl application::View for GraphEditor {
GraphEditor::new(app)
}
fn default_shortcuts() -> Vec<application::shortcut::Shortcut> {
fn global_shortcuts() -> Vec<application::shortcut::Shortcut> {
use crate::shortcuts::SHORTCUTS;
SHORTCUTS.iter().map(|(a, b, c, d)| Self::self_shortcut_when(*a, *c, *d, *b)).collect()
}
@ -3448,13 +3432,6 @@ fn init_remaining_graph_editor_frp(
impl display::Object for GraphEditor {
fn display_object(&self) -> &display::object::Instance {
self.model.display_object()
}
}
// =============
// === Tests ===
// =============

View File

@ -124,11 +124,11 @@ ensogl::define_endpoints! {
// ========================
/// Breadcrumbs panel model.
#[derive(Debug, Clone, CloneRef)]
#[derive(Debug, Clone, CloneRef, display::Object)]
pub struct BreadcrumbsModel {
/// The breadcrumbs panel display object.
#[display_object]
background: Rectangle,
/// A container for all the breadcrumbs after project name. This contained and all its
/// A container for all the breadcrumbs after project name. This container and all its
/// breadcrumbs are moved when project name component is resized.
breadcrumbs_container: display::object::Instance,
// Required for creating new breadcrumbs
@ -394,12 +394,6 @@ impl BreadcrumbsModel {
}
}
impl display::Object for BreadcrumbsModel {
fn display_object(&self) -> &display::object::Instance {
self.background.display_object()
}
}
// ===================
@ -407,10 +401,12 @@ impl display::Object for BreadcrumbsModel {
// ===================
/// The breadcrumbs panel's view used for visualizing the breadcrumbs and navigating them.
#[derive(Debug, Clone, CloneRef)]
#[derive(Debug, Clone, CloneRef, display::Object, Deref)]
#[allow(missing_docs)]
pub struct Breadcrumbs {
#[display_object]
model: BreadcrumbsModel,
#[deref]
frp: Frp,
}
@ -480,16 +476,3 @@ impl Breadcrumbs {
Self { model, frp }
}
}
impl display::Object for Breadcrumbs {
fn display_object(&self) -> &display::object::Instance {
self.model.display_object()
}
}
impl Deref for Breadcrumbs {
type Target = Frp;
fn deref(&self) -> &Self::Target {
&self.frp
}
}

View File

@ -214,7 +214,7 @@ pub struct BreadcrumbInfo {
// =======================
/// Breadcrumbs model.
#[derive(Debug, Clone, CloneRef)]
#[derive(Debug, Clone, CloneRef, display::Object)]
pub struct BreadcrumbModel {
display_object: display::object::Instance,
overlay: Rectangle,
@ -357,12 +357,6 @@ impl BreadcrumbModel {
}
}
impl display::Object for BreadcrumbModel {
fn display_object(&self) -> &display::object::Instance {
&self.display_object
}
}
// ==================
@ -370,10 +364,11 @@ impl display::Object for BreadcrumbModel {
// ==================
/// The breadcrumb's view which displays its name and exposes mouse press interactions.
#[derive(Debug, Clone, CloneRef, Deref)]
#[derive(Debug, Clone, CloneRef, Deref, display::Object)]
#[allow(missing_docs)]
pub struct Breadcrumb {
#[deref]
#[display_object]
model: Rc<BreadcrumbModel>,
pub frp: Frp,
}
@ -449,9 +444,3 @@ impl Breadcrumb {
Self { model, frp }
}
}
impl display::Object for Breadcrumb {
fn display_object(&self) -> &display::object::Instance {
&self.display_object
}
}

View File

@ -61,7 +61,7 @@ mod icon {
// ============
/// Provides a button to switch back from the project view to the dashboard.
#[derive(Debug, Clone, CloneRef, Deref)]
#[derive(Debug, Clone, CloneRef, Deref, display::Object)]
pub struct View {
button: ToggleButton<icon::Shape>,
}
@ -93,9 +93,3 @@ impl View {
}
}
}
impl display::Object for View {
fn display_object(&self) -> &display::object::Instance {
self.button.display_object()
}
}

View File

@ -49,10 +49,11 @@ mod go_to_dashboard_button;
/// A container for the project name and execution environment selector.
#[allow(missing_docs)]
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
pub struct ProjectNameWithEnvironmentSelector {
pub project_name: ProjectName,
pub selector: ide_view_execution_environment_selector::ExecutionEnvironmentSelector,
#[display_object]
background: Rectangle,
network: frp::Network,
}
@ -104,21 +105,16 @@ impl ProjectNameWithEnvironmentSelector {
}
}
impl display::Object for ProjectNameWithEnvironmentSelector {
fn display_object(&self) -> &display::object::Instance {
self.background.display_object()
}
}
// ============================
// === Project View Top Bar ===
// ============================
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
#[allow(missing_docs)]
pub struct ProjectViewTopBar {
#[display_object]
root: display::object::Instance,
/// These buttons are only visible in a cloud environment.
pub window_control_buttons: window_control_buttons::View,
@ -183,9 +179,3 @@ impl ProjectViewTopBar {
&self.project_name_with_environment_selector.project_name
}
}
impl display::Object for ProjectViewTopBar {
fn display_object(&self) -> &display::object::Instance {
&self.root
}
}

View File

@ -76,7 +76,7 @@ impl Animations {
// === ProjectNameModel ===
// ========================
#[derive(Debug, Clone, CloneRef)]
#[derive(Debug, Clone, CloneRef, display::Object)]
struct ProjectNameModel {
display_object: display::object::Instance,
overlay: Rectangle,
@ -145,12 +145,6 @@ impl ProjectNameModel {
}
}
impl display::Object for ProjectNameModel {
fn display_object(&self) -> &display::object::Instance {
&self.display_object
}
}
// ===================
@ -158,10 +152,12 @@ impl display::Object for ProjectNameModel {
// ===================
/// The view used for displaying and renaming it.
#[derive(Debug, Clone, CloneRef)]
#[derive(Debug, Clone, CloneRef, Deref, display::Object)]
#[allow(missing_docs)]
pub struct ProjectName {
#[display_object]
model: Rc<ProjectNameModel>,
#[deref]
pub frp: Frp,
}
@ -232,19 +228,6 @@ impl ProjectName {
}
}
impl display::Object for ProjectName {
fn display_object(&self) -> &display::object::Instance {
&self.model.display_object
}
}
impl Deref for ProjectName {
type Target = Frp;
fn deref(&self) -> &Self::Target {
&self.frp
}
}
impl FrpNetworkProvider for ProjectName {
fn network(&self) -> &frp::Network {
&self.frp.network

View File

@ -59,7 +59,7 @@ mod shape {
// =============
/// An internal model of Status Bar component
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
pub struct Model {
display_object: display::object::Instance,
shape: shape::View,
@ -132,10 +132,11 @@ ensogl::define_endpoints! {
///
/// The panel contains two buttons: one for closing IDE and one for toggling the fullscreen mode.
/// The panel is meant to be displayed only when IDE runs in a cloud environment.
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
pub struct View {
#[allow(missing_docs)]
pub frp: Frp,
#[display_object]
model: Model,
style: StyleWatchFrp,
}
@ -182,12 +183,6 @@ impl View {
}
}
impl display::Object for View {
fn display_object(&self) -> &display::object::Instance {
&self.model.display_object
}
}
impl Deref for View {
type Target = Frp;
fn deref(&self) -> &Self::Target {

View File

@ -28,7 +28,7 @@ pub const PADDING_LEFT: f32 = 7.0;
// === Frp ===
// ===========
ensogl::define_endpoints! {
ensogl::define_endpoints_2! {
Input {
/// Show the Code Editor.
show(),
@ -52,20 +52,15 @@ ensogl::define_endpoints! {
// ============
/// The View of IDE Code Editor.
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Deref, Debug, display::Object)]
pub struct View {
#[display_object]
model: text::Text,
styles: StyleWatchFrp,
#[deref]
frp: Frp,
}
impl Deref for View {
type Target = Frp;
fn deref(&self) -> &Self::Target {
&self.frp
}
}
impl View {
/// Create Code Editor component.
pub fn new(app: &Application) -> Self {
@ -85,38 +80,35 @@ impl View {
model.hover();
frp::extend! { network
let is_visible = frp.output.is_visible.clone_ref();
let is_visible = frp.output.is_visible.clone_ref();
show_after_toggle <- frp.toggle.gate_not(&is_visible);
hide_after_toggle <- frp.toggle.gate (&is_visible);
show <- any(frp.input.show,show_after_toggle);
hide <- any(frp.input.hide,hide_after_toggle);
hide_after_toggle <- frp.toggle.gate(&is_visible);
show <- any(frp.input.show, show_after_toggle);
hide <- any(frp.input.hide, hide_after_toggle);
eval_ show (height_fraction.set_target_value(HEIGHT_FRACTION));
focus <- show.gate_not(&frp.set_read_only);
eval_ focus ({
model.deprecated_focus();
model.focus();
});
eval_ focus (model.focus());
eval_ hide (height_fraction.set_target_value(0.0));
enable_read_only <- frp.set_read_only.on_true();
defocus <- any(hide, enable_read_only);
eval_ defocus ([model] {
model.remove_all_cursors();
model.deprecated_defocus();
model.blur();
});
frp.source.is_visible <+ bool(&frp.input.hide,&frp.input.show);
frp.source.is_visible <+ frp.toggle.map2(&is_visible, |(),b| !b);
frp.private.output.is_visible <+ bool(&frp.input.hide, &frp.input.show);
frp.private.output.is_visible <+ frp.toggle.map2(&is_visible, |(), b| !b);
def init = source_();
let shape = app.display.default_scene.shape();
position <- all_with3(&height_fraction.value,shape,&init, |height_f,scene_size,_init| {
let height = height_f * scene_size.height;
let x = -scene_size.width / 2.0 + PADDING_LEFT;
let y = -scene_size.height / 2.0 + height;
Vector2(x,y)
});
let shape = app.display.default_scene.shape();
position <- all_with3(&height_fraction.value, shape, &init,
|height_f, scene_size, _init| {
let height = height_f * scene_size.height;
let x = -scene_size.width / 2.0 + PADDING_LEFT;
let y = -scene_size.height / 2.0 + height;
Vector2(x,y)
});
eval position ((pos) model.set_xy(*pos));
let color = styles.get_color(ensogl_hardcoded_theme::code::syntax::base);
@ -134,12 +126,6 @@ impl View {
}
}
impl display::Object for View {
fn display_object(&self) -> &display::object::Instance {
self.model.display_object()
}
}
impl FrpNetworkProvider for View {
fn network(&self) -> &frp::Network {
&self.frp.network
@ -155,7 +141,7 @@ impl application::View for View {
Self::new(app)
}
fn default_shortcuts() -> Vec<shortcut::Shortcut> {
fn global_shortcuts() -> Vec<shortcut::Shortcut> {
use shortcut::ActionType::*;
[(Press, "ctrl `", "toggle"), (Press, "escape", "hide")]
.iter()

View File

@ -51,9 +51,11 @@ ensogl::define_endpoints! {
// ============
/// A pop-up that signals about enabling/disabling Debug Mode of Graph Editor.
#[derive(Debug, Clone, CloneRef)]
#[derive(Debug, Clone, CloneRef, Deref, display::Object)]
pub struct View {
#[deref]
frp: Frp,
#[display_object]
popup: popup::View,
}
@ -79,17 +81,3 @@ impl View {
self.popup.content_frp_node()
}
}
impl display::Object for View {
fn display_object(&self) -> &display::object::Instance {
self.popup.display_object()
}
}
impl Deref for View {
type Target = Frp;
fn deref(&self) -> &Self::Target {
&self.frp
}
}

View File

@ -26,8 +26,9 @@ const DEFAULT_DELAY_MS: f32 = 5_000.0;
// =============
/// Text label that disappears after a predefined delay.
#[derive(Debug, Clone, CloneRef)]
#[derive(Debug, Clone, CloneRef, display::Object)]
struct Model {
#[display_object]
label: Label,
opacity_animation: Animation<f32>,
delay_animation: DelayedAnimation,
@ -97,10 +98,11 @@ ensogl::define_endpoints! {
// ============
/// A temporary text message on top of the screen.
#[derive(Debug, Clone, CloneRef, Deref)]
#[derive(Debug, Clone, CloneRef, Deref, display::Object)]
pub struct View {
#[deref]
frp: Frp,
#[display_object]
model: Model,
}
@ -135,9 +137,3 @@ impl View {
self.frp.set_label.clone_ref()
}
}
impl display::Object for View {
fn display_object(&self) -> &display::object::Instance {
self.model.label.display_object()
}
}

View File

@ -182,7 +182,7 @@ ensogl::define_endpoints! {
// === Model ===
// =============
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
struct Model {
display_object: display::object::Instance,
top_bar: ProjectViewTopBar,
@ -357,8 +357,9 @@ mod js {
/// The main view of single project opened in IDE.
#[allow(missing_docs)]
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
pub struct View {
#[display_object]
model: Model,
pub frp: Frp,
}
@ -818,12 +819,6 @@ impl View {
}
}
impl display::Object for View {
fn display_object(&self) -> &display::object::Instance {
&self.model.display_object
}
}
impl FrpNetworkProvider for View {
fn network(&self) -> &frp::Network {
&self.frp.network
@ -839,7 +834,7 @@ impl application::View for View {
View::new(app)
}
fn default_shortcuts() -> Vec<application::shortcut::Shortcut> {
fn global_shortcuts() -> Vec<application::shortcut::Shortcut> {
use shortcut::ActionType::*;
[
(Press, "!is_searcher_opened", "cmd o", "show_project_list"),

View File

@ -0,0 +1,67 @@
//! Defines a UI container for the window control buttons and the "go to dashboard" button. This is
//! merely here to make use of the auto-layout functionality.
use ensogl::prelude::*;
use enso_config::ARGS;
use ensogl::application::Application;
use ensogl::display;
mod go_to_dashboard_button;
pub mod window_control_buttons;
// =================
// === Constants ===
// =================
/// The gap in pixels between the various components of the project view top bar.
const GAP: f32 = 16.0;
/// The padding left of the project view top bar.
const PADDING_LEFT: f32 = 19.0;
// ============================
// === Project View Top Bar ===
// ============================
/// Defines a UI container for the window control buttons and the "go to dashboard" button. This is
/// merely here to make use of the auto-layout functionality.
#[derive(Clone, CloneRef, Debug, display::Object)]
#[allow(missing_docs)]
pub struct ProjectViewTopBar {
display_object: display::object::Instance,
/// These buttons are only visible in a cloud environment.
pub window_control_buttons: window_control_buttons::View,
pub go_to_dashboard_button: go_to_dashboard_button::View,
}
impl ProjectViewTopBar {
/// Constructor.
pub fn new(app: &Application) -> Self {
let display_object = display::object::Instance::new_named("ProjectViewTopBar");
let window_control_buttons = app.new_view::<window_control_buttons::View>();
let go_to_dashboard_button = go_to_dashboard_button::View::new(app);
if ARGS.groups.startup.options.platform.value == "web" {
display_object.add_child(&window_control_buttons);
}
display_object.add_child(&go_to_dashboard_button);
display_object
.use_auto_layout()
.set_gap((GAP, 0.0))
.set_padding_left(PADDING_LEFT)
// We use `GAP` as the right padding since it delimits the space to the part of the top
// bar that's defined in the graph editor.
.set_padding_right(GAP)
.set_children_alignment_center();
app.display.default_scene.layers.panel.add(&display_object);
Self { display_object, window_control_buttons, go_to_dashboard_button }
}
}

View File

@ -74,7 +74,7 @@ pub struct EntryStyle {
// === Data ===
/// The model of the list entry. Displays the name of the project.
#[derive(Debug, Clone, CloneRef)]
#[derive(Debug, Clone, CloneRef, display::Object)]
struct Data {
display_object: display::object::Instance,
text: text::Text,
@ -101,18 +101,13 @@ impl Data {
// === Entry ===
/// The list entry. Displays the name of the project.
#[derive(Debug, Clone, CloneRef)]
#[derive(Debug, Clone, CloneRef, display::Object)]
pub struct Entry {
#[display_object]
data: Data,
frp: grid_view::entry::EntryFrp<Self>,
}
impl display::Object for Entry {
fn display_object(&self) -> &display::object::Instance {
&self.data.display_object
}
}
impl grid_view::Entry for Entry {
type Model = ImString;
type Params = ();
@ -202,7 +197,7 @@ mod background {
/// The Project List GUI Component.
///
/// This is a list of projects in a nice frame with a title.
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
pub struct ProjectList {
network: frp::Network,
display_object: display::object::Instance,
@ -273,9 +268,3 @@ impl ProjectList {
Self { network, display_object, background, caption, grid }
}
}
impl display::Object for ProjectList {
fn display_object(&self) -> &display::object::Instance {
&self.display_object
}
}

View File

@ -30,7 +30,7 @@ enum State {
/// Root View model. Stores both Welcome Screen and Project views and handles their
/// visibility.
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
pub struct Model {
// Required for creating project view dynamically
app: Application,
@ -121,20 +121,15 @@ ensogl::define_endpoints! {
// ============
/// Root View of the IDE. Displays either Welcome Screen or Project View.
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, Deref, display::Object)]
#[allow(missing_docs)]
pub struct View {
#[display_object]
model: Model,
#[deref]
pub frp: Frp,
}
impl Deref for View {
type Target = Frp;
fn deref(&self) -> &Self::Target {
&self.frp
}
}
impl View {
/// Constuctor.
pub fn new(app: &Application) -> Self {
@ -176,12 +171,6 @@ impl View {
}
}
impl display::Object for View {
fn display_object(&self) -> &display::object::Instance {
&self.model.display_object
}
}
impl FrpNetworkProvider for View {
fn network(&self) -> &frp::Network {
&self.frp.network

View File

@ -105,7 +105,7 @@ impl<T: DocumentationProvider + 'static> From<Rc<T>> for AnyDocumentationProvide
/// A type of ListView entry used in searcher.
pub type Entry = list_view::entry::GlyphHighlightedLabel;
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
struct Model {
display_object: display::object::Instance,
list: ListView<Entry>,
@ -183,19 +183,14 @@ ensogl::define_endpoints! {
/// additional graph node in edit mode, so we could easily display e.g. connections between selected
/// node and searcher input.
#[allow(missing_docs)]
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, Deref, display::Object)]
pub struct View {
#[deref]
pub frp: Frp,
#[display_object]
model: Model,
}
impl Deref for View {
type Target = Frp;
fn deref(&self) -> &Self::Target {
&self.frp
}
}
impl View {
/// Create new component.
pub fn new(app: &Application) -> Self {
@ -269,12 +264,6 @@ impl View {
}
}
impl display::Object for View {
fn display_object(&self) -> &display::object::Instance {
&self.model.display_object
}
}
impl FrpNetworkProvider for View {
fn network(&self) -> &frp::Network {
&self.frp.network
@ -290,7 +279,7 @@ impl application::View for View {
Self::new(app)
}
fn default_shortcuts() -> Vec<shortcut::Shortcut> {
fn global_shortcuts() -> Vec<shortcut::Shortcut> {
use shortcut::ActionType::*;
[(Press, "tab", "use_as_suggestion")]
.iter()

View File

@ -107,7 +107,7 @@ ensogl::define_endpoints! {
// =============
/// An internal model of Status Bar component
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
struct Model {
display_object: display::object::Instance,
root: display::object::Instance,
@ -219,9 +219,10 @@ impl Model {
///
/// The status bar gathers information about events and processes occurring in the Application.
// TODO: This is a stub. Extend it when doing https://github.com/enso-org/ide/issues/1193
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
pub struct View {
frp: Frp,
#[display_object]
model: Model,
}
@ -299,12 +300,6 @@ impl View {
}
}
impl display::Object for View {
fn display_object(&self) -> &display::object::Instance {
&self.model.display_object
}
}
impl Deref for View {
type Target = Frp;

View File

@ -114,7 +114,7 @@ static STYLESHEET: &str = include_str!("../style.css");
// === Model ===
/// Model of Welcome Screen that generates HTML DOM elements.
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
pub struct Model {
dom: DomSymbol,
display_object: display::object::Instance,
@ -190,20 +190,15 @@ ensogl::define_endpoints! {
// ============
/// View of the Welcome Screen.
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, Deref, display::Object)]
#[allow(missing_docs)]
pub struct View {
#[display_object]
model: Model,
#[deref]
pub frp: Frp,
}
impl Deref for View {
type Target = Frp;
fn deref(&self) -> &Self::Target {
&self.frp
}
}
impl View {
/// Constructor.
pub fn new(app: &Application) -> Self {
@ -236,12 +231,6 @@ impl View {
}
}
impl display::Object for View {
fn display_object(&self) -> &display::object::Instance {
&self.model.display_object
}
}
impl application::command::FrpNetworkProvider for View {
fn network(&self) -> &frp::Network {
&self.frp.network

View File

@ -1,6 +1,6 @@
# Options intended to be common for all developers.
wasm-size-limit: 16.07 MiB
wasm-size-limit: 16.20 MiB
required-versions:
# NB. The Rust version is pinned in rust-toolchain.toml.

View File

@ -13,5 +13,5 @@ proc-macro2 = { workspace = true }
quote = { workspace = true }
regex = { workspace = true }
serde_yaml = { workspace = true }
syn = { workspace = true }
syn_1 = { workspace = true }
derive_more = { workspace = true }

View File

@ -26,6 +26,7 @@ mod prelude {
pub use syn::Data;
pub use syn::DeriveInput;
pub use syn::Ident;
pub use syn_1 as syn;
}
use prelude::*;

View File

@ -10,7 +10,7 @@ proc-macro = true
[dependencies]
enso-build-base = { path = "../../base" }
enso-build-macros-lib = { path = "../lib" }
syn = { workspace = true }
syn_1 = { workspace = true }
[dev-dependencies]
itertools = { workspace = true }

View File

@ -6,6 +6,8 @@
#![allow(clippy::bool_to_int_with_if)]
#![allow(clippy::let_and_return)]
use syn_1 as syn;
#[proc_macro_derive(Arg, attributes(arg))]

View File

@ -5,6 +5,7 @@ use enso_build_base::prelude::*;
use itertools::Itertools;
use std::str::FromStr;
use syn_1 as syn;

View File

@ -9,5 +9,5 @@ proc-macro = true
[dependencies]
proc-macro2 = { workspace = true }
syn = { workspace = true }
syn_1 = { workspace = true }
quote = { workspace = true }

View File

@ -10,6 +10,7 @@ use quote::ToTokens;
use syn::DeriveInput;
use syn::Path;
use syn::Type;
use syn_1 as syn;

View File

@ -80,6 +80,7 @@ extern crate proc_macro;
use proc_macro::TokenStream;
use syn::parse_macro_input;
use syn::DeriveInput;
use syn_1 as syn;
mod from_theme;

View File

@ -199,7 +199,7 @@ pub mod shape {
// =============
/// An internal model of the button component.
#[derive(CloneRef, Debug, Derivative)]
#[derive(CloneRef, Debug, Derivative, display::Object)]
#[derivative(Clone(bound = ""))]
#[allow(missing_docs)]
pub struct Model<S: Shape> {
@ -260,12 +260,13 @@ ensogl_core::define_endpoints! {
/// the primary mouse button pressed without interrupting the click.
///
/// The button is fully theme-aware and dynamically sized.
#[derive(CloneRef, Debug, Deref, Derivative)]
#[derive(CloneRef, Debug, Deref, Derivative, display::Object)]
#[derivative(Clone(bound = ""))]
#[allow(missing_docs)]
pub struct View<S: Shape> {
#[deref]
frp: Frp,
#[display_object]
model: Model<S>,
style: StyleWatchFrp,
}
@ -366,12 +367,6 @@ impl<Shape: ButtonShape> View<Shape> {
}
}
impl<S: Shape> display::Object for View<S> {
fn display_object(&self) -> &display::object::Instance {
&self.model.display_object
}
}
impl<S: Shape> FrpNetworkProvider for View<S> {
fn network(&self) -> &frp::Network {
&self.frp.network

View File

@ -140,7 +140,7 @@ ensogl_core::define_endpoints! {
/// A type of Entry used in DropDownMenu's ListView.
pub type Entry = list_view::entry::Label;
#[derive(Clone, Debug)]
#[derive(Clone, Debug, display::Object)]
struct Model {
display_object: display::object::Instance,
@ -211,12 +211,6 @@ impl Model {
}
}
impl display::Object for Model {
fn display_object(&self) -> &display::object::Instance {
&self.display_object
}
}
// ============================
@ -225,19 +219,14 @@ impl display::Object for Model {
/// UI entity that shows a button that opens a list of visualizations that can be selected from.
#[allow(missing_docs)]
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, Deref, display::Object)]
pub struct DropDownMenu {
#[display_object]
model: Rc<Model>,
#[deref]
pub frp: Frp,
}
impl Deref for DropDownMenu {
type Target = Frp;
fn deref(&self) -> &Self::Target {
&self.frp
}
}
impl DropDownMenu {
/// Constructor.
pub fn new(app: &Application) -> Self {
@ -438,9 +427,3 @@ impl DropDownMenu {
self.model.label.add_to_scene_layer(layer);
}
}
impl display::Object for DropDownMenu {
fn display_object(&self) -> &display::object::Instance {
&self.model.display_object
}
}

View File

@ -81,7 +81,7 @@ impl EntryModel {
/// An internal structure of [`Entry`], which may be passed to FRP network.
#[allow(missing_docs)]
#[derive(Clone, Debug)]
#[derive(Clone, Debug, display::Object)]
pub struct EntryData {
display_object: display::object::Instance,
label_thin: text::Text,
@ -146,9 +146,10 @@ impl EntryData {
// === Entry ===
/// A [`SimpleGridView`] entry - a label with background.
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
pub struct Entry {
frp: EntryFrp<Self>,
#[display_object]
data: Rc<EntryData>,
}
@ -223,9 +224,3 @@ impl ensogl_grid_view::Entry for Entry {
&self.frp
}
}
impl display::Object for Entry {
fn display_object(&self) -> &display::object::Instance {
&self.data.display_object
}
}

View File

@ -41,7 +41,7 @@ const OPEN_ANIMATION_OFFSET: f32 = OPEN_ANIMATION_SCALE - 1.001;
// === Model ===
// =============
#[derive(Derivative, CloneRef, Debug)]
#[derive(Derivative, CloneRef, Debug, display::Object)]
#[derivative(Clone(bound = ""))]
pub struct Model<T> {
display_object: display::object::Instance,
@ -291,12 +291,6 @@ impl<T: DropdownValue> Model<T> {
}
}
impl<T: PartialEq + Hash> display::Object for Model<T> {
fn display_object(&self) -> &display::object::Instance {
&self.display_object
}
}
type Grid = grid_view::scrollable::SelectableGridView<Entry>;

View File

@ -75,20 +75,13 @@ ensogl_core::define_endpoints! {
/// A file browser component. It allows to browse the content of a folder and it's subfolders and
/// emits an event when an entry is chosen.
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, Deref, display::Object)]
pub struct FileBrowser {
#[deref]
frp: Frp,
display_object: display::object::Instance,
}
impl Deref for FileBrowser {
type Target = Frp;
fn deref(&self) -> &Self::Target {
&self.frp
}
}
impl FileBrowser {
/// Constructore
pub fn new() -> Self {
@ -103,9 +96,3 @@ impl Default for FileBrowser {
Self::new()
}
}
impl display::Object for FileBrowser {
fn display_object(&self) -> &display::object::Instance {
&self.display_object
}
}

View File

@ -93,7 +93,7 @@ impl component::Frp<Model> for Frp {
// === Model ===
// =============
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
pub struct Model {
background: background::View,
label: Rc<RefCell<Option<text::Text>>>,
@ -134,12 +134,6 @@ impl Model {
}
}
impl display::Object for Model {
fn display_object(&self) -> &display::object::Instance {
&self.display_object
}
}
// =================

View File

@ -108,7 +108,7 @@ impl<BlockType: IntoThemePath> IntoThemePath for profiler_flame_graph::Block<Blo
/// EnsoGL FlameGraph component. Consists of stacked blocks that indicate hierarchical time
/// intervals. The blocks can be hovered to reveal a label associated with the block.
#[derive(Debug)]
#[derive(Debug, display::Object)]
pub struct FlameGraph {
display_object: display::object::Instance,
blocks: Vec<Block>,
@ -273,9 +273,3 @@ impl FlameGraph {
self.origin_x = new_origin
}
}
impl display::Object for FlameGraph {
fn display_object(&self) -> &display::object::Instance {
&self.display_object
}
}

View File

@ -96,7 +96,7 @@ impl component::Frp<Model> for Frp {
// === Model ===
// =============
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
pub struct Model {
background: background::View,
label: Rc<RefCell<Option<text::Text>>>,
@ -133,12 +133,6 @@ impl Model {
}
}
impl display::Object for Model {
fn display_object(&self) -> &display::object::Instance {
&self.display_object
}
}
// =================

View File

@ -46,6 +46,10 @@ impl<E: display::Object> display::Object for VisibleEntry<E> {
fn display_object(&self) -> &display::object::Instance {
self.entry.display_object()
}
fn focus_receiver(&self) -> &display::object::Instance {
self.entry.focus_receiver()
}
}

View File

@ -536,6 +536,10 @@ where
fn display_object(&self) -> &display::object::Instance {
self.model.grid.display_object()
}
fn focus_receiver(&self) -> &display::object::Instance {
self.model.grid.focus_receiver()
}
}
@ -553,7 +557,7 @@ mod tests {
use ensogl_core::application::frp::API;
use ensogl_core::application::Application;
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
struct TestEntry {
parent: ParentEntry,
}
@ -577,12 +581,6 @@ mod tests {
}
}
impl display::Object for TestEntry {
fn display_object(&self) -> &display::object::Instance {
self.parent.display_object()
}
}
fn setup_grid_view<const COL_COUNT: Col>(
app: &Application,
network: &frp::Network,

View File

@ -178,10 +178,13 @@ ensogl_core::define_endpoints_2! {
/// Declare what area of the GridView is visible. The area position is relative to left-top
/// corner of the Grid View.
set_viewport(Viewport),
/// If `true`, the selection state will not be visible until it goes back to `false`.
disable_selection(bool),
}
Output {
grid_size(Row, Col),
multicolumn(bool),
viewport(Viewport),
entries_size(Vector2),
entries_params(EntryParams),
@ -200,7 +203,7 @@ ensogl_core::define_endpoints_2! {
column_resized(Col, f32),
/// Event emitted after a request was made to move the selection in a direction, but the
/// currently selected entry is the last one in the grid in that direction.
selection_movement_out_of_grid_prevented(Option<frp::io::keyboard::ArrowDirection>),
selection_movement_out_of_grid_prevented(frp::io::keyboard::ArrowDirection),
}
}
@ -214,7 +217,7 @@ ensogl_core::define_endpoints_2! {
/// The Model of [`GridView`].
#[allow(missing_docs)]
#[derive(Clone, Debug)]
#[derive(Clone, Debug, display::Object)]
pub struct Model<Entry, EntryParams> {
display_object: display::object::Instance,
visible_entries: RefCell<HashMap<(Row, Col), entry::visible::VisibleEntry<Entry>>>,
@ -420,7 +423,7 @@ impl<E: Entry> Model<E, E::Params> {
/// `Entry` bound in each place. Otherwise, it's better to use [`GridView`].
///
/// Note that some bounds are still required, as we use [`Widget`] and [`Frp`] nodes.
#[derive(CloneRef, Debug, Deref, Derivative)]
#[derive(CloneRef, Debug, Deref, Derivative, display::Object)]
#[derivative(Clone(bound = ""))]
pub struct GridViewTemplate<
Entry: 'static,
@ -522,6 +525,7 @@ impl<E: Entry> GridView<E> {
let model = Rc::new(Model::new(entry_creation_ctx));
frp::extend! { network
grid_size <- any(input.resize_grid, input.reset_entries);
out.multicolumn <+ grid_size.map(|(_, col)| *col > 1);
// We want to update `properties` output first, as some could listen for specific
// event (e.g. the `viewport` and expect the `properties` output is up-to-date.
out.properties <+ all_with3(
@ -588,8 +592,13 @@ impl<E: Entry> GridView<E> {
out.model_for_entry_needed <+ request_models_after_text_layer_change;
out.model_for_entry_needed <+ request_models_for_request;
let selection_hidden = &input.disable_selection;
hide_selection <- input.disable_selection.on_true();
show_selection <- input.disable_selection.on_false();
out.entry_hovered <+ input.hover_entry;
out.entry_selected <+ input.select_entry;
out.entry_selected <+ input.select_entry.gate_not(selection_hidden);
out.entry_selected <+ input.select_entry.sample(&show_selection);
out.entry_selected <+ hide_selection.constant(None);
out.entry_accepted <+ input.accept_entry;
out.entry_accepted <+ out.entry_selected.filter_map(|e| *e).sample(&input.accept_selected_entry);
@ -604,8 +613,7 @@ impl<E: Entry> GridView<E> {
);
out.entry_shown <+ input.model_for_entry.map(|(row, col, _)| (*row, *col));
}
let display_object = model.display_object.clone_ref();
let widget = Widget::new(app, frp, model, display_object);
let widget = Widget::new(app, frp, model);
Self { widget }
}
}
@ -666,14 +674,6 @@ impl<Entry, EntryModel: frp::node::Data, EntryParams: frp::node::Data> AsRef<Sel
}
}
impl<Entry, EntryModel: frp::node::Data, EntryParams: frp::node::Data> display::Object
for GridViewTemplate<Entry, EntryModel, EntryParams>
{
fn display_object(&self) -> &display::object::Instance {
self.widget.display_object()
}
}
impl<E: Entry> FrpNetworkProvider for GridView<E> {
fn network(&self) -> &frp::Network {
self.widget.network()
@ -689,17 +689,19 @@ impl<E: Entry> application::View for GridView<E> {
GridView::<E>::new(app)
}
fn default_shortcuts() -> Vec<application::shortcut::Shortcut> {
fn focused_shortcuts() -> Vec<application::shortcut::Shortcut> {
use application::shortcut::ActionType::*;
[
(PressAndRepeat, "up", "move_selection_up"),
(PressAndRepeat, "down", "move_selection_down"),
(PressAndRepeat, "left", "move_selection_left"),
(PressAndRepeat, "right", "move_selection_right"),
(Press, "enter", "accept_selected_entry"),
(PressAndRepeat, "up", "move_selection_up", ""),
(PressAndRepeat, "down", "move_selection_down", ""),
(PressAndRepeat, "left", "move_selection_left", "multicolumn"),
(PressAndRepeat, "right", "move_selection_right", "multicolumn"),
(Press, "enter", "accept_selected_entry", ""),
]
.iter()
.map(|(a, b, c)| Self::self_shortcut_when(*a, *b, *c, "focused"))
.map(|(action, pattern, command, condition)| {
Self::self_shortcut_when(*action, *pattern, *command, *condition)
})
.collect()
}
}
@ -720,7 +722,7 @@ pub(crate) mod tests {
pub param: Immutable<usize>,
}
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
pub struct TestEntry {
pub frp: EntryFrp<Self>,
pub param_set: Rc<Cell<usize>>,
@ -750,12 +752,6 @@ pub(crate) mod tests {
}
}
impl display::Object for TestEntry {
fn display_object(&self) -> &display::object::Instance {
&self.display_object
}
}
#[test]
fn initializing_grid_view() {
let app = Application::new("root");

View File

@ -268,8 +268,12 @@ impl<E: Entry, H: Entry<Params = E::Params>> SelectableGridViewWithHeaders<E, H>
}
}
impl<InnerGridView> display::Object for GridViewTemplate<InnerGridView> {
impl<InnerGridView: display::Object> display::Object for GridViewTemplate<InnerGridView> {
fn display_object(&self) -> &display::object::Instance {
self.area.display_object()
}
fn focus_receiver(&self) -> &display::object::Instance {
self.inner_grid.focus_receiver()
}
}

View File

@ -197,7 +197,7 @@ where
);
grid_frp.select_entry <+ selection_after_movement.filter_map(|s| s.location()).some();
grid_frp.private.output.selection_movement_out_of_grid_prevented <+
selection_after_movement.map(|s| s.out_of_bounds());
selection_after_movement.filter_map(|s| s.out_of_bounds());
}
Self { grid, highlights, header_highlights, selection_handler, hover_handler }
@ -268,6 +268,10 @@ where
fn display_object(&self) -> &display::object::Instance {
self.grid.display_object()
}
fn focus_receiver(&self) -> &display::object::Instance {
self.grid.focus_receiver()
}
}
@ -318,7 +322,7 @@ mod tests {
}
}
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
struct TestEntry {
display_object: display::object::Instance,
frp: EntryFrp<Self>,
@ -353,12 +357,6 @@ mod tests {
}
}
impl display::Object for TestEntry {
fn display_object(&self) -> &display::object::Instance {
&self.display_object
}
}
#[test]
fn selecting_entries() {
let app = Application::new("root");

View File

@ -90,7 +90,7 @@ impl<T: Into<ImString>> From<T> for EntryModel {
/// An internal structure of [`Entry`], which may be passed to FRP network.
#[allow(missing_docs)]
#[derive(Clone, Debug)]
#[derive(Clone, Debug, display::Object)]
pub struct EntryData {
display_object: display::object::Instance,
pub label: text::Text,
@ -122,9 +122,10 @@ impl EntryData {
// === Entry ===
/// A [`SimpleGridView`] entry - a label with background.
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
pub struct Entry {
frp: EntryFrp<Self>,
#[display_object]
data: Rc<EntryData>,
}
@ -187,12 +188,6 @@ impl crate::Entry for Entry {
}
}
impl display::Object for Entry {
fn display_object(&self) -> &display::object::Instance {
&self.data.display_object
}
}
// ======================

View File

@ -83,7 +83,7 @@ pub struct ComponentView<Model: 'static, Frp: 'static> {
impl<M, F> ComponentView<M, F>
where
M: Model + display::Object + 'static,
M: Model + 'static + display::Object,
F: Frp<M> + 'static,
{
/// Constructor.
@ -93,8 +93,7 @@ where
let style = StyleWatchFrp::new(&app.display.default_scene.style_sheet);
F::init(frp.network(), frp.private(), app, &model, &style);
F::init_inputs(frp.public());
let display_object = model.display_object().clone_ref();
let widget = Widget::new(app, frp, model, display_object);
let widget = Widget::new(app, frp, model);
Self { widget }
}
@ -112,10 +111,16 @@ where
}
}
impl<M: 'static, F: 'static> display::Object for ComponentView<M, F> {
impl<M: 'static, F: 'static> display::Object for ComponentView<M, F>
where M: display::Object
{
fn display_object(&self) -> &display::object::Instance {
self.widget.display_object()
}
fn focus_receiver(&self) -> &display::object::Instance {
self.widget.focus_receiver()
}
}
impl<M, F: Frp<M>> Deref for ComponentView<M, F> {
@ -144,7 +149,7 @@ where
ComponentView::new(app)
}
fn default_shortcuts() -> Vec<shortcut::Shortcut> {
fn global_shortcuts() -> Vec<shortcut::Shortcut> {
F::default_shortcuts()
}
}

View File

@ -50,7 +50,7 @@ ensogl_core::define_endpoints! {
// === Model ===
// =============
#[derive(Clone, Debug)]
#[derive(Clone, Debug, display::Object)]
struct Model {
background: Rectangle,
label: text::Text,
@ -133,9 +133,11 @@ impl Model {
// =======================
#[allow(missing_docs)]
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, Deref, display::Object)]
pub struct Label {
#[display_object]
model: Rc<Model>,
#[deref]
pub frp: Rc<Frp>,
}
@ -171,17 +173,3 @@ impl Label {
self
}
}
impl Deref for Label {
type Target = Frp;
fn deref(&self) -> &Self::Target {
&self.frp
}
}
impl display::Object for Label {
fn display_object(&self) -> &display::object::Instance {
&self.model.display_object
}
}

View File

@ -17,10 +17,11 @@ ensogl_core::define_endpoints_2! {
}
}
#[derive(Debug)]
#[derive(Debug, display::Object)]
pub struct Item<T> {
pub frp: Frp,
pub elem: T,
#[display_object]
pub placeholder: StrongPlaceholder,
pub debug: Rc<Cell<bool>>,
}
@ -61,9 +62,3 @@ impl<T: display::Object> Item<T> {
self.frp.set_margin_left.emit(margin)
}
}
impl<T> display::Object for Item<T> {
fn display_object(&self) -> &display::object::Instance {
self.placeholder.display_object()
}
}

View File

@ -338,11 +338,12 @@ ensogl_core::define_endpoints_2! { <T: ('static + Debug)>
}
}
#[derive(Derivative, CloneRef, Debug, Deref)]
#[derive(Derivative, CloneRef, Debug, Deref, display::Object)]
#[derivative(Clone(bound = ""))]
pub struct ListEditor<T: 'static + Debug> {
#[deref]
pub frp: Frp<T>,
#[display_object]
root: display::object::Instance,
model: SharedModel<T>,
}
@ -1202,9 +1203,3 @@ impl<T: display::Object + CloneRef + 'static> Model<T> {
center_points.iter().position(|t| x < *t).unwrap_or(self.items.len()).into()
}
}
impl<T: 'static + Debug> display::Object for ListEditor<T> {
fn display_object(&self) -> &display::object::Instance {
&self.root
}
}

View File

@ -89,30 +89,30 @@ impl Default for Placeholder {
/// A space holder for a list item. It is used to keep the list layout consistent when items are
/// added or removed.
#[derive(Debug, Clone, CloneRef, Deref)]
#[derive(Debug, Clone, CloneRef, Deref, display::Object)]
pub struct StrongPlaceholder {
model: Rc<PlaceholderModel>,
}
/// Internal model of [`StrongPlaceholder`].
#[allow(missing_docs)]
#[derive(Debug, Deref)]
#[derive(Debug, Deref, display::Object)]
pub struct PlaceholderModel {
#[deref]
pub frp: Frp,
root: display::object::Instance,
pub frp: Frp,
display_object: display::object::Instance,
/// A self-reference used to keep the [`WeakPlaceholder`] alive until the collapsing animation
/// ends.
self_ref: Rc<RefCell<Option<StrongPlaceholder>>>,
collapsing: Rc<Cell<bool>>,
size: Animation<f32>,
_deubg_viz: Option<Rectangle>,
self_ref: Rc<RefCell<Option<StrongPlaceholder>>>,
collapsing: Rc<Cell<bool>>,
size: Animation<f32>,
_debug_viz: Option<Rectangle>,
}
impl PlaceholderModel {
fn new() -> Self {
let frp = Frp::new();
let root = display::object::Instance::new_named("Placeholder");
let display_object = display::object::Instance::new_named("Placeholder");
let self_ref = default();
let collapsing = default();
let size = Animation::<f32>::new(frp.network());
@ -124,13 +124,13 @@ impl PlaceholderModel {
.set_border_and_inset(2.0)
.set_border_color(color::Rgba::new(1.0, 0.0, 0.0, 1.0));
});
root.add_child(&viz);
display_object.add_child(&viz);
with_context(|ctx| {
ctx.layers.above_nodes.add(&viz);
});
viz
});
Self { frp, root, self_ref, collapsing, size, _deubg_viz }
Self { frp, display_object, self_ref, collapsing, size, _debug_viz: _deubg_viz }
}
}
@ -139,7 +139,7 @@ impl StrongPlaceholder {
pub fn new() -> Self {
let model = PlaceholderModel::new();
let model = Rc::new(model);
let root = model.root.clone_ref();
let display_object = &model.display_object;
let collapsing = &model.collapsing;
let self_ref = &model.self_ref;
@ -151,7 +151,7 @@ impl StrongPlaceholder {
size.skip <+ model.frp.private.input.skip_animation;
model.frp.private.output.target_size <+ model.frp.private.input.set_target_size;
eval size.value ((t) { root.set_size_x(*t); });
eval size.value ((t) display_object.set_size_x(*t).void());
eval_ size.on_end ([collapsing, self_ref] {
if collapsing.get() {
self_ref.borrow_mut().take();
@ -209,12 +209,6 @@ impl Default for StrongPlaceholder {
}
}
impl display::Object for StrongPlaceholder {
fn display_object(&self) -> &display::object::Instance {
&self.root
}
}
// =======================

View File

@ -86,7 +86,7 @@ pub trait Entry: CloneRef + Debug + display::Object + 'static {
/// The [`Entry`] being a single text field displaying String.
#[allow(missing_docs)]
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
pub struct Label {
display_object: display::object::Instance,
pub label: text::Text,
@ -156,12 +156,6 @@ impl Entry for Label {
}
}
impl display::Object for Label {
fn display_object(&self) -> &display::object::Instance {
&self.display_object
}
}
// === HighlightedLabel ===
@ -177,8 +171,9 @@ pub struct GlyphHighlightedLabelModel {
/// The [`Entry`] similar to the [`Label`], but allows highlighting some parts of text.
#[allow(missing_docs)]
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
pub struct GlyphHighlightedLabel {
#[display_object]
pub inner: Label,
highlight: frp::Source<Vec<text::Range<text::Byte>>>,
}
@ -221,12 +216,6 @@ impl Entry for GlyphHighlightedLabel {
}
}
impl display::Object for GlyphHighlightedLabel {
fn display_object(&self) -> &display::object::Instance {
self.inner.display_object()
}
}
// =======================

View File

@ -62,7 +62,7 @@ impl IdAtYPosition {
pub type List<E> = ListData<E, <E as Entry>::Params>;
/// Data of a [`List`].
#[derive(CloneRef, Debug, Derivative)]
#[derive(CloneRef, Debug, Derivative, display::Object)]
#[derivative(Clone(bound = ""))]
#[clone_ref(bound = "E:CloneRef")]
pub struct ListData<E, P> {
@ -282,9 +282,3 @@ impl<E: Entry> ListData<E, E::Params> {
entry.entry.set_y(Self::position_y_of_entry(id));
}
}
impl<E, P> display::Object for ListData<E, P> {
fn display_object(&self) -> &display::object::Instance {
&self.display_object
}
}

View File

@ -71,7 +71,7 @@ pub const CORNER_RADIUS_PX: f32 = 12.0;
// === Shapes ===
// ==============
#[derive(Clone, Debug, Default, CloneRef)]
#[derive(Clone, Debug, Default, CloneRef, display::Object)]
struct Selection {
shape: Rectangle,
}
@ -86,12 +86,6 @@ impl Selection {
}
}
impl display::Object for Selection {
fn display_object(&self) -> &display::object::Instance {
self.shape.display_object()
}
}
// =============
@ -122,7 +116,7 @@ impl Default for JumpTarget {
}
/// The Model of Select Component.
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
struct Model<E: Entry> {
entries: entry::List<E>,
selection: Selection,
@ -365,20 +359,15 @@ impl StyleFrp {
/// This is a displayed list of entries (of any type `E`) with possibility of selecting one and
/// "choosing" by clicking or pressing enter. The basic entry types are defined in [`entry`] module.
#[allow(missing_docs)]
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, Deref, display::Object)]
pub struct ListView<E: Entry> {
#[display_object]
model: Model<E>,
#[deref]
pub frp: Frp<E>,
style_frp: StyleFrp,
}
impl<E: Entry> Deref for ListView<E> {
type Target = Frp<E>;
fn deref(&self) -> &Self::Target {
&self.frp
}
}
impl<E: Entry> ListView<E>
where E::Model: Default
{
@ -618,12 +607,6 @@ where E::Model: Default
}
}
impl<E: Entry> display::Object for ListView<E> {
fn display_object(&self) -> &display::object::Instance {
&self.model.display_object
}
}
impl<E: Entry> FrpNetworkProvider for ListView<E> {
fn network(&self) -> &frp::Network {
&self.frp.network
@ -639,7 +622,7 @@ impl<E: Entry> application::View for ListView<E> {
ListView::new(app)
}
fn default_shortcuts() -> Vec<shortcut::Shortcut> {
fn global_shortcuts() -> Vec<shortcut::Shortcut> {
use shortcut::ActionType::*;
[
(PressAndRepeat, "up", "move_selection_up"),

View File

@ -185,7 +185,7 @@ mod mask {
}
/// Internal representaton of the scroll area.
#[derive(Debug, Clone, CloneRef)]
#[derive(Debug, Clone, CloneRef, display::Object)]
struct Model {
content: display::object::Instance,
scrollbars: display::object::Instance,
@ -222,26 +222,14 @@ impl Model {
/// left corner. All scroll coordinates describe the point of the `content` object at that corner.
/// The scrollbars are only active when the content is actually larger than the viewport on the
/// respective axis. The component does not have a background.
#[derive(Debug, Clone, CloneRef)]
#[derive(Debug, Clone, CloneRef, Deref, display::Object)]
pub struct ScrollArea {
#[display_object]
model: Model,
#[deref]
frp: Frp,
}
impl Deref for ScrollArea {
type Target = Frp;
fn deref(&self) -> &Self::Target {
&self.frp
}
}
impl display::Object for ScrollArea {
fn display_object(&self) -> &display::object::Instance {
&self.model.display_object
}
}
impl ScrollArea {
/// Create a new scroll area for use in the given application.
#[profile(Detail)]

View File

@ -353,10 +353,11 @@ impl Frp {
///
/// All operations related to the scroll position take as argument a number of pixels describing a
/// position or distance on the scrolled area. We call them scroll units.
#[derive(Clone, CloneRef, Debug, Derivative)]
#[derive(Clone, CloneRef, Debug, display::Object)]
pub struct Scrollbar {
/// Public FRP api of the Component.
pub frp: Rc<Frp>,
#[display_object]
model: Rc<Model>,
}
@ -372,12 +373,6 @@ impl Scrollbar {
}
}
impl display::Object for Scrollbar {
fn display_object(&self) -> &display::object::Instance {
self.model.display_object()
}
}
impl Deref for Scrollbar {
type Target = Frp;
fn deref(&self) -> &Self::Target {

View File

@ -37,32 +37,32 @@ ensogl_core::define_endpoints! {
// === Model ===
// ==============
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
pub struct Model {
/// Root object. Required as the rendered text label will have an offset relative to the
/// base position of the root, depending on the position of the decimal separator.
root: display::object::Instance,
display_object: display::object::Instance,
/// Label containing the text to display. This is the label that will be shown.
label_full: text::Text,
label_full: text::Text,
/// This label contains the text to the left of the decimal. This is here, so we can get
/// information about the text width of this portion of the label. This label will
/// not appear in the UI.
label_left: text::Text,
label_left: text::Text,
}
impl Model {
fn new(app: &Application) -> Self {
let root = display::object::Instance::new();
let display_object = display::object::Instance::new();
let label_full = app.new_view::<text::Text>();
let label_left = app.new_view::<text::Text>();
app.display.default_scene.layers.main.remove(&label_full);
label_full.add_to_scene_layer(&app.display.default_scene.layers.label);
root.add_child(&label_full);
root.add_child(&label_left);
display_object.add_child(&label_full);
display_object.add_child(&label_left);
Self { root, label_full, label_left }
Self { display_object, label_full, label_left }
}
}
@ -88,17 +88,13 @@ impl Frp {
}
}
impl display::Object for Model {
fn display_object(&self) -> &display::object::Instance {
self.root.display_object()
}
}
/// Decimal aligned text label that shows the text representation of a floating point number.
#[allow(missing_docs)]
#[derive(Clone, CloneRef, Debug, Derivative)]
#[derive(Clone, CloneRef, Debug, Deref, display::Object)]
pub struct FloatLabel {
#[deref]
pub frp: Rc<Frp>,
#[display_object]
model: Rc<Model>,
}
@ -113,19 +109,6 @@ impl FloatLabel {
}
}
impl display::Object for FloatLabel {
fn display_object(&self) -> &display::object::Instance {
self.model.display_object()
}
}
impl Deref for FloatLabel {
type Target = Frp;
fn deref(&self) -> &Self::Target {
&self.frp
}
}
impl FrpNetworkProvider for FloatLabel {
fn network(&self) -> &frp::Network {
self.frp.network()

View File

@ -72,10 +72,11 @@ pub use crate::frp::*;
/// background that corresponds to the value relative in the range, for example, 0.0 would be not
/// filled in, 128.0 would be about halfway filled in, and 128.0 would be completely filled in.
/// The value can be changed by clicking and dragging on the shape.
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
pub struct NumberPicker {
/// Public FRP api of the Component.
pub frp: Rc<number::Frp>,
#[display_object]
model: Rc<Model>,
}
@ -91,12 +92,6 @@ impl NumberPicker {
}
}
impl display::Object for NumberPicker {
fn display_object(&self) -> &display::object::Instance {
self.model.display_object()
}
}
impl Deref for NumberPicker {
type Target = number::Frp;
fn deref(&self) -> &Self::Target {
@ -135,10 +130,11 @@ impl application::View for NumberPicker {
/// would show the track covering the right half of the background. The selected range can be
/// changed by clicking and dragging the track, which changes the whole range, but preserves the
/// width, or the individual edges of the track which changes just the respective end of the range.
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
pub struct NumberRangePicker {
/// Public FRP api of the Component.
pub frp: Rc<range::Frp>,
#[display_object]
model: Rc<Model>,
}
@ -154,12 +150,6 @@ impl NumberRangePicker {
}
}
impl display::Object for NumberRangePicker {
fn display_object(&self) -> &display::object::Instance {
self.model.display_object()
}
}
impl Deref for NumberRangePicker {
type Target = range::Frp;
fn deref(&self) -> &Self::Target {

View File

@ -29,7 +29,7 @@ const LABEL_OFFSET: f32 = 13.0;
/// A Selector Component Model.
#[allow(missing_docs)]
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
pub struct Model {
/// Background shape that the other UI elements are placed on.
pub background: background::View,
@ -63,7 +63,7 @@ pub struct Model {
pub caption_center: text::Text,
/// Shape root that all other elements are parented to. Should be used to place the shapes as
/// a group.
pub root: display::object::Instance,
display_object: display::object::Instance,
background_color: Rc<RefCell<color::Rgba>>,
track_color: Rc<RefCell<color::Rgba>>,
@ -75,7 +75,7 @@ pub struct Model {
#[allow(missing_docs)]
impl Model {
pub fn new(app: &Application) -> Self {
let root = display::object::Instance::new();
let display_object = display::object::Instance::new();
let label = FloatLabel::new(app);
let label_left = app.new_view::<text::Text>();
let label_right = app.new_view::<text::Text>();
@ -95,14 +95,14 @@ impl Model {
let scene = &app.display.default_scene;
root.add_child(&label);
root.add_child(&label_left);
root.add_child(&label_right);
root.add_child(&caption_left);
root.add_child(&caption_center);
root.add_child(&background);
root.add_child(&track);
root.add_child(&right_overflow);
display_object.add_child(&label);
display_object.add_child(&label_left);
display_object.add_child(&label_right);
display_object.add_child(&caption_left);
display_object.add_child(&caption_center);
display_object.add_child(&background);
display_object.add_child(&track);
display_object.add_child(&right_overflow);
scene.layers.main.remove(&label_left);
label_left.add_to_scene_layer(&scene.layers.label);
@ -125,7 +125,7 @@ impl Model {
label_right,
caption_left,
caption_center,
root,
display_object,
background_color,
track_color,
background_left_corner_roundness,
@ -235,17 +235,17 @@ impl Model {
pub fn show_left_overflow(&self, value: bool) {
if value {
self.root.add_child(&self.left_overflow);
self.display_object.add_child(&self.left_overflow);
} else {
self.root.remove_child(&self.left_overflow);
self.display_object.remove_child(&self.left_overflow);
}
}
pub fn show_right_overflow(&self, value: bool) {
if value {
self.root.add_child(&self.right_overflow);
self.display_object.add_child(&self.right_overflow);
} else {
self.root.remove_child(&self.right_overflow);
self.display_object.remove_child(&self.right_overflow);
}
}
@ -302,9 +302,3 @@ impl Model {
}
}
}
impl display::Object for Model {
fn display_object(&self) -> &display::object::Instance {
&self.root
}
}

View File

@ -80,7 +80,7 @@ impl component::Frp<Model> for Frp {
// =============
/// Internal model of the LabeledLine.
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
pub struct Model {
line: shape::arrow::View,
}
@ -115,11 +115,5 @@ impl Model {
}
}
impl display::Object for Model {
fn display_object(&self) -> &display::object::Instance {
self.line.display_object()
}
}
/// A line that shows a tooltip on mouse hover.
pub type LabeledLine = component::ComponentView<Model, Frp>;

View File

@ -87,7 +87,7 @@ impl component::Frp<Model> for Frp {
// =============
/// Internal model of the SequenceDiagram.
#[derive(Clone, CloneRef, Debug)]
#[derive(Clone, CloneRef, Debug, display::Object)]
pub struct Model {
// Required for dynamically creating new lines.
app: Application,
@ -200,12 +200,6 @@ impl Model {
}
}
impl display::Object for Model {
fn display_object(&self) -> &display::object::Instance {
&self.display_object
}
}
/// A visualization of messages passed between different actors.
///
/// This visualization renders a horizontal line for each actor and shows an arrow for each message.

View File

@ -331,11 +331,12 @@ ensogl_core::define_endpoints_2! {
/// value within the specified range. Dragging the slider in a vertical direction adjusts the
/// resolution of the slider. The resolution affects the increments by which the value changes when
/// the mouse is moved.
#[derive(Debug, Deref, Clone, CloneRef)]
#[derive(Debug, Deref, Clone, CloneRef, display::Object)]
pub struct Slider {
/// Public FRP api of the component.
#[deref]
pub frp: Frp,
#[display_object]
model: Rc<Model>,
}
@ -370,7 +371,7 @@ impl Slider {
let model = &self.model;
let scene = &app.display.default_scene;
let mouse = &scene.mouse.frp_deprecated;
let keyboard = &scene.keyboard.frp;
let keyboard = &scene.global_keyboard.frp;
let ptr_down_any = model.background.on_event::<mouse::Down>();
let ptr_up_any = scene.on_event::<mouse::Up>();
@ -819,12 +820,6 @@ impl Slider {
}
}
impl display::Object for Slider {
fn display_object(&self) -> &display::object::Instance {
self.model.display_object()
}
}
impl FrpNetworkProvider for Slider {
fn network(&self) -> &enso_frp::Network {
self.frp.network()
@ -840,7 +835,7 @@ impl application::View for Slider {
Self::new(app)
}
fn default_shortcuts() -> Vec<shortcut::Shortcut> {
fn global_shortcuts() -> Vec<shortcut::Shortcut> {
use shortcut::ActionType::DoublePress;
use shortcut::ActionType::Press;
vec![

View File

@ -111,7 +111,7 @@ mod overflow {
// ===============================
/// The slider model contains the visual elements of the slider component.
#[derive(Debug)]
#[derive(Debug, display::Object)]
pub struct Model {
/// Background element
pub background: background::View,
@ -138,15 +138,15 @@ pub struct Model {
/// Animation component that smoothly adjusts the slider end value on large jumps.
pub end_value_animation: Animation<f32>,
/// Root of the display object.
pub root: display::object::Instance,
display_object: display::object::Instance,
/// The display object containing the text value of the slider.
pub value: display::object::Instance,
value: display::object::Instance,
}
impl Model {
/// Create a new slider model.
pub fn new(app: &Application, frp_network: &frp::Network) -> Self {
let root = display::object::Instance::new();
let display_object = display::object::Instance::new();
let value = display::object::Instance::new();
let label = app.new_view::<text::Text>();
let value_text_left = app.new_view::<text::Text>();
@ -162,10 +162,10 @@ impl Model {
let overflow_upper = overflow::View::new();
let style = StyleWatch::new(&app.display.default_scene.style_sheet);
root.add_child(&background);
root.add_child(&track);
root.add_child(&label);
root.add_child(&value);
display_object.add_child(&background);
display_object.add_child(&track);
display_object.add_child(&label);
display_object.add_child(&value);
value.add_child(&value_text_left);
value.add_child(&value_text_dot);
value.add_child(&value_text_right);
@ -184,7 +184,7 @@ impl Model {
tooltip,
start_value_animation,
end_value_animation,
root,
display_object,
value,
};
model.init(style)
@ -284,18 +284,18 @@ impl Model {
/// Set whether the lower overfow marker is visible.
pub fn set_overflow_lower_visible(&self, visible: bool) {
if visible {
self.root.add_child(&self.overflow_lower);
self.display_object.add_child(&self.overflow_lower);
} else {
self.root.remove_child(&self.overflow_lower);
self.display_object.remove_child(&self.overflow_lower);
}
}
/// Set whether the upper overfow marker is visible.
pub fn set_overflow_upper_visible(&self, visible: bool) {
if visible {
self.root.add_child(&self.overflow_upper);
self.display_object.add_child(&self.overflow_upper);
} else {
self.root.remove_child(&self.overflow_upper);
self.display_object.remove_child(&self.overflow_upper);
}
}
@ -331,18 +331,18 @@ impl Model {
/// Set whether the slider value text is hidden.
pub fn show_value(&self, visible: bool) {
if visible {
self.root.add_child(&self.value);
self.display_object.add_child(&self.value);
} else {
self.root.remove_child(&self.value);
self.display_object.remove_child(&self.value);
}
}
/// Set whether the slider label is hidden.
pub fn set_label_hidden(&self, hidden: bool) {
if hidden {
self.root.remove_child(&self.label);
self.display_object.remove_child(&self.label);
} else {
self.root.add_child(&self.label);
self.display_object.add_child(&self.label);
}
}
@ -350,18 +350,18 @@ impl Model {
/// field to enter a new value.
pub fn set_edit_mode(&self, (editing, _precision): &(bool, f32)) {
if *editing {
self.root.remove_child(&self.value);
self.root.add_child(&self.value_text_edit);
self.display_object.remove_child(&self.value);
self.display_object.add_child(&self.value_text_edit);
self.value_text_edit.deprecated_focus();
self.value_text_edit.add_cursor_at_front();
self.value_text_edit.cursor_select_to_text_end();
} else {
self.root.add_child(&self.value);
self.display_object.add_child(&self.value);
// if *precision < 1.0 {
// self.root.add_child(&self.value_text_dot);
// self.root.add_child(&self.value_text_right);
// }
self.root.remove_child(&self.value_text_edit);
self.display_object.remove_child(&self.value_text_edit);
self.value_text_edit.deprecated_defocus();
self.value_text_edit.remove_all_cursors();
}
@ -385,9 +385,3 @@ impl Model {
self.value_text_right.set_property_default(property.into());
}
}
impl display::Object for Model {
fn display_object(&self) -> &display::object::Instance {
&self.root
}
}

View File

@ -234,7 +234,7 @@ ensogl_core::define_endpoints_2! {
/// clicking inside of the text area, it allows us to binary search the place of the mouse
/// pointer.
#[allow(missing_docs)]
#[derive(Debug, Deref)]
#[derive(Debug, Deref, display::Object)]
#[cfg_attr(not(target_arch = "wasm32"), allow(dead_code))]
pub struct View {
#[deref]
@ -383,12 +383,6 @@ impl View {
}
}
impl display::Object for View {
fn display_object(&self) -> &display::object::Instance {
&self.display_object
}
}
impl<'t> IntoIterator for &'t View {
type Item = &'t Glyph;
type IntoIter = slice::Iter<'t, Glyph>;

Some files were not shown because too many files have changed in this diff Show More