コード例 #1
0
class ControlBar(QWidget):

    dtr = pyqtSignal(bool)
    rts = pyqtSignal(bool)

    def __init__(self, parent):
        super(ControlBar, self).__init__(parent)

        self.init_ui()

    def init_ui(self):
        layout = QHBoxLayout()
        self.setLayout(layout)

        self.dtr_btn = QCheckBox('DTR')
        self.dtr_btn.clicked.connect(self.handle_dtr)
        self.rts_btn = QCheckBox('RTS')
        self.rts_btn.clicked.connect(self.handle_rts)

        layout.addWidget(self.dtr_btn)
        layout.addWidget(self.rts_btn)

    def handle_dtr(self, checked):
        self.dtr.emit(checked)

    def handle_rts(self, checked):
        self.rts.emit(checked)

    def reset(self):
        self.dtr_btn.setChecked(False)
        self.rts_btn.setChecked(False)
        self.dtr.disconnect()
        self.rts.disconnect()
コード例 #2
0
class PreferencesDialog(QDialog):

    def __init__(self, parent, directory, is_checked):
        """Simple modal Preferences dialog"""
        super().__init__(parent)
        self.setWindowTitle("Preferences")
        self.setModal(True)
        
        image_dir_label = QLabel(f"<b>Images Location:</b> {directory.absolutePath()}")

        self.delete_images_checkbox = QCheckBox("Delete Original Images")
        self.delete_images_checkbox.setToolTip("""<p>If checked, images that are copied to the 
            <b>Images Location</b> are also deleted from their original location.</p>""")
        self.delete_images_checkbox.setChecked(is_checked)

        handling_v_box = QVBoxLayout()
        handling_v_box.addWidget(self.delete_images_checkbox)

        handling_group_box = QGroupBox("Image Handling:")
        handling_group_box.setLayout(handling_v_box)

        self.button_box = QDialogButtonBox(
            QDialogButtonBox.StandardButtons.Save | QDialogButtonBox.StandardButtons.Cancel)
        self.button_box.accepted.connect(self.accept)
        self.button_box.rejected.connect(self.reject)

        # Add a layout to the dialog box
        dialog_v_box = QVBoxLayout()
        dialog_v_box.addWidget(image_dir_label)
        dialog_v_box.addWidget(handling_group_box)
        dialog_v_box.addStretch(1)
        dialog_v_box.addWidget(self.button_box)
        self.setLayout(dialog_v_box)
コード例 #3
0
class GenerateMazeGroupView(QWidget):
    onMazeSpecChosen = pyqtSignal(MazeGenerationSpecification)
    __simplyConnectedCheckbox: QCheckBox
    __mazeSizePicker: XYPicker

    def __init__(
        self,
        parent: Optional[QWidget] = None,
        *args: Tuple[Any, Any],
        **kwargs: Tuple[Any, Any],
    ) -> None:
        """
        Grouped controls box for generating mazes
        """
        super(GenerateMazeGroupView, self).__init__(parent=parent,
                                                    *args,
                                                    **kwargs)
        self.setContentsMargins(0, 0, 0, 0)

        layout = QVBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)

        groupbox = QGroupBox("Generate Maze")
        layout.addWidget(groupbox)

        vbox = QFormLayout()
        groupbox.setLayout(vbox)

        self.__mazeSizePicker = XYPicker(
            minimum=XY(2, 2),
            maximum=XY(250, 250),
            initialValue=XY(2, 2),
            parent=self,
        )

        self.__simplyConnectedCheckbox = QCheckBox()
        self.__simplyConnectedCheckbox.setChecked(True)

        generateButton = QPushButton("Generate")
        generateButton.clicked.connect(
            self.__onGenerateButtonPressed)  # type: ignore

        vbox.addRow("Size", self.__mazeSizePicker)
        vbox.addRow("Simply Connected", self.__simplyConnectedCheckbox)
        vbox.addRow(generateButton)

        self.setLayout(layout)

    def __onGenerateButtonPressed(self) -> None:
        self.onMazeSpecChosen.emit(
            MazeGenerationSpecification(
                self.__mazeSizePicker.getValues(),
                self.__simplyConnectedCheckbox.isChecked(),
            ), ),
