示例#1
0
    def __init__(self, parent=None):
        """Class constructor.

        Args:
            parent (QWidget): the widget's parent
        """
        super().__init__(parent)
        self.option = QStyleOptionMenuItem()
        zoom_action = QAction("Zoom")
        QMenu(parent).initStyleOption(self.option, zoom_action)
        layout = QHBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(0)
        tool_bar = QToolBar(self)
        tool_bar.setFixedHeight(self.option.rect.height())
        minus_action = tool_bar.addAction("-")
        reset_action = tool_bar.addAction("Reset")
        plus_action = tool_bar.addAction("+")
        layout.addSpacing(self.option.rect.width())
        layout.addWidget(tool_bar)
        minus_action.setToolTip("Zoom out")
        reset_action.setToolTip("Reset zoom")
        plus_action.setToolTip("Zoom in")
        minus_action.triggered.connect(lambda x: self.minus_pressed.emit())
        plus_action.triggered.connect(lambda x: self.plus_pressed.emit())
        reset_action.triggered.connect(lambda x: self.reset_pressed.emit())
    def __init__(self, text, actions, parent=None):
        """Class constructor.

        Args:
            parent (QWidget): the widget's parent
        """
        super().__init__(parent)
        self.option = QStyleOptionMenuItem()
        action = QAction(text)
        QMenu(parent).initStyleOption(self.option, action)
        layout = QHBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(0)
        tool_bar = QToolBar(self)
        tool_bar.setFixedHeight(self.option.rect.height())
        layout.addSpacing(self.option.rect.width())
        layout.addStretch()
        layout.addWidget(tool_bar)
        for name, tool_tip in actions.items():
            action = tool_bar.addAction(name)
            action.setToolTip(tool_tip)
            action.triggered.connect(
                lambda x=False, name=name: self.action_triggered.emit(name))
示例#3
0
class USBFrame(QWidget):

    # --- Init methods ---

    def __init__(self, config):
        """
        USB control frame

        :param config: application configuration file
        """
        QWidget.__init__(self)

        self.setFixedSize(QSize(600, 200))

        self.config = config
        self.setWindowTitle("DigiQt - USB Control")

        self.sig_button_pressed = None  # signal configured by serialControler
        self.sig_firmware_update = None  #

        # Firmware update output
        self.out = ConsoleOutput()
        # Buttons
        self.to_dr_btn = ToDigiruleButton(config)
        self.to_dr_btn.to_digirule = lambda: self.sig_button_pressed.emit(0)

        self.from_dr_btn = FromDigiruleButton(config)
        self.from_dr_btn.from_digirule = lambda: self.sig_button_pressed.emit(1
                                                                              )

        # Firmware
        self.firmware_btn = FirmwareUpdate(config)
        self.firmware_btn.firmware_update = self.firmware_update
        # Port selection
        self.lab_port = QLabel("Port:")
        self.usb_combo = UsbPortCombo()
        self.refresh_btn = RefreshPortButton(config)
        self.refresh_btn.on_refresh = lambda: self.sig_button_pressed.emit(2)

        self._init_tool_bar()
        self._set_layout()
        self._set_stylesheet()

    def _init_tool_bar(self):
        """
        Creates the main toolbar with all its content
        """
        self.toolbar = QToolBar()
        self.toolbar.setFixedHeight(70)

        self.toolbar.addWidget(self.to_dr_btn)
        self.toolbar.addWidget(self.from_dr_btn)

        self.toolbar.addSeparator()
        self.toolbar.addWidget(self.firmware_btn)

        self.toolbar.addSeparator()
        self.toolbar.addWidget(self.lab_port)
        self.toolbar.addWidget(self.usb_combo)
        self.toolbar.addWidget(self.refresh_btn)

    def _set_layout(self):
        """
        Creates this Widget's Layout
        """
        box = QGridLayout()
        box.setContentsMargins(0, 0, 0, 0)

        box.addWidget(self.toolbar, 0, 0)
        box.addWidget(self.out, 1, 0)

        self.setLayout(box)

    def _set_stylesheet(self):
        self.toolbar.setStyleSheet(style.get_stylesheet("qtoolbar"))
        self.setStyleSheet(style.get_stylesheet("common"))
        self.lab_port.setStyleSheet(
            "background-color: transparent; color: #75BA6D; font-weight: bold;"
        )
        self.out.setStyleSheet("background-color: #505050; color: white;")

    def firmware_update(self):
        dlg = QFileDialog()
        dlg.setWindowTitle("Choose a digirule Firmware")
        dlg.setFileMode(QFileDialog.AnyFile)
        dlg.setNameFilter("HEX files (*.hex)")
        if dlg.exec_():
            file_path = dlg.selectedFiles()[0]
            # Call the controller method for update
            self.sig_firmware_update.emit(file_path)

    # --- Close handler ---

    def closeEvent(self, event):
        """
        Event called upon a red-cross click.
        """
        self.on_close()

    def on_close(self):
        """
        Reroute this method in the Main Frame in order to Updates the execution frame's open editor icon and tooltip
        """
        pass
