jmri_core.beans.layout_block

LayoutBlock — a track segment on the panel that a layout-editor diagram references.

This is intentionally a round-trip bean for the current pass. A real LayoutBlock in JMRI Java participates in occupancy propagation across turnout paths, block-boss signalling, and layout-editor rendering — none of which exist in the Python rewrite yet. What we carry here is enough to survive PanelPro.xml load/save and to answer the JSON schema so JMRI mobile clients don't get 404s when they probe the layoutBlock topic.

When Panel Editor lands (Tier 1 #3 in ~/workitems.txt) this file grows real logic; today it's honest scaffolding.

 1"""``LayoutBlock`` — a track segment on the panel that a layout-editor
 2diagram references.
 3
 4This is intentionally a **round-trip bean** for the current pass. A
 5real LayoutBlock in JMRI Java participates in occupancy propagation
 6across turnout paths, block-boss signalling, and layout-editor
 7rendering — none of which exist in the Python rewrite yet. What we
 8carry here is enough to survive `PanelPro.xml` load/save and to
 9answer the JSON schema so JMRI mobile clients don't get 404s when
10they probe the ``layoutBlock`` topic.
11
12When Panel Editor lands (Tier 1 #3 in ``~/workitems.txt``) this file
13grows real logic; today it's honest scaffolding.
14"""
15from __future__ import annotations
16
17from jmri_core.bean import AbstractNamedBean
18from jmri_core.manager import Manager
19
20# Default panel colours JMRI uses when it renders a layout block.
21# Strings so the wire form pins the wire form; Layout Editor is what
22# consumes them later.
23_DEFAULT_BLOCK_COLOR = "black"
24_DEFAULT_TRACK_COLOR = "black"
25_DEFAULT_OCCUPIED_COLOR = "red"
26_DEFAULT_EXTRA_COLOR = "white"
27
28
29class LayoutBlock(AbstractNamedBean):
30    """One layout-editor block. Occupancy / adjacency logic is Panel-Editor
31    territory; here we're a data holder."""
32
33    __slots__ = (
34        "block",             # underlying Block bean name (opaque string)
35        "block_color",
36        "extra_color",
37        "memory",            # associated Memory bean name (opaque string)
38        "occupancy_sensor",  # associated Sensor bean name (opaque string)
39        "occupied_color",
40        "occupied_sense",    # sensor state that means "occupied" (usually 2)
41        "state",             # opaque int the layout-editor uses
42        "track_color",
43        "use_extra_color",
44    )
45
46    type_letter = "B"
47
48    def __init__(
49        self, system_name: str, user_name: str | None = None,
50    ) -> None:
51        super().__init__(system_name, user_name)
52        self.state: int = 0
53        self.block: str | None = None
54        self.memory: str | None = None
55        self.occupancy_sensor: str | None = None
56        # JMRI Java's default: ACTIVE == 2 == occupied.
57        self.occupied_sense: int = 2
58        self.block_color: str = _DEFAULT_BLOCK_COLOR
59        self.track_color: str = _DEFAULT_TRACK_COLOR
60        self.occupied_color: str = _DEFAULT_OCCUPIED_COLOR
61        self.extra_color: str = _DEFAULT_EXTRA_COLOR
62        self.use_extra_color: bool = False
63
64
65class LayoutBlockManager(Manager[LayoutBlock]):
66    # JMRI uses ``ILB``-prefixed system names for layout blocks; the
67    # type letter is ``B`` (same as Block) but the manager is distinct.
68    # Callers pass fully-qualified system names — ``normalize_name`` will
69    # accept ``"ILB1"`` unchanged when we're constructed with prefix
70    # ``"IL"``.
71    type_letter = "B"
72
73    def _create(self, system_name: str) -> LayoutBlock:
74        return LayoutBlock(system_name)
class LayoutBlock(jmri_core.bean.AbstractNamedBean):
30class LayoutBlock(AbstractNamedBean):
31    """One layout-editor block. Occupancy / adjacency logic is Panel-Editor
32    territory; here we're a data holder."""
33
34    __slots__ = (
35        "block",             # underlying Block bean name (opaque string)
36        "block_color",
37        "extra_color",
38        "memory",            # associated Memory bean name (opaque string)
39        "occupancy_sensor",  # associated Sensor bean name (opaque string)
40        "occupied_color",
41        "occupied_sense",    # sensor state that means "occupied" (usually 2)
42        "state",             # opaque int the layout-editor uses
43        "track_color",
44        "use_extra_color",
45    )
46
47    type_letter = "B"
48
49    def __init__(
50        self, system_name: str, user_name: str | None = None,
51    ) -> None:
52        super().__init__(system_name, user_name)
53        self.state: int = 0
54        self.block: str | None = None
55        self.memory: str | None = None
56        self.occupancy_sensor: str | None = None
57        # JMRI Java's default: ACTIVE == 2 == occupied.
58        self.occupied_sense: int = 2
59        self.block_color: str = _DEFAULT_BLOCK_COLOR
60        self.track_color: str = _DEFAULT_TRACK_COLOR
61        self.occupied_color: str = _DEFAULT_OCCUPIED_COLOR
62        self.extra_color: str = _DEFAULT_EXTRA_COLOR
63        self.use_extra_color: bool = False

One layout-editor block. Occupancy / adjacency logic is Panel-Editor territory; here we're a data holder.

LayoutBlock(system_name: str, user_name: str | None = None)
49    def __init__(
50        self, system_name: str, user_name: str | None = None,
51    ) -> None:
52        super().__init__(system_name, user_name)
53        self.state: int = 0
54        self.block: str | None = None
55        self.memory: str | None = None
56        self.occupancy_sensor: str | None = None
57        # JMRI Java's default: ACTIVE == 2 == occupied.
58        self.occupied_sense: int = 2
59        self.block_color: str = _DEFAULT_BLOCK_COLOR
60        self.track_color: str = _DEFAULT_TRACK_COLOR
61        self.occupied_color: str = _DEFAULT_OCCUPIED_COLOR
62        self.extra_color: str = _DEFAULT_EXTRA_COLOR
63        self.use_extra_color: bool = False
type_letter = 'B'
state: int
block: str | None
memory: str | None
occupancy_sensor: str | None
occupied_sense: int
block_color: str
track_color: str
occupied_color: str
extra_color: str
use_extra_color: bool
66class LayoutBlockManager(Manager[LayoutBlock]):
67    # JMRI uses ``ILB``-prefixed system names for layout blocks; the
68    # type letter is ``B`` (same as Block) but the manager is distinct.
69    # Callers pass fully-qualified system names — ``normalize_name`` will
70    # accept ``"ILB1"`` unchanged when we're constructed with prefix
71    # ``"IL"``.
72    type_letter = "B"
73
74    def _create(self, system_name: str) -> LayoutBlock:
75        return LayoutBlock(system_name)

Per-type bean registry. Subclass and override _create().

Attributes set on the class describe the bean type:

  • type_letter — single uppercase letter the bean class owns (e.g. "T" for Turnout). Must be set by subclass.
  • system_prefix — connection prefix (e.g. "L"). Set per-instance because one bean class can have many connection-specific managers.
type_letter = 'B'