class

Phosphor::DebugOverlay

Inherits Reference < Object

Renders the app's own state, View focus/subscription info, and — only when App.run(stats: true) — a performance section (FPS, cells changed, bytes written, average draw time) as a floating panel over the current screen — a BorderMock wrapping a ViewportMock, painted into the same Buffer the screen just rendered into so its cells overwrite whatever was underneath. The panel's own background is cleared first (see #clear_background) so gaps neither BorderMock nor ViewportMock happens to write don't let the screen's own content show through.

Content is one already-formatted line per entry (see #debug_lines), rendered via ViewportMock rather than ParagraphMockParagraphMock word-wraps on whitespace, which silently swallows embedded newlines (String#split treats \n as just another separator) and reflows every labelled line into one run-on paragraph. ViewportMock draws each Array(String) entry on its own row, unwrapped, and scrolls rather than garbling content taller than the panel.

Purely a render-time overlay: never touches the app's own state, never routes events to the active screen, and never appears unless App.run(debug: true) and the debug hotkey (default Key::F12) are both engaged — see App#run.

A class rather than a module of self. methods (unlike most other framework singletons) because it now carries scroll position across renders in @scroll_offset — Crystal doesn't allow mutable instance variables on a module's own metaclass, only @@ class variables, which can't be typed with a default the way an instance ivar can here. App owns one instance for the lifetime of the run loop.

Constants

HEIGHT = 30
HORIZONTAL_RULE = "─"

The character #debug_lines repeats to draw a section-separator rule.

LABEL_WIDTH = 12

Label column width for the performance metrics — every label is ljusted to this so values line up under one another regardless of label length ("FPS:" vs. "Draw time:").

TITLE = "debug — F11: ↓ Shift+F11: ↑"

Border title hinting at the scroll hotkeys — see App#run's debug_scroll_down_hotkey/debug_scroll_up_hotkey — so the keys are discoverable without reading documentation.

WIDTH = 50

Fixed size for the overlay panel, clamped to frame if it's smaller.

WIDTH is 50 — wide enough that a @long_field_name=value line from a state struct with descriptive field names (e.g. WidgetDemoState's @focused_field_index=0) isn't truncated before the value.

HEIGHT gives enough rows for the 4 metric lines + 1 rule (stats), State: + one line per state field + 1 rule, and View: + 2 lines, plus 2 border rows — comfortably covers WidgetDemoState's 15 fields (27 content rows + border) with headroom for a few more. A state struct with more fields than that scrolls off rather than garbling, since ViewportMock (unlike the old ParagraphMock) never reflows content, just shows fewer of the trailing lines.

Instance methods

render(state : S, view : View(S, M), fps : Float64, frame : Frame, buf : Buffer, stats : Stats | Nil = nil) : Void forall S, M

Renders the overlay into buf, in the top-right corner of frame.

stats, if given (only when App.run(stats: true) — see App#run), adds the whole FPS/Cells/Bytes/Draw-time performance section, plus the rule that separates it from State:. Omitted entirely when nil, the default — the overlay then starts directly with State:, no performance section or leading rule at all.

Generic (forall S, M) so the overlay can render any app's own state and message type — it only ever calls state.inspect, never anything specific to the app's own state type.

Source
reset_scroll

Resets #scroll_offset to 0. App calls this whenever the debug hotkey closes the overlay, so it always reopens at the top rather than wherever it was last left scrolled to.

Source
scroll_down

Scrolls the overlay's content down (toward later lines) by one row, clamped so the last row of content stays flush with the bottom of the viewport rather than scrolling past into blank space — see #max_scroll_offset.

Source
scroll_offset

How far into #debug_lines the visible window currently starts. Driven by #scroll_down/#scroll_up, reset to 0 by #reset_scroll (called by App when the overlay is toggled off), and copied into ViewportMock::Props#scroll_offset on every #render call.

Source
scroll_up

Scrolls the overlay's content up (toward earlier lines) by one row, clamped at 0.

Source