Skip to content

Commit e8a2570

Browse files
committed
fix(plot_directpainter): set and clear attributes as requested
QwtPlotDirectPainter.setAttribute decided whether to set or to clear the attribute by comparing its current state with `on`, instead of using `on`: enabling AtomicPainter twice disabled it, and FullRepaint or CopyBackingStore could not be disabled anymore once enabled (their non-boolean flag values never compare equal to `on`). - Restore the Qwt C++ logic: change the attribute only when its state differs from `on`, set it when `on` is true and clear it otherwise, and reset the painter only when AtomicPainter gets enabled. - Regression tests: set, set again, clear, clear again and default `on` for each attribute, other attributes unchanged; painter reset count. - Changelog entry. Refs #115 Assisted-by: Claude Opus 5.5
1 parent f266dd8 commit e8a2570

3 files changed

Lines changed: 75 additions & 6 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
- Fixed `QwtPlotMarker.legendIcon` for markers with a symbol, which raised an `AssertionError` or a `TypeError`: such markers can now be shown in a legend ([Issue #115](https://github.com/PlotPyStack/PythonQwt/issues/115))
1414
- Fixed `QwtPlotGrid.make`, which raised a `TypeError` when only some of the minor pen arguments (`mincolor`, `minwidth`, `minstyle`) were given: each of them is now honored, the missing ones taking their documented default value ([Issue #115](https://github.com/PlotPyStack/PythonQwt/issues/115))
1515
- Fixed `QwtPowerTransform`, which raised a `ValueError` when drawing a curve on an axis with a power scale (curve data are mapped as NumPy arrays), and an `AttributeError` with NumPy < 2.0 (`numpy.pow` does not exist there): it now transforms scalars (with unchanged results) as well as NumPy arrays, with any supported NumPy version ([Issue #115](https://github.com/PlotPyStack/PythonQwt/issues/115))
16+
- Fixed `QwtPlotDirectPainter.setAttribute`, which did not set or clear attributes as requested: enabling `AtomicPainter` twice disabled it, and `FullRepaint` or `CopyBackingStore` could not be disabled anymore once enabled ([Issue #115](https://github.com/PlotPyStack/PythonQwt/issues/115))
1617

1718
## Version 0.16.3
1819

‎qwt/plot_directpainter.py‎

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -119,12 +119,13 @@ def setAttribute(self, attribute, on=True):
119119
120120
:py:meth:`testAttribute()`
121121
"""
122-
if self.testAttribute(attribute) != on:
123-
self.__data.attributes |= attribute
124-
else:
125-
self.__data.attributes &= ~attribute
126-
if attribute == self.AtomicPainter and on:
127-
self.reset()
122+
if bool(self.testAttribute(attribute)) != on:
123+
if on:
124+
self.__data.attributes |= attribute
125+
else:
126+
self.__data.attributes &= ~attribute
127+
if attribute == self.AtomicPainter and on:
128+
self.reset()
128129

129130
def testAttribute(self, attribute):
130131
"""

‎qwt/tests/test_issue115_porting_bugs.py‎

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
QwtLinearScaleEngine,
2424
QwtPlot,
2525
QwtPlotCurve,
26+
QwtPlotDirectPainter,
2627
QwtPlotGrid,
2728
QwtPlotItem,
2829
QwtPlotMarker,
@@ -304,6 +305,69 @@ def test_power_transform_curve_rendering():
304305
del app
305306

306307

308+
# ---------------------------------------------------------------------------
309+
# QwtPlotDirectPainter.setAttribute
310+
# ---------------------------------------------------------------------------
311+
312+
DIRECT_PAINTER_ATTRIBUTES = (
313+
QwtPlotDirectPainter.AtomicPainter,
314+
QwtPlotDirectPainter.FullRepaint,
315+
QwtPlotDirectPainter.CopyBackingStore,
316+
)
317+
318+
319+
class _CountingDirectPainter(QwtPlotDirectPainter):
320+
"""Direct painter counting the calls to `reset`"""
321+
322+
def __init__(self):
323+
super().__init__()
324+
self.reset_count = 0
325+
326+
def reset(self):
327+
self.reset_count += 1
328+
super().reset()
329+
330+
331+
@pytest.mark.parametrize(
332+
"attribute",
333+
DIRECT_PAINTER_ATTRIBUTES,
334+
ids=("AtomicPainter", "FullRepaint", "CopyBackingStore"),
335+
)
336+
def test_direct_painter_set_attribute(attribute):
337+
"""setAttribute sets or clears an attribute, as requested"""
338+
app = _ensure_app() # keep a reference alive for the duration of the test
339+
painter = QwtPlotDirectPainter()
340+
others = [attr for attr in DIRECT_PAINTER_ATTRIBUTES if attr != attribute]
341+
for other in others:
342+
painter.setAttribute(other, True)
343+
assert not painter.testAttribute(attribute)
344+
for on in (True, True, False, False, True):
345+
painter.setAttribute(attribute, on)
346+
assert bool(painter.testAttribute(attribute)) is on
347+
assert all(painter.testAttribute(other) for other in others)
348+
painter.setAttribute(attribute, False)
349+
painter.setAttribute(attribute) # `on` defaults to True
350+
assert painter.testAttribute(attribute)
351+
del app
352+
353+
354+
def test_direct_painter_atomic_painter_reset():
355+
"""Enabling AtomicPainter resets the painter, as in Qwt C++"""
356+
app = _ensure_app() # keep a reference alive for the duration of the test
357+
painter = _CountingDirectPainter()
358+
painter.setAttribute(QwtPlotDirectPainter.AtomicPainter, True)
359+
assert painter.reset_count == 1
360+
painter.setAttribute(QwtPlotDirectPainter.AtomicPainter, True) # unchanged
361+
assert painter.reset_count == 1
362+
painter.setAttribute(QwtPlotDirectPainter.AtomicPainter, False)
363+
assert painter.reset_count == 1
364+
painter.setAttribute(QwtPlotDirectPainter.AtomicPainter, True)
365+
assert painter.reset_count == 2
366+
painter.setAttribute(QwtPlotDirectPainter.FullRepaint, True)
367+
assert painter.reset_count == 2
368+
del app
369+
370+
307371
if __name__ == "__main__":
308372
for name in ("toPixmap", "toImage"):
309373
test_graphic_conversion_default_size(name)
@@ -315,4 +379,7 @@ def test_power_transform_curve_rendering():
315379
test_grid_make_without_minor_pen()
316380
test_power_transform_scale_map()
317381
test_power_transform_curve_rendering()
382+
for attr in DIRECT_PAINTER_ATTRIBUTES:
383+
test_direct_painter_set_attribute(attr)
384+
test_direct_painter_atomic_painter_reset()
318385
print("OK")

0 commit comments

Comments
 (0)