-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathpower_bar.py
166 lines (125 loc) · 4.91 KB
/
power_bar.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
import sys
if 'PyQt5' in sys.modules:
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt
from PyQt5.QtCore import pyqtSignal as Signal
else:
from PySide2 import QtCore, QtGui, QtWidgets
from PySide2.QtCore import Qt
from PySide2.QtCore import Signal
class _Bar(QtWidgets.QWidget):
clickedValue = Signal(int)
def __init__(self, steps, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setSizePolicy(
QtWidgets.QSizePolicy.MinimumExpanding,
QtWidgets.QSizePolicy.MinimumExpanding
)
if isinstance(steps, list):
# list of colours.
self.n_steps = len(steps)
self.steps = steps
elif isinstance(steps, int):
# int number of bars, defaults to red.
self.n_steps = steps
self.steps = ['red'] * steps
else:
raise TypeError('steps must be a list or int')
self._bar_solid_percent = 0.8
self._background_color = QtGui.QColor('black')
self._padding = 4.0 # n-pixel gap around edge.
def paintEvent(self, e):
painter = QtGui.QPainter(self)
brush = QtGui.QBrush()
brush.setColor(self._background_color)
brush.setStyle(Qt.SolidPattern)
rect = QtCore.QRect(0, 0, painter.device().width(), painter.device().height())
painter.fillRect(rect, brush)
# Get current state.
parent = self.parent()
vmin, vmax = parent.minimum(), parent.maximum()
value = parent.value()
# Define our canvas.
d_height = painter.device().height() - (self._padding * 2)
d_width = painter.device().width() - (self._padding * 2)
# Draw the bars.
step_size = d_height / self.n_steps
bar_height = step_size * self._bar_solid_percent
bar_spacer = step_size * (1 - self._bar_solid_percent) / 2
# Calculate the y-stop position, from the value in range.
pc = (value - vmin) / (vmax - vmin)
n_steps_to_draw = int(pc * self.n_steps)
for n in range(n_steps_to_draw):
brush.setColor(QtGui.QColor(self.steps[n]))
rect = QtCore.QRect(
self._padding,
self._padding + d_height - ((1 + n) * step_size) + bar_spacer,
d_width,
bar_height
)
painter.fillRect(rect, brush)
painter.end()
def sizeHint(self):
return QtCore.QSize(40, 120)
def _trigger_refresh(self):
self.update()
def _calculate_clicked_value(self, e):
parent = self.parent()
vmin, vmax = parent.minimum(), parent.maximum()
d_height = self.size().height() + (self._padding * 2)
step_size = d_height / self.n_steps
click_y = e.y() - self._padding - step_size / 2
pc = (d_height - click_y) / d_height
value = vmin + pc * (vmax - vmin)
self.clickedValue.emit(value)
def mouseMoveEvent(self, e):
self._calculate_clicked_value(e)
def mousePressEvent(self, e):
self._calculate_clicked_value(e)
class PowerBar(QtWidgets.QWidget):
"""
Custom Qt Widget to show a power bar and dial.
Demonstrating compound and custom-drawn widget.
Left-clicking the button shows the color-chooser, while
right-clicking resets the color to None (no-color).
"""
def __init__(self, steps=5, *args, **kwargs):
super().__init__(*args, **kwargs)
layout = QtWidgets.QVBoxLayout()
self._bar = _Bar(steps)
layout.addWidget(self._bar)
# Create the QDial widget and set up defaults.
# - we provide accessors on this class to override.
self._dial = QtWidgets.QDial()
self._dial.setNotchesVisible(True)
self._dial.setWrapping(False)
self._dial.valueChanged.connect(self._bar._trigger_refresh)
# Take feedback from click events on the meter.
self._bar.clickedValue.connect(self._dial.setValue)
layout.addWidget(self._dial)
self.setLayout(layout)
def __getattr__(self, name):
if name in self.__dict__:
return self[name]
try:
return getattr(self._dial, name)
except AttributeError:
raise AttributeError(
"'{}' object has no attribute '{}'".format(self.__class__.__name__, name)
)
def setColor(self, color):
self._bar.steps = [color] * self._bar.n_steps
self._bar.update()
def setColors(self, colors):
self._bar.n_steps = len(colors)
self._bar.steps = colors
self._bar.update()
def setBarPadding(self, i):
self._bar._padding = int(i)
self._bar.update()
def setBarSolidPercent(self, f):
self._bar._bar_solid_percent = float(f)
self._bar.update()
def setBackgroundColor(self, color):
self._bar._background_color = QtGui.QColor(color)
self._bar.update()