class QRangeSlider(QWidget): """ QRangeSlider class, super class for QVRangeSlider and QHRangeSlider. """ rangeChanged = QtCore.Signal(float, float) collapsedChanged = QtCore.Signal(bool) def __init__(self, slider_range, values, parent=None): QWidget.__init__(self, parent) self.bar_width = 16 self.slider_width = 8 self.emit_while_moving = 0 self.moving = "none" self.old_scale_min = 0.0 self.old_scale_max = 0.0 self.scale = 0 self.setMouseTracking(False) self.single_step = 0.0 self.default_collapse_logic = True self.collapsable = True self.collapsed = False self.prev_moving = None self.bc_min = None self.bc_max = None # Variables initialized in methods self.scale_min = None self.scale_max = None self.start_display_min = None self.start_display_max = None self.start_pos = None self.display_min = None self.display_max = None self.setBarColor(QtGui.QColor(200, 200, 200)) self.setBackgroundColor(QtGui.QColor(100, 100, 100)) self.setHandleColor(QtGui.QColor(200, 200, 200)) self.setHandleBorderColor(QtGui.QColor(200, 200, 200)) self.setEnabled(True) if slider_range: self.setRange(slider_range) else: self.setRange((0.0, 1.0, 0.01)) if values: self.setValues(values) else: self.setValues((0.3, 0.7)) def emitRange(self): change_min = self.old_scale_min != self.scale_min change_max = self.old_scale_max != self.scale_max if change_min or change_max: self.rangeChanged.emit(self.scale_min, self.scale_max) self.old_scale_min = self.scale_min self.old_scale_max = self.scale_max # For debug purposes # if False: # print("Range change:", self.scale_min, self.scale_max) def emitCollapse(self, collapsed_state): self.collapsedChanged.emit(collapsed_state) def getValues(self): """Values of the range bar. Returns ------- values : 2-tuple of int Start and end of the range. """ return [self.scale_min, self.scale_max] def setValues(self, values): """Set values of the range bar. Parameters ---------- values : 2-tuple of float or int Start and end of the range. """ if values is not None: self.scale_min, self.scale_max = values if self.scale_min is None: self.scale_min = self.start if self.scale_max is None: self.scale_max = self.end else: self.scale_min = self.start self.scale_max = self.end self.emitRange() self.updateDisplayValues() self.update() def setValue(self, value): """Set values of the range bar. Parameters ---------- value : float | int Value to used when collapsed """ self.setValues((value, value)) def mouseMoveEvent(self, event): if self.enabled: size = self.rangeSliderSize() pos = self.getPos(event) if self.moving == "min": if pos <= self.bar_width / 2: self.display_min = self.bar_width / 2 elif pos > self.display_max - self.bar_width / 4: self.display_min = self.display_max - self.bar_width / 4 else: self.display_min = pos elif self.moving == "max": if pos >= size + self.bar_width / 2: self.display_max = size + self.bar_width / 2 elif pos < self.display_min + self.bar_width / 4: self.display_max = self.display_min + self.bar_width / 4 else: self.display_max = pos elif self.moving == "bar": width = self.start_display_max - self.start_display_min lower_part = self.start_pos - self.start_display_min upper_part = self.start_display_max - self.start_pos if pos + upper_part >= size + self.bar_width / 2: self.display_max = size + self.bar_width / 2 self.display_min = self.display_max - width elif pos - lower_part <= self.bar_width / 2: self.display_min = self.bar_width / 2 self.display_max = self.display_min + width else: self.display_min = pos - lower_part self.display_max = self.display_min + width self.updateScaleValues() if self.emit_while_moving: self.emitRange() def mousePressEvent(self, event): if self.enabled: pos = self.getPos(event) top = self.rangeSliderSize() + self.bar_width / 2 if event.button() == QtCore.Qt.LeftButton: if not self.collapsed: if abs(self.display_min - pos) <= (self.bar_width / 2): self.moving = "min" elif abs(self.display_max - pos) <= (self.bar_width / 2): self.moving = "max" elif pos > self.display_min and pos < self.display_max: self.moving = "bar" elif pos > self.display_max and pos < top: self.display_max = pos self.moving = "max" self.updateScaleValues() if self.emit_while_moving: self.emitRange() elif pos < self.display_min and pos > self.bar_width / 2: self.display_min = pos self.moving = "min" self.updateScaleValues() if self.emit_while_moving: self.emitRange() else: self.moving = "bar" if pos > self.bar_width / 2 and pos < top: self.display_max = pos self.display_min = pos self.updateScaleValues() if self.emit_while_moving: self.emitRange() else: if self.collapsable: if self.collapsed: # print("collapsed already") self.expand() else: # print("not collapsed") self.collapse() self.emitCollapse(self.collapsed) self.start_display_min = self.display_min self.start_display_max = self.display_max self.start_pos = pos def collapse(self): if self.default_collapse_logic: self.bc_min, self.bc_max = self.scale_min, self.scale_max min_value = (self.scale_max + self.scale_min) / 2 max_value = (self.scale_max + self.scale_min) / 2 self.setValues((min_value, max_value)) else: # self.setValues((self.scale_min, self.scale_max)) self.update() self.collapsed = True def expand(self): if self.default_collapse_logic: min_value = self.scale_min - (self.bc_max - self.bc_min) / 2 max_value = self.scale_min + (self.bc_max - self.bc_min) / 2 if min_value < self.start: min_value = self.start max_value = min_value + self.bc_max - self.bc_min elif max_value > self.end: max_value = self.end min_value = max_value - (self.bc_max - self.bc_min) self.setValues((min_value, max_value)) else: # self.setValues((self.scale_min, self.scale_max)) self.update() self.collapsed = False def mouseReleaseEvent(self, event): if self.enabled: if not (self.moving == "none"): self.emitRange() self.moving = "none" def resizeEvent(self, event): self.updateDisplayValues() def setRange(self, slider_range): self.start, self.end, self.single_step = slider_range self.scale = self.end - self.start def setEmitWhileMoving(self, flag): if flag: self.emit_while_moving = 1 else: self.emit_while_moving = 0 def updateDisplayValues(self): size = self.rangeSliderSize() range = int(size * (self.scale_min - self.start) / self.scale) self.display_min = range + self.bar_width / 2 range = int(size * (self.scale_max - self.start) / self.scale) self.display_max = range + self.bar_width / 2 def updateScaleValues(self): size = self.rangeSliderSize() if (self.moving == "min") or (self.moving == "bar"): ratio = (self.display_min - self.bar_width / 2) / float(size) scale_min = self.start + ratio * self.scale ratio = float(round(scale_min / self.single_step)) self.scale_min = ratio * self.single_step if (self.moving == "max") or (self.moving == "bar"): ratio = (self.display_max - self.bar_width / 2) / float(size) scale_max = self.start + ratio * self.scale ratio = float(round(scale_max / self.single_step)) self.scale_max = ratio * self.single_step self.updateDisplayValues() self.update() def getBarColor(self): return self.bar_color def setBarColor(self, barColor): self.bar_color = barColor barColor = QtCore.Property(QtGui.QColor, getBarColor, setBarColor) def getBackgroundColor(self): return self.background_color def setBackgroundColor(self, backgroundColor): self.background_color = backgroundColor backgroundColor = QtCore.Property(QtGui.QColor, getBackgroundColor, setBackgroundColor) def getHandleColor(self): return self.handle_color def setHandleColor(self, handleColor): self.handle_color = handleColor handleColor = QtCore.Property(QtGui.QColor, getHandleColor, setHandleColor) def getHandleBorderColor(self): return self.handle_border_color def setHandleBorderColor(self, handleBorderColor): self.handle_border_color = handleBorderColor handleBorderColor = QtCore.Property(QtGui.QColor, getHandleBorderColor, setHandleBorderColor) def setEnabled(self, bool): if bool: self.enabled = True else: self.enabled = False self.update()
class MqttClient(QtCore.QObject): cleanSessionChanged = QtCore.Signal(bool) clientIdChanged = QtCore.Signal(str) errorChanged = QtCore.Signal(int) hostnameChanged = QtCore.Signal(str) keepAliveChanged = QtCore.Signal(int) passwordChanged = QtCore.Signal(str) portChanged = QtCore.Signal(int) protocolVersionChanged = QtCore.Signal(int) stateChanged = QtCore.Signal(int) usernameChanged = QtCore.Signal(str) connected = QtCore.Signal() disconnected = QtCore.Signal() messageSent = QtCore.Signal(int) messageReceived = QtCore.Signal(bytes, MqttTopicName) def __init__(self, parent: typing.Optional[QtCore.QObject] = None) -> None: super(MqttClient, self).__init__(parent) self.m_hostname = "" self.m_port = 1883 self.m_clientId = "" self.m_keepAlive = 60 self.m_protocolVersion = ProtocolVersion.MQTT_3_1_1 self.m_state = ClientState.Disconnected self.m_error = ClientError.NoError self.m_username = "" self.m_password = "" self.m_cleanSession = True self.m_connection = MqttConnection(self) self.m_connection.setClient(self) @QtCore.Property(bool, notify=cleanSessionChanged) def cleanSession(self) -> bool: return self.m_cleanSession @cleanSession.setter def cleanSession(self, v: bool) -> None: if self.m_cleanSession == v: return self.m_cleanSession = v self.cleanSessionChanged.emit(v) def get_clientId(self) -> str: return self.m_clientId def set_clientId(self, v: str) -> None: if self.m_clientId == v: return self.m_clientId = v self.clientIdChanged.emit(v) clientId = QtCore.Property( str, fget=get_clientId, fset=set_clientId, notify=clientIdChanged, ) @QtCore.Property(int, notify=errorChanged) def error(self) -> int: return self.m_error @error.setter def error(self, v: int) -> None: if self.m_error == v: return self.m_error = v self.errorChanged.emit(v) def get_hostname(self) -> str: return self.m_hostname def set_hostname(self, v: str) -> None: if self.m_hostname == v: return self.m_hostname = v self.hostnameChanged.emit(v) hostname = QtCore.Property( str, fget=get_hostname, fset=set_hostname, notify=hostnameChanged, ) def get_keepAlive(self) -> int: return self.m_keepAlive def set_keepAlive(self, v: int) -> None: if self.m_keepAlive == v: return self.m_keepAlive = v self.keepAliveChanged.emit(v) keepAlive = QtCore.Property( int, fget=get_keepAlive, fset=set_keepAlive, notify=keepAliveChanged, ) @QtCore.Property(str, notify=passwordChanged) def password(self) -> str: return self.m_password @password.setter def password(self, v: str) -> None: if self.m_password == v: return self.m_password = v self.passwordChanged.emit(v) def get_port(self) -> int: return self.m_port def set_port(self, v: int) -> None: if self.m_port == v: return self.m_port = v self.portChanged.emit(v) port = QtCore.Property(int, fget=get_port, fset=set_port, notify=portChanged) @QtCore.Property(int, notify=protocolVersionChanged) def protocolVersion(self) -> int: return self.m_protocolVersion @protocolVersion.setter def protocolVersion(self, v: int) -> None: if self.m_protocolVersion == v: return self.m_protocolVersion = v self.protocolVersionChanged.emit(v) def get_state(self) -> int: return self.m_state def set_state(self, v: int) -> None: if self.m_state == v: return self.m_state = v self.stateChanged.emit(v) if v == ClientState.Connected: self.connected.emit() elif v == ClientState.Disconnected: self.disconnected.emit() state = QtCore.Property(int, fget=get_state, fset=set_state, notify=stateChanged) @QtCore.Property(str, notify=usernameChanged) def username(self) -> str: return self.m_username @username.setter def username(self, v: str) -> None: if self.m_username == v: return self.m_username = v self.usernameChanged.emit(v) @QtCore.Slot() def connectToHost(self) -> None: if self.state == ClientState.Connected: return self.m_error = ClientError.NoError self.m_connection.ensureTransportOpen() @QtCore.Slot() def disconnectFromHost(self) -> None: if self.state == ClientState.Disconnected: return self.m_connection.sendControlDisconnect() def publish( self, topic: MqttTopicName, message: bytes = b"", qos: int = 0, retain: bool = False, ) -> int: if isinstance(topic, str): topic = MqttTopicName(topic) if not isinstance(topic, MqttTopicName): return -1 if qos < 0 or qos > 2: return -1 if self.state != ClientState.Connected: return -1 return self.m_connection.sendControlPublish(topic, message, qos, retain) def subscribe(self, topic: MqttTopicFilter, qos: int = 0) -> MqttSubscription: if self.state != ClientState.Connected: return None return self.m_connection.sendControlSubscribe(topic, qos) def unsubscribe(self, topic: MqttTopicFilter) -> None: self.m_connection.sendControlUnsubscribe(topic)