@@ -52,6 +52,9 @@ pub(crate) fn generate_class_files(
52
52
modules. push ( GeneratedClassModule {
53
53
class_name,
54
54
module_name,
55
+ own_notification_enum_name : generated_class
56
+ . has_own_notification_enum
57
+ . then_some ( generated_class. notification_enum_name ) ,
55
58
inherits_macro_ident : generated_class. inherits_macro_ident ,
56
59
is_pub : generated_class. has_pub_module ,
57
60
} ) ;
@@ -176,8 +179,16 @@ fn make_class(class: &Class, class_name: &TyName, ctx: &mut Context) -> Generate
176
179
let constants = make_constants ( & class. constants , class_name, ctx) ;
177
180
let inherits_macro = format_ident ! ( "inherits_transitive_{}" , class_name. rust_ty) ;
178
181
let all_bases = ctx. inheritance_tree ( ) . collect_all_bases ( class_name) ;
179
- let virtual_trait = make_virtual_methods_trait ( class, & all_bases, & virtual_trait_str, ctx) ;
180
- let notification_enum = make_notification_enum ( class_name, & all_bases, ctx) ;
182
+ let ( notification_enum, notification_enum_name) =
183
+ make_notification_enum ( class_name, & all_bases, ctx) ;
184
+ let virtual_trait = make_virtual_methods_trait (
185
+ class,
186
+ & all_bases,
187
+ & virtual_trait_str,
188
+ & notification_enum_name,
189
+ ctx,
190
+ ) ;
191
+ let notify_method = make_notify_method ( class_name, ctx) ;
181
192
182
193
let memory = if class_name. rust_ty == "Object" {
183
194
ident ( "DynamicRefCount" )
@@ -191,6 +202,7 @@ fn make_class(class: &Class, class_name: &TyName, ctx: &mut Context) -> Generate
191
202
let tokens = quote ! {
192
203
use godot_ffi as sys;
193
204
use crate :: engine:: * ;
205
+ use crate :: engine:: notify:: * ;
194
206
use crate :: builtin:: * ;
195
207
use crate :: obj:: { AsArg , Gd } ;
196
208
use sys:: GodotFfi as _;
@@ -207,6 +219,7 @@ fn make_class(class: &Class, class_name: &TyName, ctx: &mut Context) -> Generate
207
219
#notification_enum
208
220
impl #class_name {
209
221
#constructor
222
+ #notify_method
210
223
#methods
211
224
#constants
212
225
}
@@ -261,19 +274,43 @@ fn make_class(class: &Class, class_name: &TyName, ctx: &mut Context) -> Generate
261
274
262
275
GeneratedClass {
263
276
tokens,
277
+ notification_enum_name,
278
+ has_own_notification_enum : notification_enum. is_some ( ) ,
264
279
inherits_macro_ident : inherits_macro,
265
280
has_pub_module : !enums. is_empty ( ) ,
266
281
}
267
282
}
268
283
284
+ fn make_notify_method ( class_name : & TyName , ctx : & mut Context ) -> TokenStream {
285
+ let enum_name = ctx. notification_enum_name ( class_name) ;
286
+
287
+ quote ! {
288
+ /// Sends the `notification` to all classes inherited by the object, triggering calls to `on_notification()`.
289
+ ///
290
+ /// Starts from the highest ancestor (the `Object` class) and goes down the hierarchy.
291
+ ///
292
+ /// See [docs for `Object::notification()`](https://docs.godotengine.org/en/latest/classes/class_object.html#id3) in Godot.
293
+ pub fn issue_notification( & mut self , what: #enum_name) {
294
+ self . notification( i32 :: from( what) as i64 , false ) ;
295
+ }
296
+
297
+ /// Like [`Self::issue_notification()`], but starts at the most-derived class and goes up the hierarchy.
298
+ ///
299
+ /// See [docs for `Object::notification()`](https://docs.godotengine.org/en/latest/classes/class_object.html#id3) in Godot.
300
+ pub fn issue_notification_reversed( & mut self , what: #enum_name) {
301
+ self . notification( i32 :: from( what) as i64 , true ) ;
302
+ }
303
+ }
304
+ }
305
+
269
306
fn make_notification_enum (
270
307
class_name : & TyName ,
271
308
all_bases : & Vec < TyName > ,
272
309
ctx : & mut Context ,
273
- ) -> TokenStream {
310
+ ) -> ( Option < TokenStream > , Ident ) {
274
311
let Some ( all_constants) = ctx. notification_constants ( class_name) else {
275
312
// Class has no notification constants: reuse (direct/indirect) base enum
276
- return TokenStream :: new ( ) ;
313
+ return ( None , ctx . notification_enum_name ( class_name ) ) ;
277
314
} ;
278
315
279
316
// Collect all notification constants from current and base classes
@@ -287,6 +324,10 @@ fn make_notification_enum(
287
324
workaround_constant_collision ( & mut all_constants) ;
288
325
289
326
let enum_name = ctx. notification_enum_name ( class_name) ;
327
+ let doc_str = format ! (
328
+ "Notification type for class [`{c}`][crate::engine::{c}]." ,
329
+ c = class_name. rust_ty
330
+ ) ;
290
331
291
332
let mut notification_enumerators_pascal = Vec :: new ( ) ;
292
333
let mut notification_enumerators_ord = Vec :: new ( ) ;
@@ -295,8 +336,8 @@ fn make_notification_enum(
295
336
notification_enumerators_ord. push ( constant_value) ;
296
337
}
297
338
298
- quote ! {
299
- /// Notification type for class `#class_name`.
339
+ let code = quote ! {
340
+ # [ doc = #doc_str ]
300
341
///
301
342
/// Makes it easier to keep an overview all possible notification variants for a given class, including
302
343
/// notifications defined in base classes.
@@ -312,27 +353,31 @@ fn make_notification_enum(
312
353
Unknown ( i32 ) ,
313
354
}
314
355
315
- impl #enum_name {
356
+ impl From < i32 > for #enum_name {
316
357
/// Always succeeds, mapping unknown integers to the `Unknown` variant.
317
- pub fn from_i32 ( enumerator: i32 ) -> Self {
358
+ fn from ( enumerator: i32 ) -> Self {
318
359
match enumerator {
319
360
#(
320
361
#notification_enumerators_ord => Self :: #notification_enumerators_pascal,
321
362
) *
322
363
other_int => Self :: Unknown ( other_int) ,
323
364
}
324
365
}
366
+ }
325
367
326
- pub fn to_i32( self ) -> i32 {
327
- match self {
368
+ impl From <#enum_name> for i32 {
369
+ fn from( notification: #enum_name) -> i32 {
370
+ match notification {
328
371
#(
329
- Self :: #notification_enumerators_pascal => #notification_enumerators_ord,
372
+ #enum_name :: #notification_enumerators_pascal => #notification_enumerators_ord,
330
373
) *
331
- Self :: Unknown ( int) => int,
374
+ #enum_name :: Unknown ( int) => int,
332
375
}
333
376
}
334
377
}
335
- }
378
+ } ;
379
+
380
+ ( Some ( code) , enum_name)
336
381
}
337
382
338
383
/// Workaround for Godot bug https://github.com/godotengine/godot/issues/75839
@@ -408,23 +453,36 @@ fn make_builtin_class(
408
453
}
409
454
410
455
fn make_module_file ( classes_and_modules : Vec < GeneratedClassModule > ) -> TokenStream {
411
- let decls = classes_and_modules. iter ( ) . map ( |m| {
456
+ let mut class_decls = Vec :: new ( ) ;
457
+ let mut notify_decls = Vec :: new ( ) ;
458
+
459
+ for m in classes_and_modules. iter ( ) {
412
460
let GeneratedClassModule {
413
461
module_name,
414
462
class_name,
463
+ own_notification_enum_name,
415
464
is_pub,
416
465
..
417
466
} = m;
418
467
let virtual_trait_name = ident ( & class_name. virtual_trait_name ( ) ) ;
419
468
420
469
let vis = is_pub. then_some ( quote ! { pub } ) ;
421
470
422
- quote ! {
471
+ let class_decl = quote ! {
423
472
#vis mod #module_name;
424
473
pub use #module_name:: re_export:: #class_name;
425
474
pub use #module_name:: re_export:: #virtual_trait_name;
475
+ } ;
476
+ class_decls. push ( class_decl) ;
477
+
478
+ if let Some ( enum_name) = own_notification_enum_name {
479
+ let notify_decl = quote ! {
480
+ pub use super :: #module_name:: re_export:: #enum_name;
481
+ } ;
482
+
483
+ notify_decls. push ( notify_decl) ;
426
484
}
427
- } ) ;
485
+ }
428
486
429
487
let macros = classes_and_modules. iter ( ) . map ( |m| {
430
488
let GeneratedClassModule {
@@ -440,7 +498,11 @@ fn make_module_file(classes_and_modules: Vec<GeneratedClassModule>) -> TokenStre
440
498
} ) ;
441
499
442
500
quote ! {
443
- #( #decls ) *
501
+ #( #class_decls ) *
502
+
503
+ pub mod notify {
504
+ #( #notify_decls ) *
505
+ }
444
506
445
507
#[ doc( hidden) ]
446
508
pub mod class_macros {
@@ -1076,12 +1138,13 @@ fn make_virtual_methods_trait(
1076
1138
class : & Class ,
1077
1139
all_bases : & [ TyName ] ,
1078
1140
trait_name : & str ,
1141
+ notification_enum_name : & Ident ,
1079
1142
ctx : & mut Context ,
1080
1143
) -> TokenStream {
1081
1144
let trait_name = ident ( trait_name) ;
1082
1145
1083
1146
let virtual_method_fns = make_all_virtual_methods ( class, all_bases, ctx) ;
1084
- let special_virtual_methods = special_virtual_methods ( ) ;
1147
+ let special_virtual_methods = special_virtual_methods ( notification_enum_name ) ;
1085
1148
1086
1149
quote ! {
1087
1150
#[ allow( unused_variables) ]
@@ -1093,7 +1156,7 @@ fn make_virtual_methods_trait(
1093
1156
}
1094
1157
}
1095
1158
1096
- fn special_virtual_methods ( ) -> TokenStream {
1159
+ fn special_virtual_methods ( notification_enum_name : & Ident ) -> TokenStream {
1097
1160
quote ! {
1098
1161
fn register_class( builder: & mut crate :: builder:: ClassBuilder <Self >) {
1099
1162
unimplemented!( )
@@ -1126,7 +1189,7 @@ fn special_virtual_methods() -> TokenStream {
1126
1189
/// See also in Godot docs:
1127
1190
/// * [`Object::_notification`](https://docs.godotengine.org/en/stable/classes/class_object.html#class-object-method-notification).
1128
1191
/// * [Godot notifications](https://docs.godotengine.org/en/stable/tutorials/best_practices/godot_notifications.html).
1129
- fn on_notification( & mut self , what: i32 ) {
1192
+ fn on_notification( & mut self , what: #notification_enum_name ) {
1130
1193
unimplemented!( )
1131
1194
}
1132
1195
}
0 commit comments