docs
Systems
Presentation
UISystem
Architecture and Design

Overview

The UISystem sits between UI MonoBehaviours and the SaffronLibrary message buses. It has two directions of traffic:

  • Commands in: UI components register themselves, and other systems send UI-domain commands. These arrive at a UIFlowController through the command bus, and the flow controller routes them to registered components.
  • Events out: UI components raise UI events describing what happened, such as a click or a page opening. These go to the event bus through BusUtility.

Design patterns in the code

  • Static factory classes. UICommandFactory and UIEventFactory are static classes whose methods build a message and send it. Callers never construct Command or Event objects themselves for UI work. UIEventFactory is declared partial, so it can be extended in other files.
  • Typed parameter keys. UIParamKeys declares static readonly ParamKey<T> fields. Each key fixes the type of its value, so values are read back without casting.
  • Key-name constants. UIParamKeyNames holds the string names for every key. UIParamKeys builds its keys from those names, so the names are defined in one place.
  • Base class with abstract hooks. UIFlowController extends FlowController. It supplies the Domain value (Domain.UI) and overrides HandleCommand. The base class calls these from its Init, which registers the controller on the command bus. UIRoot is an abstract MonoBehaviour that requires a RegistrationKey from each derived class.
  • Keyed registries. UIFlowController keeps two dictionaries keyed by registration string: one for all registered IFlowControllable components, and one for those that also implement ICommandProcessor.
  • Verb enums. Each message family has its own verb enum: UICommandVerb for commands, UIEventVerb for events, and UIRequestVerb for requests. The receiving code switches on the verb to choose the action.

Connections to dependencies

  • Contracts. Domain.UI identifies the UI domain. CoreParamKeys supplies the shared Key, Tag, and DomainContext keys. The UI system uses CoreParamKeys.Key as the routing key for both registration and processing.
  • Params. Every command and event carries a Params container. The UI system writes values with Set and reads them with Get, TryGet, or Has.
  • Commands. Command.Create builds the command envelope. ICommand exposes TargetDomain, Verb, and Params. IFlowControllable and ICommandProcessor are the interfaces that registered components implement.
  • Events. Event is the envelope for UI events. UIEventFactory builds these and passes them to the bus.
  • Bus. BusUtility.Send delivers commands. BusUtility.Raise delivers events. The UI system does not call the bus registry directly.
  • Flow. FlowController owns the UI domain. Its Init registers HandleCommand on the command bus for Domain.UI.

Key concepts and terminology

  • Domain: The owner of a set of commands. The UI system owns Domain.UI.
  • Verb: An integer that says what a message asks for or reports. The UI system uses UICommandVerb for commands and UIEventVerb for events.
  • Subject: A UISubjects value stored under UIParamKeys.UISubject. It says which kind of UI element an event concerns.
  • Registration key: A string that identifies a registered UI component. It is stored under CoreParamKeys.Key when the component is registered, and it is used later to route commands to that component.
  • Flow controllable: A component that registers with the UI flow controller. UIRoot is the base class for these.
  • Command processor: A flow controllable that also implements ICommandProcessor. The flow controller hands routed commands to it.

Event and command flow

  1. A UIRoot derived component's Start runs. It calls Register.
  2. Register calls UICommandFactory.RegisterFlowControllable with the component's RegistrationKey. This creates a Register command with the key and the component attached as params.
  3. BusUtility.Send delivers the command to the command bus, which passes it to the UIFlowController registered for Domain.UI.
  4. UIFlowController.HandleCommand returns early if the command has no Key param. If the verb is Register, it stores the component in its registry. Otherwise it looks up the processor for the key and passes the command to ProcessCommand.
  5. When a UI element is clicked, a caller invokes a UIEventFactory method. That method creates a UIEventVerb event, sets its params, and calls BusUtility.Raise.
  6. Listeners on the event bus receive the event and read its verb and params.

Thread safety

The code does not show any thread-safety measures. The registries are plain Dictionary instances with no locking, so UI commands should be sent and handled on the Unity main thread.