How to follow a plan action from a view¶
Each action of a plan can have its own button in a view. Pressing the button
asks the component's ActionManager for the action, and the view then sets
the button from what the plan answers.
How presenters run plans
explains the states an action goes through.
Prerequisites¶
You need a component that offers a plan declaring actions, and owns the
ActionManager the plan waits on. See
Actions while a plan runs.
Ask, and follow the answer¶
The view asks with a signal carrying the name of the action and whether the button is pressed, and follows the answer in a slot:
from psygnal import Signal
from redsun import slot
from redsun.engine.actions import ActionState
class MyView(QWidget):
sig_action_request = Signal(str, bool)
def ask(self, name: str) -> None:
self.sig_action_request.emit(name, True)
def ask_or_release(self, checked: bool, name: str) -> None:
self.sig_action_request.emit(name, checked)
@slot
def on_action_changed(self, name: str, state: str) -> None:
button = self.widget.action_buttons[name]
match state:
case ActionState.IDLE:
button.setEnabled(False)
button.release()
case ActionState.OFFERED:
button.setEnabled(True)
case ActionState.RUNNING:
button.setEnabled(button.isCheckable())
ask and ask_or_release are the action_clicked_callback and
action_toggled_callback of the
plan widget, here self.widget.
release shows a button as released without emitting toggled. Unchecking
the button would emit it, and the view would then ask to end an action that
has already ended.
Link the view and the component¶
In wire:
class MyApp(QtSession):
ctrl: AsPresenter[MyController]
panel: AsView[MyView]
def wire(self) -> Iterator[Link]:
yield self.panel.sig_action_request, self.ctrl.actions.request
yield self.ctrl.actions.sig_changed, self.panel.on_action_changed
The wiring section can't make these links
A path in wiring is component.port, and the ports of a component don't
include those of an object it holds. Make the links in wire.
The session records an ActionManager under the name of the component holding
it, so it records the two links as panel.sig_action_request -> ctrl.request
and ctrl.sig_changed -> panel.on_action_changed. See
Inspect what is connected.