コード例 #4
0
 def show_setting(self, conf: dict, layout: QGridLayout):
     groups = list()
     x = 0
     y = 0
     shape = 3
     for key in conf.keys():
         if type(conf[key]) == bool or type(conf[key]) == str:
             continue
         conf_title = conf[key]["title"]
         conf_enabled = conf[key]["enabled"]
         conf_times = conf[key]["times"]
         group = QGroupBox(conf_title)
         group.setStyleSheet("QGroupBox{border-radius:5px;}")
         group.setToolTip(conf_title + "  的设置")
         enabled = QCheckBox("启用")
         enabled.setObjectName(key)
         enabled.setToolTip("单击切换开关状态")
         enabled.setChecked(conf_enabled)
         enabled.setStyleSheet(
             "QCheckBox::indicator{width:10px;height:10px;border:none;border-radius:5px;background:#9BE3DE;}QCheckBox::indicator:unchecked{background:#BEEBE9;}QCheckBox::indicator:unchecked:hover{background:#9AD3BC;}QCheckBox::indicator:checked{background:#95E1D3;}QCheckBox::indicator:checked:hover{background:#98DED9;}"
         )
         times = QHBoxLayout()
         times_label = QLabel("次数:")
         times_label.setStyleSheet(
             "QLabel{background:transparent;border:none;border-radius:5px;}"
         )
         times_input = EnhancedEdit()
         times_input.setObjectName(key)
         times_input.setText(str(conf_times))
         times_input.setToolTip("仅限正整数")
         times_input.setValidator(
             QRegularExpressionValidator(
                 QRegularExpression("^[1-9][0-9]{1,8}$")))
         times_input.setStyleSheet(
             "QLineEdit{border:1px solid #F3EAC2;border-radius:5px;background:transparent;}QLineEdit:hover{border:1px solid #F5B461;}"
         )
         times.addWidget(times_label)
         times.addWidget(times_input)
         group_layout = QVBoxLayout()
         group_layout.addWidget(enabled)
         group_layout.addLayout(times)
         group.setLayout(group_layout)
         group.setObjectName(key)
         groups.append(group)
     for group in groups:
         if y >= shape:
             x = x + 1
             y = 0
         layout.addWidget(group, x, y)
         y = y + 1
     self.logger.debug("最后的元素位置:(%d,%d)" % (x, y))
     return (x, y)
コード例 #5
0
    def load_chapter(self, chapter_info: ChapterInfo):
        if self.i % 26 == 0:
            self.searchVBoxLayout = QVBoxLayout()
            self.searchVBoxLayout.setAlignment(QtCore.Qt.AlignmentFlag.AlignTop)  # 对齐方式,研究了3个小时 o(╥﹏╥)o
            self.searchHBoxLayout.addLayout(self.searchVBoxLayout)

        check_box = QCheckBox()
        self.check_box_list.append(check_box)
        check_box.setText(chapter_info.title)
        check_box.setProperty("chapter_info", chapter_info)
        task = constant.downloaded_task_map.get(chapter_info.url)
        if task and task.status == -1:
            check_box.setStyleSheet('color:red')
            check_box.setChecked(True)

        self.searchVBoxLayout.addWidget(check_box)
        self.i += 1
