Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 52 additions & 3 deletions godot-core/src/registry/signal/typed_signal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ use crate::meta::{InParamTuple, ObjectToOwned, UniformObjectDeref};
use crate::obj::{Gd, GodotClass, WithSignals};
use crate::registry::signal::signal_receiver::{IndirectSignalReceiver, SignalReceiver};

// ----------------------------------------------------------------------------------------------------------------------------------------------

/// Type-safe version of a Godot signal.
///
/// Short-lived type, only valid in the scope of its surrounding object type `C`, for lifetime `'c`. The generic argument `Ps` represents
Expand All @@ -42,13 +40,65 @@ use crate::registry::signal::signal_receiver::{IndirectSignalReceiver, SignalRec
/// - [`builder()`][Self::builder] for more complex setups (such as choosing [`ConnectFlags`] or making thread-safe connections).
///
/// # Emitting a signal
// --------------------
/// Code-generated signal types provide a method `emit(...)`, which adopts the names and types of the `#[signal]` parameter list.
/// In most cases, that's the method you are looking for.
///
/// For generic use, you can also use [`emit_tuple()`][Self::emit_tuple], which does not provide parameter names.
///
/// # Generic programming and code reuse
/// If you want to build higher-level abstractions that operate on `TypedSignal`, you will need the [`SignalReceiver`] trait.
///
// Keep in sync with https://godot-rust.github.io/book/register/signals.html#admonition-availability-of-signal-api.
/// # Availability
/// For typed signals to be available, you need:
/// - A `#[godot_api] impl MyClass {}` block.
/// - This must be an inherent impl, the `I*` trait `impl` won't be enough.
/// - Leave the impl empty if necessary.
/// - A `Base<T>` field.
///
/// Signals, typed or not, cannot be declared in secondary impl blocks (those annotated with `#[godot_api(secondary)]` attribute).
/// # Examples
/// ```no_run
/// # use godot::prelude::*;
/// # use godot::classes::Button;
/// # #[derive(GodotClass)]
/// # #[class(init,base=Node)]
/// # pub struct ExampleClass {
/// # button: OnEditor<Gd<Button>>,
/// # other_button: OnEditor<Gd<Button>>,
/// # base: Base<Node>,
/// # }
/// #[godot_api]
/// impl ExampleClass {
/// #[signal]
/// fn signal();
/// fn method(&mut self) { /* ... */ }
/// fn method_with_args(&mut self, value: bool) { /* ... */ }
/// }
/// impl ExampleClass {
/// fn example(&mut self) {
/// // Connect Self to Self (Self::method).
/// self.signals().signal().connect_self(Self::method);
/// // Connect Self to Self (closure).
/// self.signals()
/// .signal()
/// .connect_self(|s| s.method_with_args(true));
/// // Connect other to Self (Self::method).
/// self.button
/// .signals()
/// .pressed()
/// .connect_other(self, Self::method);
/// // Connect other to other (closure).
/// self.button
/// .signals()
/// .toggled()
/// .connect_other(&*self.other_button, |other_button, toggled| {
/// other_button.set_pressed(toggled)
/// });
/// }
/// }
/// ```
pub struct TypedSignal<'c, C: WithSignals, Ps> {
/// In Godot, valid signals (unlike funcs) are _always_ declared in a class and become part of each instance. So there's always an object.
object: C::__SignalObj<'c>,
Expand Down Expand Up @@ -214,7 +264,6 @@ impl<C: WithSignals, Ps: InParamTuple + 'static> TypedSignal<'_, C, Ps> {
/// - Any `&Gd<OtherC>` (e.g.: `&Gd<Node>`, `&Gd<CustomUserClass>`).
/// - `&OtherC`, as long as `OtherC` is a user class that contains a `base` field (it implements the
/// [`WithBaseField`][crate::obj::WithBaseField] trait).
///
/// ---
///
/// - To connect to methods on the object that owns this signal, use [`connect_self()`][Self::connect_self].
Expand Down
Loading