QT-PyQt-PySide-Custom-Widgets-Pro 1.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- custom_widgets_pro/__init__.py +73 -0
- custom_widgets_pro/_catalog.py +25 -0
- custom_widgets_pro/_cli.py +132 -0
- custom_widgets_pro/_license.py +419 -0
- custom_widgets_pro/_version.py +14 -0
- custom_widgets_pro/datatable/__init__.py +17 -0
- custom_widgets_pro/datatable/datatable_pro.py +319 -0
- custom_widgets_pro/datatable/export.py +143 -0
- custom_widgets_pro/datatable/frozen_view.py +112 -0
- custom_widgets_pro/datatable/grouping.py +309 -0
- custom_widgets_pro/datatable/pivot.py +100 -0
- custom_widgets_pro/datatable/provider.py +98 -0
- custom_widgets_pro/datatable/virtual_model.py +451 -0
- custom_widgets_pro/widgets/__init__.py +7 -0
- custom_widgets_pro/widgets/charts/QCustomBeeswarm.py +317 -0
- custom_widgets_pro/widgets/charts/QCustomBubbleChart.py +655 -0
- custom_widgets_pro/widgets/charts/QCustomCandlestickChart.py +522 -0
- custom_widgets_pro/widgets/charts/QCustomDivergingBarChart.py +430 -0
- custom_widgets_pro/widgets/charts/QCustomDotMatrix.py +266 -0
- custom_widgets_pro/widgets/charts/QCustomFunnelChart.py +474 -0
- custom_widgets_pro/widgets/charts/QCustomGanttChart.py +376 -0
- custom_widgets_pro/widgets/charts/QCustomHeatmap.py +555 -0
- custom_widgets_pro/widgets/charts/QCustomRadarChart.py +600 -0
- custom_widgets_pro/widgets/charts/QCustomRadialBars.py +441 -0
- custom_widgets_pro/widgets/charts/QCustomRadialLines.py +554 -0
- custom_widgets_pro/widgets/charts/QCustomRangeBarChart.py +504 -0
- custom_widgets_pro/widgets/charts/QCustomSankey.py +539 -0
- custom_widgets_pro/widgets/charts/QCustomScatterChart.py +623 -0
- custom_widgets_pro/widgets/charts/__init__.py +1 -0
- custom_widgets_pro/widgets/data/QCustomCodeEditor.py +391 -0
- custom_widgets_pro/widgets/data/QCustomNodeGraph.py +1030 -0
- custom_widgets_pro/widgets/data/QCustomRichTextEditor.py +189 -0
- custom_widgets_pro/widgets/data/QCustomTableToolbar.py +566 -0
- custom_widgets_pro/widgets/data/__init__.py +1 -0
- custom_widgets_pro/widgets/media/QCustomImageViewer.py +300 -0
- custom_widgets_pro/widgets/media/QCustomMediaGrid.py +197 -0
- custom_widgets_pro/widgets/media/QCustomMediaTimeline.py +607 -0
- custom_widgets_pro/widgets/media/QCustomVideoPlayer.py +326 -0
- custom_widgets_pro/widgets/media/__init__.py +1 -0
- qt_pyqt_pyside_custom_widgets_pro-1.1.0.dist-info/METADATA +112 -0
- qt_pyqt_pyside_custom_widgets_pro-1.1.0.dist-info/RECORD +45 -0
- qt_pyqt_pyside_custom_widgets_pro-1.1.0.dist-info/WHEEL +5 -0
- qt_pyqt_pyside_custom_widgets_pro-1.1.0.dist-info/entry_points.txt +2 -0
- qt_pyqt_pyside_custom_widgets_pro-1.1.0.dist-info/licenses/LICENSE +91 -0
- qt_pyqt_pyside_custom_widgets_pro-1.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,441 @@
|
|
|
1
|
+
########################################################################
|
|
2
|
+
## SPINN DESIGN CODE
|
|
3
|
+
# YOUTUBE: (SPINN TV) https://www.youtube.com/@SpinnTV
|
|
4
|
+
# WEBSITE: customwidgets.org
|
|
5
|
+
########################################################################
|
|
6
|
+
|
|
7
|
+
########################################################################
|
|
8
|
+
## QCustomRadialBars - a painted radial bar chart.
|
|
9
|
+
##
|
|
10
|
+
## Concentric arcs, one per category, each sweeping in proportion to its
|
|
11
|
+
## value. The "activity rings" form: compact, reads at a glance, and unlike a
|
|
12
|
+
## pie it compares values that do NOT sum to a whole.
|
|
13
|
+
##
|
|
14
|
+
## QPainter only, NO QtCharts (see docs/design/mui-charts-gap.md). Angles come
|
|
15
|
+
## from the shared _chart_axis polar helpers, so this winds the same way as
|
|
16
|
+
## QCustomRadarChart and QCustomRadialLines.
|
|
17
|
+
##
|
|
18
|
+
## Data goes in with setBars([...]) in code, or barsCsv in Qt Designer:
|
|
19
|
+
##
|
|
20
|
+
## barsCsv = "Move=82,Exercise=64,Stand=95"
|
|
21
|
+
##
|
|
22
|
+
## Emits barHovered(int) and barClicked(int); -1 means "nothing".
|
|
23
|
+
########################################################################
|
|
24
|
+
import math
|
|
25
|
+
|
|
26
|
+
from qtpy.QtCore import Qt, Signal, Property, QRectF, QSize, QPointF
|
|
27
|
+
from qtpy.QtGui import QColor, QPainter, QPen, QBrush, QFontMetrics
|
|
28
|
+
from qtpy.QtWidgets import QWidget, QSizePolicy
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class QCustomRadialBars(QWidget):
|
|
32
|
+
barHovered = Signal(int)
|
|
33
|
+
barClicked = Signal(int)
|
|
34
|
+
|
|
35
|
+
WIDGET_ICON = "components/icons/donut_large.png"
|
|
36
|
+
WIDGET_TOOLTIP = "A painted radial bar chart (activity rings)"
|
|
37
|
+
WIDGET_MODULE = "Custom_Widgets.QCustomRadialBars"
|
|
38
|
+
WIDGET_DOM_XML = """
|
|
39
|
+
<ui language='c++'>
|
|
40
|
+
<widget class='QCustomRadialBars' name='customRadialBars'>
|
|
41
|
+
<property name='geometry'><rect><x>0</x><y>0</y><width>300</width><height>300</height></rect></property>
|
|
42
|
+
<property name='barsCsv'><string>Move=82,Exercise=64,Stand=95</string></property>
|
|
43
|
+
</widget>
|
|
44
|
+
</ui>
|
|
45
|
+
"""
|
|
46
|
+
__catalog__ = {
|
|
47
|
+
"name": "QCustomRadialBars",
|
|
48
|
+
"props": {"barsCsv": {"type": "string", "default": ""},
|
|
49
|
+
"colorsCsv": {"type": "string", "default": ""},
|
|
50
|
+
"maxValue": {"type": "float", "default": 100.0},
|
|
51
|
+
"startAngle": {"type": "int", "default": 90},
|
|
52
|
+
"clockwise": {"type": "bool", "default": True},
|
|
53
|
+
"thickness": {"type": "int", "default": 18},
|
|
54
|
+
"spacing": {"type": "int", "default": 6},
|
|
55
|
+
"holeRatio": {"type": "float", "default": 0.35},
|
|
56
|
+
"rounded": {"type": "bool", "default": True},
|
|
57
|
+
"showTrack": {"type": "bool", "default": True},
|
|
58
|
+
"showLabels": {"type": "bool", "default": True},
|
|
59
|
+
"showValues": {"type": "bool", "default": True},
|
|
60
|
+
"trackColor": {"type": "color", "default": "#e2e8f0"},
|
|
61
|
+
"labelColor": {"type": "color", "default": "#0f172a"}},
|
|
62
|
+
"signals": ["barHovered", "barClicked"],
|
|
63
|
+
"tokens_used": ["surface-muted", "on-surface"],
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
# Rich editors for the Designer "Custom Properties" dock (see
|
|
67
|
+
# DesignerTools.CustomPropertiesDock).
|
|
68
|
+
DESIGNER_CUSTOM_PROPS = [
|
|
69
|
+
{"name": "barsCsv", "kind": "str", "group": "General"},
|
|
70
|
+
{"name": "colorsCsv", "kind": "str", "group": "Colors"},
|
|
71
|
+
{"name": "maxValue", "kind": "float", "group": "General"},
|
|
72
|
+
{"name": "startAngle", "kind": "int", "group": "General"},
|
|
73
|
+
{"name": "clockwise", "kind": "bool", "group": "General"},
|
|
74
|
+
{"name": "thickness", "kind": "int", "group": "General"},
|
|
75
|
+
{"name": "spacing", "kind": "int", "group": "General"},
|
|
76
|
+
{"name": "holeRatio", "kind": "float", "group": "General"},
|
|
77
|
+
{"name": "rounded", "kind": "bool", "group": "General"},
|
|
78
|
+
{"name": "showTrack", "kind": "bool", "group": "General"},
|
|
79
|
+
{"name": "showLabels", "kind": "bool", "group": "General"},
|
|
80
|
+
{"name": "showValues", "kind": "bool", "group": "General"},
|
|
81
|
+
{"name": "trackColor", "kind": "color", "group": "Colors"},
|
|
82
|
+
{"name": "labelColor", "kind": "color", "group": "Colors"},
|
|
83
|
+
]
|
|
84
|
+
|
|
85
|
+
_DEFAULT_COLORS = ["#2563eb", "#16a34a", "#f59e0b", "#dc2626", "#7c3aed",
|
|
86
|
+
"#0891b2"]
|
|
87
|
+
|
|
88
|
+
def __init__(self, parent=None, bars=None):
|
|
89
|
+
super().__init__(parent)
|
|
90
|
+
self.setObjectName("QCustomRadialBars")
|
|
91
|
+
self._bars = [] # list of (label, value)
|
|
92
|
+
self._colors = []
|
|
93
|
+
self._maxValue = 100.0
|
|
94
|
+
self._startAngle = 90
|
|
95
|
+
self._clockwise = True
|
|
96
|
+
self._thickness = 18
|
|
97
|
+
self._spacing = 6
|
|
98
|
+
self._holeRatio = 0.35
|
|
99
|
+
self._rounded = True
|
|
100
|
+
self._showTrack = True
|
|
101
|
+
self._showLabels = True
|
|
102
|
+
self._showValues = True
|
|
103
|
+
self._hover = -1
|
|
104
|
+
|
|
105
|
+
self._trackColor = QColor("#e2e8f0")
|
|
106
|
+
self._labelColor = QColor("#0f172a")
|
|
107
|
+
|
|
108
|
+
self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
|
109
|
+
self.setMouseTracking(True)
|
|
110
|
+
if bars:
|
|
111
|
+
self.setBars(bars)
|
|
112
|
+
|
|
113
|
+
# ------------------------------------------------------------------ #
|
|
114
|
+
## Data
|
|
115
|
+
# ------------------------------------------------------------------ #
|
|
116
|
+
@staticmethod
|
|
117
|
+
def _coerce(bar):
|
|
118
|
+
if isinstance(bar, dict):
|
|
119
|
+
label, value = bar.get("label"), bar.get("value")
|
|
120
|
+
elif isinstance(bar, (tuple, list)) and len(bar) >= 2:
|
|
121
|
+
label, value = bar[0], bar[1]
|
|
122
|
+
else:
|
|
123
|
+
return None
|
|
124
|
+
try:
|
|
125
|
+
return (str(label), max(0.0, float(value)))
|
|
126
|
+
except (TypeError, ValueError):
|
|
127
|
+
return None
|
|
128
|
+
|
|
129
|
+
def setBars(self, bars):
|
|
130
|
+
self._bars = [b for b in (self._coerce(x) for x in (bars or [])) if b]
|
|
131
|
+
self._hover = -1
|
|
132
|
+
self.update()
|
|
133
|
+
|
|
134
|
+
def bars(self):
|
|
135
|
+
return list(self._bars)
|
|
136
|
+
|
|
137
|
+
def barCount(self):
|
|
138
|
+
return len(self._bars)
|
|
139
|
+
|
|
140
|
+
def clearBars(self):
|
|
141
|
+
self._bars = []
|
|
142
|
+
self._hover = -1
|
|
143
|
+
self.update()
|
|
144
|
+
|
|
145
|
+
def maximum(self):
|
|
146
|
+
if self._maxValue > 0:
|
|
147
|
+
return self._maxValue
|
|
148
|
+
return max((v for _l, v in self._bars), default=0.0) or 1.0
|
|
149
|
+
|
|
150
|
+
def barColor(self, index):
|
|
151
|
+
if 0 <= index < len(self._colors) and self._colors[index] is not None:
|
|
152
|
+
return QColor(self._colors[index])
|
|
153
|
+
return QColor(self._DEFAULT_COLORS[index % len(self._DEFAULT_COLORS)])
|
|
154
|
+
|
|
155
|
+
def fractionFor(self, index):
|
|
156
|
+
"""0..1 of the maximum. Values above the maximum are clamped so a bar
|
|
157
|
+
cannot wrap past its own start and read as a smaller number."""
|
|
158
|
+
if not (0 <= index < len(self._bars)):
|
|
159
|
+
return 0.0
|
|
160
|
+
return max(0.0, min(1.0, self._bars[index][1] / self.maximum()))
|
|
161
|
+
|
|
162
|
+
# ------------------------------------------------------------------ #
|
|
163
|
+
## Geometry
|
|
164
|
+
# ------------------------------------------------------------------ #
|
|
165
|
+
def sizeHint(self):
|
|
166
|
+
return QSize(300, 300)
|
|
167
|
+
|
|
168
|
+
def minimumSizeHint(self):
|
|
169
|
+
return QSize(110, 110)
|
|
170
|
+
|
|
171
|
+
def _legendHeight(self):
|
|
172
|
+
if not (self._showLabels or self._showValues) or not self._bars:
|
|
173
|
+
return 0.0
|
|
174
|
+
return QFontMetrics(self.font()).height() + 8
|
|
175
|
+
|
|
176
|
+
def _plotRect(self):
|
|
177
|
+
bottom = self._legendHeight()
|
|
178
|
+
side = max(10.0, min(self.width(), self.height() - bottom) - 16)
|
|
179
|
+
return QRectF((self.width() - side) / 2.0,
|
|
180
|
+
(self.height() - bottom - side) / 2.0, side, side)
|
|
181
|
+
|
|
182
|
+
def ringRect(self, index):
|
|
183
|
+
"""Bounding rect of ring `index`, outermost first."""
|
|
184
|
+
rect = self._plotRect()
|
|
185
|
+
inset = index * (self._thickness + self._spacing) + self._thickness / 2.0
|
|
186
|
+
limit = rect.width() / 2.0 * (1.0 - max(0.0, min(0.95, self._holeRatio)))
|
|
187
|
+
inset = min(inset, max(1.0, limit))
|
|
188
|
+
return rect.adjusted(inset, inset, -inset, -inset)
|
|
189
|
+
|
|
190
|
+
def _sweepFor(self, index):
|
|
191
|
+
"""(startAngle, spanAngle) in Qt's 1/16-degree units."""
|
|
192
|
+
span = self.fractionFor(index) * 360.0
|
|
193
|
+
if self._clockwise:
|
|
194
|
+
span = -span
|
|
195
|
+
return int(self._startAngle * 16), int(span * 16)
|
|
196
|
+
|
|
197
|
+
# ------------------------------------------------------------------ #
|
|
198
|
+
## Painting
|
|
199
|
+
# ------------------------------------------------------------------ #
|
|
200
|
+
def paintEvent(self, e):
|
|
201
|
+
p = QPainter(self)
|
|
202
|
+
p.setRenderHint(QPainter.Antialiasing)
|
|
203
|
+
p.setFont(self.font())
|
|
204
|
+
if not self._bars:
|
|
205
|
+
return
|
|
206
|
+
|
|
207
|
+
cap = Qt.RoundCap if self._rounded else Qt.FlatCap
|
|
208
|
+
for index in range(len(self._bars)):
|
|
209
|
+
ring = self.ringRect(index)
|
|
210
|
+
if self._showTrack:
|
|
211
|
+
pen = QPen(self._trackColor, self._thickness)
|
|
212
|
+
pen.setCapStyle(Qt.FlatCap)
|
|
213
|
+
p.setPen(pen)
|
|
214
|
+
p.setBrush(Qt.NoBrush)
|
|
215
|
+
p.drawArc(ring, 0, 360 * 16)
|
|
216
|
+
|
|
217
|
+
colour = self.barColor(index)
|
|
218
|
+
if index == self._hover:
|
|
219
|
+
colour = colour.lighter(115)
|
|
220
|
+
pen = QPen(colour, self._thickness)
|
|
221
|
+
pen.setCapStyle(cap)
|
|
222
|
+
p.setPen(pen)
|
|
223
|
+
start, span = self._sweepFor(index)
|
|
224
|
+
if span:
|
|
225
|
+
p.drawArc(ring, start, span)
|
|
226
|
+
|
|
227
|
+
if self._showLabels or self._showValues:
|
|
228
|
+
self._paintLabels(p)
|
|
229
|
+
|
|
230
|
+
def _paintLabels(self, p):
|
|
231
|
+
"""A legend strip below the rings.
|
|
232
|
+
|
|
233
|
+
Anchoring each label to its own ring's start angle put the text
|
|
234
|
+
straight over the arcs — every ring starts at the same angle, so the
|
|
235
|
+
labels stacked on top of each other and on the bars underneath. A
|
|
236
|
+
legend also matches the other charts in the family.
|
|
237
|
+
"""
|
|
238
|
+
fm = QFontMetrics(self.font())
|
|
239
|
+
swatch, gap = 9.0, 14.0
|
|
240
|
+
entries = []
|
|
241
|
+
for index, (label, value) in enumerate(self._bars):
|
|
242
|
+
parts = []
|
|
243
|
+
if self._showLabels:
|
|
244
|
+
parts.append(label)
|
|
245
|
+
if self._showValues:
|
|
246
|
+
parts.append("%g" % value)
|
|
247
|
+
text = " ".join(parts)
|
|
248
|
+
if text:
|
|
249
|
+
entries.append((index, text))
|
|
250
|
+
if not entries:
|
|
251
|
+
return
|
|
252
|
+
|
|
253
|
+
widths = [swatch + 5 + fm.horizontalAdvance(text) for _i, text in entries]
|
|
254
|
+
x = (self.width() - (sum(widths) + gap * (len(widths) - 1))) / 2.0
|
|
255
|
+
y = self.height() - self._legendHeight() + 4
|
|
256
|
+
for slot, (index, text) in enumerate(entries):
|
|
257
|
+
p.setPen(Qt.NoPen)
|
|
258
|
+
p.setBrush(QBrush(self.barColor(index)))
|
|
259
|
+
p.drawEllipse(QRectF(x, y + (fm.height() - swatch) / 2.0,
|
|
260
|
+
swatch, swatch))
|
|
261
|
+
p.setPen(QPen(self._labelColor))
|
|
262
|
+
p.drawText(QRectF(x + swatch + 5, y, widths[slot], fm.height()),
|
|
263
|
+
int(Qt.AlignLeft | Qt.AlignVCenter), text)
|
|
264
|
+
x += widths[slot] + gap
|
|
265
|
+
|
|
266
|
+
# ------------------------------------------------------------------ #
|
|
267
|
+
## Interaction
|
|
268
|
+
# ------------------------------------------------------------------ #
|
|
269
|
+
def barAt(self, pos):
|
|
270
|
+
"""Index of the ring under a point, or -1.
|
|
271
|
+
|
|
272
|
+
Tests the radius band only: a point anywhere on the ring counts, filled
|
|
273
|
+
or not, so hovering the empty part of a track still identifies it.
|
|
274
|
+
"""
|
|
275
|
+
point = QPointF(pos)
|
|
276
|
+
for index in range(len(self._bars)):
|
|
277
|
+
ring = self.ringRect(index)
|
|
278
|
+
centre = ring.center()
|
|
279
|
+
distance = math.hypot(point.x() - centre.x(), point.y() - centre.y())
|
|
280
|
+
radius = ring.width() / 2.0
|
|
281
|
+
if abs(distance - radius) <= self._thickness / 2.0:
|
|
282
|
+
return index
|
|
283
|
+
return -1
|
|
284
|
+
|
|
285
|
+
def mouseMoveEvent(self, e):
|
|
286
|
+
index = self.barAt(e.pos())
|
|
287
|
+
if index != self._hover:
|
|
288
|
+
self._hover = index
|
|
289
|
+
self.barHovered.emit(index)
|
|
290
|
+
self.update()
|
|
291
|
+
super().mouseMoveEvent(e)
|
|
292
|
+
|
|
293
|
+
def leaveEvent(self, e):
|
|
294
|
+
if self._hover != -1:
|
|
295
|
+
self._hover = -1
|
|
296
|
+
self.barHovered.emit(-1)
|
|
297
|
+
self.update()
|
|
298
|
+
super().leaveEvent(e)
|
|
299
|
+
|
|
300
|
+
def mouseReleaseEvent(self, e):
|
|
301
|
+
if e.button() == Qt.LeftButton:
|
|
302
|
+
index = self.barAt(e.pos())
|
|
303
|
+
if index >= 0:
|
|
304
|
+
self.barClicked.emit(index)
|
|
305
|
+
super().mouseReleaseEvent(e)
|
|
306
|
+
|
|
307
|
+
# ------------------------------------------------------------------ #
|
|
308
|
+
## Designer properties
|
|
309
|
+
# ------------------------------------------------------------------ #
|
|
310
|
+
@Property(str)
|
|
311
|
+
def barsCsv(self):
|
|
312
|
+
return ",".join("%s=%g" % (label, value) for label, value in self._bars)
|
|
313
|
+
|
|
314
|
+
@barsCsv.setter
|
|
315
|
+
def barsCsv(self, text):
|
|
316
|
+
bars = []
|
|
317
|
+
for chunk in str(text).replace(";", ",").split(","):
|
|
318
|
+
chunk = chunk.strip()
|
|
319
|
+
if not chunk:
|
|
320
|
+
continue
|
|
321
|
+
if "=" in chunk:
|
|
322
|
+
label, _, raw = chunk.partition("=")
|
|
323
|
+
else:
|
|
324
|
+
label, raw = "Bar %d" % (len(bars) + 1), chunk
|
|
325
|
+
try:
|
|
326
|
+
bars.append((label.strip() or "Bar %d" % (len(bars) + 1),
|
|
327
|
+
max(0.0, float(raw.strip()))))
|
|
328
|
+
except ValueError:
|
|
329
|
+
continue
|
|
330
|
+
self.setBars(bars)
|
|
331
|
+
|
|
332
|
+
@Property(str)
|
|
333
|
+
def colorsCsv(self):
|
|
334
|
+
return ",".join(c.name() if c is not None else "" for c in self._colors)
|
|
335
|
+
|
|
336
|
+
@colorsCsv.setter
|
|
337
|
+
def colorsCsv(self, text):
|
|
338
|
+
colors = []
|
|
339
|
+
for token in str(text).replace(";", ",").split(","):
|
|
340
|
+
token = token.strip()
|
|
341
|
+
colour = QColor(token) if token else QColor()
|
|
342
|
+
colors.append(colour if colour.isValid() else None)
|
|
343
|
+
self._colors = colors
|
|
344
|
+
self.update()
|
|
345
|
+
|
|
346
|
+
@Property(float)
|
|
347
|
+
def maxValue(self):
|
|
348
|
+
return self._maxValue
|
|
349
|
+
|
|
350
|
+
@maxValue.setter
|
|
351
|
+
def maxValue(self, value):
|
|
352
|
+
self._maxValue = max(0.0, float(value)); self.update()
|
|
353
|
+
|
|
354
|
+
@Property(int)
|
|
355
|
+
def startAngle(self):
|
|
356
|
+
return self._startAngle
|
|
357
|
+
|
|
358
|
+
@startAngle.setter
|
|
359
|
+
def startAngle(self, value):
|
|
360
|
+
self._startAngle = int(value) % 360; self.update()
|
|
361
|
+
|
|
362
|
+
@Property(bool)
|
|
363
|
+
def clockwise(self):
|
|
364
|
+
return self._clockwise
|
|
365
|
+
|
|
366
|
+
@clockwise.setter
|
|
367
|
+
def clockwise(self, value):
|
|
368
|
+
self._clockwise = bool(value); self.update()
|
|
369
|
+
|
|
370
|
+
@Property(int)
|
|
371
|
+
def thickness(self):
|
|
372
|
+
return self._thickness
|
|
373
|
+
|
|
374
|
+
@thickness.setter
|
|
375
|
+
def thickness(self, value):
|
|
376
|
+
self._thickness = max(1, int(value)); self.update()
|
|
377
|
+
|
|
378
|
+
@Property(int)
|
|
379
|
+
def spacing(self):
|
|
380
|
+
return self._spacing
|
|
381
|
+
|
|
382
|
+
@spacing.setter
|
|
383
|
+
def spacing(self, value):
|
|
384
|
+
self._spacing = max(0, int(value)); self.update()
|
|
385
|
+
|
|
386
|
+
@Property(float)
|
|
387
|
+
def holeRatio(self):
|
|
388
|
+
return self._holeRatio
|
|
389
|
+
|
|
390
|
+
@holeRatio.setter
|
|
391
|
+
def holeRatio(self, value):
|
|
392
|
+
self._holeRatio = max(0.0, min(0.95, float(value))); self.update()
|
|
393
|
+
|
|
394
|
+
@Property(bool)
|
|
395
|
+
def rounded(self):
|
|
396
|
+
return self._rounded
|
|
397
|
+
|
|
398
|
+
@rounded.setter
|
|
399
|
+
def rounded(self, value):
|
|
400
|
+
self._rounded = bool(value); self.update()
|
|
401
|
+
|
|
402
|
+
@Property(bool)
|
|
403
|
+
def showTrack(self):
|
|
404
|
+
return self._showTrack
|
|
405
|
+
|
|
406
|
+
@showTrack.setter
|
|
407
|
+
def showTrack(self, value):
|
|
408
|
+
self._showTrack = bool(value); self.update()
|
|
409
|
+
|
|
410
|
+
@Property(bool)
|
|
411
|
+
def showLabels(self):
|
|
412
|
+
return self._showLabels
|
|
413
|
+
|
|
414
|
+
@showLabels.setter
|
|
415
|
+
def showLabels(self, value):
|
|
416
|
+
self._showLabels = bool(value); self.update()
|
|
417
|
+
|
|
418
|
+
@Property(bool)
|
|
419
|
+
def showValues(self):
|
|
420
|
+
return self._showValues
|
|
421
|
+
|
|
422
|
+
@showValues.setter
|
|
423
|
+
def showValues(self, value):
|
|
424
|
+
self._showValues = bool(value); self.update()
|
|
425
|
+
|
|
426
|
+
# -- colours (from tokens via qproperty) --
|
|
427
|
+
@Property(QColor)
|
|
428
|
+
def trackColor(self):
|
|
429
|
+
return self._trackColor
|
|
430
|
+
|
|
431
|
+
@trackColor.setter
|
|
432
|
+
def trackColor(self, c):
|
|
433
|
+
self._trackColor = QColor(c); self.update()
|
|
434
|
+
|
|
435
|
+
@Property(QColor)
|
|
436
|
+
def labelColor(self):
|
|
437
|
+
return self._labelColor
|
|
438
|
+
|
|
439
|
+
@labelColor.setter
|
|
440
|
+
def labelColor(self, c):
|
|
441
|
+
self._labelColor = QColor(c); self.update()
|