feat(*): implement v0.1.0, add docs

This commit is contained in:
h
2026-01-19 01:25:44 +01:00
commit 506a975052
34 changed files with 3285 additions and 0 deletions

20
docs/Makefile Normal file
View File

@@ -0,0 +1,20 @@
# Minimal makefile for Sphinx documentation
#
# You can set these variables from the command line, and also
# from the environment for the first two.
SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build
SOURCEDIR = .
BUILDDIR = _build
# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

40
docs/api.rst Normal file
View File

@@ -0,0 +1,40 @@
API Reference
=============
This page documents the public API of pyqt-liquidglass.
pyqt_liquidglass
----------------
.. automodule:: pyqt_liquidglass
:members:
:undoc-members:
:show-inheritance:
:exclude-members: __all__
Platform Constants
------------------
.. py:data:: pyqt_liquidglass.IS_MACOS
:type: bool
:noindex:
``True`` if running on macOS, ``False`` otherwise.
.. py:data:: pyqt_liquidglass.MACOS_VERSION
:type: tuple[int, int, int] | None
:noindex:
macOS version as a tuple (major, minor, patch), or ``None`` on other platforms.
.. py:data:: pyqt_liquidglass.HAS_GLASS_EFFECT
:type: bool
:noindex:
``True`` if ``NSGlassEffectView`` is available (macOS 26+).
.. py:data:: pyqt_liquidglass.HAS_VISUAL_EFFECT
:type: bool
:noindex:
``True`` if ``NSVisualEffectView`` is available.

55
docs/conf.py Normal file
View File

@@ -0,0 +1,55 @@
# Configuration file for the Sphinx documentation builder.
#
# For the full list of built-in configuration values, see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html
import os
import sys
import tomllib
sys.path.insert(0, os.path.abspath("."))
sys.path.insert(0, os.path.abspath("../."))
# -- Project information -----------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
project = "pyqt-liquidglass"
copyright = "2025, h"
author = "h"
release = tomllib.load(open("../pyproject.toml", "rb"))["project"]["version"]
# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
extensions = [
"sphinx.ext.autodoc",
"sphinx.ext.viewcode",
"sphinx.ext.napoleon",
"sphinx_autodoc_typehints",
]
templates_path = ["_templates"]
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
autodoc_default_options = {
"members": True,
"member-order": "bysource",
"special-members": "__init__",
"undoc-members": True,
"exclude-members": "__weakref__",
"inherited-members": False,
}
autodoc_typehints = "description"
typehints_use_signature = True
typehints_use_signature_return = True
autodoc_member_order = "bysource"
# -- Options for HTML output -------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
html_theme = "furo"
html_static_path = ["_static"]
html_title = "pyqt-liquidglass"
html_theme_options = {"sidebar_hide_name": False, "navigation_with_keys": True}

200
docs/core_concepts.rst Normal file
View File

