spacr.qt.widgets.glass

Give every popup the translucent card and the travelling rim.

Every settings popup in the program – preferences, the hyperparameter search, live settings, AI settings, figure settings and the rest – gets the same translucent background and the same rim.

ONE INSTALL POINT, NOT THIRTY-NINE EDITS. There are thirty-nine QDialog subclasses in this package and there will be more next week; a look applied by hand in each of them is a look that is missing from the fortieth. This installs an application event filter instead, so a dialog gets the treatment the first time it is shown, whoever wrote it and whenever it was added.

WHAT THE TREATMENT IS, and each part is here for a reason the setup screen found the hard way:

  • a SetupCard is put BEHIND the dialog’s own contents and kept at its size. It paints the translucent body and runs the rim; it holds no layout, so it cannot disturb one;

  • the dialog and its layout CONTAINERS are made transparent. This palette’s bg is literally #000000, so any untagged container between the card and the eye paints a black rectangle over it – which is what “black boxes” meant on the setup screen, and is invisible to a code reading;

  • the controls are left alone. A control you can see through is a control you cannot read, so combos, edits, buttons and tables keep their own surface.

A DIALOG CAN SAY NO by carrying the spacrNoGlass property. Nothing in spaCR sets it today; it is there because the next thing somebody embeds may be a native colour picker or a video surface that must own its own painting.

Functions

button_direction(→ Optional[bool])

True for a forward button, False for a back one, None if unclear.

clear_the_containers(→ int)

Stop the layout containers painting over the card. Returns how many.

glass(→ bool)

Give one dialog the card and the rim. True if it was applied.

install_glass_everywhere(→ bool)

Install the filter. True when it was installed by this call.

let_the_user_resize(→ bool)

Give window edge-drag resizing. True when it was installed.

make_frameless(→ bool)

Drop the title bar and let the card's rounded corners show.

round_the_corners(→ bool)

Keep antialiased alpha edges on translucent windows.

spin_on_every_button(→ int)

Send the rim round on each button. Returns how many were wired.

uninstall_glass_everywhere(→ bool)

Remove the application-wide glass event filter.

wants_glass(→ bool)

Whether widget should be given the card and the rim.

Module Contents

spacr.qt.widgets.glass.button_direction(button: PySide6.QtWidgets.QAbstractButton) → bool | None[source]

True for a forward button, False for a back one, None if unclear.

THE ROLE FIRST. A QDialogButtonBox already knows which of its buttons accepts and which rejects, and that answer is better than any reading of the label – it survives translation, which the words below do not.

Parameters:

button – the button to classify: by its role in an enclosing QDialogButtonBox when it has one, otherwise by the words of its text.

spacr.qt.widgets.glass.clear_the_containers(dialog: PySide6.QtWidgets.QWidget) → int[source]

Stop the layout containers painting over the card. Returns how many.

Walks the whole tree, so a dialog whose settings live on the pages of a tab widget is covered as well: “every tab of every popup panel” is a page that is itself a plain QWidget, and one of those is enough to bury the card under a black rectangle.

Parameters:

dialog – the dialog whose descendant widgets, other than opaque controls and their children, are made transparent.

spacr.qt.widgets.glass.glass(dialog: PySide6.QtWidgets.QDialog) → bool[source]

Give one dialog the card and the rim. True if it was applied.

Idempotent: a dialog that already carries GLASSED is left alone, so a dialog shown, closed and shown again does not accumulate cards.

Parameters:

dialog – the dialog to decorate; it is left alone unless wants_glass() accepts it.

spacr.qt.widgets.glass.install_glass_everywhere(application=None) → bool[source]

Install the filter. True when it was installed by this call.

Called once at startup. Every dialog opened afterwards – Preferences, the hyperparameter search, live settings, the AI providers, the figure settings, and the thirty-odd others – is treated on its first show without knowing anything about this module.

spacr.qt.widgets.glass.let_the_user_resize(window) → bool[source]

Give window edge-drag resizing. True when it was installed.

