Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
jnsebgosselin committed Oct 11, 2023
2 parents 502fb35 + 7991861 commit bc92c73
Show file tree
Hide file tree
Showing 4 changed files with 409 additions and 1 deletion.
45 changes: 45 additions & 0 deletions qtapputils/qthelpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,17 @@
# ---- Standard imports
import sys
import platform
from math import pi

# ---- Third party imports
from qtpy.QtGui import QKeySequence
from qtpy.QtCore import QByteArray, Qt, QSize
from qtpy.QtWidgets import (
QWidget, QSizePolicy, QToolButton, QApplication, QStyleFactory, QAction)

# --- Local imports
from qtapputils.widgets import WaitingSpinner


def qbytearray_to_hexstate(qba):
"""Convert QByteArray object to a str hexstate."""
Expand Down Expand Up @@ -129,6 +133,47 @@ def create_action(parent, text: str = None, shortcut: str = None,
return action


def create_waitspinner(
size: int = 32, n: int = 11, parent: QWidget = None
) -> WaitingSpinner:
"""
Create a wait spinner.
Parameters
----------
size : int, optional
The size of the spinner in integer point precision (one point is equal
to 1/72 of an inch). The default is 32.
n : int, optional
The number of dots used to draw the spinner. The default is 11.
parent : QWidget, optional
The parent widget of the spinner. The default is None.
Returns
-------
spinner : WaitingSpinner
The waitspinner created with the specified parameters
"""
dot_padding = 1

# To calculate the size of the dots, we need to solve the following
# system of two equations in two variables.
# (1) middle_circumference = pi * (size - dot_size)
# (2) middle_circumference = n * (dot_size + dot_padding)
dot_size = (pi * size - n * dot_padding) / (n + pi)
inner_radius = (size - 2 * dot_size) / 2

spinner = WaitingSpinner(parent, centerOnParent=False)
spinner.setTrailSizeDecreasing(True)
spinner.setNumberOfLines(n)
spinner.setLineLength(dot_size)
spinner.setLineWidth(dot_size)
spinner.setInnerRadius(inner_radius)
spinner.setColor(Qt.black)

return spinner


def format_statustip(text: str, shortcuts: list[str] | str):
"""
Format text and shortcut into a single str to be set
Expand Down
108 changes: 108 additions & 0 deletions qtapputils/tests/test_qthelpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# -*- coding: utf-8 -*-
# -----------------------------------------------------------------------------
# Copyright © QtAppUtils Project Contributors
# https://github.com/jnsebgosselin/apputils
#
# This file is part of QtAppUtils.
# Licensed under the terms of the MIT License.
# -----------------------------------------------------------------------------

"""Tests for the qthelpers functions."""

# ---- Standard imports
from math import pi
from itertools import product

# ---- Third party imports
from qtpy.QtCore import Qt
import pytest

# ---- Local imports
from qtapputils.qthelpers import format_tooltip, create_waitspinner


# =============================================================================
# Fixtures
# =============================================================================
@pytest.fixture
def spinner(qtbot):
spinner = create_waitspinner(size=48, n=24)
qtbot.addWidget(spinner)
return spinner


# =============================================================================
# ---- Tests
# =============================================================================
def test_format_tooltip():
"""Test that tooltip are formatted correctly."""
texts = ['TEXT', None, '']
shortcuts = ['S', None, '', 'BADSHORTCUT']
tips = ['TOOLTIPTEXT', None, '']
for text, shortcut, tip in product(texts, shortcuts, tips):
keystr = 'S' if shortcut == 'S' else ''
if text and keystr and tip:
expected_ttip = ("<p style='white-space:pre'><b>TEXT (S)</b></p>"
"<p>TOOLTIPTEXT</p>")
elif text and keystr:
expected_ttip = "<p style='white-space:pre'><b>TEXT (S)</b></p>"
elif text and tip:
expected_ttip = ("<p style='white-space:pre'><b>TEXT</b></p>"
"<p>TOOLTIPTEXT</p>")
elif keystr and tip:
expected_ttip = ("<p style='white-space:pre'><b>(S)</b></p>"
"<p>TOOLTIPTEXT</p>")
elif text:
expected_ttip = "<p style='white-space:pre'><b>TEXT</b></p>"
elif keystr:
expected_ttip = "<p style='white-space:pre'><b>(S)</b></p>"
elif tip:
expected_ttip = "<p>TOOLTIPTEXT</p>"
else:
expected_ttip = ""

tooltip = format_tooltip(text=text, shortcuts=shortcut, tip=tip)
assertion_error = {'text': text, 'shortcut': shortcut, 'tip': tip}

assert tooltip == expected_ttip, assertion_error


def test_create_waitspinner(spinner, qtbot):
"""Test that creating a waitspinner is working as expected."""
n = 24
size = 48
dot_padding = 1

dot_size = (pi * size - n * dot_padding) / (n + pi)
inner_radius = (size - 2 * dot_size) / 2

assert spinner._numberOfLines == 24
assert spinner.lineLength() == dot_size
assert spinner.lineWidth() == dot_size
assert spinner.innerRadius() == inner_radius
assert spinner.isTrailSizeDecreasing() is True
assert spinner.color() == Qt.black

assert spinner.isVisible() is False
assert spinner.isSpinning() is False
assert spinner._currentCounter == 0

# Start the spinner.
spinner.start()
qtbot.wait(100)

assert spinner.isVisible() is True
assert spinner.isSpinning() is True
assert spinner._currentCounter > 0

# Stop the spinner.
spinner.stop()
qtbot.wait(100)

assert spinner.isVisible() is False
assert spinner.isSpinning() is False
assert spinner._currentCounter == 0


if __name__ == "__main__":
pytest.main(['-x', __file__, '-v', '-rw'])
2 changes: 1 addition & 1 deletion qtapputils/widgets/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@
# This file is part of QtAppUtils.
# Licensed under the terms of the MIT License.
# -----------------------------------------------------------------------------

from .range import RangeSpinBox, RangeWidget
from .waitingspinner import WaitingSpinner
Loading

0 comments on commit bc92c73

Please sign in to comment.