Source code for spacr.qt.widgets.colour_picker
"""The one colour picker the GUI uses, with the platform dialog turned off.
WHY THIS MODULE EXISTS AT ALL
-----------------------------
``QColorDialog.getColor`` defaults to the *platform's* colour chooser. On a
GNOME desktop with ``xdg-desktop-portal`` running, that is not a Qt widget at
all: Qt asks the portal, the portal starts (or wakes) the GTK implementation
over D-Bus, and the dialog can be slow to appear. Every colour picker in the
tree was reached through an unguarded ``getColor`` — six of them, none passing
``DontUseNativeDialog``.
Qt's own dialog opens immediately, looks the same on every platform, and
follows the application palette — which the GTK one does not, so the option is
a consistency win as well as a speed one.
The portal round trip **cannot be reproduced
headless**: an offscreen Qt never asks the portal, so no test in this suite can
observe the stall or its absence. The restyle work itself is free
(``set_line_style`` 0.000 s on a 1,200
point plot) so the wait is in the dialog — and "the portal is what the wait is"
is a named, checkable hypothesis to be confirmed on a real display, not
something this file proves. What IS proven here, by
``tests/qt/test_colour_picker.py``, is that no call site can ask for the
platform dialog any more.
USE IT INSTEAD OF ``QColorDialog.getColor``. That is the whole point: an
option that has to be remembered at every call site is an option that will be
forgotten at the seventh. The grep test enforces it.
"""
from __future__ import annotations
from typing import Optional, Union
from PySide6.QtGui import QColor
from PySide6.QtWidgets import QColorDialog, QWidget
[docs]
def pick_colour(parent: Optional[QWidget] = None,
initial: Union[QColor, str, None] = None,
title: Optional[str] = None) -> QColor:
"""Ask the user for a colour, using Qt's own dialog.
:param parent: dialog parent, as for :meth:`QColorDialog.getColor`.
:param initial: the colour to open on — a :class:`QColor`, a string
Qt understands (``"#ff0000"``, ``"red"``), or None for white.
:param title: window title; Qt's default when omitted.
:returns: the chosen :class:`QColor`, or an **invalid** ``QColor`` when
the user cancelled.
Returning an invalid colour rather than ``None`` is deliberate: every
existing call site already tests ``colour.isValid()`` before using it, so
adopting this helper is a one-line change at each and cannot silently
turn a cancel into a colour.
"""
if isinstance(initial, QColor):
start = QColor(initial)
elif initial is None:
start = QColor("#ffffff")
else:
start = QColor(str(initial))
if not start.isValid():
start = QColor("#ffffff")
return QColorDialog.getColor(
start, parent, title or "",
QColorDialog.ColorDialogOption.DontUseNativeDialog)