mirror of
https://github.com/enso-org/enso.git
synced 2024-12-23 03:51:43 +03:00
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:
parent
b288ccaa64
commit
828d160c56
16
Cargo.lock
generated
16
Cargo.lock
generated
@ -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",
|
||||
|
10
Cargo.toml
10
Cargo.toml
@ -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",
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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))
|
||||
|
@ -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(());
|
||||
|
@ -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(),
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ====================================
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ===================
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ===================
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ========================
|
||||
|
@ -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;
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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(¬_selected);
|
||||
mouse_out_if_not_selected <- model.view.events_deprecated.mouse_out.gate(¬_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 }
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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 ===
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ============
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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)]
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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();
|
||||
|
@ -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());
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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────────────────────╮
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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 ===
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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 ===
|
||||
// =============
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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"),
|
||||
|
67
app/gui/view/src/project/project_view_top_bar.rs
Normal file
67
app/gui/view/src/project/project_view_top_bar.rs
Normal 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 }
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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 }
|
||||
|
@ -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::*;
|
||||
|
@ -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 }
|
||||
|
@ -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))]
|
||||
|
@ -5,6 +5,7 @@ use enso_build_base::prelude::*;
|
||||
|
||||
use itertools::Itertools;
|
||||
use std::str::FromStr;
|
||||
use syn_1 as syn;
|
||||
|
||||
|
||||
|
||||
|
@ -9,5 +9,5 @@ proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
proc-macro2 = { workspace = true }
|
||||
syn = { workspace = true }
|
||||
syn_1 = { workspace = true }
|
||||
quote = { workspace = true }
|
||||
|
@ -10,6 +10,7 @@ use quote::ToTokens;
|
||||
use syn::DeriveInput;
|
||||
use syn::Path;
|
||||
use syn::Type;
|
||||
use syn_1 as syn;
|
||||
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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>;
|
||||
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// =================
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// =================
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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");
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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");
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ======================
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// =======================
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// =======================
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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"),
|
||||
|
@ -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)]
|
||||
|
@ -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 {
|
||||
|
@ -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()
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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>;
|
||||
|
@ -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.
|
||||
|
@ -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![
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user