示例#4
0
class ExecutionFrame(QWidget):

    # --- Init methods ---

    def __init__(self, config, sig_update_config):
        """
        Main application frame. Contains the MenuBar, main toolbar, DR canvas and status bar.

        :param config: application configuration file
        """
        QWidget.__init__(self)

        self.config = config
        self.is_quitting = False

        app_version = self.config.get('main', 'APP_VERSION')
        self.setWindowTitle("DigiQt - Emulator for Digirule - " +
                            str(app_version))
        window_width = int(self.config.get('main', 'WINDOW_WIDTH'))
        self.setFixedSize(window_width, 320)

        self.current_digirule_model = self.config.get('digirule', 'DR_MODEL')

        sliderbar_width = 200
        bottom_widget_height = 26

        self.statusbar = StatusBar(window_width - sliderbar_width,
                                   bottom_widget_height, config)
        self.dr_canvas = DRCanvas(self.statusbar.sig_temp_message,
                                  window_width, self.current_digirule_model,
                                  config)
        self.slider = SpeedSlider(sliderbar_width, bottom_widget_height,
                                  config)

        # Buttons open/hide frames
        self.editor_frame = EditorFrame(config,
                                        self.statusbar.sig_temp_message)
        self.open_editor_btn = OpenEditorButton(self.editor_frame, config)
        self.editor_frame.on_close = lambda: self.open_editor_btn.show_editor_frame(
            False)

        self.ram_frame = RAMFrame(config)
        self.open_ram_btn = OpenRamButton(self.ram_frame, config)
        self.ram_frame.on_close = lambda: self.open_ram_btn.show_ram_frame(
            False)

        self.monitor_frame = TerminalFrame(config)
        self.open_monitor_btn = OpenTerminalButton(self.monitor_frame, config)
        self.monitor_frame.on_close = lambda: self.open_monitor_btn.show_terminal_frame(
            False)

        self.usb_frame = USBFrame(config)
        self.open_usb_btn = OpenUSBButton(self.usb_frame, config)
        self.usb_frame.on_close = lambda: self.open_usb_btn.show_usb_frame(
            False)

        self.open_monitor_btn.is_opened = lambda b: self.open_usb_btn.setEnabled(
            not b)
        self.open_usb_btn.is_opened = lambda b: self.open_monitor_btn.setEnabled(
            not b)

        self.symbol_frame = SymbolViewFrame(config)
        self.open_symbol_btn = OpenSymbolButton(self.symbol_frame, config)
        self.symbol_frame.on_close = lambda: self.open_symbol_btn.show_symbol_frame(
            False)
        self.symbol_frame.place_search_text = self.editor_frame.do_search

        self.about_frame = AboutFrame(self.config)
        self.open_about_btn = AboutButton(self.about_frame, config)
        self.about_frame.on_close = lambda: self.open_about_btn.show_about_frame(
            False)

        self._init_tool_bar()
        self._set_layout()
        self._set_stylesheets()

        self.sig_update_config = sig_update_config

    def _init_tool_bar(self):
        """
        Creates the main toolbar with all its content
        """
        self.toolbar = QToolBar()
        self.toolbar.setFixedHeight(70)

        # Open/hide buttons
        self.toolbar.addWidget(self.open_editor_btn)
        self.toolbar.addWidget(self.open_ram_btn)
        self.toolbar.addWidget(self.open_usb_btn)
        self.toolbar.addWidget(self.open_monitor_btn)
        self.toolbar.addWidget(self.open_symbol_btn)

        # Digirule model selection
        self.toolbar.addSeparator()
        self.digimodel_dropdown = DigiruleModelDropdown(
            self.on_digimodel_dropdown_changed)
        self.toolbar.addWidget(self.digimodel_dropdown)

        # Empty space to align the about button to the right
        spacer = QWidget()
        spacer.setStyleSheet("background-color: transparent;")
        spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.toolbar.addWidget(spacer)

        # About button
        self.toolbar.addWidget(self.open_about_btn)

    def _set_layout(self):
        """
        Creates this Widget's Layout
        """
        box = QVBoxLayout()
        box.setContentsMargins(0, 0, 0, 0)

        box.addWidget(self.toolbar)
        box.setAlignment(self.toolbar, Qt.AlignTop)

        box.addWidget(self.dr_canvas)
        box.setAlignment(self.dr_canvas, Qt.AlignTop)

        bottom_box = QHBoxLayout()
        bottom_box.setContentsMargins(0, 0, 0, 0)

        bottom_box.addWidget(self.statusbar)
        bottom_box.addWidget(self.slider)

        box.addLayout(bottom_box)
        box.setAlignment(bottom_box, Qt.AlignBottom)

        self.setLayout(box)

    def _set_stylesheets(self):
        self.toolbar.setStyleSheet(style.get_stylesheet("qtoolbar"))

        # Execution Frame
        self.setStyleSheet(style.get_stylesheet("common"))

    # --- Callbacks methods ---

    def on_digimodel_dropdown_changed(self):
        """
        Handles the Digirule's model-combo-box-selection-changed process. Calls the canvas redraw.
        """
        self.sig_update_config.emit(
            self.digimodel_dropdown.get_digirule_model())

        self.dr_canvas.digirule_changed(self.config.get(
            'digirule', 'DR_MODEL'))

    # --- Close handler ---
    def do_quit(self):
        pass

    def closeEvent(self, event):
        """
        Event called upon a red-cross click
        """
        if self.ask_quit_confirmation():
            self.is_quitting = True
            self.do_quit()

            # Reset status bar
            self.statusbar.sig_persistent_message.emit("")

            # Call the secondary frames close methods as well
            self.editor_frame.on_close()
            self.ram_frame.on_close()
            self.monitor_frame.on_close()
            self.usb_frame.on_close()
            self.symbol_frame.on_close()
            self.about_frame.on_close()

            event.accept()
        else:
            event.ignore()

    def ask_quit_confirmation(self):
        """
        Asks a quit confirmation message
        :return: True if the user wants to quit the app
        """
        return DialogQuitConfirmation().exec_()
