package display import ( "git.piksar.eu/piotr/groundstation/internal/osd" ) // SnapshotSource serves the latest supervisor-published OSD snapshot while // it is fresh. The file-backed implementation lives in the osd package; the // template only consumes the contract. type SnapshotSource interface { Latest() (osd.Snapshot, bool) } // OSDTemplate is the flight OSD layout of a display target: a transparent, // input-transparent surface above pilot video. While decoded video is // absent the fallback canvas owns the screen and the OSD presents nothing; // while video is present the OSD draws deliberately minimal telemetry from // the latest published snapshot — arm state and requested CH6 WFB power. // The rendering gate is the video presence the display observes on the // display server, never the snapshot's Video field: the supervisor's field // is its launcher knowledge, while the display trusts only the presented // video output itself. The OSD never draws the fallback: it is a telemetry // surface, not a video substitute, and WFB or video decode never move into // the UI process to feed it. The OSD refreshes on its own slower cadence // than the video and the video window keeps rendering priority. type OSDTemplate struct { video *VideoPresence source SnapshotSource } // NewOSDTemplate builds the OSD surface for a target from the shared video // presence and the supervisor-published snapshot source. func NewOSDTemplate(video *VideoPresence, source SnapshotSource) OSDTemplate { return OSDTemplate{video: video, source: source} } func (t OSDTemplate) Draw(canvas Canvas) { canvas.Clear() if t.video.Active() { if snapshot, ok := t.source.Latest(); ok { drawOSD(canvas, snapshot) } } canvas.Flush() } // drawOSD renders the deliberately minimal flight telemetry: two short // lines in the top-left corner. The full final RC state stays in the // snapshot; the pilot-facing overlay stays terse. func drawOSD(canvas Canvas, snapshot osd.Snapshot) { arm := "OFF" if snapshot.Armed { arm = "ARMED" } power := "OFF" if snapshot.Power { power = "ON" } canvas.Text(32, 32, "ARM "+arm) canvas.Text(32, 64, "PWR "+power) }