@@ -0,0 +1,200 @@
Core Concepts
=============
This page explains how pyqt-liquidglass works under the hood.
How Glass Effects Work
----------------------
Native Views
~~~~~~~~~~~~
macOS provides two classes for blur/glass effects:
- **NSGlassEffectView**: New in macOS 26 (Tahoe), provides the Liquid Glass effect
- **NSVisualEffectView**: Available since macOS 10.10, provides vibrancy effects
pyqt-liquidglass automatically uses ``NSGlassEffectView`` when available and falls back to ``NSVisualEffectView`` on older systems.
View Hierarchy
~~~~~~~~~~~~~~
Qt widgets map to native ``NSView`` objects. When you apply a glass effect, the library:
1. Gets the native ``NSView`` for your Qt widget
2. Creates a glass effect view (``NSGlassEffectView`` or ``NSVisualEffectView``)
3. Inserts it behind your widget's view in the z-order
4. Configures autoresizing so it tracks widget size changes
The glass view renders the blur effect, and your Qt content draws on top.
Window vs Widget Glass
----------------------
Window Glass
~~~~~~~~~~~~
``apply_glass_to_window()`` fills the entire window content area with glass:
.. code-block:: python
glass.apply_glass_to_window(window)
This is ideal for:
- Full-window blur backgrounds
- Floating panels
- Modal dialogs
The function configures the window for transparent titlebar and full-size content view automatically.
Widget Glass
~~~~~~~~~~~~
``apply_glass_to_widget()`` applies glass to a specific widget region:
.. code-block:: python
glass.apply_glass_to_widget(sidebar, options=glass.GlassOptions.sidebar())
This is ideal for:
- Sidebars (like macOS System Settings)
- Navigation panels
- Toolbars
The glass view tracks the widget's position and size, updating automatically on resize or move.
GlassOptions Configuration
--------------------------
The ``GlassOptions`` dataclass controls glass effect appearance:
.. code-block:: python
from pyqt_liquidglass import GlassOptions
options = GlassOptions(
corner_radius=16.0, # Rounded corners (NSGlassEffectView only)
material=GlassMaterial.SIDEBAR, # Material type
blending_mode=BlendingMode.BEHIND_WINDOW, # Blending mode
padding=(10, 10, 10, 10), # Left, top, right, bottom
)
Attributes
~~~~~~~~~~
**corner_radius** (float)
Corner radius in points. Only applies to ``NSGlassEffectView`` on macOS 26+. Default: 0.0
**material** (GlassMaterial)
The visual effect material. Only applies to ``NSVisualEffectView`` fallback. Options include:
- ``TITLEBAR``, ``SIDEBAR``, ``MENU``, ``POPOVER``
- ``SHEET``, ``WINDOW_BACKGROUND``, ``HUD``, ``TOOLTIP``
- ``CONTENT_BACKGROUND``, ``UNDER_WINDOW_BACKGROUND``
**blending_mode** (BlendingMode)
How the effect blends with content:
- ``BEHIND_WINDOW``: Blurs content behind the window
- ``WITHIN_WINDOW``: Blurs content within the window
**padding** (tuple)
Inset from widget edges in points: (left, top, right, bottom). Default: (0, 0, 0, 0)
Preset Methods
~~~~~~~~~~~~~~
For common use cases:
.. code-block:: python
# Full window glass (no corner radius, no padding)
options = GlassOptions.window()
# Sidebar glass (10pt radius, 9pt padding)
options = GlassOptions.sidebar()
# Custom sidebar
options = GlassOptions.sidebar(corner_radius=16.0, padding=12.0)
Coordinate Systems
------------------
Qt and Cocoa use different coordinate systems:
- **Qt**: Origin at top-left, Y increases downward
- **Cocoa**: Origin at bottom-left, Y increases upward
pyqt-liquidglass handles this conversion internally. When specifying ``y_offset`` for traffic lights, positive values move the buttons down from center.
Traffic Lights
--------------
The traffic lights are the close, minimize, and zoom buttons in the window titlebar.
Positioning
~~~~~~~~~~~
``setup_traffic_lights_inset()`` repositions the buttons using ``NSLayoutConstraint``:
.. code-block:: python
glass.setup_traffic_lights_inset(window, x_offset=20, y_offset=12)
- **x_offset**: Distance from the left edge in points
- **y_offset**: Vertical offset from center (positive = down)
This method survives window resizes because it uses Auto Layout constraints rather than absolute positioning.
Visibility
~~~~~~~~~~
Hide the buttons while keeping window functionality:
.. code-block:: python
glass.hide_traffic_lights(window)
glass.show_traffic_lights(window)
The window remains closable, minimizable, and zoomable via keyboard shortcuts and menu commands.
Platform Detection
------------------
The library provides constants for platform detection:
.. code-block:: python
from pyqt_liquidglass import (
IS_MACOS, # True if running on macOS
MACOS_VERSION, # Tuple like (15, 1, 0) or None
HAS_GLASS_EFFECT, # True if NSGlassEffectView is available
HAS_VISUAL_EFFECT, # True if NSVisualEffectView is available
)
All glass functions are safe to call on non-macOS platforms. They return ``None`` or ``False`` without side effects.
Effect Lifecycle
----------------
Effect IDs
~~~~~~~~~~
``apply_glass_to_window()`` and ``apply_glass_to_widget()`` return an effect ID:
.. code-block:: python
effect_id = glass.apply_glass_to_window(window)
Use this ID to remove the effect later:
.. code-block:: python
glass.remove_glass_effect(effect_id)
Cleanup
~~~~~~~
When a window is closed, Qt destroys the widget hierarchy. The glass effect views are removed automatically as part of the native view cleanup. You don't need to manually remove effects before closing windows.

