[−][src]Struct azul_core::callbacks::Ref
The two-way binding system
A fundamental problem in UI development is where and how to store
states of widgets, without impacting reusability, extensability or
performance. Azul solves this problem using a type-erased
Rc<RefCell<Box<Any>>>
type (RefAny
), whic can be up and downcasted to
a Rc<RefCell<Box<T>>>
type (Ref<T>
). Ref
and RefAny
exist mostly to
reduce typing and to prevent multiple mutable access to the inner
RefCell
at compile time. Azul stores all RefAny
s inside the Dom
tree
and does NOT clone or mutate them at all. Only user-defined callbacks
or the default callbacks have access to the RefAny
data.
Overriding the default behaviour of widgets
While Rust does not support inheritance with language constructs such
as @override
(Java) or the override
keyword in C#, emulating structs
that can change their behaviour at runtime is quite easy. Imagine a
struct in which all methods are stored as public function pointers
inside the struct itself:
// The struct has all methods as function pointers, // so that they can be "overridden" and exchanged with other // implementations if necessary struct A { pub function_a: fn(&A, i32) -> i32, pub function_b: fn(&A) -> &'static str, } impl A { pub fn default_impl_a(&self, num: i32) -> i32 { num + num } pub fn default_impl_b(&self) -> &'static str { "default b method!" } // Don't call default_impl_a() directly, just the function pointer pub fn do_a(&self, num: i32) -> i32 { (self.function_a)(self, num) } pub fn do_b(&self) -> &'static str { (self.function_b)(self) } } // Here we provide the default ("base class") implementation impl Default for A { fn default() -> A { A { function_a: A::default_impl_a, function_b: A::default_impl_b, } } } // Alternative function that will override the original method fn override_a(_: &A, num: i32) -> i32 { num * num } fn main() { let mut a = A::default(); println!("{}", a.do_a(5)); // prints "10" (5 + 5) println!("{}", a.do_b()); // prints "default b method" a.function_a = override_a; // Here we override the behaviour println!("{}", a.do_a(5)); // prints "25" (5 * 5) println!("{}", a.do_b()); // still prints "default b method", since method isn't overridden }
Applied to widgets, the "A" class (a placeholder for a "Button", "Table" or other widget) can look something like this:
fn layout(&self, _: &LayoutInfo) -> Dom { Spreadsheet::new() .override_oncellchange(my_func_1) .override_onworkspacechange(my_func_2) .override_oncellselect(my_func_3) .dom() }
The spreadsheet has some "default" event handlers, which can be exchanged for custom implementations via an open API. The benefit is that functions can be mixed and matched, and widgets can be composed of sub-widgets as well as be re-used. Another benefit is that now the widget can react to "custom" events such as "oncellchange" or "oncellselect", without Azul knowing that such events even exist. The downside is that this coding style requires more work on behalf of the widget designer (but not the user).
Implementations
impl<T: 'static> Ref<T>
[src]
pub fn new(data: T) -> Self
[src]
pub fn borrow(&self) -> StdRef<T>
[src]
pub fn borrow_mut(&mut self) -> StdRefMut<T>
[src]
pub fn get_type_name(&self) -> &'static str
[src]
pub fn upcast(self) -> RefAny
[src]
Trait Implementations
impl<T: 'static> Clone for Ref<T>
[src]
fn clone(&self) -> Self
[src]
fn clone_from(&mut self, source: &Self)
1.0.0[src]
impl<T: Debug + 'static> Debug for Ref<T>
[src]
impl<T: Default + 'static> Default for Ref<T>
[src]
impl<T: Eq + 'static> Eq for Ref<T>
[src]
impl<T: 'static> From<Ref<T>> for RefAny
[src]
impl<T: 'static + Hash> Hash for Ref<T>
[src]
fn hash<H>(&self, state: &mut H) where
H: Hasher,
[src]
H: Hasher,
fn hash_slice<H>(data: &[Self], state: &mut H) where
H: Hasher,
1.3.0[src]
H: Hasher,
impl<T: Ord + 'static> Ord for Ref<T>
[src]
fn cmp(&self, other: &Ref<T>) -> Ordering
[src]
#[must_use]fn max(self, other: Self) -> Self
1.21.0[src]
#[must_use]fn min(self, other: Self) -> Self
1.21.0[src]
#[must_use]fn clamp(self, min: Self, max: Self) -> Self
[src]
impl<T: PartialEq + 'static> PartialEq<Ref<T>> for Ref<T>
[src]
impl<T: PartialOrd + 'static> PartialOrd<Ref<T>> for Ref<T>
[src]
fn partial_cmp(&self, other: &Ref<T>) -> Option<Ordering>
[src]
fn lt(&self, other: &Ref<T>) -> bool
[src]
fn le(&self, other: &Ref<T>) -> bool
[src]
fn gt(&self, other: &Ref<T>) -> bool
[src]
fn ge(&self, other: &Ref<T>) -> bool
[src]
impl<T: 'static> StructuralEq for Ref<T>
[src]
impl<T: 'static> StructuralPartialEq for Ref<T>
[src]
Auto Trait Implementations
impl<T> !RefUnwindSafe for Ref<T>
impl<T> !Send for Ref<T>
impl<T> !Sync for Ref<T>
impl<T> Unpin for Ref<T>
impl<T> !UnwindSafe for Ref<T>
Blanket Implementations
impl<T> Any for T where
T: 'static + ?Sized,
[src]
T: 'static + ?Sized,
impl<T> Borrow<T> for T where
T: ?Sized,
[src]
T: ?Sized,
impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]
T: ?Sized,
fn borrow_mut(&mut self) -> &mut T
[src]
impl<T> From<T> for T
[src]
impl<T, U> Into<U> for T where
U: From<T>,
[src]
U: From<T>,
impl<T> ToOwned for T where
T: Clone,
[src]
T: Clone,
type Owned = T
The resulting type after obtaining ownership.
fn to_owned(&self) -> T
[src]
fn clone_into(&self, target: &mut T)
[src]
impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]
U: Into<T>,
type Error = Infallible
The type returned in the event of a conversion error.
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]
impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]
U: TryFrom<T>,