Source code for simvx.editor.panels._game_host
"""The node a viewport panel reaches the running game through.
A hosted tree is reached through a node, not as a second destination. Each
viewport panel holds a :class:`GameHost` over the rect the game is drawn in,
and the host is an ordinary :class:`~simvx.core.SceneHost`: it forwards the
pointer while it is over that rect or holds a press, and keys, text and pads
while it holds focus, which it takes as the mouse comes to rest over the game.
So the hierarchy decides who gets what:
- the toolbar and the docks are in front of or beside the host, so a click
there never reaches the game;
- the editor's F5, F6 and F7 are capture handlers on its root, heard before
the host's, whatever the game is doing;
- a focused inspector field keeps its typing, because the host does not hold
focus then, and taking the focus away hands the game's keys over.
Play mode steps and draws the game; the host only forwards and hands over.
Pausing turns ``forwarding`` off, which hands everything over; hiding the
panel, or play stopping, does too.
"""
from __future__ import annotations
from typing import Any
from simvx.core import FocusMode, Property, SceneHost, Vec2
[docs]
class GameHost(SceneHost):
"""A viewport panel's host for the game play mode runs."""
visible = Property(
False,
coerce=bool,
hint="Shown only while a panel on screen hosts the running game",
on_change="_on_visible_changed",
)
def __init__(self, **kwargs: Any) -> None:
kwargs.setdefault("name", "GameHost")
kwargs.setdefault("focus_mode", FocusMode.HOVER)
super().__init__(**kwargs)
[docs]
def sync(self, panel: Any, rect: tuple[float, float, float, float]) -> None:
"""Host the running game over *rect*, in *panel*'s own space, or nothing when none runs.
Called by the panel once a frame. Only the panel on screen hosts: the
game has one host, and taking it moves it here from the other panel,
which hands over what the other one was forwarding.
"""
play_mode = getattr(panel.state, "play_mode", None)
tree = play_mode.game_tree if play_mode is not None and panel.state.is_playing else None
if play_mode is None or tree is None or not panel.visible_in_tree:
if self.guest is not None:
self.guest = None
self.visible = False
return
x, y, w, h = rect
self.position = Vec2(x, y)
self.size = Vec2(w, h)
self.visible = True
self.forwarding = play_mode.should_route_input_to_game()
if self.guest is not tree:
self.guest = tree