544
docs/examples.rst Normal file
View File

@@ -0,0 +1,544 @@
Examples
========
This page contains complete, runnable examples demonstrating various use cases.
Full Window Glass
-----------------
The simplest example: glass filling the entire window content area.
.. code-block:: python
"""Full window glass effect example."""
import sys
from PySide6.QtCore import Qt
from PySide6.QtWidgets import QApplication, QLabel, QMainWindow, QVBoxLayout, QWidget
import pyqt_liquidglass as glass
class MainWindow(QMainWindow):
def __init__(self) -> None:
super().__init__()
self.setWindowTitle("Window Glass")
self.resize(600, 400)
central = QWidget()
central.setStyleSheet("background: transparent;")
layout = QVBoxLayout(central)
layout.setContentsMargins(40, 60, 40, 40)
label = QLabel("Hello, Liquid Glass!")
label.setAlignment(Qt.AlignmentFlag.AlignCenter)
label.setStyleSheet("""
font-size: 28px;
font-weight: 600;
color: white;
background: transparent;
""")
layout.addWidget(label)
self.setCentralWidget(central)
def main() -> int:
app = QApplication(sys.argv)
window = MainWindow()
# Prepare window BEFORE showing
glass.prepare_window_for_glass(window)
window.show()
# Apply glass AFTER showing
glass.apply_glass_to_window(window)
return app.exec()
if __name__ == "__main__":
sys.exit(main())
Sidebar Pattern
---------------
Settings-style window with a glass sidebar and opaque content area. This is the most common pattern for macOS applications.
.. code-block:: python
"""Sidebar with glass effect example."""
import sys
from PySide6.QtWidgets import (
QApplication,
QHBoxLayout,
QLabel,
QListWidget,
QListWidgetItem,
QMainWindow,
QVBoxLayout,
QWidget,
)
import pyqt_liquidglass as glass
class Sidebar(QWidget):
"""Transparent sidebar widget for glass effect."""
def __init__(self, parent: QWidget | None = None) -> None:
super().__init__(parent)
self.setFixedWidth(250)
self.setStyleSheet("background: transparent;")
layout = QVBoxLayout(self)
layout.setContentsMargins(9, 18, 9, 9)
self.list_widget = QListWidget()
self.list_widget.setStyleSheet("""
QListWidget {
font-size: 13px;
background: transparent;
border: none;
outline: none;
}
QListWidget::item {
padding: 5px 2px;
margin: 0px 9px;
border-radius: 4px;
}
QListWidget::item:selected {
background: rgba(255, 255, 255, 0.1);
}
""")
self.list_widget.viewport().setStyleSheet("background: transparent;")
for item_text in ["General", "Appearance", "Sound", "Network", "Privacy"]:
self.list_widget.addItem(QListWidgetItem(item_text))
self.list_widget.setCurrentRow(0)
layout.addWidget(self.list_widget)
class Content(QWidget):
"""Opaque content area."""
def __init__(self, parent: QWidget | None = None) -> None:
super().__init__(parent)
self.setStyleSheet("background-color: #1e1e1e;")
layout = QVBoxLayout(self)
layout.setContentsMargins(20, 20, 20, 20)
self.title = QLabel("General")
self.title.setStyleSheet("""
font-size: 18px;
font-weight: bold;
color: white;
background: transparent;
""")
self.description = QLabel("Configure general application settings.")
self.description.setStyleSheet("""
font-size: 14px;
color: #888888;
background: transparent;
""")
layout.addWidget(self.title)
layout.addSpacing(8)
layout.addWidget(self.description)
layout.addStretch()
class MainWindow(QMainWindow):
def __init__(self) -> None:
super().__init__()
self.setWindowTitle("Settings")
self.resize(720, 600)
central = QWidget()
layout = QHBoxLayout(central)
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(0)
self.sidebar = Sidebar()
self.content = Content()
layout.addWidget(self.sidebar)
layout.addWidget(self.content, 1)
self.setCentralWidget(central)
def main() -> int:
app = QApplication(sys.argv)
window = MainWindow()
glass.prepare_window_for_glass(window)
window.show()
# Inset traffic lights to sit nicely on sidebar
glass.setup_traffic_lights_inset(window, x_offset=18, y_offset=12)
# Apply glass to sidebar with rounded corners
glass.apply_glass_to_widget(window.sidebar, options=glass.GlassOptions.sidebar())
return app.exec()
if __name__ == "__main__":
sys.exit(main())
Frameless Floating Panel
------------------------
A frameless, draggable panel useful for HUDs, tool palettes, or popovers.
.. code-block:: python
"""Frameless window with glass effect example."""
import sys
from PySide6.QtCore import QPoint, Qt
from PySide6.QtGui import QMouseEvent
from PySide6.QtWidgets import QApplication, QLabel, QPushButton, QVBoxLayout, QWidget
import pyqt_liquidglass as glass
class FloatingPanel(QWidget):
"""A frameless, draggable floating panel with glass effect."""
def __init__(self) -> None:
super().__init__()
self.setWindowTitle("Floating Panel")
self.resize(300, 200)
self._drag_position: QPoint | None = None
self.setStyleSheet("background: transparent;")
layout = QVBoxLayout(self)
layout.setContentsMargins(24, 24, 24, 24)
layout.setSpacing(16)
title = QLabel("Floating Panel")
title.setAlignment(Qt.AlignmentFlag.AlignCenter)
title.setStyleSheet("""
font-size: 18px;
font-weight: 600;
color: white;
background: transparent;
""")
subtitle = QLabel("Drag anywhere to move")
subtitle.setAlignment(Qt.AlignmentFlag.AlignCenter)
subtitle.setStyleSheet("""
font-size: 12px;
color: rgba(255, 255, 255, 0.7);
background: transparent;
""")
close_button = QPushButton("Close")
close_button.setStyleSheet("""
QPushButton {
background: rgba(255, 255, 255, 0.15);
border: none;
border-radius: 8px;
padding: 10px 24px;
color: white;
font-size: 13px;
}
QPushButton:hover {
background: rgba(255, 255, 255, 0.25);
}
QPushButton:pressed {
background: rgba(255, 255, 255, 0.1);
}
""")
close_button.clicked.connect(self.close)
layout.addWidget(title)
layout.addWidget(subtitle)
layout.addStretch()
layout.addWidget(close_button)
def mousePressEvent(self, event: QMouseEvent) -> None:
if event.button() == Qt.MouseButton.LeftButton:
self._drag_position = (
event.globalPosition().toPoint() - self.frameGeometry().topLeft()
)
event.accept()
def mouseMoveEvent(self, event: QMouseEvent) -> None:
if (
event.buttons() == Qt.MouseButton.LeftButton
and self._drag_position is not None
):
self.move(event.globalPosition().toPoint() - self._drag_position)
event.accept()
def mouseReleaseEvent(self, event: QMouseEvent) -> None:
self._drag_position = None
def main() -> int:
app = QApplication(sys.argv)
panel = FloatingPanel()
# Prepare with frameless=True to remove window decorations
glass.prepare_window_for_glass(panel, frameless=True)
panel.show()
# Apply glass with rounded corners for the floating look
glass.apply_glass_to_window(panel, options=glass.GlassOptions(corner_radius=16.0))
return app.exec()
if __name__ == "__main__":
sys.exit(main())
Custom GlassOptions
-------------------
Demonstrates different glass configurations side by side.
.. code-block:: python
"""Custom GlassOptions example."""
import sys
from PySide6.QtCore import Qt
from PySide6.QtWidgets import (
QApplication,
QHBoxLayout,
QLabel,
QMainWindow,
QVBoxLayout,
QWidget,
)
import pyqt_liquidglass as glass
class GlassPanel(QWidget):
"""A panel that will have glass applied to it."""
def __init__(self, title: str, parent: QWidget | None = None) -> None:
super().__init__(parent)
self.setStyleSheet("background: transparent;")
layout = QVBoxLayout(self)
layout.setContentsMargins(20, 20, 20, 20)
label = QLabel(title)
label.setAlignment(Qt.AlignmentFlag.AlignCenter)
label.setStyleSheet("""
font-size: 16px;
font-weight: 600;
color: white;
background: transparent;
""")
layout.addWidget(label)
class MainWindow(QMainWindow):
def __init__(self) -> None:
super().__init__()
self.setWindowTitle("Custom Glass Options")
self.resize(800, 400)
central = QWidget()
central.setStyleSheet("background: transparent;")
layout = QHBoxLayout(central)
layout.setContentsMargins(20, 60, 20, 20)
layout.setSpacing(20)
self.panel_default = GlassPanel("Default\n(no radius)")
self.panel_default.setFixedWidth(200)
self.panel_rounded = GlassPanel("Rounded\n(radius: 16)")
self.panel_rounded.setFixedWidth(200)
self.panel_padded = GlassPanel("Padded\n(padding: 20)")
self.panel_padded.setFixedWidth(200)
layout.addWidget(self.panel_default)
layout.addWidget(self.panel_rounded)
layout.addWidget(self.panel_padded)
self.setCentralWidget(central)
def main() -> int:
app = QApplication(sys.argv)
window = MainWindow()
glass.prepare_window_for_glass(window)
window.show()
# Apply window glass as background
glass.apply_glass_to_window(window)
# Apply different glass options to each panel
glass.apply_glass_to_widget(
window.panel_default,
options=glass.GlassOptions(corner_radius=0.0, padding=(8, 8, 8, 8)),
)
glass.apply_glass_to_widget(
window.panel_rounded,
options=glass.GlassOptions(corner_radius=16.0, padding=(8, 8, 8, 8)),
)
glass.apply_glass_to_widget(
window.panel_padded,
options=glass.GlassOptions(corner_radius=12.0, padding=(20, 20, 20, 20)),
)
return app.exec()
if __name__ == "__main__":
sys.exit(main())
Traffic Lights Control
----------------------
Demonstrates hiding, showing, and repositioning the macOS window buttons.
.. code-block:: python
"""Traffic lights control example."""
import sys
from PySide6.QtCore import Qt
from PySide6.QtWidgets import (
QApplication,
QHBoxLayout,
QLabel,
QMainWindow,
QPushButton,
QVBoxLayout,
QWidget,
)
import pyqt_liquidglass as glass
class MainWindow(QMainWindow):
def __init__(self) -> None:
super().__init__()
self.setWindowTitle("Traffic Lights Demo")
self.resize(500, 300)
self._lights_visible = True
central = QWidget()
central.setStyleSheet("background: transparent;")
layout = QVBoxLayout(central)
layout.setContentsMargins(40, 80, 40, 40)
layout.setSpacing(20)
title = QLabel("Traffic Lights Control")
title.setAlignment(Qt.AlignmentFlag.AlignCenter)
title.setStyleSheet("""
font-size: 22px;
font-weight: 600;
color: white;
background: transparent;
""")
description = QLabel(
"The traffic lights have been repositioned.\n"
"Use the button below to hide or show them."
)
description.setAlignment(Qt.AlignmentFlag.AlignCenter)
description.setStyleSheet("""
font-size: 13px;
color: rgba(255, 255, 255, 0.7);
background: transparent;
""")
buttons_layout = QHBoxLayout()
buttons_layout.setSpacing(12)
self.toggle_button = QPushButton("Hide Traffic Lights")
self.toggle_button.setStyleSheet("""
QPushButton {
background: rgba(255, 255, 255, 0.15);
border: none;
border-radius: 8px;
padding: 12px 24px;
color: white;
font-size: 13px;
min-width: 160px;
}
QPushButton:hover {
background: rgba(255, 255, 255, 0.25);
}
QPushButton:pressed {
background: rgba(255, 255, 255, 0.1);
}
""")
self.toggle_button.clicked.connect(self._toggle_traffic_lights)
buttons_layout.addStretch()
buttons_layout.addWidget(self.toggle_button)
buttons_layout.addStretch()
layout.addWidget(title)
layout.addWidget(description)
layout.addStretch()
layout.addLayout(buttons_layout)
self.setCentralWidget(central)
def _toggle_traffic_lights(self) -> None:
if self._lights_visible:
glass.hide_traffic_lights(self)
self.toggle_button.setText("Show Traffic Lights")
else:
glass.show_traffic_lights(self)
self.toggle_button.setText("Hide Traffic Lights")
self._lights_visible = not self._lights_visible
def main() -> int:
app = QApplication(sys.argv)
window = MainWindow()
glass.prepare_window_for_glass(window)
window.show()
# Apply glass to window
glass.apply_glass_to_window(window)
# Reposition traffic lights with custom offset
glass.setup_traffic_lights_inset(window, x_offset=20, y_offset=16)
return app.exec()
if __name__ == "__main__":
sys.exit(main())

