I figured out what I needed to do.
Incase anyone else comes across it, here is what I learned from zdrmlpzdrmlp
Project Settings > Autoload > add a new script. this is where i added EventBus.cs
now this class can be referenced anywhere by
GetNode<EventBus>("/root/EventBus");
Here is my definition for EventBus. it has 2 signals, SaveStarted and SaveCompleted. Note that it’s required that they end in “EventHandler”
public partial class EventBus : Node
{
[Signal]
public delegate void SaveStartedEventHandler();
[Signal]
public delegate void SaveCompletedEventHandler();
}
Here is my SaveButton class.
I create a private property _eventBus, then set the method that should be run when the SaveCompleted signal is emitted.
in the editor i configure the “pressed” signal to trigger SaveStarted in this class.
SaveStarted will emit a signal “SaveStarted” from the event bus, and disable the button.
public partial class SaveButton : Button
{
private EventBus _eventBus;
public override void _Ready()
{
_eventBus = GetNode<EventBus>("/root/EventBus");
_eventBus.SaveCompleted += SaveComplete;
}
private void SaveStarted()
{
GD.Print("Save Started");
Disabled = true;
_eventBus.EmitSignal(nameof(EventBus.SaveStarted));
}
public void SaveComplete()
{
GD.Print("Save Completed");
Disabled = false;
}
}
In my Root node class (not the actual class, just the parts relevant to the discussion)
I again get the EventBus in a private property, then add the Save method to the SaveStarted event. now when a SaveStarted signal is emitted, i can run some save code (not yet implemented) and once it is completed emit the SaveCompleted signal.
This will trigger SaveComplete in the SaveButton class, which will reenable the button.
public partial class Root : Control
{
private EventBus _eventBus;
public override void _Ready()
{
_eventBus = GetNode<EventBus>("/root/EventBus");
_eventBus.SaveStarted += Save;
}
private void Save()
{
GD.Print("Saved");
_eventBus.EmitSignal(nameof(EventBus.SaveCompleted));
}
}
Hopefully this helps somebody else. I’ve included print statements to help verify it is working.
if configured correctly, clicking the save button should print
Save Started
Saved
Save Completed
Edit:
For posterity, incase anyone gets frustrated because I didn’t do what I original asked, this is how you would get a reference to the node that emitted the signal:
_eventBus.EmitSignal(nameof(EventBus.SaveStarted), this);
[Signal]
public delegate void SaveStartedEventHandler(Button button);
private void Save(Button button)
If you absolutely must pass a reference to the emitting node (in this case, SaveButton) you simply need to define the event handler to expect a reference to whatever object type you intend to emit as an arugment, then pass “this” as an argument in EmitSignal.
I didn’t do it this way because I felt that it was probably bad practice for my root node to have any control over the behavior of my button. Rather, the button itself should simply react appropriately to being pushed without any other modules being concerned with implementation details.