コード例 #6
0
 def __init__(self, parent: QWidget):
     super().__init__()
     self.logger = logging.getLogger(__name__)
     with open(file="config.json", mode="r",
               encoding="utf-8") as conf_reader:
         self.conf = json.loads(conf_reader.read())
     self.logger.debug("初始化设置界面。设置内容:%s" % self.conf)
     layout = QGridLayout()
     self.setLayout(layout)
     self.setModal(True)
     self.setParent(parent)
     self.resize(400, 300)
     title = QLabel("设置")
     title.setStyleSheet(
         "QLabel{border:none;border-radius:5px;background:transparent;color:#9AD3BC;font-size:20px;}"
     )
     title.setAlignment(Qt.Alignment.AlignCenter)
     layout.addWidget(title, 0, 1, Qt.Alignment.AlignCenter)
     control_close = QPushButton()
     control_close.setStyleSheet(
         "QPushButton{background:#FFE3ED;border-radius:5px;border:none;}QPushButton:hover{background:#EC524B;}"
     )
     control_close.setToolTip("关闭")
     control_close.setFixedHeight(20)
     control_close.clicked.connect(self.close_callback)
     layout.addWidget(control_close, 0, 0)
     debug_check = QCheckBox("调试模式")
     debug_check.setChecked(self.conf["debug"])
     debug_check.setToolTip("单击切换开关状态")
     debug_check.setStyleSheet(
         "QCheckBox::indicator{width:10px;height:10px;border:none;border-radius:5px;background:#9BE3DE;}QCheckBox::indicator:unchecked{background:#BEEBE9;}QCheckBox::indicator:unchecked:hover{background:#9AD3BC;}QCheckBox::indicator:checked{background:#95E1D3;}QCheckBox::indicator:checked:hover{background:#98DED9;}"
     )
     self.content = QGridLayout()
     (x, y) = self.show_setting(conf=self.conf,
                                layout=self.content)  # 返回content的最后一个元素的x,y
     proxy = QGroupBox()
     proxy.setObjectName("proxy")
     proxy_layout = QVBoxLayout()
     proxy_label = QLabel("代理地址:")
     proxy_label.setStyleSheet(
         "QLabel{background:transparent;border:none;}")
     proxy_input = EnhancedEdit()
     proxy_input.setText(self.conf["proxy"])
     proxy_input.setToolTip("格式为协议://IP:端口,留空保持直连")
     proxy_input.setStyleSheet(
         "QLineEdit{border:1px solid #F3EAC2;border-radius:5px;background:transparent;}QLineEdit:hover{border:1px solid #F5B461;}"
     )
     proxy_layout.addWidget(proxy_label)
     proxy_layout.addWidget(proxy_input)
     proxy.setLayout(proxy_layout)
     proxy.setStyleSheet("QGroupBox{border-radius:5px;}")
     proxy.setToolTip("代理设置")
     if y + 1 >= 3:
         y_ = 0
         x_ = x + 1
     else:
         y_ = y + 1
         x_ = x
     self.content.addWidget(proxy, x_, y_)
     self.content.addWidget(debug_check)
     layout.addLayout(self.content, 1, 1)