151
docs/getting_started.rst Normal file
View File

@@ -0,0 +1,151 @@
Getting Started
===============
This guide covers installation and basic usage of pyqt-liquidglass.
Installation
------------
Using pip
~~~~~~~~~
.. code-block:: bash
pip install pyqt-liquidglass
Using uv
~~~~~~~~
.. code-block:: bash
uv add pyqt-liquidglass
Requirements
------------
- **Python**: 3.12 or higher
- **Operating System**: macOS (functions are safe no-ops on other platforms)
- **Qt Binding**: PySide6 or PyQt6
The library automatically detects your Qt binding.
Quick Start
-----------
The Three-Step Pattern
~~~~~~~~~~~~~~~~~~~~~~
Every glass effect follows the same pattern:
1. **Prepare** the window before showing
2. **Show** the window
3. **Apply** the glass effect
.. code-block:: python
import pyqt_liquidglass as glass
# 1. Prepare before showing
glass.prepare_window_for_glass(window)
# 2. Show the window
window.show()
# 3. Apply glass after showing
glass.apply_glass_to_window(window)
Full Window Example
~~~~~~~~~~~~~~~~~~~
.. code-block:: python
import sys
from PySide6.QtCore import Qt
from PySide6.QtWidgets import QApplication, QLabel, QMainWindow, QVBoxLayout, QWidget
import pyqt_liquidglass as glass
class MainWindow(QMainWindow):
def __init__(self) -> None:
super().__init__()
self.setWindowTitle("Glass Demo")
self.resize(600, 400)
central = QWidget()
central.setStyleSheet("background: transparent;")
layout = QVBoxLayout(central)
layout.setContentsMargins(40, 60, 40, 40)
label = QLabel("Hello, Liquid Glass!")
label.setAlignment(Qt.AlignmentFlag.AlignCenter)
label.setStyleSheet("""
font-size: 28px;
font-weight: 600;
color: white;
background: transparent;
""")
layout.addWidget(label)
self.setCentralWidget(central)
def main() -> int:
app = QApplication(sys.argv)
window = MainWindow()
glass.prepare_window_for_glass(window)
window.show()
glass.apply_glass_to_window(window)
return app.exec()
if __name__ == "__main__":
sys.exit(main())
Key Points
~~~~~~~~~~
- Set ``background: transparent`` on widgets that should show the glass through
- Call ``prepare_window_for_glass()`` before ``show()``
- Call ``apply_glass_to_window()`` after ``show()``
- The window needs to be visible for the native view hierarchy to exist
Widget Glass
~~~~~~~~~~~~
For applying glass to specific widgets (like sidebars):
.. code-block:: python
sidebar = QWidget()
sidebar.setFixedWidth(250)
sidebar.setStyleSheet("background: transparent;")
# After window.show():
glass.apply_glass_to_widget(sidebar, options=glass.GlassOptions.sidebar())
Traffic Lights
~~~~~~~~~~~~~~
Reposition the macOS window buttons:
.. code-block:: python
glass.setup_traffic_lights_inset(window, x_offset=20, y_offset=12)
Hide or show them:
.. code-block:: python
glass.hide_traffic_lights(window)
glass.show_traffic_lights(window)
Next Steps
----------
- Learn about :doc:`core_concepts` to understand how glass effects work
- See :doc:`examples` for complete working examples
- Check the :doc:`api` for detailed function signatures

