Skip to content

Generalise stylesheet parsing to extract colours for light/dark theme callback. #105

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions src/napari_matplotlib/tests/test_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,29 +18,37 @@ def test_interval():

def test_get_size_from_css(mocker):
"""Test getting the max-width and max-height from something in css"""
# some weird (but valid) css to check we can skip things correctly
test_css = """
Flibble {
padding: 0 0 1px 2px;
color: rgb(3, 4, 555);
min-width : 0;
max-width : 123px;
min-height : 0px;
min-height : 0%;
max-height : 456px;
padding: 0px;
}
"""
mocker.patch("napari.qt.get_current_stylesheet").return_value = test_css
assert from_napari_css_get_size_of("Flibble", (1, 2)) == QSize(123, 456)
assert from_napari_css_get_size_of("Flibble", fallback=(1, 2)) == QSize(
123, 456
)


def test_fallback_if_missing_dimensions(mocker):
"""Test fallback if given something that doesn't have dimensions"""
test_css = " Flobble { background-color: rgb(0, 97, 163); } "
mocker.patch("napari.qt.get_current_stylesheet").return_value = test_css
with pytest.warns(RuntimeWarning, match="Unable to find DimensionToken"):
assert from_napari_css_get_size_of("Flobble", (1, 2)) == QSize(1, 2)
assert from_napari_css_get_size_of(
"Flobble", fallback=(1, 2)
) == QSize(1, 2)


def test_fallback_if_prelude_not_in_css():
"""Test fallback if given something not in the css"""
doesntexist = "AQButtonThatDoesntExist"
with pytest.warns(RuntimeWarning, match=f"Unable to find {doesntexist}"):
assert from_napari_css_get_size_of(doesntexist, (1, 2)) == QSize(1, 2)
assert from_napari_css_get_size_of(
doesntexist, fallback=(1, 2)
) == QSize(1, 2)
26 changes: 18 additions & 8 deletions src/napari_matplotlib/util.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import List, Optional, Tuple, Union
from typing import Generator, List, Optional, Tuple, Union
from warnings import warn

import napari.qt
Expand Down Expand Up @@ -47,6 +47,21 @@ def __contains__(self, val: int) -> bool:
return True


def _logical_lines(
nodes: List[tinycss2.ast.Node],
) -> Generator[Tuple[tinycss2.ast.Node, tinycss2.ast.Node], None, None]:
"""Generator to provide logical lines (thing: value) of css (terminated by ';')"""
ident, dimension = None, None
for node in nodes:
if node == ";":
yield (ident, dimension)
ident, dimension = None, None
elif node.type == "ident":
ident = node
elif node.type == "dimension":
dimension = node


def _has_id(nodes: List[tinycss2.ast.Node], id_name: str) -> bool:
"""
Is `id_name` in IdentTokens in the list of CSS `nodes`?
Expand All @@ -66,13 +81,8 @@ def _get_dimension(
-------
None if no IdentToken is found.
"""
cleaned_nodes = [node for node in nodes if node.type != "whitespace"]
for name, _, value, _ in zip(*(iter(cleaned_nodes),) * 4):
if (
name.type == "ident"
and value.type == "dimension"
and name.value == id_name
):
for name, value in _logical_lines(nodes):
if name.value == id_name:
return value.int_value
warn(f"Unable to find DimensionToken for {id_name}", RuntimeWarning)
return None
Expand Down