コード例 #7
0
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setFixedSize(800, 410)
        self.setWindowTitle("PyLX16A Servo Testing Software")

        self.port_selection_box = QComboBox(self)
        self.port_selection_box.setFixedSize(200, 27)
        self.port_selection_box.move(30, 65)
        port_selection_box_label = QLabel("Select Port:", self)
        port_selection_box_label.move(30, 35)

        self.port_selection_box_refresh_button = QPushButton("Refresh", self)
        self.port_selection_box_refresh_button.setFixedSize(60, 23)
        self.port_selection_box_refresh_button.move(170, 38)

        self.id_selection_box = QListWidget(self)
        self.id_selection_box.setFixedSize(200, 200)
        self.id_selection_box.move(30, 135)
        id_selection_box_label = QLabel("Connected Servos:", self)
        id_selection_box_label.setFixedWidth(200)
        id_selection_box_label.move(30, 105)

        self.id_selection_box_refresh_button = QPushButton("Refresh", self)
        self.id_selection_box_refresh_button.setFixedSize(60, 23)
        self.id_selection_box_refresh_button.move(170, 108)

        self.set_id_line_edit = QLineEdit(self)
        self.set_id_line_edit.setFixedSize(50, 27)
        self.set_id_line_edit.move(80, 355)
        set_id_line_edit_label = QLabel("Set ID:", self)
        set_id_line_edit_label.move(30, 355)
        set_id_line_edit_label.setFixedSize(50, 27)

        self.set_id_button = QPushButton("Change ID!", self)
        self.set_id_button.setFixedSize(85, 27)
        self.set_id_button.move(145, 355)

        self.position_slider = QSlider(Qt.Orientation.Horizontal, self)
        self.position_slider.setMinimum(0)
        self.position_slider.setMaximum(240)
        self.position_slider.setFixedWidth(200)
        self.position_slider.move(300, 55)
        self.position_slider_readout = QLabel("0.00°", self)
        self.position_slider_readout.setFixedWidth(50)
        self.position_slider_readout.move(450, 30)
        self.position_slider_readout.setAlignment(
            Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)
        position_slider_label = QLabel("Angle (degrees):", self)
        position_slider_label.move(300, 30)

        self.position_offset_slider = QSlider(Qt.Orientation.Horizontal, self)
        self.position_offset_slider.setMinimum(-30)
        self.position_offset_slider.setMaximum(30)
        self.position_offset_slider.setFixedWidth(200)
        self.position_offset_slider.move(300, 125)
        self.position_offset_slider_readout = QLabel("0.00°", self)
        self.position_offset_slider_readout.setFixedWidth(50)
        self.position_offset_slider_readout.move(450, 100)
        self.position_offset_slider_readout.setAlignment(
            Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)
        position_offset_slider_label = QLabel("Angle offset (degrees):", self)
        position_offset_slider_label.setFixedWidth(200)
        position_offset_slider_label.move(300, 100)

        self.angle_lower_limit_textentry = QLineEdit(self)
        self.angle_lower_limit_textentry.setFixedWidth(50)
        self.angle_lower_limit_textentry.move(450, 175)
        self.angle_lower_limit_textentry.setValidator(
            QIntValidator(0, 240, self))
        self.angle_upper_limit_textentry = QLineEdit(self)
        self.angle_upper_limit_textentry.setFixedWidth(50)
        self.angle_upper_limit_textentry.move(450, 210)
        self.angle_upper_limit_textentry.setValidator(
            QIntValidator(0, 240, self))
        self.angle_lower_limit_textentry_label = QLabel(
            "Lower Limit (degrees):", self)
        self.angle_lower_limit_textentry_label.move(300, 175)
        self.angle_lower_limit_textentry_label.setFixedWidth(150)
        self.angle_upper_limit_textentry_label = QLabel(
            "Upper Limit (degrees):", self)
        self.angle_upper_limit_textentry_label.move(300, 210)
        self.angle_upper_limit_textentry_label.setFixedWidth(150)

        self.vin_lower_limit_textentry = QLineEdit(self)
        self.vin_lower_limit_textentry.setFixedWidth(50)
        self.vin_lower_limit_textentry.move(450, 265)
        self.vin_lower_limit_textentry.setValidator(
            QIntValidator(4500, 12000, self))
        self.vin_upper_limit_textentry = QLineEdit(self)
        self.vin_upper_limit_textentry.setFixedWidth(50)
        self.vin_upper_limit_textentry.move(450, 300)
        self.vin_upper_limit_textentry.setValidator(
            QIntValidator(4500, 12000, self))
        self.vin_lower_limit_textentry_label = QLabel(
            "Voltage Lower Limit (mV):", self)
        self.vin_lower_limit_textentry_label.move(300, 265)
        self.vin_lower_limit_textentry_label.setFixedWidth(150)
        self.vin_upper_limit_textentry_label = QLabel(
            "Voltage Upper Limit (mV):", self)
        self.vin_upper_limit_textentry_label.move(300, 300)
        self.vin_upper_limit_textentry_label.setFixedWidth(150)

        self.temp_limit_textentry = QLineEdit(self)
        self.temp_limit_textentry.setFixedWidth(50)
        self.temp_limit_textentry.move(450, 355)
        self.temp_limit_textentry.setValidator(QIntValidator(50, 100, self))
        self.temp_limit_textentry_label = QLabel("Temp Limit (°C):", self)
        self.temp_limit_textentry_label.move(300, 355)
        self.temp_limit_textentry_label.setFixedWidth(150)

        self.servo_mode_radio_button = QRadioButton("Servo Mode", self)
        self.servo_mode_radio_button.move(565, 50)
        self.motor_mode_radio_button = QRadioButton("Motor Mode", self)
        self.motor_mode_radio_button.move(565, 75)

        self.motor_speed_slider = QSlider(Qt.Orientation.Horizontal, self)
        self.motor_speed_slider.setMinimum(-1000)
        self.motor_speed_slider.setMaximum(1000)
        self.motor_speed_slider.setFixedWidth(200)
        self.motor_speed_slider.move(565, 125)
        motor_speed_slider_label = QLabel("Motor Speed:", self)
        motor_speed_slider_label.move(565, 100)

        self.torque_enabled_checkbox = QCheckBox("Torque Enabled", self)
        self.torque_enabled_checkbox.move(565, 175)
        self.torque_enabled_checkbox.setFixedWidth(200)

        self.led_enabled_checkbox = QCheckBox("LED Enabled", self)
        self.led_enabled_checkbox.move(565, 210)
        self.led_enabled_checkbox.setFixedWidth(200)

        self.led_over_temp_checkbox = QCheckBox("LED Over Temperature", self)
        self.led_over_temp_checkbox.move(565, 258)
        self.led_over_temp_checkbox.setFixedWidth(200)
        self.led_over_voltage_checkbox = QCheckBox("LED Over Voltage", self)
        self.led_over_voltage_checkbox.move(565, 283)
        self.led_over_voltage_checkbox.setFixedWidth(200)
        self.led_rotor_locked_checkbox = QCheckBox("LED Rotor Locked", self)
        self.led_rotor_locked_checkbox.move(565, 308)
        self.led_rotor_locked_checkbox.setFixedWidth(200)

        self.physical_position_readout = QLabel("--°", self)
        self.physical_position_readout.move(565, 367)
        self.physical_position_readout.setFixedWidth(200)
        self.physical_position_readout_label = QLabel("Position", self)
        self.physical_position_readout_label.move(565, 347)

        self.temperature_readout = QLabel("-- °C", self)
        self.temperature_readout.move(635, 367)
        self.temperature_readout.setFixedWidth(200)
        self.temperature_readout_label = QLabel("Temperature", self)
        self.temperature_readout_label.move(635, 347)

        self.voltage_readout = QLabel("-- V", self)
        self.voltage_readout.move(730, 367)
        self.voltage_readout.setFixedWidth(200)
        self.voltage_readout_label = QLabel("Voltage", self)
        self.voltage_readout_label.move(730, 347)

        self.readout_update_timer = QTimer(self)
        self.readout_update_timer.timeout.connect(self.update_readouts)
        self.readout_update_timer.start(250)

        self.active_servo: LX16A = None

        self.position_slider.setValue(0)
        self.position_offset_slider.setValue(0)
        self.motor_speed_slider.setValue(0)
        self.id_selection_box_refresh_button.setEnabled(False)
        self.disable_widgets()

        self.port_selection_box.currentTextChanged.connect(
            self.port_selection_box_changed)
        self.port_selection_box_refresh_button.clicked.connect(
            self.port_refresh_button_clicked)
        self.id_selection_box.currentTextChanged.connect(
            self.id_selection_box_changed)
        self.id_selection_box_refresh_button.clicked.connect(
            self.id_refresh_button_clicked)
        self.set_id_button.pressed.connect(self.id_updated)
        self.position_slider.sliderMoved.connect(self.position_slider_updated)
        self.position_offset_slider.sliderMoved.connect(
            self.position_offset_slider_updated)
        self.angle_lower_limit_textentry.textChanged.connect(
            self.angle_lower_limit_updated)
        self.angle_upper_limit_textentry.textChanged.connect(
            self.angle_upper_limit_updated)
        self.vin_lower_limit_textentry.textChanged.connect(
            self.vin_lower_limit_updated)
        self.vin_upper_limit_textentry.textChanged.connect(
            self.vin_upper_limit_updated)
        self.temp_limit_textentry.textChanged.connect(self.temp_limit_updated)
        self.servo_mode_radio_button.toggled.connect(
            self.servo_mode_radio_button_toggled)
        self.motor_mode_radio_button.toggled.connect(
            self.motor_mode_radio_button_toggled)
        self.motor_speed_slider.valueChanged.connect(
            self.motor_speed_slider_updated)
        self.torque_enabled_checkbox.stateChanged.connect(
            self.torque_enabled_checkbox_toggled)
        self.led_enabled_checkbox.stateChanged.connect(
            self.led_enabled_checkbox_toggled)
        self.led_over_temp_checkbox.stateChanged.connect(
            self.led_error_triggers_checkbox_toggled)
        self.led_over_voltage_checkbox.stateChanged.connect(
            self.led_error_triggers_checkbox_toggled)
        self.led_rotor_locked_checkbox.stateChanged.connect(
            self.led_error_triggers_checkbox_toggled)

        self.scan_for_ports()

    def disable_widgets(self):
        self.set_id_line_edit.setEnabled(False)
        self.position_slider.setEnabled(False)
        self.position_offset_slider.setEnabled(False)
        self.angle_lower_limit_textentry.setEnabled(False)
        self.angle_upper_limit_textentry.setEnabled(False)
        self.vin_lower_limit_textentry.setEnabled(False)
        self.vin_upper_limit_textentry.setEnabled(False)
        self.temp_limit_textentry.setEnabled(False)
        self.servo_mode_radio_button.setEnabled(False)
        self.motor_mode_radio_button.setEnabled(False)
        self.motor_speed_slider.setEnabled(False)
        self.torque_enabled_checkbox.setEnabled(False)
        self.led_enabled_checkbox.setEnabled(False)
        self.led_over_temp_checkbox.setEnabled(False)
        self.led_over_voltage_checkbox.setEnabled(False)
        self.led_rotor_locked_checkbox.setEnabled(False)

    def enable_widgets(self):
        self.set_id_line_edit.setEnabled(True)
        self.position_slider.setEnabled(True)
        self.position_offset_slider.setEnabled(True)
        self.angle_lower_limit_textentry.setEnabled(True)
        self.angle_upper_limit_textentry.setEnabled(True)
        self.vin_lower_limit_textentry.setEnabled(True)
        self.vin_upper_limit_textentry.setEnabled(True)
        self.temp_limit_textentry.setEnabled(True)
        self.servo_mode_radio_button.setEnabled(True)
        self.motor_mode_radio_button.setEnabled(True)
        self.motor_speed_slider.setEnabled(True)
        self.torque_enabled_checkbox.setEnabled(True)
        self.led_enabled_checkbox.setEnabled(True)
        self.led_over_temp_checkbox.setEnabled(True)
        self.led_over_voltage_checkbox.setEnabled(True)
        self.led_rotor_locked_checkbox.setEnabled(True)

    def clear_servo(self):
        self.active_servo = None

    @catch_disconnection
    def set_servo_id(self, id_):
        if not id_.isdigit():
            return

        self.active_servo = LX16A(int(id_))
        self.active_servo.enable_torque()

        self.position_slider.setValue(
            int(self.active_servo.get_physical_angle()))
        self.position_slider_readout.setText(
            f"{int(self.active_servo.get_physical_angle() * 25 / 6) * 6 / 25:0.2f}°"
        )
        self.position_offset_slider.setValue(
            int(self.active_servo.get_angle_offset()))
        self.position_offset_slider_readout.setText(
            f"{int(self.active_servo.get_angle_offset() * 25 / 6) * 6 / 25:0.2f}°"
        )
        self.angle_lower_limit_textentry.setText(
            str(int(self.active_servo.get_angle_limits()[0])))
        self.angle_upper_limit_textentry.setText(
            str(int(self.active_servo.get_angle_limits()[1])))
        self.vin_lower_limit_textentry.setText(
            str(self.active_servo.get_vin_limits()[0]))
        self.vin_upper_limit_textentry.setText(
            str(self.active_servo.get_vin_limits()[1]))
        self.temp_limit_textentry.setText(
            str(self.active_servo.get_temp_limit()))
        self.motor_speed_slider.setValue(self.active_servo.get_motor_speed(
        ) if self.active_servo.is_motor_mode() else 0)
        if self.active_servo.is_motor_mode():
            self.motor_mode_radio_button.setChecked(True)
        else:
            self.servo_mode_radio_button.setChecked(True)
        self.motor_speed_slider.setEnabled(self.active_servo.is_motor_mode())
        self.torque_enabled_checkbox.setChecked(
            self.active_servo.is_torque_enabled())
        self.led_enabled_checkbox.setChecked(
            self.active_servo.is_led_power_on())
        self.led_over_temp_checkbox.setChecked(
            self.active_servo.get_led_error_triggers()[0])
        self.led_over_voltage_checkbox.setChecked(
            self.active_servo.get_led_error_triggers()[1])
        self.led_rotor_locked_checkbox.setChecked(
            self.active_servo.get_led_error_triggers()[2])

    @catch_disconnection
    def scan_for_servos(self, port):
        self.setCursor(Qt.CursorShape.WaitCursor)

        LX16A.initialize(port)

        self.id_selection_box.clear()

        for i in range(0, 254):
            try:
                servo = LX16A(i)
                self.id_selection_box.addItem(str(i))
            except:
                pass

        self.setCursor(Qt.CursorShape.ArrowCursor)

    @catch_disconnection
    def scan_for_ports(self):
        ports = serial.tools.list_ports.comports()
        for port in ports:
            self.port_selection_box.addItem(port.device)

    @catch_disconnection
    def update_readouts(self):
        if self.active_servo is None:
            return

        try:
            self.physical_position_readout.setText(
                f"{self.active_servo.get_physical_angle():0.2f}°")
            self.temperature_readout.setText(
                f"{self.active_servo.get_temp()} °C")
            self.voltage_readout.setText(
                f"{self.active_servo.get_vin() / 1000} V")
        except (ServoTimeoutError, ServoChecksumError):
            pass

    @catch_disconnection
    def id_updated(self):
        new_id = self.set_id_line_edit.text()

        try:
            servo = LX16A(int(new_id))
        except ServoTimeoutError:
            # Meaning this ID is not taken
            self.active_servo.set_id(int(new_id))
            self.id_selection_box.item(
                self.id_selection_box.currentRow()).setText(new_id)

            return

        QMessageBox.warning(None, "Error", "ID already taken")

    @catch_disconnection
    def position_slider_updated(self, pos):
        if float(self.voltage_readout.text()[:-2]) < 5:
            QMessageBox.warning(
                None,
                "Error",
                "The voltage going through the servo is too low. Is your battery powered on?",
            )

            return
        self.active_servo.move(pos)
        self.position_slider_readout.setText(
            f"{int(pos * 25 / 6) * 6 / 25:0.2f}°")

    @catch_disconnection
    def position_offset_slider_updated(self, pos):
        self.active_servo.set_angle_offset(pos)
        self.position_offset_slider_readout.setText(
            f"{int(pos * 25 / 6) * 6 / 25:0.2f}°")

    @catch_disconnection
    def angle_lower_limit_updated(self, text):
        if (QIntValidator(0, 240, self).validate(text, 0) !=
                QIntValidator.State.Acceptable):
            return

        if int(text) > int(self.angle_upper_limit_textentry.text()):
            return

        self.active_servo.set_angle_limits(
            int(text), int(self.angle_upper_limit_textentry.text()))

    @catch_disconnection
    def angle_upper_limit_updated(self, text):
        if (QIntValidator(0, 240, self).validate(text, 0) !=
                QIntValidator.State.Acceptable):
            return

        if int(text) < int(self.angle_lower_limit_textentry.text()):
            return

        self.active_servo.set_angle_limits(
            int(self.angle_lower_limit_textentry.text()), int(text))

    @catch_disconnection
    def vin_lower_limit_updated(self, text):
        if (QIntValidator(4500, 12000, self).validate(text, 0) !=
                QIntValidator.State.Acceptable):
            return

        if int(text) > int(self.vin_upper_limit_textentry.text()):
            return

        self.active_servo.set_vin_limits(
            int(text), int(self.vin_upper_limit_textentry.text()))

    @catch_disconnection
    def vin_upper_limit_updated(self, text):
        if (QIntValidator(4500, 12000, self).validate(text, 0) !=
                QIntValidator.State.Acceptable):
            return

        if int(text) < int(self.vin_lower_limit_textentry.text()):
            return

        self.active_servo.set_vin_limits(
            int(self.vin_lower_limit_textentry.text()), int(text))

    @catch_disconnection
    def temp_limit_updated(self, text):
        if (QIntValidator(50, 100, self).validate(text, 0) !=
                QIntValidator.State.Acceptable):
            return

        self.active_servo.set_temp_limit(int(text))

    @catch_disconnection
    def servo_mode_radio_button_toggled(self, checked):
        if checked:
            self.active_servo.servo_mode()
            self.motor_speed_slider.setEnabled(False)
            self.position_slider.setEnabled(True)
            self.position_offset_slider.setEnabled(True)
        else:
            self.active_servo.motor_mode(int(self.motor_speed_slider.value()))
            self.motor_speed_slider.setEnabled(True)
            self.position_slider.setEnabled(False)
            self.position_offset_slider.setEnabled(False)

    @catch_disconnection
    def motor_mode_radio_button_toggled(self, checked):
        if checked:
            self.active_servo.motor_mode(int(self.motor_speed_slider.value()))
            self.motor_speed_slider.setEnabled(True)
            self.position_slider.setEnabled(False)
            self.position_offset_slider.setEnabled(False)
        else:
            self.active_servo.servo_mode()
            self.motor_speed_slider.setEnabled(False)
            self.position_slider.setEnabled(True)
            self.position_offset_slider.setEnabled(True)

    @catch_disconnection
    def motor_speed_slider_updated(self, pos):
        self.active_servo.motor_mode(pos)

    @catch_disconnection
    def torque_enabled_checkbox_toggled(self, checked):
        if checked:
            self.active_servo.enable_torque()
        else:
            self.active_servo.disable_torque()

        self.position_slider.setEnabled(checked)
        self.position_offset_slider.setEnabled(checked)
        self.servo_mode_radio_button.setEnabled(checked)
        self.motor_mode_radio_button.setEnabled(checked)
        self.motor_speed_slider.setEnabled(checked)

    @catch_disconnection
    def led_enabled_checkbox_toggled(self, checked):
        if checked:
            self.active_servo.led_power_on()
        else:
            self.active_servo.led_power_off()

    @catch_disconnection
    def led_error_triggers_checkbox_toggled(self):
        self.active_servo.set_led_error_triggers(
            self.led_over_voltage_checkbox.isChecked(),
            self.led_over_temp_checkbox.isChecked(),
            self.led_rotor_locked_checkbox.isChecked(),
        )

    @catch_disconnection
    def port_refresh_button_clicked(self, value):
        self.id_selection_box_refresh_button.setEnabled(False)
        self.disable_widgets()
        self.port_selection_box.clear()
        self.id_selection_box.clear()
        self.scan_for_ports()

    @catch_disconnection
    def id_refresh_button_clicked(self, value):
        self.disable_widgets()
        self.id_selection_box.clear()
        self.scan_for_servos(self.port_selection_box.currentText())

    @catch_disconnection
    def port_selection_box_changed(self, text):
        if text == "":
            return

        self.id_selection_box_refresh_button.setEnabled(True)
        self.disable_widgets()
        self.id_selection_box.clear()
        self.clear_servo()
        self.scan_for_servos(text)

    @catch_disconnection
    def id_selection_box_changed(self, text):
        if text == "":
            return

        self.enable_widgets()
        self.set_servo_id(text)