89
docs/index.rst Normal file
View File

@@ -0,0 +1,89 @@
pyqt-liquidglass
================
**macOS Liquid Glass effects for PySide6 and PyQt6**
pyqt-liquidglass brings Apple's Liquid Glass visual effects to your Qt applications on macOS. It provides a clean Python API to apply the native ``NSGlassEffectView`` (macOS 26+) or ``NSVisualEffectView`` (fallback) to windows and widgets.
----
Features
--------
- **Window Glass**: Apply glass effects to entire windows
- **Widget Glass**: Target specific widgets like sidebars or panels
- **Traffic Lights Control**: Reposition, hide, or show window buttons
- **GlassOptions**: Configure corner radius, padding, materials, and blending
- **Cross-Version**: Uses ``NSGlassEffectView`` on macOS 26+, falls back to ``NSVisualEffectView``
- **Safe No-ops**: All functions work on non-macOS platforms (return ``None`` or ``False``)
Quick Example
-------------
.. code-block:: python
from PySide6.QtWidgets import QApplication, QMainWindow
import pyqt_liquidglass as glass
app = QApplication([])
window = QMainWindow()
window.resize(800, 600)
# Prepare before showing
glass.prepare_window_for_glass(window)
window.show()
# Apply glass after showing
glass.apply_glass_to_window(window)
app.exec()
Installation
------------
.. code-block:: bash
pip install pyqt-liquidglass
Or with uv:
.. code-block:: bash
uv add pyqt-liquidglass
**Requirements**: Python 3.12+, macOS, PySide6 or PyQt6
----
Documentation
=============
.. toctree::
:maxdepth: 2
:caption: User Guide
getting_started
core_concepts
examples
.. toctree::
:maxdepth: 2
:caption: API Reference
api
----
Indices
=======
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
----
License
=======
MIT License. See LICENSE.md for details.

35
docs/make.bat Normal file
View File

@@ -0,0 +1,35 @@
@ECHO OFF
pushd %~dp0
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set SOURCEDIR=.
set BUILDDIR=_build
%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.https://www.sphinx-doc.org/
exit /b 1
)
if "%1" == "" goto help
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
goto end
:help
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
:end
popd

3
docs/requirements.txt Normal file
View File

@@ -0,0 +1,3 @@
sphinx
furo
sphinx-autodoc-typehints