示例#5
0
class EditorFrame(QWidget):

    # --- Init methods ---

    def __init__(self, config, sig_message):
        """
        Editor frame. Contains a toolbar and an editor widget

        :param config: application configuration file
        :param sig_message: signal to emit to display a message in the main frame's status bar
        """
        QWidget.__init__(self)

        self.setMinimumSize(QSize(630, 500))

        self.config = config

        # Widgets
        self.editor = CodeEditor(config)
        self.editor.setMinimumSize(QSize(600, 430))

        self.open_file_btn = OpenFileButton(config)
        self.open_file_btn.set_content = self.editor.setPlainText  # Reroute text set method directly to the text editor widget
        self.open_file_btn.set_new_file_name = self.__init_title

        self.save_as_btn = SaveAsFileButton(config, sig_message)
        self.save_as_btn.get_content_to_save = self.retrieve_text  # Bind the text retrieve method in order to get the text to save
        self.save_as_btn.set_new_file_name = self.__init_title

        self.save_btn = SaveFileButton(config, sig_message)
        self.save_btn.get_content_to_save = self.retrieve_text

        self.assemble_btn = AssembleButton(config)

        self.search_field = QLineEdit()
        self.search_field.setPlaceholderText("Search (press return)")
        self.search_field.returnPressed.connect(self.do_search)

        # Editor's shortcuts binding
        self.editor.on_ctrl_o_activated = self.open_file_btn.on_open  # Open action
        self.editor.on_ctrl_s_activated = self.do_save
        self.editor.on_ctrl_f_activated = self.do_search

        # Final initialization
        self.__init_title()
        self._init_tool_bar()
        self._set_layout()
        self._connect_all()
        self._set_stylesheet()

        self.editor.setFocus()  # Set the default focus on the Editor

    def __init_title(self, file_name=""):
        """
        Sets the currently edited file in this frame's title

        :param file_name: full file path
        """
        if file_name:
            self.setWindowTitle("DigiQt - Editing '" +
                                file_name.split("/")[-1] + "'")
        else:
            # In the case no file name is specified, we have an empty editor, we display default text
            self.setWindowTitle("DigiQt - Assemble Editor")

        self.save_btn.setEnabled(file_name != "")
        self.save_btn.set_file_path(file_name)

    def _init_tool_bar(self):
        """
        Creates the main toolbar with all its content
        """
        self.toolbar = QToolBar()
        self.toolbar.setFixedHeight(70)

        self.toolbar.addWidget(self.open_file_btn)
        self.toolbar.addWidget(self.save_btn)
        self.toolbar.addWidget(self.save_as_btn)

        self.toolbar.addSeparator()
        self.toolbar.addWidget(self.search_field)

        # Empty space to align the assemble button to the right
        spacer = QWidget()
        spacer.setStyleSheet("background-color: transparent;")
        spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.toolbar.addWidget(spacer)

        self.toolbar.addWidget(self.assemble_btn)

    def _set_layout(self):
        """
        Creates this Widget's Layout
        """
        box = QGridLayout()
        box.setContentsMargins(0, 0, 0, 0)

        box.addWidget(self.toolbar, 0, 0)

        box.addWidget(self.editor, 1, 0)

        self.setLayout(box)

    def _connect_all(self):
        """
        Connects all the buttons to methods
        """

    def _set_stylesheet(self):
        self.toolbar.setStyleSheet(style.get_stylesheet("qtoolbar"))
        self.editor.setStyleSheet(
            "background-color: " + self.config.get('colors', 'editor_bg') +
            "; color: " + self.config.get('colors', 'asm_text_default') + ";")

        self.search_field.setStyleSheet(
            "border: 2px solid gray; border-radius: 10px; padding: 0 8px; background: #585858; color: white"
        )

        # Execution Frame
        self.setStyleSheet(style.get_stylesheet("common"))

    # --- Buttons callbacks methods ---

    def retrieve_text(self):
        """
        Gets the content of the code editor widget
        :return: the code
        """
        return self.editor.toPlainText()

    def do_save(self):
        """
        Delegating method triggered upon Ctrl+S action. Performs a Save if a file is opened, or a SaveAs if not.
        """
        if self.save_btn.file_path:
            self.save_btn.on_save()
        else:
            self.save_as_btn.on_save_as()

    def do_search(self, text=None):
        """
        Searches the value present in the search field, or the places the specified text if there is one as search
        value, but does not triggers the search.

        :param text: Text to search (None will trigger a search on the field content)
        """
        if text:
            self.search_field.setText(text)
        else:
            self.editor.selectNext(self.search_field.text())

    # --- Close handler ---

    def closeEvent(self, event):
        """
        Event called upon a red-cross click.
        """
        self.on_close()

    def on_close(self):
        """
        Reroot this method in the Main Frame in order to Updates the execution frame's open editor icon and tooltip
        :return:
        """
        pass
