Skip to content

Commit c8b2e98

Browse files
committed
Implement builtin type Signal
1 parent 52628a0 commit c8b2e98

File tree

4 files changed

+194
-55
lines changed

4 files changed

+194
-55
lines changed

godot-core/src/builtin/macros.rs

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -123,34 +123,6 @@ macro_rules! impl_builtin_traits {
123123
)
124124
}
125125

126-
macro_rules! impl_builtin_stub {
127-
// ($Class:ident, $OpaqueTy:ident $( ; )? $( $Traits:ident ),* ) => {
128-
($Class:ident, $OpaqueTy:ident) => {
129-
#[repr(C)]
130-
// #[derive(Copy, Clone)]
131-
pub struct $Class {
132-
opaque: sys::types::$OpaqueTy,
133-
}
134-
135-
impl $Class {
136-
fn from_opaque(opaque: sys::types::$OpaqueTy) -> Self {
137-
Self { opaque }
138-
}
139-
}
140-
141-
// SAFETY:
142-
// This is simply a wrapper around an `Opaque` value representing a value of the type.
143-
// So this is safe.
144-
unsafe impl GodotFfi for $Class {
145-
fn variant_type() -> sys::VariantType {
146-
sys::VariantType::$Class
147-
}
148-
149-
ffi_methods! { type sys::GDExtensionTypePtr = *mut Opaque; .. }
150-
}
151-
};
152-
}
153-
154126
macro_rules! impl_builtin_froms {
155127
($To:ty; $($From:ty => $from_fn:ident),* $(,)?) => {
156128
$(impl From<&$From> for $To {

godot-core/src/builtin/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ pub use basis::*;
4242
pub use callable::*;
4343
pub use color::*;
4444
pub use dictionary_inner::Dictionary;
45-
pub use others::*;
4645
pub use packed_array::*;
4746
pub use plane::*;
4847
pub use projection::*;
@@ -51,6 +50,7 @@ pub use real_inner::*;
5150
pub use rect2::*;
5251
pub use rect2i::*;
5352
pub use rid::*;
53+
pub use signal::*;
5454
pub use string::*;
5555
pub use transform2d::*;
5656
pub use transform3d::*;
@@ -84,14 +84,14 @@ mod aabb;
8484
mod basis;
8585
mod callable;
8686
mod color;
87-
mod others;
8887
mod packed_array;
8988
mod plane;
9089
mod projection;
9190
mod quaternion;
9291
mod rect2;
9392
mod rect2i;
9493
mod rid;
94+
mod signal;
9595
mod string;
9696
mod transform2d;
9797
mod transform3d;

godot-core/src/builtin/others.rs

Lines changed: 0 additions & 25 deletions
This file was deleted.

godot-core/src/builtin/signal.rs

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
/*
2+
* Copyright (c) godot-rust; Bromeon and contributors.
3+
* This Source Code Form is subject to the terms of the Mozilla Public
4+
* License, v. 2.0. If a copy of the MPL was not distributed with this
5+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
6+
*/
7+
8+
use std::fmt;
9+
10+
// Stub for various other built-in classes, which are currently incomplete, but whose types
11+
// are required for codegen
12+
use godot_ffi as sys;
13+
use sys::{ffi_methods, GodotFfi};
14+
15+
use crate::{
16+
builtin::meta::ToGodot,
17+
engine::{global::Error, object::ConnectFlags, Object},
18+
obj::{EngineEnum, Gd, GodotClass, InstanceId},
19+
};
20+
21+
use super::{
22+
inner,
23+
meta::{impl_godot_as_self, FromGodot, GodotType},
24+
Array, Callable, Dictionary, StringName, Variant,
25+
};
26+
27+
/// A `Signal` represents a signal of an Object instance in Godot.
28+
///
29+
/// Signals are composed of a reference to an `Object` and the name of the signal on this object.
30+
#[repr(C, align(8))]
31+
pub struct Signal {
32+
opaque: sys::types::OpaqueSignal,
33+
}
34+
35+
impl Signal {
36+
fn from_opaque(opaque: sys::types::OpaqueSignal) -> Self {
37+
Self { opaque }
38+
}
39+
40+
/// Create a signal for the signal `object::signal_name`.
41+
///
42+
/// _Godot equivalent: `Signal(Object object, StringName signal)`_
43+
pub fn from_object_signal<T, S>(object: &Gd<T>, signal_name: S) -> Self
44+
where
45+
T: GodotClass,
46+
S: Into<StringName>,
47+
{
48+
let signal = signal_name.into();
49+
unsafe {
50+
sys::from_sys_init_or_init_default::<Self>(|self_ptr| {
51+
let ctor = sys::builtin_fn!(signal_from_object_signal);
52+
let raw = object.to_ffi();
53+
let args = [raw.as_arg_ptr(), signal.sys_const()];
54+
ctor(self_ptr, args.as_ptr());
55+
})
56+
}
57+
}
58+
59+
/// Connects this signal to the specified callable.
60+
///
61+
/// Optional flags can be also added to configure the connection's behavior (see [`ConnectFlags`](crate::engine::object::ConnectFlags) constants).
62+
/// You can provide additional arguments to the connected callable by using `Callable::bind`.
63+
///
64+
/// A signal can only be connected once to the same `Callable`. If the signal is already connected,
65+
/// returns [`Error::ERR_INVALID_PARAMETER`](crate::engine::global::Error::ERR_INVALID_PARAMETER) and
66+
/// pushes an error message, unless the signal is connected with `ConnectFlags::CONNECT_REFERENCE_COUNTED`.
67+
/// To prevent this, use [`Self::is_connected`](Self::is_connected) first to check for existing connections.
68+
pub fn connect(&self, callable: Callable, flags: ConnectFlags) -> Error {
69+
let error = self.as_inner().connect(callable, flags.ord() as i64);
70+
71+
Error::from_godot(error as i32)
72+
}
73+
74+
/// Disconnects this signal from the specified Callable.
75+
///
76+
/// If the connection does not exist, generates an error. Use []`Self::is_connected`](Self::is_connected)
77+
/// to make sure that the connection exists.
78+
pub fn disconnect(&self, callable: Callable) {
79+
self.as_inner().disconnect(callable);
80+
}
81+
82+
/// Emits this signal.
83+
///
84+
/// All Callables connected to this signal will be triggered.
85+
pub fn emit(&self, varargs: &[Variant]) {
86+
let Some(mut object) = self.object() else {
87+
return;
88+
};
89+
90+
object.emit_signal(self.name(), varargs);
91+
}
92+
93+
/// Returns an `Array` of connections for this signal.
94+
///
95+
/// Each connection is represented as a Dictionary that contains three entries:
96+
/// - `signal` is a reference to this `Signal`;
97+
/// - `callable` is a reference to the connected `Callable`;
98+
/// - `flags` is a combination of `ConnectFlags`.
99+
///
100+
/// _Godot equivalent: `get_connections`_
101+
pub fn connections(&self) -> Array<Dictionary> {
102+
self.as_inner()
103+
.get_connections()
104+
.iter_shared()
105+
.map(|variant| variant.to())
106+
.collect()
107+
}
108+
109+
/// Returns the name of the signal.
110+
pub fn name(&self) -> StringName {
111+
self.as_inner().get_name()
112+
}
113+
114+
/// Returns the object to which this signal belongs.
115+
///
116+
/// Returns `None` when this signal doesn't have any object.
117+
///
118+
/// _Godot equivalent: `get_object`_
119+
pub fn object(&self) -> Option<Gd<Object>> {
120+
self.as_inner().get_object()
121+
}
122+
123+
/// Returns the ID of this signal's object, see also [`Gd::instance_id`].
124+
///
125+
/// Returns `None` when this signal doesn't have any object.
126+
///
127+
/// _Godot equivalent: `get_object_id`_
128+
pub fn object_id(&self) -> Option<InstanceId> {
129+
let id = self.as_inner().get_object_id();
130+
InstanceId::try_from_i64(id)
131+
}
132+
133+
/// Returns `true` if the specified [`Callable`] is connected to this signal.
134+
pub fn is_connected(&self, callable: Callable) -> bool {
135+
self.as_inner().is_connected(callable)
136+
}
137+
138+
/// Returns `true` if the signal's name does not exist in its object, or the object is not valid.
139+
pub fn is_null(&self) -> bool {
140+
self.as_inner().is_null()
141+
}
142+
143+
#[doc(hidden)]
144+
pub fn as_inner(&self) -> inner::InnerSignal {
145+
inner::InnerSignal::from_outer(self)
146+
}
147+
}
148+
149+
unsafe impl GodotFfi for Signal {
150+
fn variant_type() -> sys::VariantType {
151+
sys::VariantType::Signal
152+
}
153+
154+
ffi_methods! { type sys::GDExtensionTypePtr = *mut Opaque;
155+
fn from_sys;
156+
fn sys;
157+
fn from_sys_init;
158+
fn move_return_ptr;
159+
}
160+
161+
unsafe fn from_arg_ptr(ptr: sys::GDExtensionTypePtr, _call_type: sys::PtrcallType) -> Self {
162+
Self::from_sys(ptr)
163+
}
164+
}
165+
166+
impl_builtin_traits! {
167+
for Signal {
168+
Clone => signal_construct_copy;
169+
Drop => signal_destroy;
170+
PartialEq => signal_operator_equal;
171+
}
172+
}
173+
174+
impl_godot_as_self!(Signal);
175+
176+
impl fmt::Debug for Signal {
177+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
178+
let method = self.name();
179+
let object = self.object();
180+
181+
f.debug_struct("Callable")
182+
.field("method", &method)
183+
.field("object", &object)
184+
.finish()
185+
}
186+
}
187+
188+
impl fmt::Display for Signal {
189+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
190+
write!(f, "{}", self.to_variant())
191+
}
192+
}

0 commit comments

Comments
 (0)