Пример #1
0
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()
Пример #2
0
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)