Idempotent: a window that already carries the filter keeps the one it has, so a dialog shown, closed and shown again does not collect two.

Parameters:

window – the top-level widget that gets an edge-drag resize filter; None or a window that already has one returns False.

spacr.qt.widgets.glass.make_frameless(dialog: PySide6.QtWidgets.QDialog) → bool[source]

Drop the title bar and let the card’s rounded corners show.

“they also dont need the x and minus at the top make the edges rounded on all” – a settings window is dismissed by its own Cancel or by Escape, so the close and minimise buttons were chrome around chrome.

TRANSLUCENT, or the corners are not round: the card paints a rounded body, and without this the square window behind it fills the four corners with the theme’s background and the shape is lost.

AND STILL MOVABLE. See _DragByBackground – the title bar was where a window was dragged from.

IT PUTS BACK A DIALOG IT HAD TO HIDE. setWindowFlags on a VISIBLE widget hides it, and Qt requires show() to bring it back. This runs from the filter below, which fires while a dialog is being shown – so without the restore, opening Preferences hid Preferences, and an exec() sat on an invisible modal window with no way to dismiss it.

Parameters:

dialog – the dialog made translucent, frameless, draggable by its background and resizable by its edges; it is shown again if changing its flags hid it.

spacr.qt.widgets.glass.round_the_corners(dialog: PySide6.QtWidgets.QWidget, radius: int = CARD_RADIUS) → bool[source]

Keep antialiased alpha edges on translucent windows.

A QRegion is binary and quantizes its outline to logical pixels, even on high-DPI screens. Cutting the antialiased card to that shape erased partially covered edge pixels, producing a jagged white/dark fringe against the desktop. Translucent windows already carry the card’s exact per-pixel alpha only when their native format has an alpha buffer. Clear the mask in that case; the QWidget attribute alone is not proof. Until a native alpha surface exists, retain the rounded platform mask.

Parameters:
  • dialog – window carrying the shared rounded card.

  • radius – corner radius in logical pixels for the opaque fallback.

Returns:

false for an empty or deleted widget, true after adjustment.

spacr.qt.widgets.glass.spin_on_every_button(dialog: PySide6.QtWidgets.QDialog, card) → int[source]

Send the rim round on each button. Returns how many were wired.

A POSITIVE CLICK GOES CLOCKWISE AND A NEGATIVE ONE BACK. The direction is the message – it says which way through the dialog the click just took you – which is why a button nobody can classify spins nothing at all rather than being guessed at.

ONCE PER BUTTON. A dialog reaches the installer on Polish and again on Show, and a second connection would send the light round twice on one click – which, since the two laps run down together, reads as a rim moving at double speed rather than as a bug.

Parameters:
  • dialog – the dialog whose descendant buttons are wired; a button already wired, or whose direction button_direction() cannot tell, is skipped.

  • card – the card whose circuit(clockwise=...) runs on each click, clockwise for a forward button.

spacr.qt.widgets.glass.uninstall_glass_everywhere(application=None) → bool[source]

Remove the application-wide glass event filter.

When install_glass_everywhere() has registered a filter, remove it from application or, when omitted, from QApplication.instance(). The module’s installation state is cleared even if no application instance exists or Qt raises while removing the filter. Styling already applied to dialogs is not reverted.

Parameters:

application – Qt application from which to remove the filter. If None, use the current QApplication instance.

Returns:

True if an installed filter was registered when the call began; False if no filter was installed.

spacr.qt.widgets.glass.wants_glass(widget: PySide6.QtWidgets.QWidget) → bool[source]

Whether widget should be given the card and the rim.

A DIALOG THAT BROUGHT ITS OWN CARD IS LEFT ALONE. The setup screen builds one and lays its slides out inside it; glassing it added a SECOND card, and the second one covered the first one’s contents – childAt over the GitHub button returned the card, so the click never reached it.

Checked by looking rather than by asking, so anything else that builds its own card is covered without having to remember to say so.

Parameters:

widget – the widget to test; only a QDialog without the opt-out or already-glassed property and without its own SetupCard qualifies.