ferroui_reactiveui/binding/command_binding/
creates_command_binding_via_command_parameter.rs1use crate::binding::bindings::BindingAffinity;
11use crate::binding::interfaces::{CommandEventSubscription, CommandParameter, ICreatesCommandBinding};
12use crate::reactive_command::ICommand;
13use ferroui_reactive::disposables::{CompositeDisposable, Disposable};
14use ferroui_reactive::ObservableExt;
15use ferroui_system::component_model::PropertyPath;
16use ferroui_system::{IDisposable, IObservable};
17use std::any::{Any, TypeId};
18use std::fmt;
19use std::rc::Rc;
20
21pub struct CreatesCommandBindingViaCommandParameter<C> {
28 command: PropertyPath<Rc<C>, Option<Rc<dyn ICommand>>>,
29 set_command: Rc<dyn Fn(&C, Option<Rc<dyn ICommand>>)>,
30 command_parameter: PropertyPath<Rc<C>, CommandParameter>,
31 set_command_parameter: Rc<dyn Fn(&C, CommandParameter)>,
32}
33
34impl<C> fmt::Debug for CreatesCommandBindingViaCommandParameter<C> {
35 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36 f.debug_struct("CreatesCommandBindingViaCommandParameter").finish_non_exhaustive()
37 }
38}
39
40impl<C: 'static> CreatesCommandBindingViaCommandParameter<C> {
41 pub fn new(
44 command: PropertyPath<Rc<C>, Option<Rc<dyn ICommand>>>,
45 set_command: impl Fn(&C, Option<Rc<dyn ICommand>>) + 'static,
46 command_parameter: PropertyPath<Rc<C>, CommandParameter>,
47 set_command_parameter: impl Fn(&C, CommandParameter) + 'static,
48 ) -> Self {
49 Self { command, set_command: Rc::new(set_command), command_parameter, set_command_parameter: Rc::new(set_command_parameter) }
50 }
51}
52
53impl<C: 'static> ICreatesCommandBinding for CreatesCommandBindingViaCommandParameter<C> {
54 fn get_affinity_for_object(&self, target_type: TypeId, has_event_target: bool) -> i32 {
55 if has_event_target || target_type != TypeId::of::<C>() {
56 return 0;
57 }
58 BindingAffinity::EXPLICIT
59 }
60
61 fn bind_command_to_object(
62 &self,
63 command: Option<Rc<dyn ICommand>>,
64 target: Option<Rc<dyn Any>>,
65 command_parameter: Rc<dyn IObservable<CommandParameter>>,
66 ) -> Option<Rc<dyn IDisposable>> {
67 let command = command?;
68 let control = target?.downcast::<C>().ok()?;
69
70 let original_command = self.command.get(&control);
72 let original_parameter = self.command_parameter.get(&control);
73
74 let set_parameter = self.set_command_parameter.clone();
76 let parameter_control = control.clone();
77 let parameters = command_parameter.subscribe_next(move |parameter| set_parameter(¶meter_control, parameter));
78 (self.set_command)(&control, Some(command));
79
80 let set_command = self.set_command.clone();
81 let restore_parameter = self.set_command_parameter.clone();
82 let restore = Disposable::create(move || {
83 set_command(&control, original_command);
84 restore_parameter(&control, original_parameter);
85 });
86 Some(CompositeDisposable::from_disposables([parameters, restore]))
87 }
88
89 fn bind_command_to_object_event(
91 &self,
92 _command: Option<Rc<dyn ICommand>>,
93 _target: Option<Rc<dyn Any>>,
94 _command_parameter: Rc<dyn IObservable<CommandParameter>>,
95 _event_name: &str,
96 ) -> Option<Rc<dyn IDisposable>> {
97 None
98 }
99
100 fn bind_command_to_object_with_handlers(
102 &self,
103 _command: Option<Rc<dyn ICommand>>,
104 _target: Option<Rc<dyn Any>>,
105 _command_parameter: Rc<dyn IObservable<CommandParameter>>,
106 _subscription: CommandEventSubscription,
107 ) -> Option<Rc<dyn IDisposable>> {
108 None
109 }
110}