spacr.qt.first_run

First-launch tour — one-time coach-marks over the home screen.

Fires the first time spacr boots (state stored in QSettings). A translucent full-window overlay dims the app; a numbered card walks the user through: sidebar → test data → home tiles → hint bar. The user can dismiss at any point via Skip / Esc; the “seen” flag is saved on skip OR after the last step so the tour never fires twice unless they hit “Reset” in Preferences.

Public API:

from spacr.qt.first_run import (
    maybe_show_tour, was_tour_shown, mark_tour_seen,
    reset_tour_state,
)

# In MainWindow.__init__ after everything is built:
maybe_show_tour(self)

# From a Preferences reset button:
reset_tour_state()

The tour is deliberately spartan — five steps, ~90 seconds tops. Users who don’t want it hit Esc and never see it again.

Classes

TourStep

One narrated coach-mark.

Functions

find_menu(→ Optional[PySide6.QtWidgets.QWidget])

The window's menu-bar menu titled title, ignoring &.

mark_tour_seen(→ None)

Persist the "seen" flag so the tour doesn't fire on future boots.

maybe_show_tour(→ Optional[_TourOverlay])

Show the tour if it hasn't been seen (or if force=True).

reset_tour_state(→ None)

Clear the "seen" flag — next launch shows the tour again.

was_tour_shown(→ bool)

Return True iff the user has completed or dismissed the tour.

Module Contents

class spacr.qt.first_run.TourStep[source]

One narrated coach-mark.

Variables:
  • title – short headline shown on the card.

  • body – 1-2 sentences under the title.

  • highlight – callable returning the widget to highlight, or None to centre the card without a highlight box.

spacr.qt.first_run.find_menu(window: PySide6.QtWidgets.QMainWindow, title: str) → PySide6.QtWidgets.QWidget | None[source]

The window’s menu-bar menu titled title, ignoring &.

Found through findChildren rather than by walking the menu bar’s actions and calling QAction.menu(). That reading is the obvious one and it does not survive on PySide6 6.11: the QMenu wrapper it returns is only valid while the QAction wrapper it came off is alive, so the menu went stale the moment this function returned — “Internal C++ object (PySide6.QtWidgets.QMenu) already deleted” on the very next line — and keeping the owners alive as attributes segfaulted during the next event dispatch instead. findChildren hands back children the menu bar owns in C++, which stay valid for as long as the window does.

Parameters:
  • window – the live main window.

  • title – menu title without its mnemonic ampersand.

spacr.qt.first_run.mark_tour_seen() → None[source]

Persist the “seen” flag so the tour doesn’t fire on future boots.

spacr.qt.first_run.maybe_show_tour(window: PySide6.QtWidgets.QMainWindow, force: bool = False) → _TourOverlay | None[source]

Show the tour if it hasn’t been seen (or if force=True).

Parameters:
  • window – the MainWindow to overlay.

  • force – skip the “seen” check and show anyway.

Returns:

the overlay widget (already visible) or None if the tour was skipped because it had been seen.

spacr.qt.first_run.reset_tour_state() → None[source]

Clear the “seen” flag — next launch shows the tour again.

spacr.qt.first_run.was_tour_shown() → bool[source]

Return True iff the user has completed or dismissed the tour.