示例#6
0
class TerminalFrame(QWidget):

    # --- Init methods ---

    def __init__(self, config):
        """
        Serial Console frame

        :param config: application configuration file
        """
        QWidget.__init__(self)

        self.config = config
        self.setWindowTitle("DigiQt - Terminal")

        self.sig_keyseq_pressed = None  # signal configured by serialControler
        self.sig_button_pressed = None  # signal configured by serialControler

        # Virtual Serial out
        self.serial_out = SerialOut(self.config)

        # Serial terminal (real)
        self.terminal = SerialTerminalFrame(self.config)

        # Tab
        self.tab_widget = QTabWidget()
        self.tab_widget.addTab(self.serial_out, "Virtual terminal")
        self.tab_widget.addTab(self.terminal, "Serial terminal")

        # Serial in
        self.serial_in = QLabel()
        self.serial_in.setAlignment(Qt.AlignCenter)
        self.serial_in.setFixedSize(QSize(44, 36))
        font = QFont()
        font.setPointSize(30)
        font.setBold(True)
        self.serial_in.setFont(font)

        # Buttons
        self.clear_btn = ClearButton(config)
        self.clear_btn.on_clear = lambda: self.sig_button_pressed.emit(3)

        shortcut_space = QShortcut(QKeySequence(Qt.Key_Space), self)
        shortcut_space.activated.connect(lambda: self.__send_key(" "))

        self.tab_widget.currentChanged.connect(self.__on_tab_changed)

        self._init_tool_bar()

        # Compute max size
        max_w = self.terminal.maximumWidth()
        max_h = self.terminal.maximumHeight() + self.tab_widget.tabBar(
        ).minimumHeight() + self.toolbar.maximumHeight()
        self.setMaximumSize(QSize(max_w, max_h))

        self._set_layout()
        self._set_stylesheet()

    def _init_tool_bar(self):
        """
        Creates the main toolbar with all its content
        """
        self.toolbar = QToolBar()
        self.toolbar.setFixedHeight(70)

        self.toolbar.addWidget(self.clear_btn)
        self.toolbar.addWidget(self.serial_in)

    def __on_tab_changed(self):
        """
        Hides the serial in display when current widget is the real terminal
        """
        if self.tab_widget.currentWidget() == self.serial_out:
            self.serial_in.setStyleSheet(style.get_stylesheet("serial_in"))
        else:
            self.serial_in.setStyleSheet(
                "background: #333333; color: #333333;")
            self.terminal.textbox.setFocus()

    def _set_layout(self):
        """
        Creates this Widget's Layout
        """
        box = QGridLayout()
        box.setContentsMargins(0, 0, 0, 0)

        box.addWidget(self.toolbar, 0, 0)

        box.addWidget(self.tab_widget, 1, 0)

        self.setLayout(box)

    def clear(self):
        """
        Clears the content of the current tab
        """
        if self.tab_widget.currentWidget() == self.serial_out:
            self.serial_out.console.setPlainText("")
            self.set_serial_in(" ")
        else:
            self.terminal.textbox.setPlainText("")
            self.terminal.textbox.setFocus()

    def _set_stylesheet(self):
        self.toolbar.setStyleSheet(style.get_stylesheet("qtoolbar"))
        self.setStyleSheet(style.get_stylesheet("common"))
        self.serial_in.setStyleSheet(style.get_stylesheet("serial_in"))
        self.serial_out.console.setStyleSheet(
            "background-color: #000000; color: white; padding-left: 10px;")
        self.terminal.textbox.setStyleSheet(
            "background-color: #000000; color: #44DD44;")
        self.tab_widget.setStyleSheet(style.get_stylesheet("tab"))

    def keyPressEvent(self, event):
        """
        Intercepts key press events
        """
        self.__send_key(event.text())

    def __send_key(self, key_typed):
        """
        Sends signal to serialControler
        :param key_type: key typed
        """
        if self.tab_widget.currentWidget() == self.serial_out:
            self.sig_keyseq_pressed.emit(key_typed)

    def set_serial_in(self, val):
        """
        Sets the serial in value
        """
        self.serial_in.setText(val)

    def append_serial_out(self, byte):
        """
        Appends the given text inside the serial out area
        """
        # First, we place the cursor at the end (this will also clear the selection before inserting new text)
        if byte != 10:
            cursor = self.serial_out.console.textCursor()
            cursor.movePosition(QTextCursor.End)
            self.serial_out.console.setTextCursor(cursor)
            try:
                self.serial_out.console.insertPlainText(chr(byte))
            except ValueError:
                self.serial_out.console.insertPlainText(" ")

    def closeEvent(self, event):
        """
        Event called upon a red-cross click.
        """
        self.terminal.sig_terminal_open.emit(
            False)  # ask Serial Controller to terminate the thread
        self.on_close()

    def on_close(self):
        """
        Reroute this method in the Main Frame in order to Updates the execution frame's open editor icon and tooltip
        """
        pass