mirror of
https://github.com/enso-org/enso.git
synced 2024-12-23 19:21:54 +03:00
Passing events to sub-widgets in List Editor and refactoring of the slider component. (#6433)
This commit is contained in:
parent
d0e1dd582e
commit
ae94a9f40d
22
Cargo.lock
generated
22
Cargo.lock
generated
@ -2883,6 +2883,17 @@ dependencies = [
|
|||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ensogl-example-list-editor"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"enso-frp",
|
||||||
|
"ensogl-core",
|
||||||
|
"ensogl-list-editor",
|
||||||
|
"ensogl-slider",
|
||||||
|
"ensogl-text-msdf",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ensogl-example-list-view"
|
name = "ensogl-example-list-view"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@ -3008,15 +3019,6 @@ dependencies = [
|
|||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ensogl-example-vector-editor"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"ensogl-core",
|
|
||||||
"ensogl-hardcoded-theme",
|
|
||||||
"wasm-bindgen",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ensogl-examples"
|
name = "ensogl-examples"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@ -3034,6 +3036,7 @@ dependencies = [
|
|||||||
"ensogl-example-focus-management",
|
"ensogl-example-focus-management",
|
||||||
"ensogl-example-grid-view",
|
"ensogl-example-grid-view",
|
||||||
"ensogl-example-instance-ordering",
|
"ensogl-example-instance-ordering",
|
||||||
|
"ensogl-example-list-editor",
|
||||||
"ensogl-example-list-view",
|
"ensogl-example-list-view",
|
||||||
"ensogl-example-mouse-events",
|
"ensogl-example-mouse-events",
|
||||||
"ensogl-example-profiling-run-graph",
|
"ensogl-example-profiling-run-graph",
|
||||||
@ -3043,7 +3046,6 @@ dependencies = [
|
|||||||
"ensogl-example-sprite-system",
|
"ensogl-example-sprite-system",
|
||||||
"ensogl-example-sprite-system-benchmark",
|
"ensogl-example-sprite-system-benchmark",
|
||||||
"ensogl-example-text-area",
|
"ensogl-example-text-area",
|
||||||
"ensogl-example-vector-editor",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -73,15 +73,11 @@
|
|||||||
#![allow(clippy::bool_to_int_with_if)]
|
#![allow(clippy::bool_to_int_with_if)]
|
||||||
#![allow(clippy::let_and_return)]
|
#![allow(clippy::let_and_return)]
|
||||||
|
|
||||||
use ensogl_core::display::shape::compound::rectangle::*;
|
|
||||||
use ensogl_core::display::world::*;
|
use ensogl_core::display::world::*;
|
||||||
use ensogl_core::prelude::*;
|
use ensogl_core::prelude::*;
|
||||||
|
|
||||||
use ensogl_core::application::Application;
|
|
||||||
use ensogl_core::control::io::mouse;
|
use ensogl_core::control::io::mouse;
|
||||||
use ensogl_core::data::color;
|
|
||||||
use ensogl_core::display;
|
use ensogl_core::display;
|
||||||
use ensogl_core::display::navigation::navigator::Navigator;
|
|
||||||
use ensogl_core::display::object::Event;
|
use ensogl_core::display::object::Event;
|
||||||
use ensogl_core::display::object::ObjectOps;
|
use ensogl_core::display::object::ObjectOps;
|
||||||
use ensogl_core::gui::cursor;
|
use ensogl_core::gui::cursor;
|
||||||
@ -262,30 +258,50 @@ impl<T> From<StrongPlaceholder> for ItemOrPlaceholder<T> {
|
|||||||
// === ListEditor ===
|
// === ListEditor ===
|
||||||
// ==================
|
// ==================
|
||||||
|
|
||||||
ensogl_core::define_endpoints_2! { <T: ('static)>
|
ensogl_core::define_endpoints_2! { <T: ('static + Debug)>
|
||||||
Input {
|
Input {
|
||||||
/// Push a new element to the end of the list.
|
/// Push a new element to the end of the list.
|
||||||
push(Weak<T>),
|
push(Rc<RefCell<Option<T>>>),
|
||||||
|
|
||||||
insert((Index, Weak<T>)),
|
/// Insert a new element in the given position. If the index is bigger than the list length,
|
||||||
|
/// the item will be placed at the end of the list.
|
||||||
|
insert((Index, Rc<RefCell<Option<T>>>)),
|
||||||
|
|
||||||
/// Remove the element at the given index. If the index is invalid, nothing will happen.
|
/// Remove the element at the given index. If the index is invalid, nothing will happen.
|
||||||
remove(Index),
|
remove(Index),
|
||||||
|
|
||||||
|
/// Set the spacing between elements.
|
||||||
gap(f32),
|
gap(f32),
|
||||||
|
|
||||||
|
/// The distance the user needs to drag the element along secondary axis to start dragging
|
||||||
|
/// the element. See docs of this module to learn more.
|
||||||
secondary_axis_drag_threshold(f32),
|
secondary_axis_drag_threshold(f32),
|
||||||
|
|
||||||
|
/// The distance the user needs to drag the element along primary axis to consider it not a
|
||||||
|
/// drag movement and thus to pass mouse events to the item. See docs of this module to
|
||||||
|
/// learn more.
|
||||||
primary_axis_no_drag_threshold(f32),
|
primary_axis_no_drag_threshold(f32),
|
||||||
|
|
||||||
|
/// The time in which the `primary_axis_no_drag_threshold` drops to zero.
|
||||||
primary_axis_no_drag_threshold_decay_time(f32),
|
primary_axis_no_drag_threshold_decay_time(f32),
|
||||||
|
|
||||||
|
/// Controls the distance an item needs to be dragged out of the list for it to be trashed.
|
||||||
|
/// See docs of this module to learn more.
|
||||||
thrashing_offset_ratio(f32),
|
thrashing_offset_ratio(f32),
|
||||||
|
|
||||||
|
/// Enable insertion points (plus icons) when moving mouse next to any of the list items.
|
||||||
enable_all_insertion_points(bool),
|
enable_all_insertion_points(bool),
|
||||||
|
|
||||||
|
/// Enable insertion points (plus icons) when moving mouse after the last list item.
|
||||||
enable_last_insertion_point(bool),
|
enable_last_insertion_point(bool),
|
||||||
}
|
}
|
||||||
Output {
|
Output {
|
||||||
/// Fires whenever a new element was added to the list.
|
/// Fires whenever a new element was added to the list.
|
||||||
on_item_added(Response<(Index, Weak<T>)>),
|
on_item_added(Response<Index>),
|
||||||
|
|
||||||
on_item_removed(Response<(Index, Weak<T>)>),
|
/// Fires whenever an element was removed from the list. This can happen when dragging the
|
||||||
|
/// element to switch its position.
|
||||||
|
on_item_removed(Response<(Index, Rc<RefCell<Option<T>>>)>),
|
||||||
|
|
||||||
/// Request new item to be inserted at the provided index. In most cases, this happens after
|
/// Request new item to be inserted at the provided index. In most cases, this happens after
|
||||||
/// clicking a "plus" icon to add new element to the list. As a response, you should use the
|
/// clicking a "plus" icon to add new element to the list. As a response, you should use the
|
||||||
@ -296,7 +312,7 @@ ensogl_core::define_endpoints_2! { <T: ('static)>
|
|||||||
|
|
||||||
#[derive(Derivative, CloneRef, Debug, Deref)]
|
#[derive(Derivative, CloneRef, Debug, Deref)]
|
||||||
#[derivative(Clone(bound = ""))]
|
#[derivative(Clone(bound = ""))]
|
||||||
pub struct ListEditor<T: 'static> {
|
pub struct ListEditor<T: 'static + Debug> {
|
||||||
#[deref]
|
#[deref]
|
||||||
pub frp: Frp<T>,
|
pub frp: Frp<T>,
|
||||||
root: display::object::Instance,
|
root: display::object::Instance,
|
||||||
@ -339,7 +355,7 @@ impl<T> From<Model<T>> for SharedModel<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl<T: display::Object + CloneRef> ListEditor<T> {
|
impl<T: display::Object + CloneRef + Debug> ListEditor<T> {
|
||||||
pub fn new(cursor: &Cursor) -> Self {
|
pub fn new(cursor: &Cursor) -> Self {
|
||||||
let frp = Frp::new();
|
let frp = Frp::new();
|
||||||
let model = Model::new(cursor);
|
let model = Model::new(cursor);
|
||||||
@ -359,10 +375,6 @@ impl<T: display::Object + CloneRef> ListEditor<T> {
|
|||||||
let on_move = scene.on_event::<mouse::Move>();
|
let on_move = scene.on_event::<mouse::Move>();
|
||||||
|
|
||||||
frp::extend! { network
|
frp::extend! { network
|
||||||
|
|
||||||
// Do not pass events to children, as we don't know whether we are about to drag
|
|
||||||
// them yet.
|
|
||||||
eval on_down ([] (event) event.stop_propagation());
|
|
||||||
target <= on_down.map(|event| event.target());
|
target <= on_down.map(|event| event.target());
|
||||||
|
|
||||||
on_up <- on_up_source.identity();
|
on_up <- on_up_source.identity();
|
||||||
@ -385,13 +397,21 @@ impl<T: display::Object + CloneRef> ListEditor<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.init_add_and_remove();
|
self.init_add_and_remove();
|
||||||
let (is_dragging, drag_diff) = self.init_dragging(&on_up, &on_down, &target, &pos_diff);
|
let (is_dragging, drag_diff, no_drag) =
|
||||||
|
self.init_dragging(&on_up, &on_down, &target, &pos_diff);
|
||||||
let (is_trashing, trash_pointer_style) = self.init_trashing(&on_up, &drag_diff);
|
let (is_trashing, trash_pointer_style) = self.init_trashing(&on_up, &drag_diff);
|
||||||
self.init_dropping(&on_up, &pos_on_move_down, &is_trashing);
|
self.init_dropping(&on_up, &pos_on_move_down, &is_trashing);
|
||||||
let insert_pointer_style = self.init_insertion_points(&on_up, &pos_on_move, &is_dragging);
|
let insert_pointer_style = self.init_insertion_points(&on_up, &pos_on_move, &is_dragging);
|
||||||
|
|
||||||
frp::extend! { network
|
frp::extend! { network
|
||||||
cursor.frp.set_style_override <+ all [insert_pointer_style, trash_pointer_style].fold();
|
cursor.frp.set_style_override <+ all [insert_pointer_style, trash_pointer_style].fold();
|
||||||
|
on_down_drag <- on_down.gate_not(&no_drag);
|
||||||
|
// Do not pass events to children, as we don't know whether we are about to drag
|
||||||
|
// them yet.
|
||||||
|
eval on_down_drag ([] (event) event.stop_propagation());
|
||||||
|
_eval <- no_drag.on_true().map3(&on_down, &target, |_, event, target| {
|
||||||
|
target.emit_event(event.payload.clone());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@ -451,18 +471,18 @@ impl<T: display::Object + CloneRef> ListEditor<T> {
|
|||||||
let network = self.frp.network();
|
let network = self.frp.network();
|
||||||
|
|
||||||
frp::extend! { network
|
frp::extend! { network
|
||||||
push_ix <= frp.push.map(f!((item) model.push_weak(item)));
|
push_ix <= frp.push.map(f!((item) model.push_cell(item)));
|
||||||
on_pushed <- frp.push.map2(&push_ix, |t, ix| Response::api((*ix, t.clone())));
|
on_pushed <- push_ix.map(|ix| Response::api(*ix));
|
||||||
frp.private.output.on_item_added <+ on_pushed;
|
frp.private.output.on_item_added <+ on_pushed;
|
||||||
|
|
||||||
insert_ix <= frp.insert.map(f!(((index, item)) model.insert_weak(*index, item)));
|
insert_ix <= frp.insert.map(f!(((index, item)) model.insert_cell(*index, item)));
|
||||||
on_inserted <- frp.insert.map2(&insert_ix, |t, ix| Response::api((*ix, t.1.clone())));
|
on_inserted <- insert_ix.map(|ix| Response::api(*ix));
|
||||||
frp.private.output.on_item_added <+ on_inserted;
|
frp.private.output.on_item_added <+ on_inserted;
|
||||||
|
|
||||||
let on_item_removed = &frp.private.output.on_item_removed;
|
let on_item_removed = &frp.private.output.on_item_removed;
|
||||||
eval frp.remove([model, on_item_removed] (index) {
|
eval frp.remove([model, on_item_removed] (index) {
|
||||||
if let Some(item) = model.borrow_mut().trash_item_at(*index) {
|
if let Some(item) = model.borrow_mut().trash_item_at(*index) {
|
||||||
on_item_removed.emit(Response::api((*index, Rc::new(item).downgrade())));
|
on_item_removed.emit(Response::api((*index, Rc::new(RefCell::new(Some(item))))));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -475,7 +495,7 @@ impl<T: display::Object + CloneRef> ListEditor<T> {
|
|||||||
on_down: &frp::Stream<Event<mouse::Down>>,
|
on_down: &frp::Stream<Event<mouse::Down>>,
|
||||||
target: &frp::Stream<display::object::Instance>,
|
target: &frp::Stream<display::object::Instance>,
|
||||||
pos_diff: &frp::Stream<Vector2>,
|
pos_diff: &frp::Stream<Vector2>,
|
||||||
) -> (frp::Stream<bool>, frp::Stream<Vector2>) {
|
) -> (frp::Stream<bool>, frp::Stream<Vector2>, frp::Stream<bool>) {
|
||||||
let model = &self.model;
|
let model = &self.model;
|
||||||
let on_up = on_up.clone_ref();
|
let on_up = on_up.clone_ref();
|
||||||
let on_down = on_down.clone_ref();
|
let on_down = on_down.clone_ref();
|
||||||
@ -499,6 +519,7 @@ impl<T: display::Object + CloneRef> ListEditor<T> {
|
|||||||
init_drag_not_disabled <- init_drag.gate_not(&drag_disabled);
|
init_drag_not_disabled <- init_drag.gate_not(&drag_disabled);
|
||||||
is_dragging <- bool(&on_up, &init_drag_not_disabled).on_change();
|
is_dragging <- bool(&on_up, &init_drag_not_disabled).on_change();
|
||||||
drag_diff <- pos_diff.gate(&is_dragging);
|
drag_diff <- pos_diff.gate(&is_dragging);
|
||||||
|
no_drag <- drag_disabled.gate_not(&is_dragging).on_change();
|
||||||
|
|
||||||
status <- bool(&on_up, &drag_diff).on_change();
|
status <- bool(&on_up, &drag_diff).on_change();
|
||||||
start <- status.on_true();
|
start <- status.on_true();
|
||||||
@ -506,11 +527,11 @@ impl<T: display::Object + CloneRef> ListEditor<T> {
|
|||||||
let on_item_removed = &frp.private.output.on_item_removed;
|
let on_item_removed = &frp.private.output.on_item_removed;
|
||||||
eval target_on_start([model, on_item_removed] (t) {
|
eval target_on_start([model, on_item_removed] (t) {
|
||||||
if let Some((index, item)) = model.borrow_mut().start_item_drag(t) {
|
if let Some((index, item)) = model.borrow_mut().start_item_drag(t) {
|
||||||
on_item_removed.emit(Response::gui((index, Rc::new(item).downgrade())));
|
on_item_removed.emit(Response::gui((index, Rc::new(RefCell::new(Some(item))))));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
(status, drag_diff)
|
(status, drag_diff, no_drag)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implementation of item trashing logic. See docs of this crate to learn more.
|
/// Implementation of item trashing logic. See docs of this crate to learn more.
|
||||||
@ -571,8 +592,8 @@ impl<T: display::Object + CloneRef> ListEditor<T> {
|
|||||||
|
|
||||||
let on_item_added = &frp.private.output.on_item_added;
|
let on_item_added = &frp.private.output.on_item_added;
|
||||||
eval insert_index_on_drop ([model, on_item_added] (index)
|
eval insert_index_on_drop ([model, on_item_added] (index)
|
||||||
if let Some((index, item)) = model.borrow_mut().place_dragged_item(*index) {
|
if let Some(index) = model.borrow_mut().place_dragged_item(*index) {
|
||||||
on_item_added.emit(Response::gui((index, Rc::new(item).downgrade())));
|
on_item_added.emit(Response::gui(index));
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -591,7 +612,7 @@ impl<T: display::Object + CloneRef> ListEditor<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn push(&self, item: T) {
|
pub fn push(&self, item: T) {
|
||||||
self.frp.push(Rc::new(item).downgrade());
|
self.frp.push(Rc::new(RefCell::new(Some(item))));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn items(&self) -> Vec<T> {
|
pub fn items(&self) -> Vec<T> {
|
||||||
@ -612,16 +633,18 @@ impl<T: display::Object + CloneRef + 'static> SharedModel<T> {
|
|||||||
self.borrow_mut().push(item)
|
self.borrow_mut().push(item)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_weak(&self, item: &Weak<T>) -> Option<Index> {
|
fn push_cell(&self, item: &Rc<RefCell<Option<T>>>) -> Option<Index> {
|
||||||
item.upgrade().map(|item| self.push((*item).clone_ref()))
|
let item = mem::take(&mut *item.borrow_mut());
|
||||||
|
item.map(|item| self.push(item))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert(&self, index: Index, item: T) -> Index {
|
fn insert(&self, index: Index, item: T) -> Index {
|
||||||
self.borrow_mut().insert(index, item)
|
self.borrow_mut().insert(index, item)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_weak(&self, index: Index, item: &Weak<T>) -> Option<Index> {
|
fn insert_cell(&self, index: Index, item: &Rc<RefCell<Option<T>>>) -> Option<Index> {
|
||||||
item.upgrade().map(|item| self.insert(index, (*item).clone_ref()))
|
let item = mem::take(&mut *item.borrow_mut());
|
||||||
|
item.map(|item| self.insert(index, item))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_index(&self, x: f32, center_points: &[f32]) -> ItemOrPlaceholderIndex {
|
fn insert_index(&self, x: f32, center_points: &[f32]) -> ItemOrPlaceholderIndex {
|
||||||
@ -681,7 +704,7 @@ impl<T: display::Object + CloneRef + 'static> Model<T> {
|
|||||||
|
|
||||||
/// Find an element by the provided display object reference.
|
/// Find an element by the provided display object reference.
|
||||||
fn item_index_of(
|
fn item_index_of(
|
||||||
&mut self,
|
&self,
|
||||||
obj: &display::object::Instance,
|
obj: &display::object::Instance,
|
||||||
) -> Option<(Index, ItemOrPlaceholderIndex)> {
|
) -> Option<(Index, ItemOrPlaceholderIndex)> {
|
||||||
self.items
|
self.items
|
||||||
@ -841,11 +864,12 @@ impl<T: display::Object + CloneRef + 'static> Model<T> {
|
|||||||
///
|
///
|
||||||
/// See docs of [`Self::start_item_drag_at`] for more information.
|
/// See docs of [`Self::start_item_drag_at`] for more information.
|
||||||
fn start_item_drag(&mut self, target: &display::object::Instance) -> Option<(Index, T)> {
|
fn start_item_drag(&mut self, target: &display::object::Instance) -> Option<(Index, T)> {
|
||||||
let index = self.item_index_of(target);
|
let objs = target.rev_parent_chain();
|
||||||
if let Some((index, index_or_placeholder_index)) = index {
|
let tarrget_index = objs.into_iter().find_map(|t| self.item_index_of(&t));
|
||||||
|
if let Some((index, index_or_placeholder_index)) = tarrget_index {
|
||||||
self.start_item_drag_at(index_or_placeholder_index).map(|item| (index, item))
|
self.start_item_drag_at(index_or_placeholder_index).map(|item| (index, item))
|
||||||
} else {
|
} else {
|
||||||
warn!("Requested to drag a non-existent item.");
|
warn!("Could not find the item to drag.");
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -941,7 +965,7 @@ impl<T: display::Object + CloneRef + 'static> Model<T> {
|
|||||||
/// Place the currently dragged element in the given index. The item will be enclosed in the
|
/// Place the currently dragged element in the given index. The item will be enclosed in the
|
||||||
/// [`Item`] object, will handles its animation. See the documentation of
|
/// [`Item`] object, will handles its animation. See the documentation of
|
||||||
/// [`ItemOrPlaceholder`] to learn more.
|
/// [`ItemOrPlaceholder`] to learn more.
|
||||||
fn place_dragged_item(&mut self, index: ItemOrPlaceholderIndex) -> Option<(Index, T)> {
|
fn place_dragged_item(&mut self, index: ItemOrPlaceholderIndex) -> Option<Index> {
|
||||||
if let Some(item) = self.cursor.stop_drag_if_is::<T>() {
|
if let Some(item) = self.cursor.stop_drag_if_is::<T>() {
|
||||||
self.collapse_all_placeholders_no_margin_update();
|
self.collapse_all_placeholders_no_margin_update();
|
||||||
if let Some((index, placeholder)) = self.get_indexed_merged_placeholder_at(index) {
|
if let Some((index, placeholder)) = self.get_indexed_merged_placeholder_at(index) {
|
||||||
@ -958,7 +982,7 @@ impl<T: display::Object + CloneRef + 'static> Model<T> {
|
|||||||
warn!("An element was inserted without a placeholder. This should not happen.");
|
warn!("An element was inserted without a placeholder. This should not happen.");
|
||||||
}
|
}
|
||||||
self.reposition_items();
|
self.reposition_items();
|
||||||
self.item_or_placeholder_index_to_index(index).map(|index| (index, item))
|
self.item_or_placeholder_index_to_index(index)
|
||||||
} else {
|
} else {
|
||||||
warn!("Called function to insert dragged element, but no element is being dragged.");
|
warn!("Called function to insert dragged element, but no element is being dragged.");
|
||||||
None
|
None
|
||||||
@ -1036,7 +1060,7 @@ impl<T: display::Object + CloneRef + 'static> Model<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: 'static> display::Object for ListEditor<T> {
|
impl<T: 'static + Debug> display::Object for ListEditor<T> {
|
||||||
fn display_object(&self) -> &display::object::Instance {
|
fn display_object(&self) -> &display::object::Instance {
|
||||||
&self.root
|
&self.root
|
||||||
}
|
}
|
||||||
@ -1092,92 +1116,3 @@ mod trash {
|
|||||||
}
|
}
|
||||||
use crate::placeholder::WeakPlaceholder;
|
use crate::placeholder::WeakPlaceholder;
|
||||||
use trash::Trash;
|
use trash::Trash;
|
||||||
|
|
||||||
|
|
||||||
// ===================
|
|
||||||
// === Entry Point ===
|
|
||||||
// ===================
|
|
||||||
|
|
||||||
pub mod glob {
|
|
||||||
use super::*;
|
|
||||||
ensogl_core::define_endpoints_2! {
|
|
||||||
Input {
|
|
||||||
}
|
|
||||||
Output {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The example entry point.
|
|
||||||
#[entry_point]
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn main() {
|
|
||||||
let app = Application::new("root");
|
|
||||||
let world = app.display.clone();
|
|
||||||
let scene = &world.default_scene;
|
|
||||||
|
|
||||||
let camera = scene.camera().clone_ref();
|
|
||||||
let navigator = Navigator::new(scene, &camera);
|
|
||||||
|
|
||||||
let vector_editor = ListEditor::<Rectangle>::new(&app.cursor);
|
|
||||||
|
|
||||||
|
|
||||||
let shape1 = Circle().build(|t| {
|
|
||||||
t.set_size(Vector2(60.0, 100.0))
|
|
||||||
.set_color(color::Rgba::new(0.0, 0.0, 0.0, 0.1))
|
|
||||||
.set_inset_border(2.0)
|
|
||||||
.set_border_color(color::Rgba::new(0.0, 0.0, 0.0, 0.5))
|
|
||||||
.keep_bottom_left_quarter();
|
|
||||||
});
|
|
||||||
let shape2 = RoundedRectangle(10.0).build(|t| {
|
|
||||||
t.set_size(Vector2(120.0, 100.0))
|
|
||||||
.set_color(color::Rgba::new(0.0, 0.0, 0.0, 0.1))
|
|
||||||
.set_inset_border(2.0)
|
|
||||||
.set_border_color(color::Rgba::new(0.0, 0.0, 0.0, 0.5));
|
|
||||||
});
|
|
||||||
let shape3 = RoundedRectangle(10.0).build(|t| {
|
|
||||||
t.set_size(Vector2(240.0, 100.0))
|
|
||||||
.set_color(color::Rgba::new(0.0, 0.0, 0.0, 0.1))
|
|
||||||
.set_inset_border(2.0)
|
|
||||||
.set_border_color(color::Rgba::new(0.0, 0.0, 0.0, 0.5));
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
let glob_frp = glob::Frp::new();
|
|
||||||
let glob_frp_network = glob_frp.network();
|
|
||||||
|
|
||||||
let shape1_down = shape1.on_event::<mouse::Down>();
|
|
||||||
frp::extend! { glob_frp_network
|
|
||||||
eval_ shape1_down ([] {
|
|
||||||
warn!("Shape 1 down");
|
|
||||||
});
|
|
||||||
new_item <- vector_editor.request_new_item.map(|_| {
|
|
||||||
let shape = RoundedRectangle(10.0).build(|t| {
|
|
||||||
t.set_size(Vector2(100.0, 100.0))
|
|
||||||
.set_color(color::Rgba::new(0.0, 0.0, 0.0, 0.1))
|
|
||||||
.set_inset_border(2.0)
|
|
||||||
.set_border_color(color::Rgba::new(0.0, 0.0, 0.0, 0.5));
|
|
||||||
});
|
|
||||||
Rc::new(shape)
|
|
||||||
});
|
|
||||||
vector_editor.insert <+ vector_editor.request_new_item.map2(&new_item, |index, item|
|
|
||||||
(**index, item.downgrade())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
vector_editor.push(shape1);
|
|
||||||
vector_editor.push(shape2);
|
|
||||||
vector_editor.push(shape3);
|
|
||||||
|
|
||||||
let root = display::object::Instance::new();
|
|
||||||
root.set_size(Vector2(300.0, 100.0));
|
|
||||||
root.add_child(&vector_editor);
|
|
||||||
world.add_child(&root);
|
|
||||||
|
|
||||||
world.keep_alive_forever();
|
|
||||||
mem::forget(app);
|
|
||||||
mem::forget(glob_frp);
|
|
||||||
mem::forget(navigator);
|
|
||||||
mem::forget(root);
|
|
||||||
mem::forget(vector_editor);
|
|
||||||
}
|
|
||||||
|
@ -1,4 +1,11 @@
|
|||||||
//! A slider UI component that allows adjusting a value through mouse interaction.
|
//! A slider UI component that allows adjusting a value through mouse interaction.
|
||||||
|
//!
|
||||||
|
//! # Important [WD]
|
||||||
|
//! Please note that the implementation is not finished yet. It was refactored to make the slider
|
||||||
|
//! implementation use the newest EnsoGL API, however, not all functionality was restored yet. As
|
||||||
|
//! this component is not used in the application yet, it is kept as is, but should be updated
|
||||||
|
//! before the real usage. In particualar, vertical sliders and sliders that behave as scrollbars
|
||||||
|
//! are not working correctly now.
|
||||||
|
|
||||||
#![recursion_limit = "512"]
|
#![recursion_limit = "512"]
|
||||||
// === Standard Linter Configuration ===
|
// === Standard Linter Configuration ===
|
||||||
@ -46,30 +53,30 @@ pub mod model;
|
|||||||
// === Constants ===
|
// === Constants ===
|
||||||
// =================
|
// =================
|
||||||
|
|
||||||
/// Default slider precision when slider dragging is initiated. The precision indicates both how
|
/// Default slider resolution when slider dragging is initiated. The resolution indicates both how
|
||||||
/// much the value is changed per pixel dragged and how many digits are displayed after the decimal.
|
/// much the value is changed per pixel dragged and how many digits are displayed after the decimal.
|
||||||
const PRECISION_DEFAULT: f32 = 1.0;
|
const RESOLUTION_DEFAULT: f32 = 1.0;
|
||||||
/// Default upper limit of the slider value.
|
/// Default upper limit of the slider value.
|
||||||
const MAX_VALUE_DEFAULT: f32 = 100.0;
|
const MAX_VALUE_DEFAULT: f32 = 100.0;
|
||||||
/// Default for the maximum number of digits after the decimal point that is displayed.
|
/// Default for the maximum number of digits after the decimal point that is displayed.
|
||||||
const MAX_DISP_DECIMAL_PLACES_DEFAULT: usize = 8;
|
const MAX_DISP_DECIMAL_PLACES_DEFAULT: usize = 8;
|
||||||
/// Margin above/below the component within which vertical mouse movement will not affect slider
|
/// Margin above/below the component within which vertical mouse movement will not affect slider
|
||||||
/// precision.
|
/// resolution.
|
||||||
const PRECISION_ADJUSTMENT_MARGIN: f32 = 10.0;
|
const PRECISION_ADJUSTMENT_MARGIN: f32 = 10.0;
|
||||||
/// The vertical mouse movement (in pixels) needed to change the slider precision by one step.
|
/// The vertical mouse movement (in pixels) needed to change the slider resolution by one step.
|
||||||
/// Dragging the mouse upward beyond the margin will decrease the precision by one step for every
|
/// Dragging the mouse upward beyond the margin will decrease the resolution by one step for every
|
||||||
/// `STEP_SIZE` pixels and adjust the slider value more quickly. Dragging the mouse downwards will
|
/// `STEP_SIZE` pixels and adjust the slider value more quickly. Dragging the mouse downwards will
|
||||||
/// increase the precision and change the value more slowly.
|
/// increase the resolution and change the value more slowly.
|
||||||
const PRECISION_ADJUSTMENT_STEP_SIZE: f32 = 50.0;
|
const PRECISION_ADJUSTMENT_STEP_SIZE: f32 = 50.0;
|
||||||
/// The actual slider precision changes exponentially with each adjustment step. When the adjustment
|
/// The actual slider resolution changes exponentially with each adjustment step. When the
|
||||||
/// is changed by one step, the slider's precision is changed to the next power of `STEP_BASE`. A
|
/// adjustment is changed by one step, the slider's resolution is changed to the next power of
|
||||||
/// `STEP_BASE` of 10.0 results in the precision being powers of 10 for consecutive steps, e.g [1.0,
|
/// `STEP_BASE`. A `STEP_BASE` of 10.0 results in the resolution being powers of 10 for consecutive
|
||||||
/// 10.0, 100.0, ...] when decreasing the precision and [0.1, 0.01, 0.001, ...] when increasing the
|
/// steps, e.g [1.0, 10.0, 100.0, ...] when decreasing the resolution and [0.1, 0.01, 0.001, ...]
|
||||||
/// precision.
|
/// when increasing the resolution.
|
||||||
const PRECISION_ADJUSTMENT_STEP_BASE: f32 = 10.0;
|
const PRECISION_ADJUSTMENT_STEP_BASE: f32 = 10.0;
|
||||||
/// Limit the number of precision steps to prevent overflow or rounding to zero of the precision.
|
/// Limit the number of resolution steps to prevent overflow or rounding to zero of the resolution.
|
||||||
const MAX_PRECISION_ADJUSTMENT_STEPS: usize = 8;
|
const MAX_PRECISION_ADJUSTMENT_STEPS: usize = 8;
|
||||||
/// A pop-up is displayed whenever the slider's precision is changed. This is the duration for
|
/// A pop-up is displayed whenever the slider's resolution is changed. This is the duration for
|
||||||
/// which the pop-up is visible.
|
/// which the pop-up is visible.
|
||||||
const PRECISION_ADJUSTMENT_POPUP_DURATION: f32 = 1000.0;
|
const PRECISION_ADJUSTMENT_POPUP_DURATION: f32 = 1000.0;
|
||||||
/// The delay before an information tooltip is displayed when hovering over a slider component.
|
/// The delay before an information tooltip is displayed when hovering over a slider component.
|
||||||
@ -100,37 +107,20 @@ pub enum LabelPosition {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ==========================
|
// ==================
|
||||||
// === Slider orientation ===
|
// === DragHandle ===
|
||||||
// ==========================
|
// ==================
|
||||||
|
|
||||||
// /// The orientation of the slider component.
|
/// Defines which part of the slider is being dragged by the user. In case the slider allows
|
||||||
// #[derive(Clone, Copy, Debug, Default)]
|
/// dragging both of its ends and the middle of the track, this struct determines which part is
|
||||||
// pub enum Axis2 {
|
/// being dragged.
|
||||||
// #[default]
|
#[allow(missing_docs)]
|
||||||
// /// The slider value is changed by dragging the slider horizontally.
|
#[derive(Debug, Copy, Clone, Default)]
|
||||||
// Horizontal,
|
pub enum DragHandle {
|
||||||
// /// The slider value is changed by dragging the slider vertically.
|
Start,
|
||||||
// Vertical,
|
Middle,
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// =================================
|
|
||||||
// === Slider position indicator ===
|
|
||||||
// =================================
|
|
||||||
|
|
||||||
/// The type of element that indicates the slider's value along its length.
|
|
||||||
#[derive(Clone, Copy, Debug, Default)]
|
|
||||||
pub enum Kind {
|
|
||||||
#[default]
|
#[default]
|
||||||
/// A track is a bar that fills the slider as the value increases. The track is empty when the
|
End,
|
||||||
/// slider's value is at the lower limit and filled when the value is at the upper limit.
|
|
||||||
SingleValue,
|
|
||||||
/// A thumb is a small element that moves across the slider as the value changes. The thumb is
|
|
||||||
/// on the left/lower end of the slider when the slider's value is at the lower limit and on
|
|
||||||
/// the right/upper end of the slider when the value is at the upper limit.
|
|
||||||
Scrollbar(f32),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -225,16 +215,16 @@ fn value_limit_clamp(
|
|||||||
|
|
||||||
ensogl_core::define_endpoints_2! {
|
ensogl_core::define_endpoints_2! {
|
||||||
Input {
|
Input {
|
||||||
// /// Set the width of the slider component.
|
|
||||||
// set_width(f32),
|
|
||||||
// /// Set the height of the slider component.
|
|
||||||
// set_height(f32),
|
|
||||||
/// Set the type of the slider's value indicator.
|
|
||||||
kind(Kind),
|
|
||||||
/// Set the color of the slider's value indicator.
|
/// Set the color of the slider's value indicator.
|
||||||
set_value_indicator_color(color::Lcha),
|
set_value_indicator_color(color::Lcha),
|
||||||
/// Set the color of the slider's background.
|
/// Set the color of the slider's background.
|
||||||
set_background_color(color::Lcha),
|
set_background_color(color::Lcha),
|
||||||
|
/// Allow dragging the start point of sliders track.
|
||||||
|
enable_start_track_drag(bool),
|
||||||
|
/// Allow dragging the end point of sliders track.
|
||||||
|
enable_end_track_drag(bool),
|
||||||
|
/// Allow dragging the sliders track by pressing in the middle of it.
|
||||||
|
enable_middle_track_drag(bool),
|
||||||
/// Set the slider value.
|
/// Set the slider value.
|
||||||
set_value(f32),
|
set_value(f32),
|
||||||
/// Set the default value to reset a slider to when `ctrl` + `click`-ed.
|
/// Set the default value to reset a slider to when `ctrl` + `click`-ed.
|
||||||
@ -249,22 +239,22 @@ ensogl_core::define_endpoints_2! {
|
|||||||
set_value_text_color(color::Lcha),
|
set_value_text_color(color::Lcha),
|
||||||
/// Set whether the slider's value text is hidden.
|
/// Set whether the slider's value text is hidden.
|
||||||
show_value(bool),
|
show_value(bool),
|
||||||
/// Set the default precision at which the slider operates. The slider's precision
|
/// Set the default resolution at which the slider operates. The slider's resolution
|
||||||
/// determines by what increment the value will be changed on mouse movement. It also
|
/// determines by what increment the value will be changed on mouse movement. It also
|
||||||
/// affects the number of digits after the decimal point displayed.
|
/// affects the number of digits after the decimal point displayed.
|
||||||
set_default_precision(f32),
|
set_default_resolution(f32),
|
||||||
/// The slider's precision can be adjusted by dragging the mouse in the vertical direction.
|
/// The slider's resolution can be adjusted by dragging the mouse in the vertical direction.
|
||||||
/// The `adjustment_margin` defines a margin above/below the slider within which no
|
/// The `adjustment_margin` defines a margin above/below the slider within which no
|
||||||
/// precision adjustment will be performed.
|
/// resolution adjustment will be performed.
|
||||||
set_precision_adjustment_margin(f32),
|
set_precision_adjustment_margin(f32),
|
||||||
/// The slider's precision can be adjusted by dragging the mouse in the vertical direction.
|
/// The slider's resolution can be adjusted by dragging the mouse in the vertical direction.
|
||||||
/// The `adjustment_step_size` defines the distance the mouse must be moved to increase or
|
/// The `adjustment_step_size` defines the distance the mouse must be moved to increase or
|
||||||
/// decrease the precision by one step.
|
/// decrease the resolution by one step.
|
||||||
set_precision_adjustment_step_size(f32),
|
set_precision_adjustment_step_size(f32),
|
||||||
/// Set the maximum number of precision steps to prevent overflow or rounding to zero of the
|
/// Set the maximum number of resolution steps to prevent overflow or rounding to zero of the
|
||||||
/// precision increments.
|
/// resolution increments.
|
||||||
set_max_precision_adjustment_steps(usize),
|
set_max_precision_adjustment_steps(usize),
|
||||||
/// Set whether the precision adjustment mechansim is disabled.
|
/// Set whether the resolution adjustment mechansim is disabled.
|
||||||
set_precision_adjustment_disabled(bool),
|
set_precision_adjustment_disabled(bool),
|
||||||
/// Set the slider's label. The label will be displayed to the left of the slider's value
|
/// Set the slider's label. The label will be displayed to the left of the slider's value
|
||||||
/// display.
|
/// display.
|
||||||
@ -281,7 +271,7 @@ ensogl_core::define_endpoints_2! {
|
|||||||
set_tooltip(ImString),
|
set_tooltip(ImString),
|
||||||
/// Set the delay of the tooltip showing after the mouse hovers over the component.
|
/// Set the delay of the tooltip showing after the mouse hovers over the component.
|
||||||
set_tooltip_delay(f32),
|
set_tooltip_delay(f32),
|
||||||
/// A pop-up is displayed whenever the slider's precision is changed. This is the duration
|
/// A pop-up is displayed whenever the slider's resolution is changed. This is the duration
|
||||||
/// for which the pop-up is visible.
|
/// for which the pop-up is visible.
|
||||||
set_precision_popup_duration(f32),
|
set_precision_popup_duration(f32),
|
||||||
/// Set whether the slider is disabled. When disabled, the slider's value cannot be changed
|
/// Set whether the slider is disabled. When disabled, the slider's value cannot be changed
|
||||||
@ -308,10 +298,12 @@ ensogl_core::define_endpoints_2! {
|
|||||||
width(f32),
|
width(f32),
|
||||||
/// The component's height.
|
/// The component's height.
|
||||||
height(f32),
|
height(f32),
|
||||||
/// The slider's value.
|
/// The slider track's start position.
|
||||||
value(f32),
|
start_value(f32),
|
||||||
/// The slider's precision.
|
/// The slider track's end position.
|
||||||
precision(f32),
|
end_value(f32),
|
||||||
|
/// The slider's resolution.
|
||||||
|
resolution(f32),
|
||||||
/// The slider value's lower limit. This takes into account limit extension if an adaptive
|
/// The slider value's lower limit. This takes into account limit extension if an adaptive
|
||||||
/// slider limit is set.
|
/// slider limit is set.
|
||||||
min_value(f32),
|
min_value(f32),
|
||||||
@ -319,15 +311,11 @@ ensogl_core::define_endpoints_2! {
|
|||||||
/// slider limit is set.
|
/// slider limit is set.
|
||||||
max_value(f32),
|
max_value(f32),
|
||||||
/// Indicates whether the mouse is currently hovered over the component.
|
/// Indicates whether the mouse is currently hovered over the component.
|
||||||
hovered(bool),
|
|
||||||
/// Indicates whether the slider is currently being dragged.
|
|
||||||
dragged(bool),
|
dragged(bool),
|
||||||
/// Indicates whether the slider is disabled.
|
/// Indicates whether the slider is disabled.
|
||||||
disabled(bool),
|
disabled(bool),
|
||||||
/// Indicates whether the slider's value is being edited currently.
|
/// Indicates whether the slider's value is being edited currently.
|
||||||
editing(bool),
|
editing(bool),
|
||||||
// /// The orientation of the slider, either horizontal or vertical.
|
|
||||||
// orientation(Axis2),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -341,9 +329,9 @@ ensogl_core::define_endpoints_2! {
|
|||||||
/// slider in a horizontal direction changes the value, limited to a range between `min_value` and
|
/// slider in a horizontal direction changes the value, limited to a range between `min_value` and
|
||||||
/// `max_value`. The selected value is displayed, and a track fills the slider proportional to the
|
/// `max_value`. The selected value is displayed, and a track fills the slider proportional to the
|
||||||
/// value within the specified range. Dragging the slider in a vertical direction adjusts the
|
/// value within the specified range. Dragging the slider in a vertical direction adjusts the
|
||||||
/// precision of the slider. The precision affects the increments by which the value changes when
|
/// resolution of the slider. The resolution affects the increments by which the value changes when
|
||||||
/// the mouse is moved.
|
/// the mouse is moved.
|
||||||
#[derive(Debug, Deref, Clone)]
|
#[derive(Debug, Deref, Clone, CloneRef)]
|
||||||
pub struct Slider {
|
pub struct Slider {
|
||||||
/// Public FRP api of the component.
|
/// Public FRP api of the component.
|
||||||
#[deref]
|
#[deref]
|
||||||
@ -391,18 +379,21 @@ impl Slider {
|
|||||||
|
|
||||||
let ptr_down_any = model.background.on_event::<mouse::Down>();
|
let ptr_down_any = model.background.on_event::<mouse::Down>();
|
||||||
let ptr_up_any = scene.on_event::<mouse::Up>();
|
let ptr_up_any = scene.on_event::<mouse::Up>();
|
||||||
let ptr_out = model.background.on_event::<mouse::Out>();
|
|
||||||
let ptr_over = model.background.on_event::<mouse::Over>();
|
|
||||||
|
|
||||||
let obj = model.display_object();
|
let obj = model.display_object();
|
||||||
|
|
||||||
frp::extend! { network
|
frp::extend! { network
|
||||||
ptr_down <- ptr_down_any.map(|e| e.button() == mouse::PrimaryButton).on_true();
|
ptr_down <- ptr_down_any.map(|e| e.button() == mouse::PrimaryButton).on_true();
|
||||||
ptr_up <- ptr_up_any.map(|e| e.button() == mouse::PrimaryButton).on_true();
|
ptr_up <- ptr_up_any.map(|e| e.button() == mouse::PrimaryButton).on_true();
|
||||||
pos <- mouse.position.map(
|
pos <- mouse.position.map(
|
||||||
f!([scene, model] (p) scene.screen_to_object_space(&model.background, *p))
|
f!([scene, model] (p) scene.screen_to_object_space(model.display_object(), *p))
|
||||||
);
|
);
|
||||||
value_on_ptr_down <- output.value.sample(&ptr_down);
|
|
||||||
|
orientation_orth <- frp.orientation.map(|o| o.orthogonal());
|
||||||
|
length <- all_with(&obj.on_resized, &frp.orientation, |size, dim| size.get_dim(dim));
|
||||||
|
width <- all_with(&obj.on_resized, &orientation_orth, |size, dim| size.get_dim(dim));
|
||||||
|
|
||||||
|
start_value_on_ptr_down <- output.start_value.sample(&ptr_down);
|
||||||
|
end_value_on_ptr_down <- output.end_value.sample(&ptr_down);
|
||||||
|
|
||||||
ptr_down <- ptr_down.gate_not(&frp.set_slider_disabled);
|
ptr_down <- ptr_down.gate_not(&frp.set_slider_disabled);
|
||||||
ptr_down <- ptr_down.gate_not(&output.editing);
|
ptr_down <- ptr_down.gate_not(&output.editing);
|
||||||
@ -410,35 +401,65 @@ impl Slider {
|
|||||||
on_editing <- output.editing.on_true();
|
on_editing <- output.editing.on_true();
|
||||||
on_drag_start <- ptr_down.gate_not(&keyboard.is_control_down);
|
on_drag_start <- ptr_down.gate_not(&keyboard.is_control_down);
|
||||||
on_drag_stop <- any3(&ptr_up, &on_disabled, &on_editing);
|
on_drag_stop <- any3(&ptr_up, &on_disabled, &on_editing);
|
||||||
dragging <- bool(&on_drag_stop, &on_drag_start);
|
output.dragged <+ bool(&on_drag_stop, &on_drag_start);
|
||||||
drag_start <- pos.sample(&on_drag_start);
|
drag_start <- pos.sample(&on_drag_start);
|
||||||
drag_end <- pos.gate(&dragging).any2(&drag_start);
|
drag_end <- pos.gate(&output.dragged).any2(&drag_start);
|
||||||
drag_delta <- all2(&drag_end, &drag_start).map(|(end, start)| end - start);
|
drag_delta <- all2(&drag_end, &drag_start).map(|(end, start)| end - start);
|
||||||
drag_delta1 <- all_with(&drag_delta, &frp.orientation, |t, d| t.get_dim(d)).on_change();
|
drag_delta1 <- all_with(&drag_delta, &frp.orientation, |t, d| t.get_dim(d)).on_change();
|
||||||
orientation_orth <- frp.orientation.map(|o| o.orthogonal());
|
|
||||||
prec_delta <- all_with(&drag_end, &orientation_orth, |t, d| t.get_dim(d)).on_change();
|
prec_delta <- all_with(&drag_end, &orientation_orth, |t, d| t.get_dim(d)).on_change();
|
||||||
|
|
||||||
output.hovered <+ bool(&ptr_out, &ptr_over);
|
handle <- drag_start.map9(
|
||||||
output.dragged <+ dragging;
|
&length,
|
||||||
|
&start_value_on_ptr_down,
|
||||||
|
&end_value_on_ptr_down,
|
||||||
|
&output.min_value,
|
||||||
|
&output.max_value,
|
||||||
|
&frp.enable_start_track_drag,
|
||||||
|
&frp.enable_middle_track_drag,
|
||||||
|
&frp.enable_end_track_drag,
|
||||||
|
|pos, length, start, end, min, max, enable_start, enable_middle, enable_end| {
|
||||||
|
match (enable_start, enable_middle, enable_end) {
|
||||||
|
(false, false, false) => None,
|
||||||
|
(true, false, false) => Some(DragHandle::Start),
|
||||||
|
(false, true, false) => Some(DragHandle::Middle),
|
||||||
|
(false, false, true) => Some(DragHandle::End),
|
||||||
|
(true, true, false) => {
|
||||||
|
let val_range = max - min;
|
||||||
|
let start_pos = start / val_range * length;
|
||||||
|
if pos.x < start_pos { Some(DragHandle::Start) }
|
||||||
|
else { Some(DragHandle::Middle) }
|
||||||
|
}
|
||||||
|
(true, false, true) => {
|
||||||
|
let val_range = max - min;
|
||||||
|
let mid_pos = (start + end) / 2.0 / val_range * length;
|
||||||
|
if pos.x < mid_pos { Some(DragHandle::Start) }
|
||||||
|
else { Some(DragHandle::End) }
|
||||||
|
}
|
||||||
|
(false, true, true) => {
|
||||||
|
let val_range = max - min;
|
||||||
|
let end_pos = end / val_range * length;
|
||||||
|
if pos.x < end_pos { Some(DragHandle::Middle) }
|
||||||
|
else { Some(DragHandle::End) }
|
||||||
|
}
|
||||||
|
(true, true, true) => {
|
||||||
|
let val_range = max - min;
|
||||||
|
let start_pos = start / val_range * length;
|
||||||
|
let end_pos = end / val_range * length;
|
||||||
|
if pos.x < start_pos { Some(DragHandle::Start) }
|
||||||
|
else if pos.x > end_pos { Some(DragHandle::End) }
|
||||||
|
else { Some(DragHandle::Middle) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
// === Precision calculation ===
|
// === Precision calculation ===
|
||||||
|
|
||||||
length <- all_with(&obj.on_resized, &frp.orientation, |size, dim| size.get_dim(dim));
|
native_resolution <- all_with3(&length, &output.max_value, &output.min_value,
|
||||||
width <- all_with(&obj.on_resized, &orientation_orth, |size, dim| size.get_dim(dim));
|
|len, max, min| (max - min) / len
|
||||||
|
|
||||||
empty_space <- all_with3(&length, &frp.kind, &frp.set_thumb_size,
|
|
||||||
|length, indicator, _thumb_size|
|
|
||||||
match indicator {
|
|
||||||
Kind::Scrollbar(thumb_size) => length * (1.0 - thumb_size),
|
|
||||||
Kind::SingleValue => *length,
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
non_native_resolution <- all_with5(
|
||||||
slider_range <- all_with(&output.max_value, &output.min_value, |max, min| *max - *min);
|
|
||||||
native_precision <- all2(&empty_space, &slider_range).map(|(l, r)| r / l);
|
|
||||||
|
|
||||||
non_native_precision <- all_with5(
|
|
||||||
&width,
|
&width,
|
||||||
&frp.set_precision_adjustment_margin,
|
&frp.set_precision_adjustment_margin,
|
||||||
&prec_delta,
|
&prec_delta,
|
||||||
@ -451,39 +472,57 @@ impl Slider {
|
|||||||
let level = min(*max_steps as i32, (offset / step_size).ceil() as i32) * sign;
|
let level = min(*max_steps as i32, (offset / step_size).ceil() as i32) * sign;
|
||||||
(level != 0).as_some_from(|| {
|
(level != 0).as_some_from(|| {
|
||||||
let exp = if level > 0 { level - 1 } else { level };
|
let exp = if level > 0 { level - 1 } else { level };
|
||||||
let precision = 10.0_f32.powf(exp as f32);
|
10.0_f32.powf(exp as f32)
|
||||||
precision
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
).on_change();
|
).on_change();
|
||||||
precision <- all_with(&non_native_precision, &native_precision, |t,s| t.unwrap_or(*s));
|
resolution <- all_with(&non_native_resolution, &native_resolution, |t,s| t.unwrap_or(*s));
|
||||||
output.precision <+ precision;
|
output.resolution <+ resolution;
|
||||||
|
|
||||||
|
|
||||||
// === Value calculation ===
|
// === Value calculation ===
|
||||||
|
|
||||||
value <- drag_delta1.map3(&value_on_ptr_down, &precision,
|
values <- drag_delta1.map5(
|
||||||
|delta, value, precision| value + delta * precision);
|
&handle,
|
||||||
value <- any2(&frp.set_value, &value);
|
&start_value_on_ptr_down,
|
||||||
value <- all5(
|
&end_value_on_ptr_down,
|
||||||
&value,
|
&resolution,
|
||||||
&frp.set_min_value,
|
|delta, handle, start_value, end_value, resolution| {
|
||||||
&frp.set_max_value,
|
let diff = delta * resolution;
|
||||||
&frp.set_lower_limit_type,
|
if let Some(handle) = handle {
|
||||||
&frp.set_upper_limit_type,
|
match handle {
|
||||||
).map(value_limit_clamp);
|
DragHandle::Start => (Some(start_value + diff), None),
|
||||||
output.value <+ value;
|
DragHandle::End => (None, Some(end_value + diff)),
|
||||||
|
DragHandle::Middle => (Some(start_value + diff), Some(end_value + diff))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
(None, None)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
start_value <= values._0();
|
||||||
|
end_value <= values._1();
|
||||||
|
value <- any2(&frp.set_value, &end_value);
|
||||||
|
// value <- all5(
|
||||||
|
// &value,
|
||||||
|
// &frp.set_min_value,
|
||||||
|
// &frp.set_max_value,
|
||||||
|
// &frp.set_lower_limit_type,
|
||||||
|
// &frp.set_upper_limit_type,
|
||||||
|
// ).map(value_limit_clamp);
|
||||||
|
output.start_value <+ start_value;
|
||||||
|
output.end_value <+ value;
|
||||||
|
|
||||||
|
|
||||||
// === Value Reset ===
|
// === Value Reset ===
|
||||||
|
|
||||||
reset_value <- ptr_down.gate(&keyboard.is_control_down);
|
reset_value <- ptr_down.gate(&keyboard.is_control_down);
|
||||||
value_on_reset <- input.set_default_value.sample(&reset_value);
|
value_on_reset <- input.set_default_value.sample(&reset_value);
|
||||||
output.value <+ value_on_reset;
|
output.end_value <+ value_on_reset;
|
||||||
|
|
||||||
|
|
||||||
// === Value Animation ===
|
// === Value Animation ===
|
||||||
model.value_animation.target <+ output.value;
|
model.start_value_animation.target <+ output.start_value;
|
||||||
|
model.end_value_animation.target <+ output.end_value;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -496,7 +535,7 @@ impl Slider {
|
|||||||
|
|
||||||
frp::extend! { network
|
frp::extend! { network
|
||||||
min_value <- all_with5(
|
min_value <- all_with5(
|
||||||
&output.value,
|
&output.end_value,
|
||||||
&input.set_min_value,
|
&input.set_min_value,
|
||||||
&input.set_max_value,
|
&input.set_max_value,
|
||||||
&output.min_value,
|
&output.min_value,
|
||||||
@ -506,7 +545,7 @@ impl Slider {
|
|||||||
output.min_value <+ min_value;
|
output.min_value <+ min_value;
|
||||||
|
|
||||||
max_value <- all_with5(
|
max_value <- all_with5(
|
||||||
&output.value,
|
&output.end_value,
|
||||||
&input.set_min_value,
|
&input.set_min_value,
|
||||||
&input.set_max_value,
|
&input.set_max_value,
|
||||||
&output.max_value,
|
&output.max_value,
|
||||||
@ -515,8 +554,8 @@ impl Slider {
|
|||||||
).on_change();
|
).on_change();
|
||||||
output.max_value <+ max_value;
|
output.max_value <+ max_value;
|
||||||
|
|
||||||
overflow_lower <- all_with(&output.value, &min_value, |v, min| v < min).on_change();
|
overflow_lower <- all_with(&output.end_value, &min_value, |v, min| v < min).on_change();
|
||||||
overflow_upper <- all_with(&output.value, &max_value, |v, max| v > max).on_change();
|
overflow_upper <- all_with(&output.end_value, &max_value, |v, max| v > max).on_change();
|
||||||
eval overflow_lower((v) model.set_overflow_lower_visible(*v));
|
eval overflow_lower((v) model.set_overflow_lower_visible(*v));
|
||||||
eval overflow_upper((v) model.set_overflow_upper_visible(*v));
|
eval overflow_upper((v) model.set_overflow_upper_visible(*v));
|
||||||
};
|
};
|
||||||
@ -533,15 +572,15 @@ impl Slider {
|
|||||||
frp::extend! { network
|
frp::extend! { network
|
||||||
eval input.show_value((v) model.show_value(*v));
|
eval input.show_value((v) model.show_value(*v));
|
||||||
|
|
||||||
value <- output.value.sampled_gate(&input.show_value);
|
value <- output.end_value.sampled_gate(&input.show_value);
|
||||||
default_value <- input.set_default_value.sampled_gate(&input.show_value);
|
default_value <- input.set_default_value.sampled_gate(&input.show_value);
|
||||||
is_default <- all_with(&value, &default_value, |val, def| val == def);
|
is_default <- all_with(&value, &default_value, |val, def| val == def);
|
||||||
text_weight <- switch_constant(&is_default, Weight::Bold, Weight::Normal);
|
text_weight <- switch_constant(&is_default, Weight::Bold, Weight::Normal);
|
||||||
eval text_weight ((v) model.set_value_text_property(*v));
|
eval text_weight ((v) model.set_value_text_property(*v));
|
||||||
|
|
||||||
precision <- output.precision.sampled_gate(&input.show_value);
|
resolution <- output.resolution.sampled_gate(&input.show_value);
|
||||||
max_decimal_places <- input.set_max_disp_decimal_places.sampled_gate(&input.show_value);
|
max_decimal_places <- input.set_max_disp_decimal_places.sampled_gate(&input.show_value);
|
||||||
text <- all_with3(&value, &precision, &max_decimal_places, display_value);
|
text <- all_with3(&value, &resolution, &max_decimal_places, display_value);
|
||||||
text_left <- text._0();
|
text_left <- text._0();
|
||||||
text_right <- text._1();
|
text_right <- text._1();
|
||||||
model.value_text_left.set_content <+ text_left;
|
model.value_text_left.set_content <+ text_left;
|
||||||
@ -552,7 +591,7 @@ impl Slider {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initialize the precision pop-up FRP network.
|
/// Initialize the resolution pop-up FRP network.
|
||||||
fn init_precision_popup(&self) {
|
fn init_precision_popup(&self) {
|
||||||
let network = self.frp.network();
|
let network = self.frp.network();
|
||||||
let input = &self.frp.input;
|
let input = &self.frp.input;
|
||||||
@ -567,16 +606,16 @@ impl Slider {
|
|||||||
&component_events.mouse_release_primary,
|
&component_events.mouse_release_primary,
|
||||||
&component_events.mouse_down_primary
|
&component_events.mouse_down_primary
|
||||||
);
|
);
|
||||||
precision <- output.precision.on_change().gate(&component_drag);
|
resolution <- output.resolution.on_change().gate(&component_drag);
|
||||||
model.tooltip.frp.set_style <+ precision.map(|precision| {
|
model.tooltip.frp.set_style <+ resolution.map(|resolution| {
|
||||||
let prec_text = format!(
|
let prec_text = format!(
|
||||||
"Precision: {precision:.MAX_DISP_DECIMAL_PLACES_DEFAULT$}",
|
"Precision: {resolution:.MAX_DISP_DECIMAL_PLACES_DEFAULT$}",
|
||||||
);
|
);
|
||||||
let prec_text = prec_text.trim_end_matches('0');
|
let prec_text = prec_text.trim_end_matches('0');
|
||||||
let prec_text = prec_text.trim_end_matches('.');
|
let prec_text = prec_text.trim_end_matches('.');
|
||||||
tooltip::Style::set_label(prec_text.into())
|
tooltip::Style::set_label(prec_text.into())
|
||||||
});
|
});
|
||||||
precision_changed <- precision.constant(());
|
precision_changed <- resolution.constant(());
|
||||||
popup_anim.reset <+ precision_changed;
|
popup_anim.reset <+ precision_changed;
|
||||||
popup_anim.start <+ precision_changed;
|
popup_anim.start <+ precision_changed;
|
||||||
popup_hide <- any2(&popup_anim.on_end, &component_events.mouse_release_primary);
|
popup_hide <- any2(&popup_anim.on_end, &component_events.mouse_release_primary);
|
||||||
@ -629,25 +668,28 @@ impl Slider {
|
|||||||
let obj = model.display_object();
|
let obj = model.display_object();
|
||||||
|
|
||||||
frp::extend! { network
|
frp::extend! { network
|
||||||
// comp_size <- all2(&input.set_width, &input.set_height).map(|(w, h)| Vector2(*w,*h));
|
|
||||||
eval obj.on_resized((size) model.update_size(*size));
|
eval obj.on_resized((size) model.update_size(*size));
|
||||||
eval input.kind((i) model.kind(i));
|
|
||||||
// output.width <+ input.set_width;
|
|
||||||
// output.height <+ input.set_height;
|
|
||||||
min_limit_anim.target <+ output.min_value;
|
min_limit_anim.target <+ output.min_value;
|
||||||
max_limit_anim.target <+ output.max_value;
|
max_limit_anim.target <+ output.max_value;
|
||||||
indicator_pos <- all3(&model.value_animation.value, &min_limit_anim.value, &max_limit_anim.value);
|
indicator_pos <- all_with4(
|
||||||
indicator_pos <- indicator_pos.map(|(value, min, max)| (value - min) / (max - min));
|
&model.start_value_animation.value,
|
||||||
indicator_pos <- all3(&indicator_pos, &input.set_thumb_size, &input.orientation);
|
&model.end_value_animation.value,
|
||||||
eval indicator_pos((v) model.set_indicator_position(v));
|
&min_limit_anim.value,
|
||||||
|
&max_limit_anim.value,
|
||||||
|
|start_value, end_value, min, max| {
|
||||||
|
let total = max - min;
|
||||||
|
((start_value - min) / total, (end_value - min) / total)
|
||||||
|
});
|
||||||
|
_eval <- all_with(&indicator_pos, &input.orientation,
|
||||||
|
f!((a, c) model.set_indicator_position(a.0, a.1, *c)));
|
||||||
|
|
||||||
value_text_left_pos_x <- all3(
|
value_text_left_pos_x <- all3(
|
||||||
&model.value_text_left.width,
|
&model.value_text_left.width,
|
||||||
&model.value_text_dot.width,
|
&model.value_text_dot.width,
|
||||||
&output.precision,
|
&output.resolution,
|
||||||
);
|
);
|
||||||
value_text_left_pos_x <- value_text_left_pos_x.map(
|
value_text_left_pos_x <- value_text_left_pos_x.map(
|
||||||
// Center text if precision higher than 1.0 (integer display), else align to dot.
|
// Center text if resolution higher than 1.0 (integer display), else align to dot.
|
||||||
|(left, dot, prec)| if *prec >= 1.0 {- *left / 2.0} else {- *left - *dot / 2.0}
|
|(left, dot, prec)| if *prec >= 1.0 {- *left / 2.0} else {- *left - *dot / 2.0}
|
||||||
);
|
);
|
||||||
eval value_text_left_pos_x((x) model.value_text_left.set_x(*x));
|
eval value_text_left_pos_x((x) model.value_text_left.set_x(*x));
|
||||||
@ -725,8 +767,8 @@ impl Slider {
|
|||||||
frp::extend! { network
|
frp::extend! { network
|
||||||
start_editing <- input.start_value_editing.gate_not(&output.disabled);
|
start_editing <- input.start_value_editing.gate_not(&output.disabled);
|
||||||
start_editing <- start_editing.gate(&input.show_value);
|
start_editing <- start_editing.gate(&input.show_value);
|
||||||
value_on_edit <- output.value.sample(&start_editing);
|
value_on_edit <- output.end_value.sample(&start_editing);
|
||||||
prec_on_edit <- output.precision.sample(&start_editing);
|
prec_on_edit <- output.resolution.sample(&start_editing);
|
||||||
max_places_on_edit <-
|
max_places_on_edit <-
|
||||||
input.set_max_disp_decimal_places.sample(&start_editing);
|
input.set_max_disp_decimal_places.sample(&start_editing);
|
||||||
value_text_on_edit <- all3(&value_on_edit, &prec_on_edit, &max_places_on_edit);
|
value_text_on_edit <- all3(&value_on_edit, &prec_on_edit, &max_places_on_edit);
|
||||||
@ -742,7 +784,7 @@ impl Slider {
|
|||||||
edit_success <- value_after_edit.map(|v| v.is_some());
|
edit_success <- value_after_edit.map(|v| v.is_some());
|
||||||
value_after_edit <- value_after_edit.map(|v| v.unwrap_or_default());
|
value_after_edit <- value_after_edit.map(|v| v.unwrap_or_default());
|
||||||
prec_after_edit <- value_text_after_edit.map(|s| get_value_text_precision(s));
|
prec_after_edit <- value_text_after_edit.map(|s| get_value_text_precision(s));
|
||||||
prec_after_edit <- all2(&prec_after_edit, &input.set_default_precision);
|
prec_after_edit <- all2(&prec_after_edit, &input.set_default_resolution);
|
||||||
prec_after_edit <- prec_after_edit.map(|(prec, default_prec)| prec.min(*default_prec));
|
prec_after_edit <- prec_after_edit.map(|(prec, default_prec)| prec.min(*default_prec));
|
||||||
value_after_edit <- all5(
|
value_after_edit <- all5(
|
||||||
&value_after_edit,
|
&value_after_edit,
|
||||||
@ -753,19 +795,19 @@ impl Slider {
|
|||||||
).map(value_limit_clamp);
|
).map(value_limit_clamp);
|
||||||
|
|
||||||
output.editing <+ editing;
|
output.editing <+ editing;
|
||||||
output.precision <+ prec_after_edit.gate(&edit_success);
|
output.resolution <+ prec_after_edit.gate(&edit_success);
|
||||||
value_after_edit <- value_after_edit.gate(&edit_success);
|
value_after_edit <- value_after_edit.gate(&edit_success);
|
||||||
output.value <+ value_after_edit;
|
output.end_value <+ value_after_edit;
|
||||||
model.value_animation.target <+ value_after_edit;
|
model.end_value_animation.target <+ value_after_edit;
|
||||||
editing_event <- any2(&start_editing, &stop_editing);
|
editing_event <- any2(&start_editing, &stop_editing);
|
||||||
editing <- all2(&editing, &output.precision).sample(&editing_event);
|
editing <- all2(&editing, &output.resolution).sample(&editing_event);
|
||||||
eval editing((t) model.set_edit_mode(t));
|
eval editing((t) model.set_edit_mode(t));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initialize the compinent with default values.
|
/// Initialize the compinent with default values.
|
||||||
fn init_slider_defaults(&self) {
|
fn init_slider_defaults(&self) {
|
||||||
self.frp.set_default_precision(PRECISION_DEFAULT);
|
self.frp.set_default_resolution(RESOLUTION_DEFAULT);
|
||||||
self.frp.set_precision_adjustment_margin(PRECISION_ADJUSTMENT_MARGIN);
|
self.frp.set_precision_adjustment_margin(PRECISION_ADJUSTMENT_MARGIN);
|
||||||
self.frp.set_precision_adjustment_step_size(PRECISION_ADJUSTMENT_STEP_SIZE);
|
self.frp.set_precision_adjustment_step_size(PRECISION_ADJUSTMENT_STEP_SIZE);
|
||||||
self.frp.set_max_precision_adjustment_steps(MAX_PRECISION_ADJUSTMENT_STEPS);
|
self.frp.set_max_precision_adjustment_steps(MAX_PRECISION_ADJUSTMENT_STEPS);
|
||||||
@ -776,6 +818,9 @@ impl Slider {
|
|||||||
self.frp.set_thumb_size(THUMB_SIZE_DEFAULT);
|
self.frp.set_thumb_size(THUMB_SIZE_DEFAULT);
|
||||||
self.show_value(true);
|
self.show_value(true);
|
||||||
self.orientation(Axis2::X);
|
self.orientation(Axis2::X);
|
||||||
|
self.enable_start_track_drag(true);
|
||||||
|
self.enable_end_track_drag(true);
|
||||||
|
self.enable_middle_track_drag(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -832,10 +877,10 @@ impl application::View for Slider {
|
|||||||
// === Value text formatting ===
|
// === Value text formatting ===
|
||||||
// =============================
|
// =============================
|
||||||
|
|
||||||
/// Rounds and truncates a floating point value to a specified precision.
|
/// Rounds and truncates a floating point value to a specified resolution.
|
||||||
fn value_text_truncate((value, precision, max_digits): &(f32, f32, usize)) -> String {
|
fn value_text_truncate((value, resolution, max_digits): &(f32, f32, usize)) -> String {
|
||||||
if *precision < 1.0 || *max_digits == 0 {
|
if *resolution < 1.0 || *max_digits == 0 {
|
||||||
let digits = (-precision.log10()).ceil() as usize;
|
let digits = (-resolution.log10()).ceil() as usize;
|
||||||
let digits = digits.min(*max_digits);
|
let digits = digits.min(*max_digits);
|
||||||
format!("{value:.digits$}")
|
format!("{value:.digits$}")
|
||||||
} else {
|
} else {
|
||||||
@ -843,17 +888,21 @@ fn value_text_truncate((value, precision, max_digits): &(f32, f32, usize)) -> St
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Rounds a floating point value to a specified precision and provides two strings: one with the
|
/// Rounds a floating point value to a specified resolution and provides two strings: one with the
|
||||||
/// digits left of the decimal point, and one optional with the digits right of the decimal point.
|
/// digits left of the decimal point, and one optional with the digits right of the decimal point.
|
||||||
fn display_value(value: &f32, precision: &f32, max_digits: &usize) -> (ImString, Option<ImString>) {
|
fn display_value(
|
||||||
let text = value_text_truncate(&(*value, *precision, *max_digits));
|
value: &f32,
|
||||||
|
resolution: &f32,
|
||||||
|
max_digits: &usize,
|
||||||
|
) -> (ImString, Option<ImString>) {
|
||||||
|
let text = value_text_truncate(&(*value, *resolution, *max_digits));
|
||||||
let mut text_iter = text.split('.');
|
let mut text_iter = text.split('.');
|
||||||
let text_left = text_iter.next().map(|s| s.to_im_string()).unwrap_or_default();
|
let text_left = text_iter.next().map(|s| s.to_im_string()).unwrap_or_default();
|
||||||
let text_right = text_iter.next().map(|s| s.to_im_string());
|
let text_right = text_iter.next().map(|s| s.to_im_string());
|
||||||
(text_left, text_right)
|
(text_left, text_right)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the precision of a string containing a decimal value.
|
/// Get the resolution of a string containing a decimal value.
|
||||||
fn get_value_text_precision(text: &str) -> f32 {
|
fn get_value_text_precision(text: &str) -> f32 {
|
||||||
let mut text_iter = text.split('.').skip(1);
|
let mut text_iter = text.split('.').skip(1);
|
||||||
let text_right_len = text_iter.next().map(|t| t.len());
|
let text_right_len = text_iter.next().map(|t| t.len());
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
use ensogl_core::display::shape::*;
|
use ensogl_core::display::shape::*;
|
||||||
use ensogl_core::prelude::*;
|
use ensogl_core::prelude::*;
|
||||||
|
|
||||||
use crate::Kind;
|
|
||||||
use crate::LabelPosition;
|
use crate::LabelPosition;
|
||||||
|
|
||||||
use ensogl_core::application::Application;
|
use ensogl_core::application::Application;
|
||||||
@ -21,8 +20,6 @@ use ensogl_tooltip::Tooltip;
|
|||||||
// === Constants ===
|
// === Constants ===
|
||||||
// =================
|
// =================
|
||||||
|
|
||||||
/// Size of the margin around the component's shapes for proper anti-aliasing.
|
|
||||||
const COMPONENT_MARGIN: f32 = 4.0;
|
|
||||||
/// Default component width on initialization.
|
/// Default component width on initialization.
|
||||||
const COMPONENT_WIDTH_DEFAULT: f32 = 200.0;
|
const COMPONENT_WIDTH_DEFAULT: f32 = 200.0;
|
||||||
/// Default component height on initialization.
|
/// Default component height on initialization.
|
||||||
@ -47,8 +44,6 @@ impl Background {
|
|||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
let width: Var<Pixels> = "input_size.x".into();
|
let width: Var<Pixels> = "input_size.x".into();
|
||||||
let height: Var<Pixels> = "input_size.y".into();
|
let height: Var<Pixels> = "input_size.y".into();
|
||||||
let width = width - COMPONENT_MARGIN.px() * 2.0;
|
|
||||||
let height = height - COMPONENT_MARGIN.px() * 2.0;
|
|
||||||
let shape = Rect((&width, &height)).corners_radius(&height / 2.0);
|
let shape = Rect((&width, &height)).corners_radius(&height / 2.0);
|
||||||
let shape = shape.into();
|
let shape = shape.into();
|
||||||
Background { width, height, shape }
|
Background { width, height, shape }
|
||||||
@ -72,62 +67,33 @@ mod background {
|
|||||||
/// Track shape that fills the slider proportional to the slider value.
|
/// Track shape that fills the slider proportional to the slider value.
|
||||||
mod track {
|
mod track {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
ensogl_core::shape! {
|
ensogl_core::shape! {
|
||||||
above = [background];
|
above = [background];
|
||||||
pointer_events = false;
|
pointer_events = false;
|
||||||
alignment = center;
|
alignment = center;
|
||||||
(style:Style, slider_fraction_horizontal:f32, slider_fraction_vertical:f32, color:Vector4) {
|
(style:Style, start: f32, end:f32, color:Vector4) {
|
||||||
let Background{width,height,shape: background} = Background::new();
|
let Background{width,height,shape: background} = Background::new();
|
||||||
let track = Rect((
|
let length = &end - &start;
|
||||||
&width * &slider_fraction_horizontal,
|
let track = Rect((&width * &length, &height));
|
||||||
&height * &slider_fraction_vertical,
|
let track = track.translate_x(&width * (length - 1.0) * 0.5 + &width * start);
|
||||||
));
|
|
||||||
let track = track.translate_x(&width * (&slider_fraction_horizontal - 1.0) * 0.5);
|
|
||||||
let track = track.translate_y(&height * (&slider_fraction_vertical - 1.0) * 0.5);
|
|
||||||
let track = track.intersection(background).fill(color);
|
let track = track.intersection(background).fill(color);
|
||||||
track.into()
|
track.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Thumb shape that moves along the slider proportional to the slider value.
|
|
||||||
mod thumb {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
ensogl_core::shape! {
|
|
||||||
above = [background];
|
|
||||||
pointer_events = false;
|
|
||||||
alignment = center;
|
|
||||||
(style:Style, slider_fraction:f32, thumb_width:f32, thumb_height:f32, color:Vector4) {
|
|
||||||
let Background{width,height,shape: background} = Background::new();
|
|
||||||
let thumb_width = &width * &thumb_width;
|
|
||||||
let thumb_height = &height * &thumb_height;
|
|
||||||
let thumb = Rect((&thumb_width, &thumb_height));
|
|
||||||
let thumb = thumb.corners_radius(&thumb_height / 2.0);
|
|
||||||
let range_x = &width - &thumb_width;
|
|
||||||
let range_y = &height - &thumb_height;
|
|
||||||
let thumb = thumb.translate_x(-&range_x * 0.5 + &range_x * &slider_fraction);
|
|
||||||
let thumb = thumb.translate_y(-&range_y * 0.5 + &range_y * &slider_fraction);
|
|
||||||
let thumb = thumb.intersection(background).fill(color);
|
|
||||||
thumb.into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Triangle shape used as an overflow indicator on either side of the range.
|
/// Triangle shape used as an overflow indicator on either side of the range.
|
||||||
mod overflow {
|
mod overflow {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
ensogl_core::shape! {
|
ensogl_core::shape! {
|
||||||
above = [background, track, thumb];
|
above = [background, track];
|
||||||
pointer_events = false;
|
pointer_events = false;
|
||||||
alignment = center;
|
alignment = center;
|
||||||
(style:Style, color:Vector4) {
|
(style:Style, color:Vector4) {
|
||||||
let width: Var<Pixels> = "input_size.x".into();
|
let width: Var<Pixels> = "input_size.x".into();
|
||||||
let height: Var<Pixels> = "input_size.y".into();
|
let height: Var<Pixels> = "input_size.y".into();
|
||||||
let width = width - COMPONENT_MARGIN.px() * 2.0;
|
|
||||||
let height = height - COMPONENT_MARGIN.px() * 2.0;
|
|
||||||
|
|
||||||
let color = style.get_color(theme::overflow::color);
|
let color = style.get_color(theme::overflow::color);
|
||||||
let triangle = Triangle(width, height);
|
let triangle = Triangle(width, height);
|
||||||
@ -148,70 +114,66 @@ mod overflow {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Model {
|
pub struct Model {
|
||||||
/// Background element
|
/// Background element
|
||||||
pub background: background::View,
|
pub background: background::View,
|
||||||
/// Slider track element that fills the slider proportional to the slider value.
|
/// Slider track element that fills the slider proportional to the slider value.
|
||||||
pub track: track::View,
|
pub track: track::View,
|
||||||
/// Slider thumb element that moves across the slider proportional to the slider value.
|
|
||||||
pub thumb: thumb::View,
|
|
||||||
/// Indicator for overflow when the value is below the lower limit.
|
/// Indicator for overflow when the value is below the lower limit.
|
||||||
pub overflow_lower: overflow::View,
|
pub overflow_lower: overflow::View,
|
||||||
/// Indicator for overflow when the value is above the upper limit.
|
/// Indicator for overflow when the value is above the upper limit.
|
||||||
pub overflow_upper: overflow::View,
|
pub overflow_upper: overflow::View,
|
||||||
/// Slider label that is shown next to the slider.
|
/// Slider label that is shown next to the slider.
|
||||||
pub label: text::Text,
|
pub label: text::Text,
|
||||||
/// Textual representation of the slider value, only part left of the decimal point.
|
/// Textual representation of the slider value, only part left of the decimal point.
|
||||||
pub value_text_left: text::Text,
|
pub value_text_left: text::Text,
|
||||||
/// Decimal point that is used to display non-integer slider values.
|
/// Decimal point that is used to display non-integer slider values.
|
||||||
pub value_text_dot: text::Text,
|
pub value_text_dot: text::Text,
|
||||||
/// Textual representation of the slider value, only part right of the decimal point.
|
/// Textual representation of the slider value, only part right of the decimal point.
|
||||||
pub value_text_right: text::Text,
|
pub value_text_right: text::Text,
|
||||||
/// Textual representation of the slider value used when editing the value as text input.
|
/// Textual representation of the slider value used when editing the value as text input.
|
||||||
pub value_text_edit: text::Text,
|
pub value_text_edit: text::Text,
|
||||||
/// Tooltip component showing either a tooltip message or slider precision changes.
|
/// Tooltip component showing either a tooltip message or slider precision changes.
|
||||||
pub tooltip: Tooltip,
|
pub tooltip: Tooltip,
|
||||||
/// Animation component that smoothly adjusts the slider value on large jumps.
|
/// Animation component that smoothly adjusts the slider start value on large jumps.
|
||||||
pub value_animation: Animation<f32>,
|
pub start_value_animation: Animation<f32>,
|
||||||
|
/// Animation component that smoothly adjusts the slider end value on large jumps.
|
||||||
|
pub end_value_animation: Animation<f32>,
|
||||||
/// Root of the display object.
|
/// Root of the display object.
|
||||||
pub root: display::object::Instance,
|
pub root: display::object::Instance,
|
||||||
|
/// The display object containing the text value of the slider.
|
||||||
|
pub value: display::object::Instance,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Model {
|
impl Model {
|
||||||
/// Create a new slider model.
|
/// Create a new slider model.
|
||||||
pub fn new(app: &Application, frp_network: &frp::Network) -> Self {
|
pub fn new(app: &Application, frp_network: &frp::Network) -> Self {
|
||||||
let root = display::object::Instance::new();
|
let root = display::object::Instance::new();
|
||||||
|
let value = display::object::Instance::new();
|
||||||
let label = app.new_view::<text::Text>();
|
let label = app.new_view::<text::Text>();
|
||||||
let value_text_left = app.new_view::<text::Text>();
|
let value_text_left = app.new_view::<text::Text>();
|
||||||
let value_text_dot = app.new_view::<text::Text>();
|
let value_text_dot = app.new_view::<text::Text>();
|
||||||
let value_text_right = app.new_view::<text::Text>();
|
let value_text_right = app.new_view::<text::Text>();
|
||||||
let value_text_edit = app.new_view::<text::Text>();
|
let value_text_edit = app.new_view::<text::Text>();
|
||||||
let tooltip = Tooltip::new(app);
|
let tooltip = Tooltip::new(app);
|
||||||
let value_animation = Animation::new_non_init(frp_network);
|
let start_value_animation = Animation::new_non_init(frp_network);
|
||||||
|
let end_value_animation = Animation::new_non_init(frp_network);
|
||||||
let background = background::View::new();
|
let background = background::View::new();
|
||||||
let track = track::View::new();
|
let track = track::View::new();
|
||||||
let thumb = thumb::View::new();
|
|
||||||
let overflow_lower = overflow::View::new();
|
let overflow_lower = overflow::View::new();
|
||||||
let overflow_upper = overflow::View::new();
|
let overflow_upper = overflow::View::new();
|
||||||
let scene = &app.display.default_scene;
|
|
||||||
let style = StyleWatch::new(&app.display.default_scene.style_sheet);
|
let style = StyleWatch::new(&app.display.default_scene.style_sheet);
|
||||||
|
|
||||||
root.add_child(&background);
|
root.add_child(&background);
|
||||||
root.add_child(&track);
|
root.add_child(&track);
|
||||||
root.add_child(&label);
|
root.add_child(&label);
|
||||||
root.add_child(&value_text_left);
|
root.add_child(&value);
|
||||||
root.add_child(&value_text_dot);
|
value.add_child(&value_text_left);
|
||||||
root.add_child(&value_text_right);
|
value.add_child(&value_text_dot);
|
||||||
|
value.add_child(&value_text_right);
|
||||||
app.display.default_scene.add_child(&tooltip);
|
app.display.default_scene.add_child(&tooltip);
|
||||||
|
|
||||||
value_text_left.add_to_scene_layer(&scene.layers.label);
|
|
||||||
value_text_dot.add_to_scene_layer(&scene.layers.label);
|
|
||||||
value_text_right.add_to_scene_layer(&scene.layers.label);
|
|
||||||
value_text_edit.add_to_scene_layer(&scene.layers.label);
|
|
||||||
label.add_to_scene_layer(&scene.layers.label);
|
|
||||||
|
|
||||||
let model = Self {
|
let model = Self {
|
||||||
background,
|
background,
|
||||||
track,
|
track,
|
||||||
thumb,
|
|
||||||
overflow_lower,
|
overflow_lower,
|
||||||
overflow_upper,
|
overflow_upper,
|
||||||
label,
|
label,
|
||||||
@ -220,8 +182,10 @@ impl Model {
|
|||||||
value_text_right,
|
value_text_right,
|
||||||
value_text_edit,
|
value_text_edit,
|
||||||
tooltip,
|
tooltip,
|
||||||
value_animation,
|
start_value_animation,
|
||||||
|
end_value_animation,
|
||||||
root,
|
root,
|
||||||
|
value,
|
||||||
};
|
};
|
||||||
model.init(style)
|
model.init(style)
|
||||||
}
|
}
|
||||||
@ -237,7 +201,6 @@ impl Model {
|
|||||||
self.label.set_font(text::font::DEFAULT_FONT);
|
self.label.set_font(text::font::DEFAULT_FONT);
|
||||||
self.background.color.set(background_color.into());
|
self.background.color.set(background_color.into());
|
||||||
self.track.color.set(track_color.into());
|
self.track.color.set(track_color.into());
|
||||||
self.thumb.color.set(track_color.into());
|
|
||||||
self.update_size(Vector2(COMPONENT_WIDTH_DEFAULT, COMPONENT_HEIGHT_DEFAULT));
|
self.update_size(Vector2(COMPONENT_WIDTH_DEFAULT, COMPONENT_HEIGHT_DEFAULT));
|
||||||
self.value_text_dot.set_content(".");
|
self.value_text_dot.set_content(".");
|
||||||
self
|
self
|
||||||
@ -245,16 +208,16 @@ impl Model {
|
|||||||
|
|
||||||
/// Set the component size.
|
/// Set the component size.
|
||||||
pub fn update_size(&self, size: Vector2<f32>) {
|
pub fn update_size(&self, size: Vector2<f32>) {
|
||||||
let margin = Vector2(COMPONENT_MARGIN * 2.0, COMPONENT_MARGIN * 2.0);
|
self.background.set_size(size);
|
||||||
self.background.set_size(size + margin);
|
self.track.set_size(size);
|
||||||
self.track.set_size(size + margin);
|
self.background.set_x(size.x / 2.0);
|
||||||
self.thumb.set_size(size + margin);
|
self.track.set_x(size.x / 2.0);
|
||||||
|
self.value.set_x(size.x / 2.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the color of the slider track or thumb.
|
/// Set the color of the slider track or thumb.
|
||||||
pub fn set_indicator_color(&self, color: &color::Lcha) {
|
pub fn set_indicator_color(&self, color: &color::Lcha) {
|
||||||
self.track.color.set(color::Rgba::from(color).into());
|
self.track.color.set(color::Rgba::from(color).into());
|
||||||
self.thumb.color.set(color::Rgba::from(color).into());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the color of the slider background.
|
/// Set the color of the slider background.
|
||||||
@ -262,43 +225,22 @@ impl Model {
|
|||||||
self.background.color.set(color::Rgba::from(color).into());
|
self.background.color.set(color::Rgba::from(color).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set whether the lower overfow marker is visible.
|
|
||||||
pub fn kind(&self, indicator: &Kind) {
|
|
||||||
match indicator {
|
|
||||||
Kind::SingleValue => {
|
|
||||||
self.root.add_child(&self.track);
|
|
||||||
self.root.remove_child(&self.thumb);
|
|
||||||
}
|
|
||||||
Kind::Scrollbar(_) => {
|
|
||||||
self.root.add_child(&self.thumb);
|
|
||||||
self.root.remove_child(&self.track);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the position of the value indicator.
|
/// Set the position of the value indicator.
|
||||||
pub fn set_indicator_position(&self, (fraction, size, orientation): &(f32, f32, Axis2)) {
|
pub fn set_indicator_position(&self, start: f32, fraction: f32, orientation: Axis2) {
|
||||||
self.thumb.slider_fraction.set(*fraction);
|
|
||||||
match orientation {
|
match orientation {
|
||||||
Axis2::X => {
|
Axis2::X => {
|
||||||
self.track.slider_fraction_horizontal.set(fraction.clamp(0.0, 1.0));
|
self.track.start.set(start.clamp(0.0, 1.0));
|
||||||
self.track.slider_fraction_vertical.set(1.0);
|
self.track.end.set(fraction.clamp(0.0, 1.0));
|
||||||
self.thumb.thumb_width.set(*size);
|
|
||||||
self.thumb.thumb_height.set(1.0);
|
|
||||||
}
|
}
|
||||||
Axis2::Y => {
|
Axis2::Y => {
|
||||||
self.track.slider_fraction_horizontal.set(1.0);
|
self.track.end.set(1.0);
|
||||||
self.track.slider_fraction_vertical.set(fraction.clamp(0.0, 1.0));
|
|
||||||
self.thumb.thumb_width.set(1.0);
|
|
||||||
self.thumb.thumb_height.set(*size);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the size and orientation of the overflow markers.
|
/// Set the size and orientation of the overflow markers.
|
||||||
pub fn set_overflow_marker_shape(&self, (size, orientation): &(f32, Axis2)) {
|
pub fn set_overflow_marker_shape(&self, (size, orientation): &(f32, Axis2)) {
|
||||||
let margin = Vector2(COMPONENT_MARGIN * 2.0, COMPONENT_MARGIN * 2.0);
|
let size = Vector2(*size, *size) * OVERFLOW_MARKER_SIZE;
|
||||||
let size = Vector2(*size, *size) * OVERFLOW_MARKER_SIZE + margin;
|
|
||||||
self.overflow_lower.set_size(size);
|
self.overflow_lower.set_size(size);
|
||||||
self.overflow_upper.set_size(size);
|
self.overflow_upper.set_size(size);
|
||||||
match orientation {
|
match orientation {
|
||||||
@ -386,13 +328,9 @@ impl Model {
|
|||||||
/// Set whether the slider value text is hidden.
|
/// Set whether the slider value text is hidden.
|
||||||
pub fn show_value(&self, visible: bool) {
|
pub fn show_value(&self, visible: bool) {
|
||||||
if visible {
|
if visible {
|
||||||
self.root.add_child(&self.value_text_left);
|
self.root.add_child(&self.value);
|
||||||
self.root.add_child(&self.value_text_dot);
|
|
||||||
self.root.add_child(&self.value_text_right);
|
|
||||||
} else {
|
} else {
|
||||||
self.root.remove_child(&self.value_text_left);
|
self.root.remove_child(&self.value);
|
||||||
self.root.remove_child(&self.value_text_dot);
|
|
||||||
self.root.remove_child(&self.value_text_right);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -407,21 +345,19 @@ impl Model {
|
|||||||
|
|
||||||
/// Set whether the value is being edited. This hides the value display and shows a text editor
|
/// Set whether the value is being edited. This hides the value display and shows a text editor
|
||||||
/// field to enter a new value.
|
/// field to enter a new value.
|
||||||
pub fn set_edit_mode(&self, (editing, precision): &(bool, f32)) {
|
pub fn set_edit_mode(&self, (editing, _precision): &(bool, f32)) {
|
||||||
if *editing {
|
if *editing {
|
||||||
self.root.remove_child(&self.value_text_left);
|
self.root.remove_child(&self.value);
|
||||||
self.root.remove_child(&self.value_text_dot);
|
|
||||||
self.root.remove_child(&self.value_text_right);
|
|
||||||
self.root.add_child(&self.value_text_edit);
|
self.root.add_child(&self.value_text_edit);
|
||||||
self.value_text_edit.deprecated_focus();
|
self.value_text_edit.deprecated_focus();
|
||||||
self.value_text_edit.add_cursor_at_front();
|
self.value_text_edit.add_cursor_at_front();
|
||||||
self.value_text_edit.cursor_select_to_text_end();
|
self.value_text_edit.cursor_select_to_text_end();
|
||||||
} else {
|
} else {
|
||||||
self.root.add_child(&self.value_text_left);
|
self.root.add_child(&self.value);
|
||||||
if *precision < 1.0 {
|
// if *precision < 1.0 {
|
||||||
self.root.add_child(&self.value_text_dot);
|
// self.root.add_child(&self.value_text_dot);
|
||||||
self.root.add_child(&self.value_text_right);
|
// self.root.add_child(&self.value_text_right);
|
||||||
}
|
// }
|
||||||
self.root.remove_child(&self.value_text_edit);
|
self.root.remove_child(&self.value_text_edit);
|
||||||
self.value_text_edit.deprecated_defocus();
|
self.value_text_edit.deprecated_defocus();
|
||||||
self.value_text_edit.remove_all_cursors();
|
self.value_text_edit.remove_all_cursors();
|
||||||
@ -431,11 +367,11 @@ impl Model {
|
|||||||
/// Set whether the value display decimal point and the text right of it are visible.
|
/// Set whether the value display decimal point and the text right of it are visible.
|
||||||
pub fn set_value_text_right_visible(&self, enabled: bool) {
|
pub fn set_value_text_right_visible(&self, enabled: bool) {
|
||||||
if enabled {
|
if enabled {
|
||||||
self.root.add_child(&self.value_text_dot);
|
self.value.add_child(&self.value_text_dot);
|
||||||
self.root.add_child(&self.value_text_right);
|
self.value.add_child(&self.value_text_right);
|
||||||
} else {
|
} else {
|
||||||
self.root.remove_child(&self.value_text_dot);
|
self.value.remove_child(&self.value_text_dot);
|
||||||
self.root.remove_child(&self.value_text_right);
|
self.value.remove_child(&self.value_text_right);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,12 +37,13 @@ pub enum State {
|
|||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
#[derive(Clone, CloneRef, Debug)]
|
#[derive(Clone, CloneRef, Debug)]
|
||||||
pub struct SomeEvent {
|
pub struct SomeEvent {
|
||||||
pub data: frp::AnyData,
|
pub data: frp::AnyData,
|
||||||
state: Rc<Cell<State>>,
|
state: Rc<Cell<State>>,
|
||||||
|
current_target: Rc<RefCell<Option<WeakInstance>>>,
|
||||||
/// Indicates whether the event participates in the capturing phase.
|
/// Indicates whether the event participates in the capturing phase.
|
||||||
pub captures: Rc<Cell<bool>>,
|
pub captures: Rc<Cell<bool>>,
|
||||||
/// Indicates whether the event participates in the bubbling phase.
|
/// Indicates whether the event participates in the bubbling phase.
|
||||||
pub bubbles: Rc<Cell<bool>>,
|
pub bubbles: Rc<Cell<bool>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SomeEvent {
|
impl SomeEvent {
|
||||||
@ -50,9 +51,10 @@ impl SomeEvent {
|
|||||||
pub fn new<T: 'static>(target: Option<WeakInstance>, payload: T) -> Self {
|
pub fn new<T: 'static>(target: Option<WeakInstance>, payload: T) -> Self {
|
||||||
let event = Event::new(target, payload);
|
let event = Event::new(target, payload);
|
||||||
let state = event.state.clone_ref();
|
let state = event.state.clone_ref();
|
||||||
|
let current_target = event.current_target.clone_ref();
|
||||||
let captures = Rc::new(Cell::new(true));
|
let captures = Rc::new(Cell::new(true));
|
||||||
let bubbles = Rc::new(Cell::new(true));
|
let bubbles = Rc::new(Cell::new(true));
|
||||||
Self { data: frp::AnyData::new(event), state, captures, bubbles }
|
Self { data: frp::AnyData::new(event), state, current_target, captures, bubbles }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The [`State]` of the event.
|
/// The [`State]` of the event.
|
||||||
@ -69,6 +71,12 @@ impl SomeEvent {
|
|||||||
pub fn set_bubbling(&self, value: bool) {
|
pub fn set_bubbling(&self, value: bool) {
|
||||||
self.bubbles.set(value);
|
self.bubbles.set(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the current target of the event. This is internal function and should not be used
|
||||||
|
/// directly.
|
||||||
|
pub(crate) fn set_current_target(&self, target: Option<&Instance>) {
|
||||||
|
self.current_target.replace(target.map(|t| t.downgrade()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for SomeEvent {
|
impl Default for SomeEvent {
|
||||||
@ -113,9 +121,10 @@ impl<T: Debug> Debug for Event<T> {
|
|||||||
#[derivative(Default(bound = "T: Default"))]
|
#[derivative(Default(bound = "T: Default"))]
|
||||||
pub struct EventData<T> {
|
pub struct EventData<T> {
|
||||||
#[deref]
|
#[deref]
|
||||||
pub payload: T,
|
pub payload: T,
|
||||||
target: Option<WeakInstance>,
|
target: Option<WeakInstance>,
|
||||||
state: Rc<Cell<State>>,
|
current_target: Rc<RefCell<Option<WeakInstance>>>,
|
||||||
|
state: Rc<Cell<State>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Debug> Debug for EventData<T> {
|
impl<T: Debug> Debug for EventData<T> {
|
||||||
@ -130,7 +139,8 @@ impl<T: Debug> Debug for EventData<T> {
|
|||||||
impl<T> Event<T> {
|
impl<T> Event<T> {
|
||||||
fn new(target: Option<WeakInstance>, payload: T) -> Self {
|
fn new(target: Option<WeakInstance>, payload: T) -> Self {
|
||||||
let state = default();
|
let state = default();
|
||||||
let data = Rc::new(EventData { payload, target, state });
|
let current_target = Rc::new(RefCell::new(target.clone()));
|
||||||
|
let data = Rc::new(EventData { payload, target, current_target, state });
|
||||||
Self { data }
|
Self { data }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,6 +162,18 @@ impl<T> Event<T> {
|
|||||||
pub fn target(&self) -> Option<Instance> {
|
pub fn target(&self) -> Option<Instance> {
|
||||||
self.data.target.as_ref().and_then(|t| t.upgrade())
|
self.data.target.as_ref().and_then(|t| t.upgrade())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The current target for the event, as the event traverses the display object hierarchy. It
|
||||||
|
/// always refers to the element to which the event handler has been attached, as opposed to
|
||||||
|
/// [`Self::target`], which identifies the element on which the event occurred and which may be
|
||||||
|
/// its descendant.
|
||||||
|
///
|
||||||
|
/// # Important Note
|
||||||
|
/// The value of [`Self::current_target`] is only available while the event is being handled. If
|
||||||
|
/// store the event in a variable and read this property later, the value will be [`None`].
|
||||||
|
pub fn current_target(&self) -> Option<Instance> {
|
||||||
|
self.data.current_target.borrow().as_ref().and_then(|t| t.upgrade())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2217,7 +2217,7 @@ impl InstanceDef {
|
|||||||
|
|
||||||
/// Get reversed parent chain of this display object (`[root, child_of root, ..., parent,
|
/// Get reversed parent chain of this display object (`[root, child_of root, ..., parent,
|
||||||
/// self]`). The last item is this object.
|
/// self]`). The last item is this object.
|
||||||
fn rev_parent_chain(&self) -> Vec<Instance> {
|
pub fn rev_parent_chain(&self) -> Vec<Instance> {
|
||||||
let mut vec = default();
|
let mut vec = default();
|
||||||
Self::build_rev_parent_chain(&mut vec, Some(self.clone_ref().into()));
|
Self::build_rev_parent_chain(&mut vec, Some(self.clone_ref().into()));
|
||||||
vec
|
vec
|
||||||
@ -2415,6 +2415,7 @@ impl InstanceDef {
|
|||||||
if event.captures.get() {
|
if event.captures.get() {
|
||||||
for object in &rev_parent_chain {
|
for object in &rev_parent_chain {
|
||||||
if !event.is_cancelled() {
|
if !event.is_cancelled() {
|
||||||
|
event.set_current_target(Some(object));
|
||||||
object.event.capturing_fan.emit(&event.data);
|
object.event.capturing_fan.emit(&event.data);
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
@ -2430,12 +2431,14 @@ impl InstanceDef {
|
|||||||
if event.bubbles.get() {
|
if event.bubbles.get() {
|
||||||
for object in rev_parent_chain.iter().rev() {
|
for object in rev_parent_chain.iter().rev() {
|
||||||
if !event.is_cancelled() {
|
if !event.is_cancelled() {
|
||||||
|
event.set_current_target(Some(object));
|
||||||
object.event.bubbling_fan.emit(&event.data);
|
object.event.bubbling_fan.emit(&event.data);
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
event.set_current_target(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_event<T>(&self, payload: T) -> event::SomeEvent
|
fn new_event<T>(&self, payload: T) -> event::SomeEvent
|
||||||
|
@ -1024,15 +1024,21 @@ impl SceneData {
|
|||||||
let layer = object.display_layer();
|
let layer = object.display_layer();
|
||||||
let camera = layer.map_or(self.camera(), |l| l.camera());
|
let camera = layer.map_or(self.camera(), |l| l.camera());
|
||||||
let origin_clip_space = camera.view_projection_matrix() * origin_world_space;
|
let origin_clip_space = camera.view_projection_matrix() * origin_world_space;
|
||||||
let inv_object_matrix = object.transformation_matrix().try_inverse().unwrap();
|
if let Some(inv_object_matrix) = object.transformation_matrix().try_inverse() {
|
||||||
|
let shape = camera.screen();
|
||||||
let shape = camera.screen();
|
let clip_space_z = origin_clip_space.z;
|
||||||
let clip_space_z = origin_clip_space.z;
|
let clip_space_x = origin_clip_space.w * 2.0 * screen_pos.x / shape.width;
|
||||||
let clip_space_x = origin_clip_space.w * 2.0 * screen_pos.x / shape.width;
|
let clip_space_y = origin_clip_space.w * 2.0 * screen_pos.y / shape.height;
|
||||||
let clip_space_y = origin_clip_space.w * 2.0 * screen_pos.y / shape.height;
|
let clip_space = Vector4(clip_space_x, clip_space_y, clip_space_z, origin_clip_space.w);
|
||||||
let clip_space = Vector4(clip_space_x, clip_space_y, clip_space_z, origin_clip_space.w);
|
let world_space = camera.inversed_view_projection_matrix() * clip_space;
|
||||||
let world_space = camera.inversed_view_projection_matrix() * clip_space;
|
(inv_object_matrix * world_space).xy()
|
||||||
(inv_object_matrix * world_space).xy()
|
} else {
|
||||||
|
warn!(
|
||||||
|
"The object transformation matrix is not invertible, \
|
||||||
|
this can cause visual artifacts."
|
||||||
|
);
|
||||||
|
default()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,4 +30,4 @@ ensogl-example-slider = { path = "slider" }
|
|||||||
ensogl-example-sprite-system = { path = "sprite-system" }
|
ensogl-example-sprite-system = { path = "sprite-system" }
|
||||||
ensogl-example-sprite-system-benchmark = { path = "sprite-system-benchmark" }
|
ensogl-example-sprite-system-benchmark = { path = "sprite-system-benchmark" }
|
||||||
ensogl-example-text-area = { path = "text-area" }
|
ensogl-example-text-area = { path = "text-area" }
|
||||||
ensogl-example-vector-editor = { path = "vector-editor" }
|
ensogl-example-list-editor = { path = "list-editor" }
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "ensogl-example-vector-editor"
|
name = "ensogl-example-list-editor"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["Enso Team <contact@enso.org>"]
|
authors = ["Enso Team <contact@enso.org>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
@ -8,9 +8,11 @@ edition = "2021"
|
|||||||
crate-type = ["cdylib", "rlib"]
|
crate-type = ["cdylib", "rlib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
enso-frp = { path = "../../../frp" }
|
||||||
ensogl-core = { path = "../../core" }
|
ensogl-core = { path = "../../core" }
|
||||||
wasm-bindgen = { workspace = true }
|
ensogl-list-editor = { path = "../../component/list-editor" }
|
||||||
ensogl-hardcoded-theme = { path = "../../../ensogl/app/theme/hardcoded" }
|
ensogl-slider = { path = "../../component/slider" }
|
||||||
|
ensogl-text-msdf = { path = "../../component/text/src/font/msdf" }
|
||||||
|
|
||||||
# Stop wasm-pack from running wasm-opt, because we run it from our build scripts in order to customize options.
|
# Stop wasm-pack from running wasm-opt, because we run it from our build scripts in order to customize options.
|
||||||
[package.metadata.wasm-pack.profile.release]
|
[package.metadata.wasm-pack.profile.release]
|
93
lib/rust/ensogl/examples/list-editor/src/lib.rs
Normal file
93
lib/rust/ensogl/examples/list-editor/src/lib.rs
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
//! An example scene showing the list editor component usage.
|
||||||
|
|
||||||
|
// === Features ===
|
||||||
|
#![feature(associated_type_defaults)]
|
||||||
|
#![feature(drain_filter)]
|
||||||
|
#![feature(fn_traits)]
|
||||||
|
#![feature(trait_alias)]
|
||||||
|
#![feature(type_alias_impl_trait)]
|
||||||
|
#![feature(unboxed_closures)]
|
||||||
|
// === Standard Linter Configuration ===
|
||||||
|
#![deny(non_ascii_idents)]
|
||||||
|
#![warn(unsafe_code)]
|
||||||
|
#![allow(clippy::bool_to_int_with_if)]
|
||||||
|
#![allow(clippy::let_and_return)]
|
||||||
|
// === Non-Standard Linter Configuration ===
|
||||||
|
#![warn(missing_copy_implementations)]
|
||||||
|
#![warn(missing_debug_implementations)]
|
||||||
|
#![warn(missing_docs)]
|
||||||
|
#![warn(trivial_casts)]
|
||||||
|
#![warn(trivial_numeric_casts)]
|
||||||
|
#![warn(unused_import_braces)]
|
||||||
|
#![warn(unused_qualifications)]
|
||||||
|
|
||||||
|
use ensogl_core::prelude::*;
|
||||||
|
|
||||||
|
use enso_frp as frp;
|
||||||
|
use ensogl_core::application::Application;
|
||||||
|
use ensogl_core::display;
|
||||||
|
use ensogl_core::display::navigation::navigator::Navigator;
|
||||||
|
use ensogl_list_editor::ListEditor;
|
||||||
|
use ensogl_slider as slider;
|
||||||
|
use ensogl_text_msdf::run_once_initialized;
|
||||||
|
use std::mem;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// ===================
|
||||||
|
// === Entry Point ===
|
||||||
|
// ===================
|
||||||
|
|
||||||
|
// A global FRP network used to handle events from the list editor.
|
||||||
|
ensogl_core::define_endpoints_2! {}
|
||||||
|
|
||||||
|
/// The example entry point.
|
||||||
|
#[entry_point]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn main() {
|
||||||
|
run_once_initialized(run);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run() {
|
||||||
|
let app = Application::new("root");
|
||||||
|
let world = app.display.clone();
|
||||||
|
let scene = &world.default_scene;
|
||||||
|
let camera = scene.camera().clone_ref();
|
||||||
|
let navigator = Navigator::new(scene, &camera);
|
||||||
|
let vector_editor = ListEditor::new(&app.cursor);
|
||||||
|
|
||||||
|
let slider1 = app.new_view::<slider::Slider>();
|
||||||
|
slider1.set_size((200.0, 24.0));
|
||||||
|
|
||||||
|
let slider2 = app.new_view::<slider::Slider>();
|
||||||
|
slider2.set_size((200.0, 24.0));
|
||||||
|
|
||||||
|
let slider3 = app.new_view::<slider::Slider>();
|
||||||
|
slider3.set_size((200.0, 24.0));
|
||||||
|
|
||||||
|
let frp = Frp::new();
|
||||||
|
let network = frp.network();
|
||||||
|
|
||||||
|
frp::extend! { network
|
||||||
|
vector_editor.insert <+ vector_editor.request_new_item.map(move |index| {
|
||||||
|
let slider = app.new_view::<slider::Slider>();
|
||||||
|
slider.set_size((200.0, 24.0));
|
||||||
|
(**index, Rc::new(RefCell::new(Some(slider))))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
vector_editor.push(slider1);
|
||||||
|
vector_editor.push(slider2);
|
||||||
|
vector_editor.push(slider3);
|
||||||
|
|
||||||
|
let root = display::object::Instance::new();
|
||||||
|
root.set_size(Vector2(300.0, 100.0));
|
||||||
|
root.add_child(&vector_editor);
|
||||||
|
world.add_child(&root);
|
||||||
|
|
||||||
|
world.keep_alive_forever();
|
||||||
|
mem::forget(frp);
|
||||||
|
mem::forget(navigator);
|
||||||
|
mem::forget(root);
|
||||||
|
mem::forget(vector_editor);
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
//! A debug scene which shows the slider component
|
//! An example scene showing the slider component usage.
|
||||||
|
|
||||||
// === Features ===
|
// === Features ===
|
||||||
#![feature(associated_type_defaults)]
|
#![feature(associated_type_defaults)]
|
||||||
@ -35,22 +35,6 @@ use ensogl_text_msdf::run_once_initialized;
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ===================================
|
|
||||||
// === Basic slider initialization ===
|
|
||||||
// ===================================
|
|
||||||
|
|
||||||
/// Create a basic slider.
|
|
||||||
fn make_slider(app: &Application) -> slider::Slider {
|
|
||||||
let slider = app.new_view::<slider::Slider>();
|
|
||||||
// slider.frp.set_background_color(color::Lcha(0.8, 0.0, 0.0, 1.0));
|
|
||||||
// slider.frp.set_max_value(5.0);
|
|
||||||
// slider.frp.set_default_value(1.0);
|
|
||||||
// slider.frp.set_value(1.0);
|
|
||||||
slider
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ========================
|
// ========================
|
||||||
// === Model definition ===
|
// === Model definition ===
|
||||||
// ========================
|
// ========================
|
||||||
@ -81,7 +65,7 @@ impl Model {
|
|||||||
|
|
||||||
/// Add example sliders to scene.
|
/// Add example sliders to scene.
|
||||||
fn init_sliders(&self) {
|
fn init_sliders(&self) {
|
||||||
let slider1 = make_slider(&self.app);
|
let slider1 = self.app.new_view::<slider::Slider>();
|
||||||
slider1.set_size((200.0, 24.0));
|
slider1.set_size((200.0, 24.0));
|
||||||
slider1.set_y(-120.0);
|
slider1.set_y(-120.0);
|
||||||
slider1.frp.set_value_indicator_color(color::Lcha(0.4, 0.7, 0.7, 1.0));
|
slider1.frp.set_value_indicator_color(color::Lcha(0.4, 0.7, 0.7, 1.0));
|
||||||
@ -92,106 +76,111 @@ impl Model {
|
|||||||
self.root.add_child(&slider1);
|
self.root.add_child(&slider1);
|
||||||
self.sliders.borrow_mut().push(slider1);
|
self.sliders.borrow_mut().push(slider1);
|
||||||
|
|
||||||
let slider2 = make_slider(&self.app);
|
// # IMPORTANT
|
||||||
slider2.set_size((400.0, 50.0));
|
// This code is commented because the slider implementation is not finished yet. Please
|
||||||
slider2.set_y(-60.0);
|
// refer to the doc comments in the slider's module to learn more.
|
||||||
slider2.frp.set_value_indicator_color(color::Lcha(0.4, 0.7, 0.7, 1.0));
|
|
||||||
slider2.frp.set_slider_disabled(true);
|
|
||||||
slider2.frp.set_label("Disabled");
|
|
||||||
self.root.add_child(&slider2);
|
|
||||||
self.sliders.borrow_mut().push(slider2);
|
|
||||||
|
|
||||||
let slider3 = make_slider(&self.app);
|
//
|
||||||
slider3.set_size((400.0, 50.0));
|
// let slider2 = self.app.new_view::<slider::Slider>();
|
||||||
slider3.set_y(0.0);
|
// slider2.set_size((400.0, 50.0));
|
||||||
slider3.frp.set_value_indicator_color(color::Lcha(0.4, 0.7, 0.7, 1.0));
|
// slider2.set_y(-60.0);
|
||||||
slider3.frp.set_default_value(100.0);
|
// slider2.frp.set_value_indicator_color(color::Lcha(0.4, 0.7, 0.7, 1.0));
|
||||||
slider3.frp.set_value(100.0);
|
// slider2.frp.set_slider_disabled(true);
|
||||||
slider3.frp.set_max_value(500.0);
|
// slider2.frp.set_label("Disabled");
|
||||||
slider3.frp.set_label("Adaptive lower limit");
|
// self.root.add_child(&slider2);
|
||||||
slider3.frp.set_lower_limit_type(slider::SliderLimit::Adaptive);
|
// self.sliders.borrow_mut().push(slider2);
|
||||||
self.root.add_child(&slider3);
|
//
|
||||||
self.sliders.borrow_mut().push(slider3);
|
// let slider3 = self.app.new_view::<slider::Slider>();
|
||||||
|
// slider3.set_size((400.0, 50.0));
|
||||||
let slider4 = make_slider(&self.app);
|
// slider3.set_y(0.0);
|
||||||
slider4.set_size((400.0, 50.0));
|
// slider3.frp.set_value_indicator_color(color::Lcha(0.4, 0.7, 0.7, 1.0));
|
||||||
slider4.set_y(60.0);
|
// slider3.frp.set_default_value(100.0);
|
||||||
slider4.frp.set_value_indicator_color(color::Lcha(0.4, 0.7, 0.7, 1.0));
|
// slider3.frp.set_value(100.0);
|
||||||
slider4.frp.set_label("Adaptive upper limit");
|
// slider3.frp.set_max_value(500.0);
|
||||||
slider4.frp.set_label_position(slider::LabelPosition::Inside);
|
// slider3.frp.set_label("Adaptive lower limit");
|
||||||
slider4.frp.set_upper_limit_type(slider::SliderLimit::Adaptive);
|
// slider3.frp.set_lower_limit_type(slider::SliderLimit::Adaptive);
|
||||||
self.root.add_child(&slider4);
|
// self.root.add_child(&slider3);
|
||||||
self.sliders.borrow_mut().push(slider4);
|
// self.sliders.borrow_mut().push(slider3);
|
||||||
|
//
|
||||||
let slider5 = make_slider(&self.app);
|
// let slider4 = self.app.new_view::<slider::Slider>();
|
||||||
slider5.set_size((75.0, 230.0));
|
// slider4.set_size((400.0, 50.0));
|
||||||
slider5.set_y(-35.0);
|
// slider4.set_y(60.0);
|
||||||
slider5.set_x(275.0);
|
// slider4.frp.set_value_indicator_color(color::Lcha(0.4, 0.7, 0.7, 1.0));
|
||||||
slider5.frp.set_value_indicator_color(color::Lcha(0.4, 0.7, 0.7, 1.0));
|
// slider4.frp.set_label("Adaptive upper limit");
|
||||||
slider5.frp.set_label("Hard limits");
|
// slider4.frp.set_label_position(slider::LabelPosition::Inside);
|
||||||
slider5.frp.orientation(Axis2::Y);
|
// slider4.frp.set_upper_limit_type(slider::SliderLimit::Adaptive);
|
||||||
slider5.frp.set_max_disp_decimal_places(4);
|
// self.root.add_child(&slider4);
|
||||||
self.root.add_child(&slider5);
|
// self.sliders.borrow_mut().push(slider4);
|
||||||
self.sliders.borrow_mut().push(slider5);
|
//
|
||||||
|
// let slider5 = self.app.new_view::<slider::Slider>();
|
||||||
let slider6 = make_slider(&self.app);
|
// slider5.set_size((75.0, 230.0));
|
||||||
slider6.set_size((75.0, 230.0));
|
// slider5.set_y(-35.0);
|
||||||
slider6.set_y(-35.0);
|
// slider5.set_x(275.0);
|
||||||
slider6.set_x(375.0);
|
// slider5.frp.set_value_indicator_color(color::Lcha(0.4, 0.7, 0.7, 1.0));
|
||||||
slider6.frp.set_value_indicator_color(color::Lcha(0.4, 0.7, 0.7, 1.0));
|
// slider5.frp.set_label("Hard limits");
|
||||||
slider6.frp.set_label("Soft\nlimits");
|
// slider5.frp.orientation(Axis2::Y);
|
||||||
slider6.frp.set_label_position(slider::LabelPosition::Inside);
|
// slider5.frp.set_max_disp_decimal_places(4);
|
||||||
slider6.frp.set_lower_limit_type(slider::SliderLimit::Soft);
|
// self.root.add_child(&slider5);
|
||||||
slider6.frp.set_upper_limit_type(slider::SliderLimit::Soft);
|
// self.sliders.borrow_mut().push(slider5);
|
||||||
slider6.frp.orientation(Axis2::Y);
|
//
|
||||||
slider6.frp.set_max_disp_decimal_places(4);
|
// let slider6 = self.app.new_view::<slider::Slider>();
|
||||||
self.root.add_child(&slider6);
|
// slider6.set_size((75.0, 230.0));
|
||||||
self.sliders.borrow_mut().push(slider6);
|
// slider6.set_y(-35.0);
|
||||||
|
// slider6.set_x(375.0);
|
||||||
let slider7 = make_slider(&self.app);
|
// slider6.frp.set_value_indicator_color(color::Lcha(0.4, 0.7, 0.7, 1.0));
|
||||||
slider7.set_size((400.0, 10.0));
|
// slider6.frp.set_label("Soft\nlimits");
|
||||||
slider7.set_y(-160.0);
|
// slider6.frp.set_label_position(slider::LabelPosition::Inside);
|
||||||
slider7.frp.set_value_indicator_color(color::Lcha(0.4, 0.7, 0.7, 1.0));
|
// slider6.frp.set_lower_limit_type(slider::SliderLimit::Soft);
|
||||||
slider7.frp.show_value(false);
|
// slider6.frp.set_upper_limit_type(slider::SliderLimit::Soft);
|
||||||
slider7.frp.set_precision_adjustment_disabled(true);
|
// slider6.frp.orientation(Axis2::Y);
|
||||||
slider7.frp.kind(slider::Kind::Scrollbar(0.1));
|
// slider6.frp.set_max_disp_decimal_places(4);
|
||||||
slider7.frp.set_thumb_size(0.1);
|
// self.root.add_child(&slider6);
|
||||||
self.root.add_child(&slider7);
|
// self.sliders.borrow_mut().push(slider6);
|
||||||
self.sliders.borrow_mut().push(slider7);
|
//
|
||||||
|
// let slider7 = self.app.new_view::<slider::Slider>();
|
||||||
let slider8 = make_slider(&self.app);
|
// slider7.set_size((400.0, 10.0));
|
||||||
slider8.set_size((400.0, 10.0));
|
// slider7.set_y(-160.0);
|
||||||
slider8.set_y(-180.0);
|
// slider7.frp.set_value_indicator_color(color::Lcha(0.4, 0.7, 0.7, 1.0));
|
||||||
slider8.frp.set_value_indicator_color(color::Lcha(0.4, 0.7, 0.7, 1.0));
|
// slider7.frp.show_value(false);
|
||||||
slider8.frp.show_value(false);
|
// slider7.frp.set_precision_adjustment_disabled(true);
|
||||||
slider8.frp.set_precision_adjustment_disabled(true);
|
// slider7.frp.kind(slider::Kind::Scrollbar(0.1));
|
||||||
slider8.frp.kind(slider::Kind::Scrollbar(0.25));
|
// slider7.frp.set_thumb_size(0.1);
|
||||||
slider8.frp.set_thumb_size(0.25);
|
// self.root.add_child(&slider7);
|
||||||
self.root.add_child(&slider8);
|
// self.sliders.borrow_mut().push(slider7);
|
||||||
self.sliders.borrow_mut().push(slider8);
|
//
|
||||||
|
// let slider8 = self.app.new_view::<slider::Slider>();
|
||||||
let slider9 = make_slider(&self.app);
|
// slider8.set_size((400.0, 10.0));
|
||||||
slider9.set_size((400.0, 10.0));
|
// slider8.set_y(-180.0);
|
||||||
slider9.set_y(-200.0);
|
// slider8.frp.set_value_indicator_color(color::Lcha(0.4, 0.7, 0.7, 1.0));
|
||||||
slider9.frp.set_value_indicator_color(color::Lcha(0.4, 0.7, 0.7, 1.0));
|
// slider8.frp.show_value(false);
|
||||||
slider9.frp.show_value(false);
|
// slider8.frp.set_precision_adjustment_disabled(true);
|
||||||
slider9.frp.set_precision_adjustment_disabled(true);
|
// slider8.frp.kind(slider::Kind::Scrollbar(0.25));
|
||||||
slider9.frp.kind(slider::Kind::Scrollbar(0.5));
|
// slider8.frp.set_thumb_size(0.25);
|
||||||
slider9.frp.set_thumb_size(0.5);
|
// self.root.add_child(&slider8);
|
||||||
self.root.add_child(&slider9);
|
// self.sliders.borrow_mut().push(slider8);
|
||||||
self.sliders.borrow_mut().push(slider9);
|
//
|
||||||
|
// let slider9 = self.app.new_view::<slider::Slider>();
|
||||||
let slider10 = make_slider(&self.app);
|
// slider9.set_size((400.0, 10.0));
|
||||||
slider10.set_size((10.0, 230));
|
// slider9.set_y(-200.0);
|
||||||
slider10.set_y(-35.0);
|
// slider9.frp.set_value_indicator_color(color::Lcha(0.4, 0.7, 0.7, 1.0));
|
||||||
slider10.set_x(430.0);
|
// slider9.frp.show_value(false);
|
||||||
slider10.frp.set_value_indicator_color(color::Lcha(0.4, 0.7, 0.7, 1.0));
|
// slider9.frp.set_precision_adjustment_disabled(true);
|
||||||
slider10.frp.show_value(false);
|
// slider9.frp.kind(slider::Kind::Scrollbar(0.5));
|
||||||
slider10.frp.set_precision_adjustment_disabled(true);
|
// slider9.frp.set_thumb_size(0.5);
|
||||||
slider10.frp.kind(slider::Kind::Scrollbar(0.1));
|
// self.root.add_child(&slider9);
|
||||||
slider10.frp.orientation(Axis2::Y);
|
// self.sliders.borrow_mut().push(slider9);
|
||||||
self.root.add_child(&slider10);
|
//
|
||||||
self.sliders.borrow_mut().push(slider10);
|
// let slider10 = self.app.new_view::<slider::Slider>();
|
||||||
|
// slider10.set_size((10.0, 230));
|
||||||
|
// slider10.set_y(-35.0);
|
||||||
|
// slider10.set_x(430.0);
|
||||||
|
// slider10.frp.set_value_indicator_color(color::Lcha(0.4, 0.7, 0.7, 1.0));
|
||||||
|
// slider10.frp.show_value(false);
|
||||||
|
// slider10.frp.set_precision_adjustment_disabled(true);
|
||||||
|
// slider10.frp.kind(slider::Kind::Scrollbar(0.1));
|
||||||
|
// slider10.frp.orientation(Axis2::Y);
|
||||||
|
// self.root.add_child(&slider10);
|
||||||
|
// self.sliders.borrow_mut().push(slider10);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Drop all sliders from scene.
|
/// Drop all sliders from scene.
|
||||||
|
@ -41,6 +41,7 @@ pub use ensogl_example_easing_animator as easing_animator;
|
|||||||
pub use ensogl_example_focus_management as focus_management;
|
pub use ensogl_example_focus_management as focus_management;
|
||||||
pub use ensogl_example_grid_view as grid_view;
|
pub use ensogl_example_grid_view as grid_view;
|
||||||
pub use ensogl_example_instance_ordering as instance_ordering;
|
pub use ensogl_example_instance_ordering as instance_ordering;
|
||||||
|
pub use ensogl_example_list_editor as list_editor;
|
||||||
pub use ensogl_example_list_view as list_view;
|
pub use ensogl_example_list_view as list_view;
|
||||||
pub use ensogl_example_mouse_events as mouse_events;
|
pub use ensogl_example_mouse_events as mouse_events;
|
||||||
pub use ensogl_example_profiling_run_graph as profiling_run_graph;
|
pub use ensogl_example_profiling_run_graph as profiling_run_graph;
|
||||||
|
@ -1,167 +0,0 @@
|
|||||||
//! Example scene showing the usage of built-in vector editor component.
|
|
||||||
//!
|
|
||||||
//! TODO[WD]: This is work in progress and will be changed in the upcoming PRs.
|
|
||||||
|
|
||||||
// === Standard Linter Configuration ===
|
|
||||||
#![deny(non_ascii_idents)]
|
|
||||||
#![warn(unsafe_code)]
|
|
||||||
#![allow(clippy::bool_to_int_with_if)]
|
|
||||||
#![allow(clippy::let_and_return)]
|
|
||||||
|
|
||||||
use ensogl_core::display::shape::compound::rectangle::*;
|
|
||||||
use ensogl_core::display::world::*;
|
|
||||||
use ensogl_core::prelude::*;
|
|
||||||
|
|
||||||
use ensogl_core::control::io::mouse;
|
|
||||||
use ensogl_core::data::color;
|
|
||||||
use ensogl_core::display;
|
|
||||||
use ensogl_core::display::navigation::navigator::Navigator;
|
|
||||||
use ensogl_core::display::object::ObjectOps;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ==============
|
|
||||||
// === Events ===
|
|
||||||
// ==============
|
|
||||||
|
|
||||||
#[derive(Clone, CloneRef, Debug, Default)]
|
|
||||||
pub struct MouseOver;
|
|
||||||
|
|
||||||
|
|
||||||
// ============
|
|
||||||
// === Glob ===
|
|
||||||
// ============
|
|
||||||
|
|
||||||
pub mod glob {
|
|
||||||
use super::*;
|
|
||||||
ensogl_core::define_endpoints_2! {
|
|
||||||
Input {
|
|
||||||
}
|
|
||||||
Output {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===========
|
|
||||||
// === FRP ===
|
|
||||||
// ===========
|
|
||||||
|
|
||||||
ensogl_core::define_endpoints_2! {
|
|
||||||
Input {
|
|
||||||
}
|
|
||||||
Output {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Derivative, CloneRef, Debug, Deref)]
|
|
||||||
#[derivative(Clone(bound = ""))]
|
|
||||||
pub struct VectorEditor<T> {
|
|
||||||
#[deref]
|
|
||||||
pub frp: Frp,
|
|
||||||
display_object: display::object::Instance,
|
|
||||||
model: Rc<RefCell<Model<T>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Derivative)]
|
|
||||||
#[derivative(Default(bound = ""))]
|
|
||||||
pub struct Model<T> {
|
|
||||||
items: Vec<T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> VectorEditor<T> {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
let frp = Frp::new();
|
|
||||||
let display_object = display::object::Instance::new();
|
|
||||||
let model = default();
|
|
||||||
display_object.use_auto_layout().set_gap((10.0, 10.0));
|
|
||||||
Self { frp, display_object, model }.init()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn init(self) -> Self {
|
|
||||||
let network = self.frp.network();
|
|
||||||
let event_handler = self.display_object.on_event::<mouse::Up>();
|
|
||||||
frp::extend! { network
|
|
||||||
eval_ event_handler ([] {
|
|
||||||
warn!("Mouse up in parent");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: display::Object> VectorEditor<T> {
|
|
||||||
fn append(&self, item: T) {
|
|
||||||
self.add_child(&item);
|
|
||||||
self.model.borrow_mut().items.push(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> display::Object for VectorEditor<T> {
|
|
||||||
fn display_object(&self) -> &display::object::Instance {
|
|
||||||
&self.display_object
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Default for VectorEditor<T> {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ===================
|
|
||||||
// === Entry Point ===
|
|
||||||
// ===================
|
|
||||||
|
|
||||||
/// The example entry point.
|
|
||||||
#[entry_point]
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn main() {
|
|
||||||
let world = World::new().displayed_in("root");
|
|
||||||
let scene = &world.default_scene;
|
|
||||||
let camera = scene.camera().clone_ref();
|
|
||||||
let navigator = Navigator::new(scene, &camera);
|
|
||||||
|
|
||||||
let vector_editor = VectorEditor::<Rectangle>::new();
|
|
||||||
|
|
||||||
|
|
||||||
let shape1 = Circle().build(|t| {
|
|
||||||
t.set_size(Vector2::new(100.0, 100.0))
|
|
||||||
.set_color(color::Rgba::new(0.5, 0.0, 0.0, 0.3))
|
|
||||||
.set_inset_border(5.0)
|
|
||||||
.set_border_color(color::Rgba::new(0.0, 0.0, 1.0, 1.0))
|
|
||||||
.keep_bottom_left_quarter();
|
|
||||||
});
|
|
||||||
let shape2 = RoundedRectangle(10.0).build(|t| {
|
|
||||||
t.set_size(Vector2::new(100.0, 100.0))
|
|
||||||
.set_color(color::Rgba::new(0.5, 0.0, 0.0, 0.3))
|
|
||||||
.set_inset_border(5.0)
|
|
||||||
.set_border_color(color::Rgba::new(0.0, 0.0, 1.0, 1.0));
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
let glob_frp = glob::Frp::new();
|
|
||||||
let glob_frp_network = glob_frp.network();
|
|
||||||
|
|
||||||
let shape1_over = shape1.on_event::<mouse::Over>();
|
|
||||||
frp::extend! { glob_frp_network
|
|
||||||
eval_ shape1_over ([] {
|
|
||||||
warn!("Shape 1 over");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
vector_editor.append(shape1);
|
|
||||||
vector_editor.append(shape2);
|
|
||||||
|
|
||||||
let root = display::object::Instance::new();
|
|
||||||
root.set_size(Vector2::new(300.0, 100.0));
|
|
||||||
root.add_child(&vector_editor);
|
|
||||||
world.add_child(&root);
|
|
||||||
|
|
||||||
world.keep_alive_forever();
|
|
||||||
mem::forget(glob_frp);
|
|
||||||
mem::forget(navigator);
|
|
||||||
mem::forget(root);
|
|
||||||
mem::forget(vector_editor);
|
|
||||||
}
|
|
@ -1056,6 +1056,172 @@ impl Network {
|
|||||||
self.register(OwnedMap4::new(label, t1, t2, t3, t4, f))
|
self.register(OwnedMap4::new(label, t1, t2, t3, t4, f))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Specialized version of `map`.
|
||||||
|
pub fn map5<T1, T2, T3, T4, T5, F, T>(
|
||||||
|
&self,
|
||||||
|
label: Label,
|
||||||
|
t1: &T1,
|
||||||
|
t2: &T2,
|
||||||
|
t3: &T3,
|
||||||
|
t4: &T4,
|
||||||
|
t5: &T5,
|
||||||
|
f: F,
|
||||||
|
) -> Stream<T>
|
||||||
|
where
|
||||||
|
T1: EventOutput,
|
||||||
|
T2: EventOutput,
|
||||||
|
T3: EventOutput,
|
||||||
|
T4: EventOutput,
|
||||||
|
T5: EventOutput,
|
||||||
|
T: Data,
|
||||||
|
F: 'static + Fn(&Output<T1>, &Output<T2>, &Output<T3>, &Output<T4>, &Output<T5>) -> T,
|
||||||
|
{
|
||||||
|
self.register(OwnedMap5::new(label, t1, t2, t3, t4, t5, f))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Specialized version of `map`.
|
||||||
|
pub fn map6<T1, T2, T3, T4, T5, T6, F, T>(
|
||||||
|
&self,
|
||||||
|
label: Label,
|
||||||
|
t1: &T1,
|
||||||
|
t2: &T2,
|
||||||
|
t3: &T3,
|
||||||
|
t4: &T4,
|
||||||
|
t5: &T5,
|
||||||
|
t6: &T6,
|
||||||
|
f: F,
|
||||||
|
) -> Stream<T>
|
||||||
|
where
|
||||||
|
T1: EventOutput,
|
||||||
|
T2: EventOutput,
|
||||||
|
T3: EventOutput,
|
||||||
|
T4: EventOutput,
|
||||||
|
T5: EventOutput,
|
||||||
|
T6: EventOutput,
|
||||||
|
T: Data,
|
||||||
|
F: 'static
|
||||||
|
+ Fn(&Output<T1>, &Output<T2>, &Output<T3>, &Output<T4>, &Output<T5>, &Output<T6>) -> T,
|
||||||
|
{
|
||||||
|
self.register(OwnedMap6::new(label, t1, t2, t3, t4, t5, t6, f))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Specialized version of `map`.
|
||||||
|
pub fn map7<T1, T2, T3, T4, T5, T6, T7, F, T>(
|
||||||
|
&self,
|
||||||
|
label: Label,
|
||||||
|
t1: &T1,
|
||||||
|
t2: &T2,
|
||||||
|
t3: &T3,
|
||||||
|
t4: &T4,
|
||||||
|
t5: &T5,
|
||||||
|
t6: &T6,
|
||||||
|
t7: &T7,
|
||||||
|
f: F,
|
||||||
|
) -> Stream<T>
|
||||||
|
where
|
||||||
|
T1: EventOutput,
|
||||||
|
T2: EventOutput,
|
||||||
|
T3: EventOutput,
|
||||||
|
T4: EventOutput,
|
||||||
|
T5: EventOutput,
|
||||||
|
T6: EventOutput,
|
||||||
|
T7: EventOutput,
|
||||||
|
T: Data,
|
||||||
|
F: 'static
|
||||||
|
+ Fn(
|
||||||
|
&Output<T1>,
|
||||||
|
&Output<T2>,
|
||||||
|
&Output<T3>,
|
||||||
|
&Output<T4>,
|
||||||
|
&Output<T5>,
|
||||||
|
&Output<T6>,
|
||||||
|
&Output<T7>,
|
||||||
|
) -> T,
|
||||||
|
{
|
||||||
|
self.register(OwnedMap7::new(label, t1, t2, t3, t4, t5, t6, t7, f))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Specialized version of `map`.
|
||||||
|
pub fn map8<T1, T2, T3, T4, T5, T6, T7, T8, F, T>(
|
||||||
|
&self,
|
||||||
|
label: Label,
|
||||||
|
t1: &T1,
|
||||||
|
t2: &T2,
|
||||||
|
t3: &T3,
|
||||||
|
t4: &T4,
|
||||||
|
t5: &T5,
|
||||||
|
t6: &T6,
|
||||||
|
t7: &T7,
|
||||||
|
t8: &T8,
|
||||||
|
f: F,
|
||||||
|
) -> Stream<T>
|
||||||
|
where
|
||||||
|
T1: EventOutput,
|
||||||
|
T2: EventOutput,
|
||||||
|
T3: EventOutput,
|
||||||
|
T4: EventOutput,
|
||||||
|
T5: EventOutput,
|
||||||
|
T6: EventOutput,
|
||||||
|
T7: EventOutput,
|
||||||
|
T8: EventOutput,
|
||||||
|
T: Data,
|
||||||
|
F: 'static
|
||||||
|
+ Fn(
|
||||||
|
&Output<T1>,
|
||||||
|
&Output<T2>,
|
||||||
|
&Output<T3>,
|
||||||
|
&Output<T4>,
|
||||||
|
&Output<T5>,
|
||||||
|
&Output<T6>,
|
||||||
|
&Output<T7>,
|
||||||
|
&Output<T8>,
|
||||||
|
) -> T,
|
||||||
|
{
|
||||||
|
self.register(OwnedMap8::new(label, t1, t2, t3, t4, t5, t6, t7, t8, f))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Specialized version of `map`.
|
||||||
|
pub fn map9<T1, T2, T3, T4, T5, T6, T7, T8, T9, F, T>(
|
||||||
|
&self,
|
||||||
|
label: Label,
|
||||||
|
t1: &T1,
|
||||||
|
t2: &T2,
|
||||||
|
t3: &T3,
|
||||||
|
t4: &T4,
|
||||||
|
t5: &T5,
|
||||||
|
t6: &T6,
|
||||||
|
t7: &T7,
|
||||||
|
t8: &T8,
|
||||||
|
t9: &T9,
|
||||||
|
f: F,
|
||||||
|
) -> Stream<T>
|
||||||
|
where
|
||||||
|
T1: EventOutput,
|
||||||
|
T2: EventOutput,
|
||||||
|
T3: EventOutput,
|
||||||
|
T4: EventOutput,
|
||||||
|
T5: EventOutput,
|
||||||
|
T6: EventOutput,
|
||||||
|
T7: EventOutput,
|
||||||
|
T8: EventOutput,
|
||||||
|
T9: EventOutput,
|
||||||
|
T: Data,
|
||||||
|
F: 'static
|
||||||
|
+ Fn(
|
||||||
|
&Output<T1>,
|
||||||
|
&Output<T2>,
|
||||||
|
&Output<T3>,
|
||||||
|
&Output<T4>,
|
||||||
|
&Output<T5>,
|
||||||
|
&Output<T6>,
|
||||||
|
&Output<T7>,
|
||||||
|
&Output<T8>,
|
||||||
|
&Output<T9>,
|
||||||
|
) -> T,
|
||||||
|
{
|
||||||
|
self.register(OwnedMap9::new(label, t1, t2, t3, t4, t5, t6, t7, t8, t9, f))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// === AllWith ===
|
// === AllWith ===
|
||||||
|
|
||||||
@ -4170,6 +4336,737 @@ impl<T1, T2, T3, T4, F> Debug for Map4Data<T1, T2, T3, T4, F> {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// ============
|
||||||
|
// === Map5 ===
|
||||||
|
// ============
|
||||||
|
|
||||||
|
pub struct Map5Data<T1, T2, T3, T4, T5, F> {
|
||||||
|
_src1: T1,
|
||||||
|
src2: watch::Ref<T2>,
|
||||||
|
src3: watch::Ref<T3>,
|
||||||
|
src4: watch::Ref<T4>,
|
||||||
|
src5: watch::Ref<T5>,
|
||||||
|
function: F,
|
||||||
|
}
|
||||||
|
pub type OwnedMap5<T1, T2, T3, T4, T5, F> = stream::Node<Map5Data<T1, T2, T3, T4, T5, F>>;
|
||||||
|
pub type Map5<T1, T2, T3, T4, T5, F> = stream::WeakNode<Map5Data<T1, T2, T3, T4, T5, F>>;
|
||||||
|
|
||||||
|
impl<T1, T2, T3, T4, T5, F, Out> HasOutput for Map5Data<T1, T2, T3, T4, T5, F>
|
||||||
|
where
|
||||||
|
T1: EventOutput,
|
||||||
|
T2: EventOutput,
|
||||||
|
T3: EventOutput,
|
||||||
|
T4: EventOutput,
|
||||||
|
T5: EventOutput,
|
||||||
|
Out: Data,
|
||||||
|
F: 'static + Fn(&Output<T1>, &Output<T2>, &Output<T3>, &Output<T4>, &Output<T5>) -> Out,
|
||||||
|
{
|
||||||
|
type Output = Out;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T1, T2, T3, T4, T5, F, Out> OwnedMap5<T1, T2, T3, T4, T5, F>
|
||||||
|
where
|
||||||
|
T1: EventOutput,
|
||||||
|
T2: EventOutput,
|
||||||
|
T3: EventOutput,
|
||||||
|
T4: EventOutput,
|
||||||
|
T5: EventOutput,
|
||||||
|
Out: Data,
|
||||||
|
F: 'static + Fn(&Output<T1>, &Output<T2>, &Output<T3>, &Output<T4>, &Output<T5>) -> Out,
|
||||||
|
{
|
||||||
|
/// Constructor.
|
||||||
|
pub fn new(label: Label, t1: &T1, t2: &T2, t3: &T3, t4: &T4, t5: &T5, function: F) -> Self {
|
||||||
|
let _src1 = t1.clone_ref();
|
||||||
|
let src2 = watch_stream(t2);
|
||||||
|
let src3 = watch_stream(t3);
|
||||||
|
let src4 = watch_stream(t4);
|
||||||
|
let src5 = watch_stream(t5);
|
||||||
|
let def = Map5Data { _src1, src2, src3, src4, src5, function };
|
||||||
|
let this = Self::construct(label, def);
|
||||||
|
let weak = this.downgrade();
|
||||||
|
t1.register_target(weak.into());
|
||||||
|
this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T1, T2, T3, T4, T5, F, Out> stream::EventConsumer<Output<T1>>
|
||||||
|
for OwnedMap5<T1, T2, T3, T4, T5, F>
|
||||||
|
where
|
||||||
|
T1: EventOutput,
|
||||||
|
T2: EventOutput,
|
||||||
|
T3: EventOutput,
|
||||||
|
T4: EventOutput,
|
||||||
|
T5: EventOutput,
|
||||||
|
Out: Data,
|
||||||
|
F: 'static + Fn(&Output<T1>, &Output<T2>, &Output<T3>, &Output<T4>, &Output<T5>) -> Out,
|
||||||
|
{
|
||||||
|
fn on_event(&self, stack: CallStack, value1: &Output<T1>) {
|
||||||
|
let value2 = self.src2.value();
|
||||||
|
let value3 = self.src3.value();
|
||||||
|
let value4 = self.src4.value();
|
||||||
|
let value5 = self.src5.value();
|
||||||
|
let out = (self.function)(value1, &value2, &value3, &value4, &value5);
|
||||||
|
self.emit_event(stack, &out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T1, T2, T3, T4, T5, F> stream::InputBehaviors for Map5Data<T1, T2, T3, T4, T5, F>
|
||||||
|
where
|
||||||
|
T1: EventOutput,
|
||||||
|
T2: EventOutput,
|
||||||
|
T3: EventOutput,
|
||||||
|
T4: EventOutput,
|
||||||
|
T5: EventOutput,
|
||||||
|
{
|
||||||
|
fn input_behaviors(&self) -> Vec<Link> {
|
||||||
|
vec![
|
||||||
|
Link::behavior(&self.src2),
|
||||||
|
Link::behavior(&self.src3),
|
||||||
|
Link::behavior(&self.src4),
|
||||||
|
Link::behavior(&self.src5),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T1, T2, T3, T4, T5, F> Debug for Map5Data<T1, T2, T3, T4, T5, F> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "Map5Data")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// ============
|
||||||
|
// === Map6 ===
|
||||||
|
// ============
|
||||||
|
|
||||||
|
pub struct Map6Data<T1, T2, T3, T4, T5, T6, F> {
|
||||||
|
_src1: T1,
|
||||||
|
src2: watch::Ref<T2>,
|
||||||
|
src3: watch::Ref<T3>,
|
||||||
|
src4: watch::Ref<T4>,
|
||||||
|
src5: watch::Ref<T5>,
|
||||||
|
src6: watch::Ref<T6>,
|
||||||
|
function: F,
|
||||||
|
}
|
||||||
|
pub type OwnedMap6<T1, T2, T3, T4, T5, T6, F> = stream::Node<Map6Data<T1, T2, T3, T4, T5, T6, F>>;
|
||||||
|
pub type Map6<T1, T2, T3, T4, T5, T6, F> = stream::WeakNode<Map6Data<T1, T2, T3, T4, T5, T6, F>>;
|
||||||
|
|
||||||
|
impl<T1, T2, T3, T4, T5, T6, F, Out> HasOutput for Map6Data<T1, T2, T3, T4, T5, T6, F>
|
||||||
|
where
|
||||||
|
T1: EventOutput,
|
||||||
|
T2: EventOutput,
|
||||||
|
T3: EventOutput,
|
||||||
|
T4: EventOutput,
|
||||||
|
T5: EventOutput,
|
||||||
|
T6: EventOutput,
|
||||||
|
Out: Data,
|
||||||
|
F: 'static
|
||||||
|
+ Fn(&Output<T1>, &Output<T2>, &Output<T3>, &Output<T4>, &Output<T5>, &Output<T6>) -> Out,
|
||||||
|
{
|
||||||
|
type Output = Out;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T1, T2, T3, T4, T5, T6, F, Out> OwnedMap6<T1, T2, T3, T4, T5, T6, F>
|
||||||
|
where
|
||||||
|
T1: EventOutput,
|
||||||
|
T2: EventOutput,
|
||||||
|
T3: EventOutput,
|
||||||
|
T4: EventOutput,
|
||||||
|
T5: EventOutput,
|
||||||
|
T6: EventOutput,
|
||||||
|
Out: Data,
|
||||||
|
F: 'static
|
||||||
|
+ Fn(&Output<T1>, &Output<T2>, &Output<T3>, &Output<T4>, &Output<T5>, &Output<T6>) -> Out,
|
||||||
|
{
|
||||||
|
/// Constructor.
|
||||||
|
pub fn new(
|
||||||
|
label: Label,
|
||||||
|
t1: &T1,
|
||||||
|
t2: &T2,
|
||||||
|
t3: &T3,
|
||||||
|
t4: &T4,
|
||||||
|
t5: &T5,
|
||||||
|
t6: &T6,
|
||||||
|
function: F,
|
||||||
|
) -> Self {
|
||||||
|
let _src1 = t1.clone_ref();
|
||||||
|
let src2 = watch_stream(t2);
|
||||||
|
let src3 = watch_stream(t3);
|
||||||
|
let src4 = watch_stream(t4);
|
||||||
|
let src5 = watch_stream(t5);
|
||||||
|
let src6 = watch_stream(t6);
|
||||||
|
let def = Map6Data { _src1, src2, src3, src4, src5, src6, function };
|
||||||
|
let this = Self::construct(label, def);
|
||||||
|
let weak = this.downgrade();
|
||||||
|
t1.register_target(weak.into());
|
||||||
|
this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T1, T2, T3, T4, T5, T6, F, Out> stream::EventConsumer<Output<T1>>
|
||||||
|
for OwnedMap6<T1, T2, T3, T4, T5, T6, F>
|
||||||
|
where
|
||||||
|
T1: EventOutput,
|
||||||
|
T2: EventOutput,
|
||||||
|
T3: EventOutput,
|
||||||
|
T4: EventOutput,
|
||||||
|
T5: EventOutput,
|
||||||
|
T6: EventOutput,
|
||||||
|
Out: Data,
|
||||||
|
F: 'static
|
||||||
|
+ Fn(&Output<T1>, &Output<T2>, &Output<T3>, &Output<T4>, &Output<T5>, &Output<T6>) -> Out,
|
||||||
|
{
|
||||||
|
fn on_event(&self, stack: CallStack, value1: &Output<T1>) {
|
||||||
|
let value2 = self.src2.value();
|
||||||
|
let value3 = self.src3.value();
|
||||||
|
let value4 = self.src4.value();
|
||||||
|
let value5 = self.src5.value();
|
||||||
|
let value6 = self.src6.value();
|
||||||
|
let out = (self.function)(value1, &value2, &value3, &value4, &value5, &value6);
|
||||||
|
self.emit_event(stack, &out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T1, T2, T3, T4, T5, T6, F> stream::InputBehaviors for Map6Data<T1, T2, T3, T4, T5, T6, F>
|
||||||
|
where
|
||||||
|
T1: EventOutput,
|
||||||
|
T2: EventOutput,
|
||||||
|
T3: EventOutput,
|
||||||
|
T4: EventOutput,
|
||||||
|
T5: EventOutput,
|
||||||
|
T6: EventOutput,
|
||||||
|
{
|
||||||
|
fn input_behaviors(&self) -> Vec<Link> {
|
||||||
|
vec![
|
||||||
|
Link::behavior(&self.src2),
|
||||||
|
Link::behavior(&self.src3),
|
||||||
|
Link::behavior(&self.src4),
|
||||||
|
Link::behavior(&self.src5),
|
||||||
|
Link::behavior(&self.src6),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T1, T2, T3, T4, T5, T6, F> Debug for Map6Data<T1, T2, T3, T4, T5, T6, F> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "Map6Data")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// ============
|
||||||
|
// === Map7 ===
|
||||||
|
// ============
|
||||||
|
|
||||||
|
pub struct Map7Data<T1, T2, T3, T4, T5, T6, T7, F> {
|
||||||
|
_src1: T1,
|
||||||
|
src2: watch::Ref<T2>,
|
||||||
|
src3: watch::Ref<T3>,
|
||||||
|
src4: watch::Ref<T4>,
|
||||||
|
src5: watch::Ref<T5>,
|
||||||
|
src6: watch::Ref<T6>,
|
||||||
|
src7: watch::Ref<T7>,
|
||||||
|
function: F,
|
||||||
|
}
|
||||||
|
pub type OwnedMap7<T1, T2, T3, T4, T5, T6, T7, F> =
|
||||||
|
stream::Node<Map7Data<T1, T2, T3, T4, T5, T6, T7, F>>;
|
||||||
|
pub type Map7<T1, T2, T3, T4, T5, T6, T7, F> =
|
||||||
|
stream::WeakNode<Map7Data<T1, T2, T3, T4, T5, T6, T7, F>>;
|
||||||
|
|
||||||
|
impl<T1, T2, T3, T4, T5, T6, T7, F, Out> HasOutput for Map7Data<T1, T2, T3, T4, T5, T6, T7, F>
|
||||||
|
where
|
||||||
|
T1: EventOutput,
|
||||||
|
T2: EventOutput,
|
||||||
|
T3: EventOutput,
|
||||||
|
T4: EventOutput,
|
||||||
|
T5: EventOutput,
|
||||||
|
T6: EventOutput,
|
||||||
|
T7: EventOutput,
|
||||||
|
Out: Data,
|
||||||
|
F: 'static
|
||||||
|
+ Fn(
|
||||||
|
&Output<T1>,
|
||||||
|
&Output<T2>,
|
||||||
|
&Output<T3>,
|
||||||
|
&Output<T4>,
|
||||||
|
&Output<T5>,
|
||||||
|
&Output<T6>,
|
||||||
|
&Output<T7>,
|
||||||
|
) -> Out,
|
||||||
|
{
|
||||||
|
type Output = Out;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T1, T2, T3, T4, T5, T6, T7, F, Out> OwnedMap7<T1, T2, T3, T4, T5, T6, T7, F>
|
||||||
|
where
|
||||||
|
T1: EventOutput,
|
||||||
|
T2: EventOutput,
|
||||||
|
T3: EventOutput,
|
||||||
|
T4: EventOutput,
|
||||||
|
T5: EventOutput,
|
||||||
|
T6: EventOutput,
|
||||||
|
T7: EventOutput,
|
||||||
|
Out: Data,
|
||||||
|
F: 'static
|
||||||
|
+ Fn(
|
||||||
|
&Output<T1>,
|
||||||
|
&Output<T2>,
|
||||||
|
&Output<T3>,
|
||||||
|
&Output<T4>,
|
||||||
|
&Output<T5>,
|
||||||
|
&Output<T6>,
|
||||||
|
&Output<T7>,
|
||||||
|
) -> Out,
|
||||||
|
{
|
||||||
|
/// Constructor.
|
||||||
|
pub fn new(
|
||||||
|
label: Label,
|
||||||
|
t1: &T1,
|
||||||
|
t2: &T2,
|
||||||
|
t3: &T3,
|
||||||
|
t4: &T4,
|
||||||
|
t5: &T5,
|
||||||
|
t6: &T6,
|
||||||
|
t7: &T7,
|
||||||
|
function: F,
|
||||||
|
) -> Self {
|
||||||
|
let _src1 = t1.clone_ref();
|
||||||
|
let src2 = watch_stream(t2);
|
||||||
|
let src3 = watch_stream(t3);
|
||||||
|
let src4 = watch_stream(t4);
|
||||||
|
let src5 = watch_stream(t5);
|
||||||
|
let src6 = watch_stream(t6);
|
||||||
|
let src7 = watch_stream(t7);
|
||||||
|
let def = Map7Data { _src1, src2, src3, src4, src5, src6, src7, function };
|
||||||
|
let this = Self::construct(label, def);
|
||||||
|
let weak = this.downgrade();
|
||||||
|
t1.register_target(weak.into());
|
||||||
|
this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T1, T2, T3, T4, T5, T6, T7, F, Out> stream::EventConsumer<Output<T1>>
|
||||||
|
for OwnedMap7<T1, T2, T3, T4, T5, T6, T7, F>
|
||||||
|
where
|
||||||
|
T1: EventOutput,
|
||||||
|
T2: EventOutput,
|
||||||
|
T3: EventOutput,
|
||||||
|
T4: EventOutput,
|
||||||
|
T5: EventOutput,
|
||||||
|
T6: EventOutput,
|
||||||
|
T7: EventOutput,
|
||||||
|
Out: Data,
|
||||||
|
F: 'static
|
||||||
|
+ Fn(
|
||||||
|
&Output<T1>,
|
||||||
|
&Output<T2>,
|
||||||
|
&Output<T3>,
|
||||||
|
&Output<T4>,
|
||||||
|
&Output<T5>,
|
||||||
|
&Output<T6>,
|
||||||
|
&Output<T7>,
|
||||||
|
) -> Out,
|
||||||
|
{
|
||||||
|
fn on_event(&self, stack: CallStack, value1: &Output<T1>) {
|
||||||
|
let value2 = self.src2.value();
|
||||||
|
let value3 = self.src3.value();
|
||||||
|
let value4 = self.src4.value();
|
||||||
|
let value5 = self.src5.value();
|
||||||
|
let value6 = self.src6.value();
|
||||||
|
let value7 = self.src7.value();
|
||||||
|
let out = (self.function)(value1, &value2, &value3, &value4, &value5, &value6, &value7);
|
||||||
|
self.emit_event(stack, &out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T1, T2, T3, T4, T5, T6, T7, F> stream::InputBehaviors
|
||||||
|
for Map7Data<T1, T2, T3, T4, T5, T6, T7, F>
|
||||||
|
where
|
||||||
|
T1: EventOutput,
|
||||||
|
T2: EventOutput,
|
||||||
|
T3: EventOutput,
|
||||||
|
T4: EventOutput,
|
||||||
|
T5: EventOutput,
|
||||||
|
T6: EventOutput,
|
||||||
|
T7: EventOutput,
|
||||||
|
{
|
||||||
|
fn input_behaviors(&self) -> Vec<Link> {
|
||||||
|
vec![
|
||||||
|
Link::behavior(&self.src2),
|
||||||
|
Link::behavior(&self.src3),
|
||||||
|
Link::behavior(&self.src4),
|
||||||
|
Link::behavior(&self.src5),
|
||||||
|
Link::behavior(&self.src6),
|
||||||
|
Link::behavior(&self.src7),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T1, T2, T3, T4, T5, T6, T7, F> Debug for Map7Data<T1, T2, T3, T4, T5, T6, T7, F> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "Map7Data")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// ============
|
||||||
|
// === Map8 ===
|
||||||
|
// ============
|
||||||
|
|
||||||
|
pub struct Map8Data<T1, T2, T3, T4, T5, T6, T7, T8, F> {
|
||||||
|
_src1: T1,
|
||||||
|
src2: watch::Ref<T2>,
|
||||||
|
src3: watch::Ref<T3>,
|
||||||
|
src4: watch::Ref<T4>,
|
||||||
|
src5: watch::Ref<T5>,
|
||||||
|
src6: watch::Ref<T6>,
|
||||||
|
src7: watch::Ref<T7>,
|
||||||
|
src8: watch::Ref<T8>,
|
||||||
|
function: F,
|
||||||
|
}
|
||||||
|
pub type OwnedMap8<T1, T2, T3, T4, T5, T6, T7, T8, F> =
|
||||||
|
stream::Node<Map8Data<T1, T2, T3, T4, T5, T6, T7, T8, F>>;
|
||||||
|
pub type Map8<T1, T2, T3, T4, T5, T6, T7, T8, F> =
|
||||||
|
stream::WeakNode<Map8Data<T1, T2, T3, T4, T5, T6, T7, T8, F>>;
|
||||||
|
|
||||||
|
impl<T1, T2, T3, T4, T5, T6, T7, T8, F, Out> HasOutput
|
||||||
|
for Map8Data<T1, T2, T3, T4, T5, T6, T7, T8, F>
|
||||||
|
where
|
||||||
|
T1: EventOutput,
|
||||||
|
T2: EventOutput,
|
||||||
|
T3: EventOutput,
|
||||||
|
T4: EventOutput,
|
||||||
|
T5: EventOutput,
|
||||||
|
T6: EventOutput,
|
||||||
|
T7: EventOutput,
|
||||||
|
T8: EventOutput,
|
||||||
|
Out: Data,
|
||||||
|
F: 'static
|
||||||
|
+ Fn(
|
||||||
|
&Output<T1>,
|
||||||
|
&Output<T2>,
|
||||||
|
&Output<T3>,
|
||||||
|
&Output<T4>,
|
||||||
|
&Output<T5>,
|
||||||
|
&Output<T6>,
|
||||||
|
&Output<T7>,
|
||||||
|
&Output<T8>,
|
||||||
|
) -> Out,
|
||||||
|
{
|
||||||
|
type Output = Out;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T1, T2, T3, T4, T5, T6, T7, T8, F, Out> OwnedMap8<T1, T2, T3, T4, T5, T6, T7, T8, F>
|
||||||
|
where
|
||||||
|
T1: EventOutput,
|
||||||
|
T2: EventOutput,
|
||||||
|
T3: EventOutput,
|
||||||
|
T4: EventOutput,
|
||||||
|
T5: EventOutput,
|
||||||
|
T6: EventOutput,
|
||||||
|
T7: EventOutput,
|
||||||
|
T8: EventOutput,
|
||||||
|
Out: Data,
|
||||||
|
F: 'static
|
||||||
|
+ Fn(
|
||||||
|
&Output<T1>,
|
||||||
|
&Output<T2>,
|
||||||
|
&Output<T3>,
|
||||||
|
&Output<T4>,
|
||||||
|
&Output<T5>,
|
||||||
|
&Output<T6>,
|
||||||
|
&Output<T7>,
|
||||||
|
&Output<T8>,
|
||||||
|
) -> Out,
|
||||||
|
{
|
||||||
|
/// Constructor.
|
||||||
|
pub fn new(
|
||||||
|
label: Label,
|
||||||
|
t1: &T1,
|
||||||
|
t2: &T2,
|
||||||
|
t3: &T3,
|
||||||
|
t4: &T4,
|
||||||
|
t5: &T5,
|
||||||
|
t6: &T6,
|
||||||
|
t7: &T7,
|
||||||
|
t8: &T8,
|
||||||
|
function: F,
|
||||||
|
) -> Self {
|
||||||
|
let _src1 = t1.clone_ref();
|
||||||
|
let src2 = watch_stream(t2);
|
||||||
|
let src3 = watch_stream(t3);
|
||||||
|
let src4 = watch_stream(t4);
|
||||||
|
let src5 = watch_stream(t5);
|
||||||
|
let src6 = watch_stream(t6);
|
||||||
|
let src7 = watch_stream(t7);
|
||||||
|
let src8 = watch_stream(t8);
|
||||||
|
let def = Map8Data { _src1, src2, src3, src4, src5, src6, src7, src8, function };
|
||||||
|
let this = Self::construct(label, def);
|
||||||
|
let weak = this.downgrade();
|
||||||
|
t1.register_target(weak.into());
|
||||||
|
this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T1, T2, T3, T4, T5, T6, T7, T8, F, Out> stream::EventConsumer<Output<T1>>
|
||||||
|
for OwnedMap8<T1, T2, T3, T4, T5, T6, T7, T8, F>
|
||||||
|
where
|
||||||
|
T1: EventOutput,
|
||||||
|
T2: EventOutput,
|
||||||
|
T3: EventOutput,
|
||||||
|
T4: EventOutput,
|
||||||
|
T5: EventOutput,
|
||||||
|
T6: EventOutput,
|
||||||
|
T7: EventOutput,
|
||||||
|
T8: EventOutput,
|
||||||
|
Out: Data,
|
||||||
|
F: 'static
|
||||||
|
+ Fn(
|
||||||
|
&Output<T1>,
|
||||||
|
&Output<T2>,
|
||||||
|
&Output<T3>,
|
||||||
|
&Output<T4>,
|
||||||
|
&Output<T5>,
|
||||||
|
&Output<T6>,
|
||||||
|
&Output<T7>,
|
||||||
|
&Output<T8>,
|
||||||
|
) -> Out,
|
||||||
|
{
|
||||||
|
fn on_event(&self, stack: CallStack, value1: &Output<T1>) {
|
||||||
|
let value2 = self.src2.value();
|
||||||
|
let value3 = self.src3.value();
|
||||||
|
let value4 = self.src4.value();
|
||||||
|
let value5 = self.src5.value();
|
||||||
|
let value6 = self.src6.value();
|
||||||
|
let value7 = self.src7.value();
|
||||||
|
let value8 = self.src8.value();
|
||||||
|
let out =
|
||||||
|
(self.function)(value1, &value2, &value3, &value4, &value5, &value6, &value7, &value8);
|
||||||
|
self.emit_event(stack, &out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T1, T2, T3, T4, T5, T6, T7, T8, F> stream::InputBehaviors
|
||||||
|
for Map8Data<T1, T2, T3, T4, T5, T6, T7, T8, F>
|
||||||
|
where
|
||||||
|
T1: EventOutput,
|
||||||
|
T2: EventOutput,
|
||||||
|
T3: EventOutput,
|
||||||
|
T4: EventOutput,
|
||||||
|
T5: EventOutput,
|
||||||
|
T6: EventOutput,
|
||||||
|
T7: EventOutput,
|
||||||
|
T8: EventOutput,
|
||||||
|
{
|
||||||
|
fn input_behaviors(&self) -> Vec<Link> {
|
||||||
|
vec![
|
||||||
|
Link::behavior(&self.src2),
|
||||||
|
Link::behavior(&self.src3),
|
||||||
|
Link::behavior(&self.src4),
|
||||||
|
Link::behavior(&self.src5),
|
||||||
|
Link::behavior(&self.src6),
|
||||||
|
Link::behavior(&self.src7),
|
||||||
|
Link::behavior(&self.src8),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T1, T2, T3, T4, T5, T6, T7, T8, F> Debug for Map8Data<T1, T2, T3, T4, T5, T6, T7, T8, F> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "Map8Data")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// ============
|
||||||
|
// === Map8 ===
|
||||||
|
// ============
|
||||||
|
|
||||||
|
pub struct Map9Data<T1, T2, T3, T4, T5, T6, T7, T8, T9, F> {
|
||||||
|
_src1: T1,
|
||||||
|
src2: watch::Ref<T2>,
|
||||||
|
src3: watch::Ref<T3>,
|
||||||
|
src4: watch::Ref<T4>,
|
||||||
|
src5: watch::Ref<T5>,
|
||||||
|
src6: watch::Ref<T6>,
|
||||||
|
src7: watch::Ref<T7>,
|
||||||
|
src8: watch::Ref<T8>,
|
||||||
|
src9: watch::Ref<T9>,
|
||||||
|
function: F,
|
||||||
|
}
|
||||||
|
pub type OwnedMap9<T1, T2, T3, T4, T5, T6, T7, T8, T9, F> =
|
||||||
|
stream::Node<Map9Data<T1, T2, T3, T4, T5, T6, T7, T8, T9, F>>;
|
||||||
|
pub type Map9<T1, T2, T3, T4, T5, T6, T7, T8, T9, F> =
|
||||||
|
stream::WeakNode<Map9Data<T1, T2, T3, T4, T5, T6, T7, T8, T9, F>>;
|
||||||
|
|
||||||
|
impl<T1, T2, T3, T4, T5, T6, T7, T8, T9, F, Out> HasOutput
|
||||||
|
for Map9Data<T1, T2, T3, T4, T5, T6, T7, T8, T9, F>
|
||||||
|
where
|
||||||
|
T1: EventOutput,
|
||||||
|
T2: EventOutput,
|
||||||
|
T3: EventOutput,
|
||||||
|
T4: EventOutput,
|
||||||
|
T5: EventOutput,
|
||||||
|
T6: EventOutput,
|
||||||
|
T7: EventOutput,
|
||||||
|
T8: EventOutput,
|
||||||
|
T9: EventOutput,
|
||||||
|
Out: Data,
|
||||||
|
F: 'static
|
||||||
|
+ Fn(
|
||||||
|
&Output<T1>,
|
||||||
|
&Output<T2>,
|
||||||
|
&Output<T3>,
|
||||||
|
&Output<T4>,
|
||||||
|
&Output<T5>,
|
||||||
|
&Output<T6>,
|
||||||
|
&Output<T7>,
|
||||||
|
&Output<T8>,
|
||||||
|
&Output<T9>,
|
||||||
|
) -> Out,
|
||||||
|
{
|
||||||
|
type Output = Out;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T1, T2, T3, T4, T5, T6, T7, T8, T9, F, Out> OwnedMap9<T1, T2, T3, T4, T5, T6, T7, T8, T9, F>
|
||||||
|
where
|
||||||
|
T1: EventOutput,
|
||||||
|
T2: EventOutput,
|
||||||
|
T3: EventOutput,
|
||||||
|
T4: EventOutput,
|
||||||
|
T5: EventOutput,
|
||||||
|
T6: EventOutput,
|
||||||
|
T7: EventOutput,
|
||||||
|
T8: EventOutput,
|
||||||
|
T9: EventOutput,
|
||||||
|
Out: Data,
|
||||||
|
F: 'static
|
||||||
|
+ Fn(
|
||||||
|
&Output<T1>,
|
||||||
|
&Output<T2>,
|
||||||
|
&Output<T3>,
|
||||||
|
&Output<T4>,
|
||||||
|
&Output<T5>,
|
||||||
|
&Output<T6>,
|
||||||
|
&Output<T7>,
|
||||||
|
&Output<T8>,
|
||||||
|
&Output<T9>,
|
||||||
|
) -> Out,
|
||||||
|
{
|
||||||
|
/// Constructor.
|
||||||
|
pub fn new(
|
||||||
|
label: Label,
|
||||||
|
t1: &T1,
|
||||||
|
t2: &T2,
|
||||||
|
t3: &T3,
|
||||||
|
t4: &T4,
|
||||||
|
t5: &T5,
|
||||||
|
t6: &T6,
|
||||||
|
t7: &T7,
|
||||||
|
t8: &T8,
|
||||||
|
t9: &T9,
|
||||||
|
function: F,
|
||||||
|
) -> Self {
|
||||||
|
let _src1 = t1.clone_ref();
|
||||||
|
let src2 = watch_stream(t2);
|
||||||
|
let src3 = watch_stream(t3);
|
||||||
|
let src4 = watch_stream(t4);
|
||||||
|
let src5 = watch_stream(t5);
|
||||||
|
let src6 = watch_stream(t6);
|
||||||
|
let src7 = watch_stream(t7);
|
||||||
|
let src8 = watch_stream(t8);
|
||||||
|
let src9 = watch_stream(t9);
|
||||||
|
let def = Map9Data { _src1, src2, src3, src4, src5, src6, src7, src8, src9, function };
|
||||||
|
let this = Self::construct(label, def);
|
||||||
|
let weak = this.downgrade();
|
||||||
|
t1.register_target(weak.into());
|
||||||
|
this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T1, T2, T3, T4, T5, T6, T7, T8, T9, F, Out> stream::EventConsumer<Output<T1>>
|
||||||
|
for OwnedMap9<T1, T2, T3, T4, T5, T6, T7, T8, T9, F>
|
||||||
|
where
|
||||||
|
T1: EventOutput,
|
||||||
|
T2: EventOutput,
|
||||||
|
T3: EventOutput,
|
||||||
|
T4: EventOutput,
|
||||||
|
T5: EventOutput,
|
||||||
|
T6: EventOutput,
|
||||||
|
T7: EventOutput,
|
||||||
|
T8: EventOutput,
|
||||||
|
T9: EventOutput,
|
||||||
|
Out: Data,
|
||||||
|
F: 'static
|
||||||
|
+ Fn(
|
||||||
|
&Output<T1>,
|
||||||
|
&Output<T2>,
|
||||||
|
&Output<T3>,
|
||||||
|
&Output<T4>,
|
||||||
|
&Output<T5>,
|
||||||
|
&Output<T6>,
|
||||||
|
&Output<T7>,
|
||||||
|
&Output<T8>,
|
||||||
|
&Output<T9>,
|
||||||
|
) -> Out,
|
||||||
|
{
|
||||||
|
fn on_event(&self, stack: CallStack, value1: &Output<T1>) {
|
||||||
|
let value2 = self.src2.value();
|
||||||
|
let value3 = self.src3.value();
|
||||||
|
let value4 = self.src4.value();
|
||||||
|
let value5 = self.src5.value();
|
||||||
|
let value6 = self.src6.value();
|
||||||
|
let value7 = self.src7.value();
|
||||||
|
let value8 = self.src8.value();
|
||||||
|
let value9 = self.src9.value();
|
||||||
|
let out = (self.function)(
|
||||||
|
value1, &value2, &value3, &value4, &value5, &value6, &value7, &value8, &value9,
|
||||||
|
);
|
||||||
|
self.emit_event(stack, &out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T1, T2, T3, T4, T5, T6, T7, T8, T9, F> stream::InputBehaviors
|
||||||
|
for Map9Data<T1, T2, T3, T4, T5, T6, T7, T8, T9, F>
|
||||||
|
where
|
||||||
|
T1: EventOutput,
|
||||||
|
T2: EventOutput,
|
||||||
|
T3: EventOutput,
|
||||||
|
T4: EventOutput,
|
||||||
|
T5: EventOutput,
|
||||||
|
T6: EventOutput,
|
||||||
|
T7: EventOutput,
|
||||||
|
T8: EventOutput,
|
||||||
|
T9: EventOutput,
|
||||||
|
{
|
||||||
|
fn input_behaviors(&self) -> Vec<Link> {
|
||||||
|
vec![
|
||||||
|
Link::behavior(&self.src2),
|
||||||
|
Link::behavior(&self.src3),
|
||||||
|
Link::behavior(&self.src4),
|
||||||
|
Link::behavior(&self.src5),
|
||||||
|
Link::behavior(&self.src6),
|
||||||
|
Link::behavior(&self.src7),
|
||||||
|
Link::behavior(&self.src8),
|
||||||
|
Link::behavior(&self.src9),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T1, T2, T3, T4, T5, T6, T7, T8, T9, F> Debug
|
||||||
|
for Map9Data<T1, T2, T3, T4, T5, T6, T7, T8, T9, F>
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "Map9Data")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ================
|
// ================
|
||||||
// === AllWith2 ===
|
// === AllWith2 ===
|
||||||
// ================
|
// ================
|
||||||
|
Loading…
Reference in New Issue
Block a user