Exemple #1
0
    def __init__(self, title, comm, topics, userWidget):
        super().__init__(title)
        self.setObjectName(title)

        self.comm = comm
        self.topics = topics

        splitter = QSplitter()

        self.fieldDataIndex = None

        plotLayout = QVBoxLayout()
        selectionLayout = QVBoxLayout()
        detailsLayout = QFormLayout()
        filterLayout = QHBoxLayout()

        w_left = QWidget()
        w_left.setLayout(plotLayout)
        splitter.addWidget(w_left)
        w_right = QWidget()
        w_right.setLayout(selectionLayout)
        splitter.addWidget(w_right)

        splitter.setCollapsible(0, False)
        splitter.setStretchFactor(0, 10)
        splitter.setStretchFactor(1, 0)

        selectionLayout.addLayout(detailsLayout)
        selectionLayout.addWidget(QLabel("Filter Data"))
        selectionLayout.addLayout(filterLayout)

        self.selectedActuatorIdLabel = QLabel("")
        self.selectedActuatorValueLabel = QLabel("")
        self.selectedActuatorWarningLabel = QLabel("")
        self.lastUpdatedLabel = TimeDeltaLabel()

        self.topicList = QListWidget()
        self.topicList.currentRowChanged.connect(self.currentTopicChanged)
        for topic in self.topics.topics:
            self.topicList.addItem(topic.name)
        self.fieldList = QListWidget()
        self.fieldList.currentRowChanged.connect(self.currentFieldChanged)

        plotLayout.addWidget(userWidget)

        detailsLayout.addRow(QLabel("Selected Actuator Details"), QLabel(""))
        detailsLayout.addRow(QLabel("Actuator Id"),
                             self.selectedActuatorIdLabel)
        detailsLayout.addRow(QLabel("Actuator Value"),
                             self.selectedActuatorValueLabel)
        detailsLayout.addRow(QLabel("Actuator Warning"),
                             self.selectedActuatorWarningLabel)
        detailsLayout.addRow(QLabel("Last Updated"), self.lastUpdatedLabel)

        filterLayout.addWidget(self.topicList)
        filterLayout.addWidget(self.fieldList)

        self.topicList.setCurrentRow(0)

        self.setWidget(splitter)
Exemple #2
0
    def _SetupUI(self):
        main_layout = QVBoxLayout()
        search_filter_widget = QWidget()
        search_filter_layout = QHBoxLayout(search_filter_widget)
        central_widget = QWidget()
        central_layout = QVBoxLayout(central_widget)

        panel_splitter = QSplitter(Qt.Horizontal)
        panel_splitter.setHandleWidth(4)
        panel_splitter.addWidget(self._source_panel)
        panel_splitter.addWidget(central_widget)
        panel_splitter.setStretchFactor(0, 0)
        panel_splitter.setStretchFactor(1, 1)
        panel_splitter.moveSplitter(LEFT_PANEL_WIDTH, 1)
        panel_splitter.setSizePolicy(QSizePolicy.Expanding,
                                     QSizePolicy.Expanding)

        search_filter_layout.addWidget(self._search_bar)
        search_filter_layout.addWidget(self._filter_bar)
        search_filter_layout.setContentsMargins(0, 0, 0, 0)

        central_layout.addWidget(search_filter_widget)
        central_layout.addWidget(self._splitter)
        central_layout.addWidget(self._status_bar)
        central_layout.setContentsMargins(0, 0, 0, 0)

        main_layout.addWidget(panel_splitter)
        self.setLayout(main_layout)
Exemple #3
0
 def __init__(self, totaltime=0):
     super().__init__()
     # 在主窗口左侧添加题干和选项
     lsplitter = QSplitter(Qt.Vertical)
     self.question_panel = Question_panel()
     lsplitter.addWidget(self.question_panel)
     # 在主窗口右侧添加绘图和文本编辑,并把比例设置为3比1
     rsplitter = QSplitter(Qt.Vertical)
     self.painter = QGraphicsView(rsplitter)
     self.note = QTextEdit(rsplitter)
     rsplitter.setStretchFactor(0, 3)
     rsplitter.setStretchFactor(1, 1)
     # 添加插件的顺序会导致左右不同
     mainSplitter = QSplitter(Qt.Horizontal)
     mainSplitter.addWidget(lsplitter)
     mainSplitter.addWidget(rsplitter)
     self.setCentralWidget(mainSplitter)
     # 点击暂停按钮切换图标和停继时间
     self.question_panel.ui.pushButtonPause.clicked.connect(
         self.toggle_play_and_pause)
     self.totaltime = totaltime  # 当前试卷答题总时间
     self.elapsed_time = QElapsedTimer()  # 答题总时间的计时器
     self.paused = False  # 默认刚打开时,还未暂停时间
     self.setTime()  # 更新时间显示
     self.timer = QTimer()
     self.timer.timeout.connect(self.setTime)  # 每秒更新时间显示的定时器
Exemple #4
0
class ProcessMonitorUI:
    def __init__(self, window: ProcessMonitorWindow):
        self.window = window

        self.main_widget = QWidget(window)
        self.main_layout = QVBoxLayout()
        self.layout_connection = QHBoxLayout()
        self.txt_conenction = QLineEdit()
        self.btn_connect = QPushButton()
        self.layout_connection.addWidget(self.txt_conenction)
        self.layout_connection.addWidget(self.btn_connect)
        self.process_list = ProcessListWidget()

        self.tabs_output = ProcessOutputTabsWidget()

        self.splitter = QSplitter(Qt.Horizontal)
        self.splitter.setMinimumSize(680, 540)
        policy = QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)
        policy.setHorizontalStretch(0)
        policy.setVerticalStretch(0)
        policy.setHeightForWidth(self.splitter.sizePolicy().hasHeightForWidth())
        self.splitter.setSizePolicy(policy)
        self.splitter.setStretchFactor(0, 1)
        self.splitter.setStretchFactor(1, 0)

        self.main_layout.addLayout(self.layout_connection)
        self.splitter.addWidget(self.process_list)
        self.splitter.addWidget(self.tabs_output)
        self.main_layout.addWidget(self.splitter)

        self.main_widget.setLayout(self.main_layout)
        self.statusbar = QStatusBar(window)

        self.txt_conenction.setPlaceholderText("ws://127.0.0.1:8766")
        self.txt_conenction.setText("ws://127.0.0.1:8766")
        self.btn_connect.setText("Connect")

        window.setCentralWidget(self.main_widget)
        window.setStatusBar(self.statusbar)
        window.setWindowTitle("Process Monitor")
        window.setWindowIcon(window.style().standardIcon(QStyle.SP_BrowserReload))
        self.set_disconnected_ui("Click on Connect to establish a connection")

    def set_disconnected_ui(self, msg: str):
        self.process_list.setDisabled(True)
        self.btn_connect.setDisabled(False)
        self.statusbar.showMessage(f"Disconnected. {msg}")

    def set_connected_ui(self):
        self.process_list.setDisabled(False)
        self.btn_connect.setDisabled(True)
        self.statusbar.showMessage("Connection established.")

    def handle_output(self, output: OutputEvent):
        self.tabs_output.append_output(output.uid, output.output)
 def _create_splitter(self, ) -> QSplitter:
     splitter = QSplitter(
         Qt.Vertical,
         self,
     )
     splitter.addWidget(self._tab_widget)
     splitter.addWidget(self._logs_widget)
     splitter.addWidget(self._progress_bar)
     splitter.setCollapsible(0, False)  # noqa: WPS425
     splitter.setCollapsible(1, False)  # noqa: WPS425
     splitter.setCollapsible(2, False)  # noqa: WPS425
     splitter.setStretchFactor(0, 98)
     splitter.setStretchFactor(1, 1)
     splitter.setStretchFactor(2, 1)
     return splitter
Exemple #6
0
class MainWindow(QMainWindow):
    def __init__(self, *, setup_input_panel=None, plot_panel=None):
        super().__init__()
        self.setup_input_panel = setup_input_panel
        self.plot_panel = plot_panel

        self.main_widget = None
        self.menu_bar = None
        self.new_menu_action = None

        self.setup_ui()
        self.setWindowTitle(TITLE)

    def setup_ui(self):
        self.main_widget = QSplitter(Qt.Horizontal)
        self.setCentralWidget(self.main_widget)

        self.main_widget.addWidget(self.setup_input_panel)
        self.main_widget.addWidget(self.plot_panel)

        self.main_widget.setStretchFactor(0, 2)
        self.main_widget.setStretchFactor(1, 1)

        self.create_menu_bar()

    def create_menu_bar(self):
        self.menu_bar = QMenuBar(self)
        self.setMenuBar(self.menu_bar)

        self.create_file_menu()

    def create_file_menu(self):
        file_menu = self.menu_bar.addMenu('&File')

        self.new_menu_action = QAction('New', self)
        self.new_menu_action.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_N))

        file_menu.addAction(self.new_menu_action)
Exemple #7
0
    def __init__(self):
        super().__init__()

        self.setLayout(QVBoxLayout())
        vsplit = QSplitter(QtCore.Qt.Vertical)
        hsplit = QSplitter(QtCore.Qt.Horizontal)
        self.layout().addWidget(vsplit)
        self.layout().setMargin(0)
        self.layout().setSpacing(0)

        self.unity_area = UnityWidget()
        self.prop_area = Properties()
        self.timeline = Timeline()

        hsplit.addWidget(self.unity_area)
        hsplit.setCollapsible(0, False)
        hsplit.addWidget(self.prop_area)
        hsplit.setStretchFactor(0, 1)
        hsplit.setSizes([hsplit.width() - 400, 400])
        vsplit.addWidget(hsplit)
        vsplit.setCollapsible(0, False)
        vsplit.addWidget(self.timeline)
        vsplit.setStretchFactor(0, 1)
        vsplit.setSizes([vsplit.height() - 150, 150])
    def _gui_setup(self):
        layout = QHBoxLayout()

        splitter = QSplitter(Qt.Horizontal)
        panel_right = QWidget(self)
        layout.addWidget(splitter)

        annotation = Annotation()
        self.annotation = annotation

        transcripts = Transcripts(annotation, self)
        transcripts.setDisabled(True)
        splitter.addWidget(transcripts)
        self.transcripts = transcripts
        splitter.addWidget(panel_right)
        l = QVBoxLayout()
        l.setContentsMargins(0, 0, 0, 0)
        panel_right.setLayout(l)
        panel_right = l

        minutes = Minutes(annotation, self)
        minutes.setDisabled(True)
        self.minutes = minutes

        problems = Problems(self)
        problems.setEnabled(False)
        problems.problem_selected.connect(self.annotation.set_problem)
        problems.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
        self.problems = problems

        splitter_right = QSplitter(Qt.Vertical)
        splitter_right.addWidget(minutes)
        splitter_right.addWidget(problems)
        panel_right.addWidget(splitter_right)

        player = Player(self)
        player.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
        self.player = player
        panel_right.addWidget(player)

        evaluation = Evaluation(self)
        evaluation.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
        self.evaluation = evaluation
        panel_right.addWidget(evaluation)

        widget = QWidget()
        widget.setLayout(layout)
        self.setCentralWidget(widget)

        menu = self.menuBar()
        file_menu = menu.addMenu('&File')

        a = file_menu.addAction('&New')
        a.setShortcut('Ctrl+n')
        a.triggered.connect(self.new)

        a = file_menu.addAction('&Open existing')
        a.setShortcut('Ctrl+o')
        a.triggered.connect(self.open_existing)

        a = file_menu.addAction('&Open repository')
        a.setShortcut('Ctrl+g')
        a.triggered.connect(self.open_repository)

        file_menu.addSeparator()

        a = file_menu.addAction('Evaluation mode')
        a.setCheckable(True)
        a.setShortcut('Ctrl+e')
        a.triggered.connect(self.set_evaluation_mode)

        file_menu.addSeparator()

        a = file_menu.addAction('&Save')
        a.setShortcut('Ctrl+s')
        a.triggered.connect(self.save)
        file_menu.addSeparator()

        a = file_menu.addAction('S&ettings')
        a.setShortcut('Ctrl++')
        a.triggered.connect(lambda: Settings(self).exec_())
        file_menu.addSeparator()

        a = file_menu.addAction('&Close')
        a.setShortcut('Alt+c')
        a.triggered.connect(self.close)

        playback_menu = menu.addMenu('&Playback')
        a = playback_menu.addAction('&Open audio')
        a.triggered.connect(self._open_audio)
        playback_menu.addSeparator()
        playback_menu.addActions(player.playback_actions)

        s = QSettings(self)
        self.splitter = splitter
        self.splitter_righ = splitter_right
        splitter.restoreState(s.value('splitter'))
        splitter_right.restoreState(s.value('splitter_righ'))
        self.restoreGeometry(s.value('window_geometry'))
        self.restoreState(s.value('window_state'))

        splitter_right.setStretchFactor(0, 10)
        splitter_right.setStretchFactor(1, 1)
Exemple #9
0
class WTreeEdit(QWidget):
    """TreeEdit widget is to show and edit all of the pyleecan objects data."""

    # Signals
    dataChanged = Signal()

    def __init__(self, obj, *args, **kwargs):
        QWidget.__init__(self, *args, **kwargs)

        self.class_dict = ClassInfo().get_dict()
        self.treeDict = None  # helper to track changes
        self.obj = obj  # the object
        self.is_save_needed = False

        self.model = TreeEditModel(obj)

        self.setupUi()

        # === Signals ===
        self.selectionModel.selectionChanged.connect(self.onSelectionChanged)
        self.treeView.collapsed.connect(self.onItemCollapse)
        self.treeView.expanded.connect(self.onItemExpand)
        self.treeView.customContextMenuRequested.connect(self.openContextMenu)
        self.model.dataChanged.connect(self.onDataChanged)
        self.dataChanged.connect(self.setSaveNeeded)

        # === Finalize ===
        # set 'root' the selected item and resize columns
        self.treeView.setCurrentIndex(self.treeView.model().index(0, 0))
        self.treeView.resizeColumnToContents(0)

    def setupUi(self):
        """Setup the UI"""
        # === Widgets ===
        # TreeView
        self.treeView = QTreeView()
        # self.treeView.rootNode = model.invisibleRootItem()
        self.treeView.setModel(self.model)
        self.treeView.setAlternatingRowColors(False)

        # self.treeView.setColumnWidth(0, 150)
        self.treeView.setMinimumWidth(100)

        self.treeView.setContextMenuPolicy(Qt.CustomContextMenu)
        self.selectionModel = self.treeView.selectionModel()

        self.statusBar = QStatusBar()
        self.statusBar.setSizeGripEnabled(False)
        self.statusBar.setSizePolicy(QSizePolicy.Expanding,
                                     QSizePolicy.Maximum)
        self.statusBar.setStyleSheet(
            "QStatusBar {border: 1px solid rgb(200, 200, 200)}")
        self.saveLabel = QLabel("unsaved")
        self.saveLabel.setVisible(False)
        self.statusBar.addPermanentWidget(self.saveLabel)

        # Splitters
        self.leftSplitter = QSplitter()
        self.leftSplitter.setStretchFactor(0, 0)
        self.leftSplitter.setStretchFactor(1, 1)

        # === Layout ===
        # Horizontal Div.
        self.hLayout = QVBoxLayout()
        self.hLayout.setContentsMargins(0, 0, 0, 0)
        self.hLayout.setSpacing(0)

        # add widgets to layout
        self.hLayout.addWidget(self.leftSplitter)
        self.hLayout.addWidget(self.statusBar)

        # add widgets
        self.leftSplitter.addWidget(self.treeView)

        self.setLayout(self.hLayout)

    def update(self, obj):
        """Check if object has changed and update tree in case."""
        if not obj is self.obj:
            self.obj = obj
            self.model = TreeEditModel(obj)
            self.treeView.setModel(self.model)
            self.model.dataChanged.connect(self.onDataChanged)
            self.selectionModel = self.treeView.selectionModel()
            self.selectionModel.selectionChanged.connect(
                self.onSelectionChanged)
            self.treeView.setCurrentIndex(self.treeView.model().index(0, 0))
            self.setSaveNeeded(True)

    def setSaveNeeded(self, state=True):
        self.is_save_needed = state
        self.saveLabel.setVisible(state)

    def openContextMenu(self, point):
        """Generate and open context the menu at the given point position."""
        index = self.treeView.indexAt(point)
        pos = QtGui.QCursor.pos()

        if not index.isValid():
            return

        # get the data
        item = self.model.item(index)
        obj_info = self.model.get_obj_info(item)

        # init the menu
        menu = TreeEditContextMenu(obj_dict=obj_info, parent=self)
        menu.exec_(pos)

        self.onSelectionChanged(self.selectionModel.selection())

    def onItemCollapse(self, index):
        """Slot for item collapsed"""
        # dynamic resize
        for ii in range(3):
            self.treeView.resizeColumnToContents(ii)

    def onItemExpand(self, index):
        """Slot for item expand"""
        # dynamic resize
        for ii in range(3):
            self.treeView.resizeColumnToContents(ii)

    def onDataChanged(self, first=None, last=None):
        """Slot for changed data"""
        self.dataChanged.emit()
        self.onSelectionChanged(self.selectionModel.selection())

    def onSelectionChanged(self, itemSelection):
        """Slot for changed item selection"""
        # get the index
        if itemSelection.indexes():
            index = itemSelection.indexes()[0]
        else:
            index = self.treeView.model().index(0, 0)
            self.treeView.setCurrentIndex(index)
            return

        # get the data
        item = self.model.item(index)
        obj = item.object()
        typ = type(obj).__name__
        obj_info = self.model.get_obj_info(item)
        ref_typ = obj_info["ref_typ"] if obj_info else None

        # set statusbar information on class typ
        msg = f"{typ} (Ref: {ref_typ})" if ref_typ else f"{typ}"
        self.statusBar.showMessage(msg)

        # --- choose the respective widget by class type ---
        # numpy array -> table editor
        if typ == "ndarray":
            widget = WTableData(obj, editable=True)
            widget.dataChanged.connect(self.dataChanged.emit)

        elif typ == "MeshSolution":
            widget = WMeshSolution(obj)  # only a view (not editable)

        # list (no pyleecan type, non empty) -> table editor
        # TODO add another widget for lists of non 'primitive' types (e.g. DataND)
        elif isinstance(obj, list) and not self.isListType(ref_typ) and obj:
            widget = WTableData(obj, editable=True)
            widget.dataChanged.connect(self.dataChanged.emit)

        # generic editor
        else:
            # widget = SimpleInputWidget().generate(obj)
            widget = WTableParameterEdit(obj)
            widget.dataChanged.connect(self.dataChanged.emit)

        # show the widget
        if self.leftSplitter.widget(1) is None:
            self.leftSplitter.addWidget(widget)
        else:
            self.leftSplitter.replaceWidget(1, widget)
            widget.setParent(
                self.leftSplitter)  # workaround for PySide2 replace bug
            widget.show()
        pass

    def isListType(self, typ):
        if not typ:
            return False
        return typ[0] == "[" and typ[-1] == "]" and typ[1:-1] in self.class_dict

    def isDictType(self, typ):
        if not typ:
            return False
        return typ[0] == "{" and typ[-1] == "}" and typ[1:-1] in self.class_dict
Exemple #10
0
    def __init__(self, path_to_rom=""):
        super(MainWindow, self).__init__()

        self.setWindowIcon(icon("foundry.ico"))

        file_menu = QMenu("File")

        open_rom_action = file_menu.addAction("&Open ROM")
        open_rom_action.triggered.connect(self.on_open_rom)
        self.open_m3l_action = file_menu.addAction("&Open M3L")
        self.open_m3l_action.triggered.connect(self.on_open_m3l)

        file_menu.addSeparator()

        self.save_rom_action = file_menu.addAction("&Save ROM")
        self.save_rom_action.triggered.connect(self.on_save_rom)
        self.save_rom_as_action = file_menu.addAction("&Save ROM as ...")
        self.save_rom_as_action.triggered.connect(self.on_save_rom_as)
        """
        file_menu.AppendSeparator()
        """
        self.save_m3l_action = file_menu.addAction("&Save M3L")
        self.save_m3l_action.triggered.connect(self.on_save_m3l)
        """
        file_menu.Append(ID_SAVE_LEVEL_TO, "&Save Level to", "")
        file_menu.AppendSeparator()
        file_menu.Append(ID_APPLY_IPS_PATCH, "&Apply IPS Patch", "")
        file_menu.AppendSeparator()
        file_menu.Append(ID_ROM_PRESET, "&ROM Preset", "")
        """
        file_menu.addSeparator()
        settings_action = file_menu.addAction("&Settings")
        settings_action.triggered.connect(show_settings)
        file_menu.addSeparator()
        exit_action = file_menu.addAction("&Exit")
        exit_action.triggered.connect(lambda _: self.close())

        self.menuBar().addMenu(file_menu)
        """
        edit_menu = wx.Menu()

        edit_menu.Append(ID_EDIT_LEVEL, "&Edit Level", "")
        edit_menu.Append(ID_EDIT_OBJ_DEFS, "&Edit Object Definitions", "")
        edit_menu.Append(ID_EDIT_PALETTE, "&Edit Palette", "")
        edit_menu.Append(ID_EDIT_GRAPHICS, "&Edit Graphics", "")
        edit_menu.Append(ID_EDIT_MISC, "&Edit Miscellaneous", "")
        edit_menu.AppendSeparator()
        edit_menu.Append(ID_FREE_FORM_MODE, "&Free form Mode", "")
        edit_menu.Append(ID_LIMIT_SIZE, "&Limit Size", "")
        """

        self.level_menu = QMenu("Level")

        self.select_level_action = self.level_menu.addAction("&Select Level")
        self.select_level_action.triggered.connect(self.open_level_selector)

        self.reload_action = self.level_menu.addAction("&Reload Level")
        self.reload_action.triggered.connect(self.reload_level)
        self.level_menu.addSeparator()
        self.edit_header_action = self.level_menu.addAction("&Edit Header")
        self.edit_header_action.triggered.connect(self.on_header_editor)
        self.edit_autoscroll = self.level_menu.addAction("Edit Autoscrolling")
        self.edit_autoscroll.triggered.connect(self.on_edit_autoscroll)

        self.menuBar().addMenu(self.level_menu)

        self.object_menu = QMenu("Objects")

        view_blocks_action = self.object_menu.addAction("&View Blocks")
        view_blocks_action.triggered.connect(self.on_block_viewer)
        view_objects_action = self.object_menu.addAction("&View Objects")
        view_objects_action.triggered.connect(self.on_object_viewer)
        self.object_menu.addSeparator()
        view_palettes_action = self.object_menu.addAction(
            "View Object Palettes")
        view_palettes_action.triggered.connect(self.on_palette_viewer)

        self.menuBar().addMenu(self.object_menu)

        self.view_menu = QMenu("View")
        self.view_menu.triggered.connect(self.on_menu)

        action = self.view_menu.addAction("Mario")
        action.setProperty(ID_PROP, ID_MARIO)
        action.setCheckable(True)
        action.setChecked(SETTINGS["draw_mario"])

        action = self.view_menu.addAction("&Jumps on objects")
        action.setProperty(ID_PROP, ID_JUMP_OBJECTS)
        action.setCheckable(True)
        action.setChecked(SETTINGS["draw_jump_on_objects"])

        action = self.view_menu.addAction("Items in blocks")
        action.setProperty(ID_PROP, ID_ITEM_BLOCKS)
        action.setCheckable(True)
        action.setChecked(SETTINGS["draw_items_in_blocks"])

        action = self.view_menu.addAction("Invisible items")
        action.setProperty(ID_PROP, ID_INVISIBLE_ITEMS)
        action.setCheckable(True)
        action.setChecked(SETTINGS["draw_invisible_items"])

        action = self.view_menu.addAction("Autoscroll Path")
        action.setProperty(ID_PROP, ID_AUTOSCROLL)
        action.setCheckable(True)
        action.setChecked(SETTINGS["draw_autoscroll"])

        self.view_menu.addSeparator()

        action = self.view_menu.addAction("Jump Zones")
        action.setProperty(ID_PROP, ID_JUMPS)
        action.setCheckable(True)
        action.setChecked(SETTINGS["draw_jumps"])

        action = self.view_menu.addAction("&Grid lines")
        action.setProperty(ID_PROP, ID_GRID_LINES)
        action.setCheckable(True)
        action.setChecked(SETTINGS["draw_grid"])

        action = self.view_menu.addAction("Resize Type")
        action.setProperty(ID_PROP, ID_RESIZE_TYPE)
        action.setCheckable(True)
        action.setChecked(SETTINGS["draw_expansion"])

        self.view_menu.addSeparator()

        action = self.view_menu.addAction("&Block Transparency")
        action.setProperty(ID_PROP, ID_TRANSPARENCY)
        action.setCheckable(True)
        action.setChecked(SETTINGS["block_transparency"])

        self.view_menu.addSeparator()
        self.view_menu.addAction(
            "&Save Screenshot of Level").triggered.connect(self.on_screenshot)
        """
        self.view_menu.Append(ID_BACKGROUND_FLOOR, "&Background & Floor", "")
        self.view_menu.Append(ID_TOOLBAR, "&Toolbar", "")
        self.view_menu.AppendSeparator()
        self.view_menu.Append(ID_ZOOM, "&Zoom", "")
        self.view_menu.AppendSeparator()
        self.view_menu.Append(ID_USE_ROM_GRAPHICS, "&Use ROM Graphics", "")
        self.view_menu.Append(ID_PALETTE, "&Palette", "")
        self.view_menu.AppendSeparator()
        self.view_menu.Append(ID_MORE, "&More", "")
        """

        self.menuBar().addMenu(self.view_menu)

        help_menu = QMenu("Help")
        """
        help_menu.Append(ID_ENEMY_COMPATIBILITY, "&Enemy Compatibility", "")
        help_menu.Append(ID_TROUBLESHOOTING, "&Troubleshooting", "")
        help_menu.AppendSeparator()
        help_menu.Append(ID_PROGRAM_WEBSITE, "&Program Website", "")
        help_menu.Append(ID_MAKE_A_DONATION, "&Make a Donation", "")
        help_menu.AppendSeparator()
        """
        update_action = help_menu.addAction("Check for updates")
        update_action.triggered.connect(self.on_check_for_update)

        help_menu.addSeparator()

        video_action = help_menu.addAction("Feature Video on YouTube")
        video_action.triggered.connect(lambda: open_url(feature_video_link))

        github_action = help_menu.addAction("Github Repository")
        github_action.triggered.connect(lambda: open_url(github_link))

        discord_action = help_menu.addAction("SMB3 Rom Hacking Discord")
        discord_action.triggered.connect(lambda: open_url(discord_link))

        help_menu.addSeparator()

        about_action = help_menu.addAction("&About")
        about_action.triggered.connect(self.on_about)

        self.menuBar().addMenu(help_menu)

        self.block_viewer = None
        self.object_viewer = None

        self.level_ref = LevelRef()
        self.level_ref.data_changed.connect(self._on_level_data_changed)

        self.context_menu = ContextMenu(self.level_ref)
        self.context_menu.triggered.connect(self.on_menu)

        self.level_view = LevelView(self, self.level_ref, self.context_menu)

        self.scroll_panel = QScrollArea()
        self.scroll_panel.setWidgetResizable(True)
        self.scroll_panel.setWidget(self.level_view)

        self.setCentralWidget(self.scroll_panel)

        self.spinner_panel = SpinnerPanel(self, self.level_ref)
        self.spinner_panel.zoom_in_triggered.connect(self.level_view.zoom_in)
        self.spinner_panel.zoom_out_triggered.connect(self.level_view.zoom_out)
        self.spinner_panel.object_change.connect(self.on_spin)

        self.object_list = ObjectList(self, self.level_ref, self.context_menu)

        self.object_dropdown = ObjectDropdown(self)
        self.object_dropdown.object_selected.connect(
            self._on_placeable_object_selected)

        self.level_size_bar = LevelSizeBar(self, self.level_ref)
        self.enemy_size_bar = EnemySizeBar(self, self.level_ref)

        self.jump_list = JumpList(self, self.level_ref)
        self.jump_list.add_jump.connect(self.on_jump_added)
        self.jump_list.edit_jump.connect(self.on_jump_edit)
        self.jump_list.remove_jump.connect(self.on_jump_removed)

        splitter = QSplitter(self)
        splitter.setOrientation(Qt.Vertical)

        splitter.addWidget(self.object_list)
        splitter.setStretchFactor(0, 1)
        splitter.addWidget(self.jump_list)

        splitter.setChildrenCollapsible(False)

        level_toolbar = QToolBar("Level Info Toolbar", self)
        level_toolbar.setContextMenuPolicy(Qt.PreventContextMenu)
        level_toolbar.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
        level_toolbar.setOrientation(Qt.Horizontal)
        level_toolbar.setFloatable(False)

        level_toolbar.addWidget(self.spinner_panel)
        level_toolbar.addWidget(self.object_dropdown)
        level_toolbar.addWidget(self.level_size_bar)
        level_toolbar.addWidget(self.enemy_size_bar)
        level_toolbar.addWidget(splitter)

        level_toolbar.setAllowedAreas(Qt.LeftToolBarArea | Qt.RightToolBarArea)

        self.addToolBar(Qt.RightToolBarArea, level_toolbar)

        self.object_toolbar = ObjectToolBar(self)
        self.object_toolbar.object_selected.connect(
            self._on_placeable_object_selected)

        object_toolbar = QToolBar("Object Toolbar", self)
        object_toolbar.setContextMenuPolicy(Qt.PreventContextMenu)
        object_toolbar.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
        object_toolbar.setFloatable(False)

        object_toolbar.addWidget(self.object_toolbar)
        object_toolbar.setAllowedAreas(Qt.LeftToolBarArea
                                       | Qt.RightToolBarArea)

        self.addToolBar(Qt.LeftToolBarArea, object_toolbar)

        self.menu_toolbar = QToolBar("Menu Toolbar", self)
        self.menu_toolbar.setOrientation(Qt.Horizontal)
        self.menu_toolbar.setIconSize(QSize(20, 20))

        self.menu_toolbar.addAction(
            icon("settings.svg"),
            "Editor Settings").triggered.connect(show_settings)
        self.menu_toolbar.addSeparator()
        self.menu_toolbar.addAction(
            icon("folder.svg"), "Open ROM").triggered.connect(self.on_open_rom)
        self.menu_toolbar.addAction(
            icon("save.svg"), "Save Level").triggered.connect(self.on_save_rom)
        self.menu_toolbar.addSeparator()

        self.undo_action = self.menu_toolbar.addAction(icon("rotate-ccw.svg"),
                                                       "Undo Action")
        self.undo_action.triggered.connect(self.level_ref.undo)
        self.undo_action.setEnabled(False)
        self.redo_action = self.menu_toolbar.addAction(icon("rotate-cw.svg"),
                                                       "Redo Action")
        self.redo_action.triggered.connect(self.level_ref.redo)
        self.redo_action.setEnabled(False)

        self.menu_toolbar.addSeparator()
        play_action = self.menu_toolbar.addAction(icon("play-circle.svg"),
                                                  "Play Level")
        play_action.triggered.connect(self.on_play)
        play_action.setWhatsThis(
            "Opens an emulator with the current Level set to 1-1.\nSee Settings."
        )
        self.menu_toolbar.addSeparator()
        self.menu_toolbar.addAction(icon("zoom-out.svg"),
                                    "Zoom Out").triggered.connect(
                                        self.level_view.zoom_out)
        self.menu_toolbar.addAction(icon("zoom-in.svg"),
                                    "Zoom In").triggered.connect(
                                        self.level_view.zoom_in)
        self.menu_toolbar.addSeparator()
        header_action = self.menu_toolbar.addAction(icon("tool.svg"),
                                                    "Edit Level Header")
        header_action.triggered.connect(self.on_header_editor)
        header_action.setWhatsThis(
            "<b>Header Editor</b><br/>"
            "Many configurations regarding the level are done in its header, like the length of "
            "the timer, or where and how Mario enters the level.<br/>")

        self.jump_destination_action = self.menu_toolbar.addAction(
            icon("arrow-right-circle.svg"), "Go to Jump Destination")
        self.jump_destination_action.triggered.connect(
            self._go_to_jump_destination)
        self.jump_destination_action.setWhatsThis(
            "Opens the level, that can be reached from this one, e.g. by entering a pipe."
        )

        self.menu_toolbar.addSeparator()

        whats_this_action = QWhatsThis.createAction()
        whats_this_action.setWhatsThis(
            "Click on parts of the editor, to receive help information.")
        whats_this_action.setIcon(icon("help-circle.svg"))
        whats_this_action.setText("Starts 'What's this?' mode")
        self.menu_toolbar.addAction(whats_this_action)

        self.menu_toolbar.addSeparator()
        self.warning_list = WarningList(self, self.level_ref)

        warning_action = self.menu_toolbar.addAction(
            icon("alert-triangle.svg"), "Warning Panel")
        warning_action.setWhatsThis("Shows a list of warnings.")
        warning_action.triggered.connect(self.warning_list.show)
        warning_action.setDisabled(True)

        self.warning_list.warnings_updated.connect(warning_action.setEnabled)

        self.addToolBar(Qt.TopToolBarArea, self.menu_toolbar)

        self.status_bar = ObjectStatusBar(self, self.level_ref)
        self.setStatusBar(self.status_bar)

        self.delete_shortcut = QShortcut(QKeySequence(Qt.Key_Delete), self,
                                         self.remove_selected_objects)

        QShortcut(QKeySequence(Qt.CTRL + Qt.Key_X), self, self._cut_objects)
        QShortcut(QKeySequence(Qt.CTRL + Qt.Key_C), self, self._copy_objects)
        QShortcut(QKeySequence(Qt.CTRL + Qt.Key_V), self, self._paste_objects)

        QShortcut(QKeySequence(Qt.CTRL + Qt.Key_Z), self, self.level_ref.undo)
        QShortcut(QKeySequence(Qt.CTRL + Qt.Key_Y), self, self.level_ref.redo)
        QShortcut(QKeySequence(Qt.CTRL + Qt.SHIFT + Qt.Key_Z), self,
                  self.level_ref.redo)

        QShortcut(QKeySequence(Qt.CTRL + Qt.Key_Plus), self,
                  self.level_view.zoom_in)
        QShortcut(QKeySequence(Qt.CTRL + Qt.Key_Minus), self,
                  self.level_view.zoom_out)

        QShortcut(QKeySequence(Qt.CTRL + Qt.Key_A), self,
                  self.level_view.select_all)

        self.on_open_rom(path_to_rom)

        self.showMaximized()
class ClassTreeWidget(QDialog):
    """
    TreeView widget to show pyleecan classes structured by their inheritance together
    with the selected class description.
    """
    def __init__(self, keys=None, expand=True):
        super(ClassTreeWidget, self).__init__()
        self.setupUi()
        self.expandAll = expand
        self.setMinimumHeight(600)

        # === default variables ===
        self.classDict = ClassInfo().get_dict()
        self.keys = keys or ClassInfo().get_base_classes()  # TODO all classes
        self.selectionModel = self.treeView.selectionModel()

        # === Signals ===
        self.selectionModel.selectionChanged.connect(self.onSelectionChanged)
        self.treeView.doubleClicked.connect(self.onClassSelected)
        self.buttons.accepted.connect(self.accept)
        self.buttons.rejected.connect(self.reject)

        # === Generate content ===
        self.generate()

    def onClassSelected(self, index):
        """Method to accept the selection if a class was double clicked."""
        if index.isValid():
            self.accept()

    def onSelectionChanged(self, itSelection):
        """ """
        index = itSelection.indexes()[0]
        desc = index.model().itemFromIndex(index).data()
        self.text.setText(desc)

    def getSelectedClass(self):
        """Get the currently selected class by its name."""
        index = self.selectionModel.selectedIndexes()[0]
        return index.model().itemFromIndex(index).text()

    def setupUi(self):
        """Init. the UI."""
        self.setWindowIcon(QIcon(ICON))
        # === Widgets ===
        # TreeView
        model = QtGui.QStandardItemModel(0, 1)
        model.setHorizontalHeaderLabels(["Class"])

        self.treeView = QTreeView()
        self.treeView.rootNode = model.invisibleRootItem()
        self.treeView.setModel(model)
        self.treeView.setAlternatingRowColors(False)

        # size options
        # setting min. width in self.generate to fit content

        self.treeView.setContextMenuPolicy(Qt.CustomContextMenu)

        # Hide Debug Columns
        # self.treeView.hideColumn(1)

        # text output
        self.text = QLabel()
        self.text.setAlignment(Qt.AlignTop)
        self.text.setWordWrap(True)
        self.text.setMinimumWidth(300)

        # Splitters
        self.splitter = QSplitter(self)
        self.splitter.setStretchFactor(0, 0)
        self.splitter.setStretchFactor(1, 1)
        self.splitter.addWidget(self.treeView)
        self.splitter.addWidget(self.text)

        # dialog buttons
        self.buttons = QDialogButtonBox(
            QDialogButtonBox.Ok | QDialogButtonBox.Cancel
        )  # window to create confirmation and cancellation buttons

        # === Layout ===
        # Horizontal Div.
        layout = QVBoxLayout()

        # layout.setContentsMargins(0, 0, 0, 0)
        # layout.setSpacing(0)

        layout.addWidget(self.splitter)
        layout.addWidget(self.buttons)

        self.setLayout(layout)

    def generate(self):
        """Method to (recursively) build the tree (view) of the data object."""
        self.treeDict = dict()
        for key in self.keys:
            self.genTreeDict(key, self.treeDict)

        self.genTreeView(self.treeDict)

        # set first row active & expand all branches
        index = self.treeView.model().index(0, 0)
        self.treeView.setCurrentIndex(index)
        self.treeView.expandAll()
        wHint = self.treeView.sizeHintForColumn(0)
        self.treeView.setMinimumWidth(wHint)
        self.treeView.setColumnWidth(0, wHint)
        if not self.expandAll:
            self.treeView.collapseAll()

    def genTreeDict(self, key, parent):
        """Generate a dict structure of the classes recursively on the parent dict."""
        parent[key] = dict()
        for typ in self.classDict[key]["daughters"]:
            if key == self.classDict[typ]["mother"]:
                self.genTreeDict(typ, parent[key])

    def genTreeView(self, tree, parent=None):
        """Generate the view item structure on the parent item."""
        # init if root
        if parent is None:
            parent = self.treeView.rootNode
            self.treeView.rootNode.removeRows(
                0, self.treeView.rootNode.rowCount())

        for key, item in tree.items():
            desc = (
                f"Class: {key} \nPackage: {self.classDict[key]['package']}" +
                f"\nDescription: {self.classDict[key]['desc']}")
            row = self.addRow(parent, key, desc)

            if item:
                self.genTreeView(item, parent=row)

    def addRow(self, parent, name="", desc=""):
        """Add a new row to the parent item."""
        item = QtGui.QStandardItem(name)
        item.setEditable(False)
        item.setData(desc)
        parent.appendRow([item])
        return item
class MainWindow(QObject):
    """
    控制系统的主窗口
    """
    def __init__(self):
        """
        初始化界面
        """
        #
        # 成员变量
        #
        super().__init__()
        self.isPolling = False  # 是否在轮询中
        self.helper = Helper()  # 控制器
        self.polling_timer = None  # 轮询定时器,设成成员变量是为了能够取消定时器
        self.play_sound = True  # 默认允许播放蜂鸣声

        #
        # 初始化界面
        #
        self.ui = QUiLoader().load('./QtDesigner/main_window.ui'
                                   )  # 加载 UI 文件,self.ui 就是应用中 MainWindow 这个对象
        self.init_window()  # 初始化主窗口
        self.init_interval_combobox()  # 初始化轮询时间下拉框
        self.init_splitter()  # 初始化分离器
        self.init_table()  # 初始化表格
        self.init_output_edit()  # 初始化输出信息的窗口
        self.init_menu_bar()  # 初始化菜单

        self.ui.btn_submit.clicked.connect(self.start_polling)  # 绑定点击事件

    def init_window(self):
        """
        初始化主窗口
        :return: 无
        """
        self.ui.setWindowTitle("光伏集群现场监控")  # 窗口标题

        #
        # 左上角图标,任务栏图标
        #
        app_icon = QIcon("./other/logo.ico")
        self.ui.setWindowIcon(app_icon)

        #
        # 读取配置文件
        #
        baudrate, address = self.helper.read_config()
        if baudrate != "" and address != "":
            self.ui.edit_baudrate.setText(baudrate)
            self.ui.edit_addr.setText(address)

    def init_menu_bar(self):
        """
        初始化菜单栏
        :return: 无
        """
        self.ui.restart.triggered.connect(
            partial(self.one_key, self.ui.restart.text()))
        self.ui.lock.triggered.connect(
            partial(self.one_key, self.ui.lock.text()))
        self.ui.unlock1.triggered.connect(
            partial(self.one_key, self.ui.unlock1.text()))
        self.ui.wind_bread.triggered.connect(
            partial(self.one_key, self.ui.wind_bread.text()))
        self.ui.planish.triggered.connect(
            partial(self.one_key, self.ui.planish.text()))
        self.ui.snow_removal.triggered.connect(
            partial(self.one_key, self.ui.snow_removal.text()))
        self.ui.clean_board.triggered.connect(
            partial(self.one_key, self.ui.clean_board.text()))
        self.ui.sub_angle.triggered.connect(
            partial(self.one_key, self.ui.sub_angle.text()))
        self.ui.add_angle.triggered.connect(
            partial(self.one_key, self.ui.add_angle.text()))
        self.ui.advance.triggered.connect(self.show_advance_dialog)

        #
        # 日志
        #
        self.ui.wind_log.triggered.connect(partial(self.show_window, "wind"))
        self.ui.error_log.triggered.connect(partial(self.show_window, "error"))

        #
        # 帮助
        #
        self.ui.about.triggered.connect(self.show_about)
        self.ui.open_book.triggered.connect(partial(self.show_window, "book"))

        #
        # 蜂鸣报警声
        #
        self.ui.close_beep.triggered.connect(self.set_play_sound)

    def init_interval_combobox(self):
        """
        初始化轮询时间下拉列表框
        :return: 无
        """
        interval_list = ['5 s', '10 s', '15 s', '30 s', '60 s']
        self.ui.combobox_interval.addItems(interval_list)

    def init_splitter(self):
        """
        初始化分离器控件
        :return: 无
        """
        self.main_splitter = QSplitter(Qt.Vertical)  # 新建一个分离器,垂直分离

        #
        # 分离器添加控件
        #
        self.main_splitter.addWidget(self.ui.tableView)
        self.main_splitter.addWidget(self.ui.output_edit)

        #
        # 设置窗口比例
        #
        self.main_splitter.setStretchFactor(0, 8)
        self.main_splitter.setStretchFactor(1, 2)

        self.ui.data_layout.addWidget(
            self.main_splitter)  # 把这个 splitter 放在一个布局里才能显示出来

    def init_output_edit(self):
        """
        初始化输出框
        :return: 无
        """
        self.ui.output_edit.setReadOnly(True)  # 禁止编辑

        #
        # 添加右键菜单
        #
        self.ui.output_edit.setContextMenuPolicy(
            Qt.ActionsContextMenu)  # 允许右键菜单
        send_option = QAction(self.ui.output_edit)  # 具体菜单项
        send_option.setText("清除内容")
        send_option.triggered.connect(
            self.ui.output_edit.clear)  # 点击菜单中的具体选项执行的函数
        self.ui.output_edit.addAction(send_option)

    def init_table(self):
        """
        初始化表格样式
        :return:无
        """
        self.ui.tableView.verticalHeader().setVisible(False)  # 隐藏垂直表头
        self.ui.tableView.horizontalHeader().setSectionResizeMode(
            QHeaderView.ResizeToContents)  # 设置每列宽度:根据表头调整表格宽度
        self.ui.tableView.resizeColumnsToContents()  # 根据内容调整列宽
        self.ui.tableView.clicked.connect(self.handle_table_click)  # 鼠标左键点击事件

    def show_window(self, name: str):
        """
        显示 Windows 资源管理器
        :param url: 路径
        :return: 无
        """
        path = None
        if name == "wind":
            path = os.getcwd() + r"\log\wind_speed"
        elif name == "error":
            path = os.getcwd() + r"\log\error_log"
        elif name == "book":
            path = os.getcwd() + r"\other\光伏集群现场监控使用说明书.pdf"

        if os.path.exists(path):
            os.system("explorer.exe %s" % path)
        else:
            dail = InfoDialog("提示", "目前还没有日志!")
            dail.exec_()

    def show_about(self):
        """
        显示关于信息
        :return: 无
        """
        dial = InfoDialog("关于", "四川近日点新能源科技有限公司\n联系电话:15108303256")
        dial.exec_()  # 进入事件循环,不关闭不会退出循环

    def set_play_sound(self):
        """
        设置蜂鸣声
        :return:
        """
        if self.play_sound is False:
            self.play_sound = True
            self.append_info("已打开蜂鸣报警声")
            self.ui.close_beep.setText("关闭蜂鸣报警声")
        else:
            self.play_sound = False
            self.append_info("已关闭蜂鸣报警声")
            self.ui.close_beep.setText("打开蜂鸣报警声")

    def get_serial_info(self):
        com_port = self.ui.box_com_port.currentText()  # 端口号
        collector_addr = self.ui.edit_addr.text()  # 数采地址
        baud_rate = self.ui.edit_baudrate.text()  # 波特率
        return com_port, collector_addr, baud_rate

    def one_key(self, option: str):
        """
        一键命令
        :param option:命令
        :return:无
        """
        # self.update_serial()
        if self.isPolling is False:
            self.append_info("请先开始轮询,然后再开始一键操作!", 'red')
        else:
            message.append({'cmd': 'one_key', 'option': "%s" % option})

    @Slot(int)
    def update_member(self, member: int):
        """
        更新成员数
        :param member:成员数
        :return:无
        """
        self.ui.label_member.setText(str(member))

    @Slot(str)
    def update_port(self, port_name_list: str):
        """
        初始化下拉列表框
        :return:无
        """
        port_name_list = eval(port_name_list)
        self.ui.box_com_port.clear()
        self.ui.box_com_port.addItems(port_name_list)
        if len(port_name_list) > 0:
            self.append_info("共扫描到 %d 个串口设备:%s" %
                             (len(port_name_list), port_name_list))
            self.ui.btn_submit.setEnabled(True)  # 可以轮询
        else:
            self.append_info('未检测到任何串口设备,请检查连接是否正常', 'red')
            #
            # 加个 if 是为了判断是不是正在轮询中,
            # 有可能是正在轮询,突然没有一个串口设备了
            #

            self.ui.btn_submit.setEnabled(False)  # 禁止轮询

    @Slot(str, str)
    def append_info(self, text: str, color: str = 'black'):
        """
        追加信息到输出狂
        :param info:信息,字典字符串
        :return:
        """
        black = QColor(0, 0, 0)
        if color == 'red':
            c = QColor(255, 0, 0)
        elif color == 'green':
            c = QColor(0, 128, 0)
        else:
            c = black

        #
        # 使用指定颜色追加文本,然后恢复为黑色
        #
        self.ui.output_edit.setTextColor(c)
        self.ui.output_edit.append(util.get_time() + " " + text)  # 显示文本
        self.ui.output_edit.setTextColor(black)
        self.ui.output_edit.moveCursor(QTextCursor.End)  # 输出信息后滚动到最后

    def handle_table_click(self, item: QModelIndex):
        """
        处理表格左键点击事件
        :param item:点击的单元格
        :return:无
        """
        #
        # 首先获取点击的行、列号
        # 判断点击的单元格是否可点击,如果可以,
        # 就弹出编辑对话框
        #
        i = item.row()
        j = item.column()
        if self.is_editable(i, j):
            #
            # 如果在轮询的话,立即停止,并标记需要恢复
            #
            # recover = False
            #
            # if self.isPolling:
            #     self.stop_polling()
            #     recover = True

            #
            # 根据行号、列号计算出机器编号,然后显示修改窗口
            #
            machine_number = self.helper.get_machine_number(i, j)
            if self.isPolling is False:
                self.append_info("请先开始轮询,再发送控制代码!", 'red')
            else:
                self.show_modify_dialog(machine_number)

            # if recover is True:
            #     self.start_polling()

    def is_editable(self, i, j) -> bool:
        """
        判断该单元格是否可编辑
        :param i:行,从 0 开始
        :param j:列,从 0 开始
        :return:是否可编辑
        """
        #
        # i % 4 == 1 表示 i 在控制代码行
        # j % 2 == 1 表示 j 在控制代码列
        #
        if i % 4 == 1 and j % 2 == 1:
            return True
        return False

    def set_enable(self, enable: bool):
        """
        是否允许编辑串口参数相关
        :param enable: 是否允许
        :return: 无
        """
        self.ui.box_com_port.setEnabled(enable)  # 端口下拉框
        self.ui.edit_baudrate.setEnabled(enable)  # 波特率
        self.ui.edit_addr.setEnabled(enable)  # 地址
        self.ui.combobox_interval.setEnabled(enable)  # 轮询时间

    def start_polling(self):
        """
        开始轮询按钮响应函数
        提交轮询 or 停止轮询
        :return:无
        """
        if not self.isPolling:
            self.isPolling = True
            self.ui.btn_submit.setText("停止轮询")
            self.set_enable(False)  # 禁止编辑
            self.update_serial()
            self.append_info("开始轮询")
            self.polling()

        else:
            self.stop_polling()

    def update_serial(self):
        com_port, collector_addr, baud_rate = self.get_serial_info()
        message.append({
            'cmd': 'update_serial',
            'com_port': com_port,
            'collector_addr': collector_addr,
            'baud_rate': baud_rate
        })

    def polling(self):
        """
        轮询查询
        :return:无
        """
        #
        # 更新界面
        #
        message.append({'cmd': 'member'})
        message.append({'cmd': 'table'})
        message.append({'cmd': 'wind_speed'})

        self.next_polling()  # 准备下一次轮询

    @Slot()
    def stop_polling(self):
        """
        立即停止轮询
        :return:无
        """
        #
        # 如果正在轮询,就停止轮询
        # 点击“停止轮询”,则按钮立即显示“开始轮询”
        #
        if self.isPolling:
            self.ui.btn_submit.setText("开始轮询")
            self.set_enable(True)  # 恢复允许编辑
            self.isPolling = False
            self.append_info("结束轮询")  # 信息台输出结束信息

            self.close_serial()
            #
            # 强制停止子线程
            #
            if self.polling_timer is not None and self.polling_timer.is_alive(
            ):
                util.stop_thread(self.polling_timer)

    def close_serial(self):
        """
        发命令关闭串口
        :return:
        """
        msg = {"cmd": 'close_serial'}
        message.append(msg)

    def next_polling(self):
        """
        设置一个定时器,到了一定时间后就启动轮询
        :return:无
        """
        interval = int(
            self.ui.combobox_interval.currentText()[:-2])  # 获取间隔时间下拉框的值
        self.polling_timer = Timer(interval, self.polling)
        self.polling_timer.setName("polling_timer")
        self.polling_timer.setDaemon(True)
        self.polling_timer.start()

    @Slot(str)
    def update_wind_speed(self, wind_speed: str):
        """
        更新风速
        :param wind_speed:风速值
        :return: 无
        """
        self.ui.label_wind_speed.setText(wind_speed + " m/s")
        collector_addr = self.ui.edit_addr.text()  # 数采地址
        self.helper.write_wind_speed(float(wind_speed), collector_addr)

    @Slot(str)
    def update_table(self, table_data: str):
        """
        更新表格数据
        :param table_data:表格数据
        :return:无
        """
        table_model, error_number = self.helper.get_table_model(table_data)
        if error_number != "":
            self.append_info("有异常机器编号:" + error_number)
            self.play_error_sound()
            collector_addr = self.ui.edit_addr.text()  # 数采地址
            self.helper.write_error(error_number, collector_addr)

        self.ui.tableView.setModel(table_model)

    def play_error_sound(self):
        """
        播放警报
        :return:
        """
        if self.play_sound:
            playsound.playsound("./other/bee.mp3")

    def show_modify_dialog(self, machine_number: int):
        """
        显示发送控制代码的对话框
        :return: 无
        """
        input_dial = ModifyDialog("发送控制代码", "%d 号控制器:" % machine_number)
        if input_dial.exec_():
            try:
                value = input_dial.textValue()

                #
                # 检查输入
                #
                obj = re.match(r"^[0-9]{1,2}$", "12")
                if obj is None:
                    raise ValueError
                else:
                    code = int(value)
                    if 1 <= code <= 99:
                        code = int(input_dial.textValue())
                        self.send_control_code(machine_number, code)
                    else:
                        raise ValueError
            except ValueError:
                #
                # 提示输入有误
                #
                info = "输入的控制代码有误!控制代码只能是:1~99"
                dial = InfoDialog("提示", info)
                dial.exec_()  # 进入事件循环

    def show_advance_dialog(self):
        """
        显示高级对话框,留着预防以后加什么新命令,可以通过这个对话框进行发送
        :return:
        """
        input_dial = ModifyDialog("发送控制代码", "对所有控制器发送:")
        if input_dial.exec_():
            try:
                value = input_dial.textValue()
                #
                # 判断输入字符的长度,大于 2 就不是 1<= x <= 99
                #
                obj = re.match(r"^[0-9]{1,2}$", "12")
                if obj is None:
                    raise ValueError
                else:
                    code = int(value)
                    if 1 <= code <= 99:
                        code = int(input_dial.textValue())
                        self.one_key(code)
                    else:
                        raise ValueError

            except ValueError:
                #
                # 提示输入有误
                #
                info = "输入的控制代码有误!控制代码只能是 1~99!"
                dial = InfoDialog("提示", info)
                dial.exec_()  # 进入事件循环

    def send_control_code(self, machine_number: int, code: int) -> None:
        """
        发送控制代码
        :param machine_number:机器编号
        :param code:控制代码
        :return:无
        """
        msg = {}
        msg["cmd"] = 'send_control_code'
        code = '{:04X}'.format(code)  # 十进制控制代码转十六进制
        msg['machine_number'] = "%d" % machine_number
        msg['code'] = "%s" % code

        message.append(msg)
class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.resize(1280, 720)
        self.central_widget = QWidget(MainWindow)

        self.splitter = QSplitter(self.central_widget)
        self.splitter.setChildrenCollapsible(False)
        self.splitter.setOpaqueResize(True)

        self.main_grid_layout = QGridLayout(self.central_widget)
        self.main_grid_layout.addWidget(self.splitter)
        self.main_grid_layout.setSizeConstraint(QLayout.SetDefaultConstraint)

        self.tab_widget = QTabWidget(self.central_widget)
        self.tab_widget.setMinimumSize(QSize(500, 0))
        self._set_up_component_tree_view()
        self.splitter.addWidget(self.tab_widget)

        self._set_up_3d_view()

        MainWindow.setCentralWidget(self.central_widget)

        self._set_up_menus(MainWindow)
        self.tab_widget.setCurrentIndex(0)
        QMetaObject.connectSlotsByName(MainWindow)
        self.splitter.setStretchFactor(0, 0)
        self.splitter.setStretchFactor(1, 1)

    def _set_up_3d_view(self):
        self.sceneWidget.setMinimumSize(QSize(600, 0))
        self.splitter.addWidget(self.sceneWidget)

    def _set_up_component_tree_view(self):
        self.sceneWidget = InstrumentView(self.splitter)
        self.component_tree_view_tab = ComponentTreeViewTab(
            scene_widget=self.sceneWidget, parent=self
        )
        self.tab_widget.addTab(self.component_tree_view_tab, "")

    def _set_up_menus(self, MainWindow: QObject):
        self.menu_bar = QMenuBar()
        self.menu_bar.setGeometry(QRect(0, 0, 1280, 720))
        self.file_menu = QMenu(self.menu_bar)
        MainWindow.setMenuBar(self.menu_bar)
        self.status_bar = QStatusBar(MainWindow)
        MainWindow.setStatusBar(self.status_bar)
        self.open_json_file_action = QAction(MainWindow)
        self.open_json_file_action.setShortcut(QKeySequence("Ctrl+O"))
        self.export_to_filewriter_JSON_action = QAction(MainWindow)
        self.export_to_filewriter_JSON_action.setShortcut(QKeySequence("Ctrl+S"))
        self.file_menu.addAction(self.open_json_file_action)
        self.file_menu.addAction(self.export_to_filewriter_JSON_action)

        self.view_menu = QMenu(self.menu_bar)
        self.show_action_labels = QAction(MainWindow)
        self.show_action_labels.setCheckable(True)
        self.show_action_labels.setChecked(True)
        self.simple_tree_view = QAction(MainWindow)
        self.simple_tree_view.setCheckable(True)
        self.about_window = QAction(MainWindow)
        self.view_menu.addAction(self.about_window)
        self.view_menu.addAction(self.show_action_labels)
        self.view_menu.addAction(self.simple_tree_view)

        self.menu_bar.addAction(self.file_menu.menuAction())
        self.menu_bar.addAction(self.view_menu.menuAction())
        self._set_up_titles(MainWindow)

    def _set_up_titles(self, MainWindow):
        MainWindow.setWindowTitle("NeXus Constructor")
        self.tab_widget.setTabText(
            self.tab_widget.indexOf(self.component_tree_view_tab), "Nexus Structure"
        )
        self.file_menu.setTitle("File")
        self.open_json_file_action.setText("Open File writer JSON file")
        self.export_to_filewriter_JSON_action.setText("Export to File writer JSON")

        self.view_menu.setTitle("View")
        self.show_action_labels.setText("Show Button Labels")
        self.simple_tree_view.setText("Use Simple Tree Model View")
        self.about_window.setText("About")

        self.menu_bar.setNativeMenuBar(False)
Exemple #14
0
    def __init__(self, path_to_rom=""):
        super(MainWindow, self).__init__()

        self.setWindowIcon(icon("foundry.ico"))

        file_menu = QMenu("File")

        open_rom_action = file_menu.addAction("&Open ROM")
        open_rom_action.triggered.connect(self.on_open_rom)
        self.open_m3l_action = file_menu.addAction("&Open M3L")
        self.open_m3l_action.triggered.connect(self.on_open_m3l)

        file_menu.addSeparator()

        save_rom_action = file_menu.addAction("&Save ROM")
        save_rom_action.triggered.connect(self.on_save_rom)
        save_rom_as_action = file_menu.addAction("&Save ROM as ...")
        save_rom_as_action.triggered.connect(self.on_save_rom_as)
        """
        file_menu.AppendSeparator()
        """
        self.save_m3l_action = file_menu.addAction("&Save M3L")
        self.save_m3l_action.triggered.connect(self.on_save_m3l)
        """
        file_menu.Append(ID_SAVE_LEVEL_TO, "&Save Level to", "")
        file_menu.AppendSeparator()
        file_menu.Append(ID_APPLY_IPS_PATCH, "&Apply IPS Patch", "")
        file_menu.AppendSeparator()
        file_menu.Append(ID_ROM_PRESET, "&ROM Preset", "")
        """
        file_menu.addSeparator()
        settings_action = file_menu.addAction("&Settings")
        settings_action.triggered.connect(show_settings)
        file_menu.addSeparator()
        exit_action = file_menu.addAction("&Exit")
        exit_action.triggered.connect(lambda _: self.close())

        self.menuBar().addMenu(file_menu)
        """
        edit_menu = wx.Menu()

        edit_menu.Append(ID_EDIT_LEVEL, "&Edit Level", "")
        edit_menu.Append(ID_EDIT_OBJ_DEFS, "&Edit Object Definitions", "")
        edit_menu.Append(ID_EDIT_PALETTE, "&Edit Palette", "")
        edit_menu.Append(ID_EDIT_GRAPHICS, "&Edit Graphics", "")
        edit_menu.Append(ID_EDIT_MISC, "&Edit Miscellaneous", "")
        edit_menu.AppendSeparator()
        edit_menu.Append(ID_FREE_FORM_MODE, "&Free form Mode", "")
        edit_menu.Append(ID_LIMIT_SIZE, "&Limit Size", "")
        """

        level_menu = QMenu("Level")

        select_level_action = level_menu.addAction("&Select Level")
        select_level_action.triggered.connect(self.open_level_selector)
        """
        level_menu.Append(ID_GOTO_NEXT_AREA, "&Go to next Area", "")
        level_menu.AppendSeparator()
        """
        self.reload_action = level_menu.addAction("&Reload Level")
        self.reload_action.triggered.connect(self.reload_level)
        level_menu.addSeparator()
        self.edit_header_action = level_menu.addAction("&Edit Header")
        self.edit_header_action.triggered.connect(self.on_header_editor)
        """
        level_menu.Append(ID_EDIT_POINTERS, "&Edit Pointers", "")
        """

        self.menuBar().addMenu(level_menu)

        object_menu = QMenu("Objects")

        view_blocks_action = object_menu.addAction("&View Blocks")
        view_blocks_action.triggered.connect(self.on_block_viewer)
        view_objects_action = object_menu.addAction("&View Objects")
        view_objects_action.triggered.connect(self.on_object_viewer)
        """
        object_menu.AppendSeparator()
        object_menu.Append(ID_CLONE_OBJECT_ENEMY, "&Clone Object/Enemy", "")
        object_menu.AppendSeparator()
        object_menu.Append(ID_ADD_3_BYTE_OBJECT, "&Add 3 Byte Object", "")
        object_menu.Append(ID_ADD_4_BYTE_OBJECT, "&Add 4 Byte Object", "")
        object_menu.Append(ID_ADD_ENEMY, "&Add Enemy", "")
        object_menu.AppendSeparator()
        object_menu.Append(ID_DELETE_OBJECT_ENEMY, "&Delete Object/Enemy", "")
        object_menu.Append(ID_DELETE_ALL, "&Delete All", "")
        """

        self.menuBar().addMenu(object_menu)

        view_menu = QMenu("View")
        view_menu.triggered.connect(self.on_menu)

        action = view_menu.addAction("Mario")
        action.setProperty(ID_PROP, ID_MARIO)
        action.setCheckable(True)
        action.setChecked(SETTINGS["draw_mario"])

        action = view_menu.addAction("&Jumps on objects")
        action.setProperty(ID_PROP, ID_JUMP_OBJECTS)
        action.setCheckable(True)
        action.setChecked(SETTINGS["draw_jump_on_objects"])

        action = view_menu.addAction("Items in blocks")
        action.setProperty(ID_PROP, ID_ITEM_BLOCKS)
        action.setCheckable(True)
        action.setChecked(SETTINGS["draw_items_in_blocks"])

        action = view_menu.addAction("Invisible items")
        action.setProperty(ID_PROP, ID_INVISIBLE_ITEMS)
        action.setCheckable(True)
        action.setChecked(SETTINGS["draw_invisible_items"])

        view_menu.addSeparator()

        action = view_menu.addAction("Jump Zones")
        action.setProperty(ID_PROP, ID_JUMPS)
        action.setCheckable(True)
        action.setChecked(SETTINGS["draw_jumps"])

        action = view_menu.addAction("&Grid lines")
        action.setProperty(ID_PROP, ID_GRID_LINES)
        action.setCheckable(True)
        action.setChecked(SETTINGS["draw_grid"])

        action = view_menu.addAction("Resize Type")
        action.setProperty(ID_PROP, ID_RESIZE_TYPE)
        action.setCheckable(True)
        action.setChecked(SETTINGS["draw_expansion"])

        view_menu.addSeparator()

        action = view_menu.addAction("&Block Transparency")
        action.setProperty(ID_PROP, ID_TRANSPARENCY)
        action.setCheckable(True)
        action.setChecked(SETTINGS["block_transparency"])

        view_menu.addSeparator()
        view_menu.addAction("&Save Screenshot of Level").triggered.connect(
            self.on_screenshot)
        """
        view_menu.Append(ID_BACKGROUND_FLOOR, "&Background & Floor", "")
        view_menu.Append(ID_TOOLBAR, "&Toolbar", "")
        view_menu.AppendSeparator()
        view_menu.Append(ID_ZOOM, "&Zoom", "")
        view_menu.AppendSeparator()
        view_menu.Append(ID_USE_ROM_GRAPHICS, "&Use ROM Graphics", "")
        view_menu.Append(ID_PALETTE, "&Palette", "")
        view_menu.AppendSeparator()
        view_menu.Append(ID_MORE, "&More", "")
        """

        self.menuBar().addMenu(view_menu)

        help_menu = QMenu("Help")
        """
        help_menu.Append(ID_ENEMY_COMPATIBILITY, "&Enemy Compatibility", "")
        help_menu.Append(ID_TROUBLESHOOTING, "&Troubleshooting", "")
        help_menu.AppendSeparator()
        help_menu.Append(ID_PROGRAM_WEBSITE, "&Program Website", "")
        help_menu.Append(ID_MAKE_A_DONATION, "&Make a Donation", "")
        help_menu.AppendSeparator()
        """
        update_action = help_menu.addAction("Check for updates")
        update_action.triggered.connect(self.on_check_for_update)

        help_menu.addSeparator()

        video_action = help_menu.addAction("Feature Video on YouTube")
        video_action.triggered.connect(lambda: open_url(feature_video_link))

        discord_action = help_menu.addAction("SMB3 Rom Hacking Discord")
        discord_action.triggered.connect(lambda: open_url(discord_link))

        help_menu.addSeparator()

        about_action = help_menu.addAction("&About")
        about_action.triggered.connect(self.on_about)

        self.menuBar().addMenu(help_menu)

        self.level_selector = LevelSelector(parent=self)

        self.block_viewer = None
        self.object_viewer = None

        self.level_ref = LevelRef()
        self.level_ref.data_changed.connect(self._on_level_data_changed)

        self.context_menu = ContextMenu(self.level_ref)
        self.context_menu.triggered.connect(self.on_menu)

        self.level_view = LevelView(self, self.level_ref, self.context_menu)

        self.scroll_panel = QScrollArea()
        self.scroll_panel.setWidgetResizable(True)
        self.scroll_panel.setWidget(self.level_view)

        self.setCentralWidget(self.scroll_panel)

        self.spinner_panel = SpinnerPanel(self, self.level_ref)
        self.spinner_panel.zoom_in_triggered.connect(self.level_view.zoom_in)
        self.spinner_panel.zoom_out_triggered.connect(self.level_view.zoom_out)
        self.spinner_panel.object_change.connect(self.on_spin)

        self.object_list = ObjectList(self, self.level_ref, self.context_menu)

        self.object_dropdown = ObjectDropdown(self)
        self.object_dropdown.object_selected.connect(
            self._on_placeable_object_selected)

        self.level_size_bar = LevelSizeBar(self, self.level_ref)
        self.enemy_size_bar = EnemySizeBar(self, self.level_ref)

        self.jump_list = JumpList(self, self.level_ref)
        self.jump_list.add_jump.connect(self.on_jump_added)
        self.jump_list.edit_jump.connect(self.on_jump_edit)
        self.jump_list.remove_jump.connect(self.on_jump_removed)

        splitter = QSplitter(self)
        splitter.setOrientation(Qt.Vertical)

        splitter.addWidget(self.object_list)
        splitter.setStretchFactor(0, 1)
        splitter.addWidget(self.jump_list)

        splitter.setChildrenCollapsible(False)

        level_toolbar = QToolBar("Level Info Toolbar", self)
        level_toolbar.setContextMenuPolicy(Qt.PreventContextMenu)
        level_toolbar.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
        level_toolbar.setOrientation(Qt.Horizontal)
        level_toolbar.setFloatable(False)

        level_toolbar.addWidget(self.spinner_panel)
        level_toolbar.addWidget(self.object_dropdown)
        level_toolbar.addWidget(self.level_size_bar)
        level_toolbar.addWidget(self.enemy_size_bar)
        level_toolbar.addWidget(splitter)

        level_toolbar.setAllowedAreas(Qt.LeftToolBarArea | Qt.RightToolBarArea)

        self.addToolBar(Qt.RightToolBarArea, level_toolbar)

        self.object_toolbar = ObjectToolBar(self)
        self.object_toolbar.object_selected.connect(
            self._on_placeable_object_selected)

        object_toolbar = QToolBar("Object Toolbar", self)
        object_toolbar.setContextMenuPolicy(Qt.PreventContextMenu)
        object_toolbar.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
        object_toolbar.setFloatable(False)

        object_toolbar.addWidget(self.object_toolbar)
        object_toolbar.setAllowedAreas(Qt.LeftToolBarArea
                                       | Qt.RightToolBarArea)

        self.addToolBar(Qt.LeftToolBarArea, object_toolbar)

        menu_toolbar = QToolBar("Menu Toolbar", self)
        menu_toolbar.setOrientation(Qt.Horizontal)
        menu_toolbar.setIconSize(QSize(20, 20))

        menu_toolbar.addAction(
            icon("settings.svg"),
            "Editor Settings").triggered.connect(show_settings)
        menu_toolbar.addSeparator()
        menu_toolbar.addAction(icon("folder.svg"),
                               "Open ROM").triggered.connect(self.on_open_rom)
        menu_toolbar.addAction(
            icon("save.svg"), "Save Level").triggered.connect(self.on_save_rom)
        menu_toolbar.addSeparator()

        self.undo_action = menu_toolbar.addAction(icon("rotate-ccw.svg"),
                                                  "Undo Action")
        self.undo_action.triggered.connect(self.level_ref.undo)
        self.undo_action.setEnabled(False)
        self.redo_action = menu_toolbar.addAction(icon("rotate-cw.svg"),
                                                  "Redo Action")
        self.redo_action.triggered.connect(self.level_ref.redo)
        self.redo_action.setEnabled(False)

        menu_toolbar.addSeparator()
        menu_toolbar.addAction(icon("play-circle.svg"),
                               "Play Level").triggered.connect(self.on_play)
        menu_toolbar.addSeparator()
        menu_toolbar.addAction(icon("zoom-out.svg"),
                               "Zoom Out").triggered.connect(
                                   self.level_view.zoom_out)
        menu_toolbar.addAction(icon("zoom-in.svg"),
                               "Zoom In").triggered.connect(
                                   self.level_view.zoom_in)
        menu_toolbar.addSeparator()
        menu_toolbar.addAction(icon("tool.svg"),
                               "Edit Level Header").triggered.connect(
                                   self.on_header_editor)
        self.jump_destination_action = menu_toolbar.addAction(
            icon("arrow-right-circle.svg"), "Go to Jump Destination")
        self.jump_destination_action.triggered.connect(
            self._go_to_jump_destination)
        menu_toolbar.addSeparator()
        # menu_toolbar.addAction(icon("help-circle.svg"), "What's this?")

        self.addToolBar(Qt.TopToolBarArea, menu_toolbar)

        self.status_bar = ObjectStatusBar(self, self.level_ref)
        self.setStatusBar(self.status_bar)

        self.delete_shortcut = QShortcut(QKeySequence(Qt.Key_Delete), self,
                                         self.remove_selected_objects)

        QShortcut(QKeySequence(Qt.CTRL + Qt.Key_X), self, self._cut_objects)
        QShortcut(QKeySequence(Qt.CTRL + Qt.Key_C), self, self._copy_objects)
        QShortcut(QKeySequence(Qt.CTRL + Qt.Key_V), self, self._paste_objects)

        QShortcut(QKeySequence(Qt.CTRL + Qt.Key_Z), self, self.level_ref.undo)
        QShortcut(QKeySequence(Qt.CTRL + Qt.Key_Y), self, self.level_ref.redo)
        QShortcut(QKeySequence(Qt.CTRL + Qt.SHIFT + Qt.Key_Z), self,
                  self.level_ref.redo)

        QShortcut(QKeySequence(Qt.CTRL + Qt.Key_Plus), self,
                  self.level_view.zoom_in)
        QShortcut(QKeySequence(Qt.CTRL + Qt.Key_Minus), self,
                  self.level_view.zoom_out)

        QShortcut(QKeySequence(Qt.CTRL + Qt.Key_A), self,
                  self.level_view.select_all)

        if not self.on_open_rom(path_to_rom):
            self.deleteLater()

        self.showMaximized()
Exemple #15
0
class BasisUI(QSplitter):
    def __init__(self, *args, **kwargs):
        super(BasisUI, self).__init__(*args, **kwargs)
        main_layout = QHBoxLayout()
        self.variety_tree = VarietyTree(self)
        main_layout.addWidget(self.variety_tree)

        self.right_widget = QWidget(self)
        right_layout = QVBoxLayout()
        right_layout.setContentsMargins(QMargins(1, 1, 1, 1))

        opts_layout = QHBoxLayout()
        opts_layout.addWidget(QLabel("合约:", self))
        self.contract_combobox = QComboBox(self)
        self.contract_combobox.setMinimumWidth(80)
        opts_layout.addWidget(self.contract_combobox)
        self.query_button = QPushButton("查询", self)
        opts_layout.addWidget(self.query_button)

        # 日期间隔选项
        self.query_month_combobox = QComboBox(self)
        self.query_month_combobox.addItem("近三月", 3)
        self.query_month_combobox.addItem("近六月", 6)
        self.query_month_combobox.addItem("近一年", 12)
        opts_layout.addWidget(self.query_month_combobox)

        self.tip_label = QLabel('选择对应品种和合约后查询数据. ', self)
        opts_layout.addWidget(self.tip_label)
        opts_layout.addStretch()

        right_layout.addLayout(opts_layout)

        self.show_splitter = QSplitter(orientation=Qt.Vertical)
        # 图形容器
        self.chart_view = QWebEngineView(self)
        self.chart_view.setMinimumHeight(int(self.height() * 0.518))
        self.show_splitter.addWidget(self.chart_view)
        # 数据展示
        self.chart_data_table = QTableWidget(self)
        self.chart_data_table.setEditTriggers(
            QAbstractItemView.NoEditTriggers)  # 不可编辑
        self.chart_data_table.setFocusPolicy(Qt.NoFocus)  # 去选中时的虚线框
        self.chart_data_table.setAlternatingRowColors(True)  # 交替行颜色
        self.chart_data_table.setFrameShape(QFrame.NoFrame)
        self.chart_data_table.setColumnCount(6)
        self.chart_data_table.setHorizontalHeaderLabels(
            ["品种", "合约", "日期", "现货价", "收盘价", "基差"])
        self.show_splitter.addWidget(self.chart_data_table)
        self.show_splitter.setStretchFactor(0, 6)
        self.show_splitter.setStretchFactor(1, 4)
        self.show_splitter.setHandleWidth(2)

        right_layout.addWidget(self.show_splitter)

        self.right_widget.setLayout(right_layout)

        main_layout.addWidget(self.right_widget)

        self.setLayout(main_layout)

        self.setStretchFactor(0, 3)
        self.setStretchFactor(1, 7)
        self.setHandleWidth(1)

        self.tip_label.setObjectName("tipLabel")
        self.chart_data_table.setObjectName("dataTable")
        self.setStyleSheet(
            "#tipLabel{border:none;color:rgb(230,50,50);font-weight:bold}"
            "#dataTable{selection-color:rgb(255,255,255);selection-background-color:rgb(51,143,255);alternate-background-color:rgb(245,250,248)}"
        )
Exemple #16
0
    def __init__(self, *args, **kwargs):
        super(ExchangeSpiderUI, self).__init__(*args, **kwargs)
        layout = QVBoxLayout()
        layout.setContentsMargins(QMargins(2, 0, 2, 1))
        main_splitter = QSplitter(self)
        main_splitter.setHandleWidth(1)
        self.tree_widget = ExchangeLibTree(self)
        main_splitter.addWidget(self.tree_widget)

        action_splitter = QSplitter(Qt.Vertical, self)
        action_splitter.setHandleWidth(1)

        spider_widget = QWidget(self)
        spider_widget.setAutoFillBackground(True)
        palette = QPalette()
        pix = QPixmap("images/spider_bg.png")
        pix = pix.scaled(QSize(700, 700), Qt.KeepAspectRatio)
        palette.setBrush(QPalette.Background, QBrush(pix))
        spider_widget.setPalette(palette)

        spider_layout = QVBoxLayout()

        tips_layout = QHBoxLayout()
        tips_layout.setSpacing(1)
        tips_layout.addWidget(QLabel("当前交易所:", self))
        self.spider_exchange_button = QPushButton("未选择", self)
        tips_layout.addWidget(self.spider_exchange_button)

        tips_layout.addWidget(QLabel(self))
        tips_layout.addWidget(QLabel("当前操作:", self))
        self.spider_action_button = QPushButton("未选择", self)
        tips_layout.addWidget(self.spider_action_button)

        tips_layout.addWidget(QLabel(self))
        tips_layout.addWidget(QLabel("选择日期:", self))
        self.spider_date_edit = QDateEdit(QDate.currentDate(), self)
        self.spider_date_edit.setCalendarPopup(True)
        self.spider_date_edit.setDisplayFormat("yyyy-MM-dd")
        tips_layout.addWidget(self.spider_date_edit)

        tips_layout.addWidget(QLabel(self))
        self.spider_start_button = QPushButton("开始", self)
        tips_layout.addWidget(self.spider_start_button)
        tips_layout.addStretch()

        spider_layout.addLayout(tips_layout)

        self.spider_status = QLabel("等待开始抓取", self)
        self.spider_status.setWordWrap(True)
        self.spider_status.setAlignment(Qt.AlignCenter)

        spider_layout.addWidget(self.spider_status)

        spider_widget.setLayout(spider_layout)

        action_splitter.addWidget(spider_widget)

        # 解析部分
        parser_widget = QWidget(self)
        parser_widget.setAutoFillBackground(True)
        palette = QPalette()
        pix = QPixmap("images/parser_bg.png")
        pix = pix.scaled(QSize(700, 700), Qt.KeepAspectRatio)
        palette.setBrush(QPalette.Background, QBrush(pix))
        parser_widget.setPalette(palette)

        parser_layout = QVBoxLayout()

        tips_layout = QHBoxLayout()
        tips_layout.setSpacing(1)
        tips_layout.addWidget(QLabel("当前交易所:", self))
        self.parser_exchange_button = QPushButton("未选择", self)
        tips_layout.addWidget(self.parser_exchange_button)

        tips_layout.addWidget(QLabel(self))
        tips_layout.addWidget(QLabel("当前操作:", self))
        self.parser_action_button = QPushButton("未选择", self)
        tips_layout.addWidget(self.parser_action_button)

        tips_layout.addWidget(QLabel(self))
        tips_layout.addWidget(QLabel("选择日期:", self))
        self.parser_date_edit = QDateEdit(QDate.currentDate(), self)
        self.parser_date_edit.setCalendarPopup(True)
        self.parser_date_edit.setDisplayFormat("yyyy-MM-dd")
        tips_layout.addWidget(self.parser_date_edit)

        tips_layout.addWidget(QLabel(self))
        self.parser_start_button = QPushButton("开始", self)
        tips_layout.addWidget(self.parser_start_button)
        tips_layout.addStretch()

        parser_layout.addLayout(tips_layout)

        self.parser_status = QLabel("等待开始解析", self)
        self.parser_status.setAlignment(Qt.AlignCenter)
        parser_layout.addWidget(self.parser_status)

        parser_widget.setLayout(parser_layout)

        action_splitter.addWidget(parser_widget)

        main_splitter.addWidget(action_splitter)

        main_splitter.setStretchFactor(0, 4)
        main_splitter.setStretchFactor(1, 6)

        layout.addWidget(main_splitter)
        self.setLayout(layout)

        main_splitter.setObjectName("mainSplitter")
        action_splitter.setObjectName("actionSplitter")

        self.spider_exchange_button.setObjectName("tipButton")
        self.spider_action_button.setObjectName("tipButton")
        self.spider_status.setObjectName("spiderStatus")

        self.parser_exchange_button.setObjectName("tipButton")
        self.parser_action_button.setObjectName("tipButton")
        self.parser_status.setObjectName("parserStatus")

        self.setStyleSheet(
            "#mainSplitter::handle{background-color:rgba(50,50,50,100)}"
            "#actionSplitter::handle{background-color:rgba(50,50,50,100)}"
            "#tipButton{border:none;color:rgb(220,100,100)}"
            "#spiderStatus,#parserStatus{font-size:16px;font-weight:bold;color:rgb(230,50,50)}"
        )
Exemple #17
0
    def init_ui(self):

        self.setWindowTitle('Trace Event Window')
        self.setGeometry(100, 100, 800, 600)

        bar = self.menuBar()

        file_ = bar.addMenu('File')
        export_log = QAction('Save to File',
                             self,
                             triggered=lambda: self.save_log())

        options = bar.addMenu('Options')
        auto_refresh = QAction(
            'Auto Refresh',
            self,
            checkable=True,
            triggered=lambda: self.timer.start(100)
            if auto_refresh.isChecked() else self.timer.stop())
        auto_refresh.setChecked(True)

        options.addAction(auto_refresh)
        file_.addAction(export_log)

        vgrid = QVBoxLayout()
        grid = QHBoxLayout()

        self.tree = QTreeWidget()
        self.tree.setHeaderLabels(['Name'])

        self.top = []
        self.lst = []

        for n, event in enumerate(self.trace_events):
            word = event.split('_')[0]
            if word not in self.top:
                self.top.append(word)
                item = QTreeWidgetItem(self.tree)
                self.lst.append(item)
                item.setText(0, word)
            subitem = QTreeWidgetItem(item)
            subitem.setText(0, '    ' + event.split(' : ')[0])
            # subitem.setCheckState(0, Qt.Unchecked)
            cbox = QCheckBox()
            cbox.stateChanged.connect(lambda state, text=subitem.text(0): self.
                                      handle_checked(state, text))
            self.tree.setItemWidget(subitem, 0, cbox)

        # self.tree.setColumnWidth(0, 25)

        self.tracelist = QLabel()
        self.disp_output()

        self.traceview = QScrollArea()
        self.traceview.setWidget(self.tracelist)
        self.traceview.setWidgetResizable(True)

        search = QHBoxLayout()

        self.search_bar = QLineEdit(self)

        self.completer = QCompleter(self.top, self)
        self.completer.setCaseSensitivity(Qt.CaseInsensitive)

        self.search_bar.setCompleter(self.completer)

        search_button = QPushButton('Search')
        search_button.clicked.connect(lambda: self.tree.setCurrentItem(
            self.lst[self.top.index(self.search_bar.text())]))

        expand = QPushButton('▼')
        expand.setFixedSize(QSize(25, 25))
        expand.clicked.connect(lambda: self.tree.expandAll())

        collapse = QPushButton('▲')
        collapse.setFixedSize(QSize(25, 25))
        collapse.clicked.connect(lambda: self.tree.collapseAll())

        self.search_bar.returnPressed.connect(lambda: search_button.click())

        search.addWidget(self.search_bar)
        search.addWidget(search_button)
        search.addWidget(expand)
        search.addWidget(collapse)

        self.digest = QLabel()

        vgrid.addLayout(search)
        vgrid.addWidget(self.tree)

        vgridwid = QWidget()
        vgridwid.setLayout(vgrid)

        split = QSplitter(Qt.Horizontal)

        split.addWidget(vgridwid)
        split.addWidget(self.traceview)

        split.setStretchFactor(1, 1)

        # grid.addLayout(vgrid)
        grid.addWidget(split)
        # grid.addWidget(self.tracelist)

        self.disp_output()

        center = QWidget()
        center.setLayout(grid)
        self.setCentralWidget(center)
        self.show()
Exemple #18
0
class TableWidget(QWidget):
    def __init__(self, db, name, select, update_ui):
        super().__init__()
        self.db = db
        self.setWindowTitle(name)
        self.dirty = False
        self.make_widgets(select)
        self.make_layout()
        self.make_connections(update_ui)

    def make_widgets(self, select):
        self.sqlEdit = SQLEdit.SQLEdit(select)
        self.sqlEdit.setTabChangesFocus(True)
        self.tableModel = TableModel.TableModel(self.db,
                                                Sql.uncommented(select))
        self.tableView = QTableView()
        self.tableView.setModel(self.tableModel)
        self.statusLabel = QLabel()
        self.statusLabel.setTextFormat(Qt.RichText)
        self.update_status(select)

    def make_layout(self):
        self.splitter = QSplitter(Qt.Vertical)
        self.splitter.addWidget(self.sqlEdit)
        self.splitter.addWidget(self.tableView)
        self.splitter.setStretchFactor(1, 11)
        vbox = QVBoxLayout()
        vbox.addWidget(self.splitter)
        vbox.addWidget(self.statusLabel)
        self.setLayout(vbox)

    def make_connections(self, update_ui):
        self.sqlEdit.textChanged.connect(update_ui)
        self.sqlEdit.copyAvailable.connect(update_ui)
        self.tableModel.sql_error.connect(self.on_sql_error)

    @property
    def sizes(self):
        return self.splitter.sizes()

    @property
    def is_select(self):
        return Sql.is_select(self.sql)

    @property
    def sql(self):
        return self.sqlEdit.toPlainText()

    def refresh(self):
        if not self.is_select:
            self.statusLabel.setText('<font color=red>Only SELECT '
                                     'statements are supported here</font>')
        else:
            select = Sql.uncommented(self.sqlEdit.toPlainText())
            if re.match(r'\s*SELECT(:?\s+(:?ALL|DISTINCT))?\s+\*', select,
                        re.IGNORECASE | re.DOTALL):
                try:
                    names = ', '.join([
                        Sql.quoted(name)
                        for name in self.db.field_names_for_select(select)
                    ])
                    select = select.replace('*', names, 1)
                except apsw.SQLError as err:
                    self.on_sql_error(str(err))
                    return
            self.tableModel.refresh(select)
            self.update_status(select)

    def on_sql_error(self, err):
        self.statusLabel.setText(f'<font color=red>{err}</font>')

    def update_status(self, select):
        try:
            count = self.db.select_row_count(select)
            s = 's' if count != 1 else ''
            self.statusLabel.setText(f'{count:,} row{s}')
        except (apsw.SQLError, Sql.Error) as err:
            self.on_sql_error(str(err))

    def closeEvent(self, event):
        self.save(closing=True)
        event.accept()

    def save(self, *, closing=False):
        print(f'TableWidget.save dirty={self.dirty} closing={closing}')
        saved = False
        errors = False
        if self.dirty and bool(self.db):
            # TODO save change to list view or form view
            errors = []  # self.db.save_...
            if errors:
                if not closing:
                    error = '\n'.join(errors)
                    QMessageBox.warning(self, f'Save error — {APPNAME}',
                                        f'Failed to save:\n{error}')
            else:
                saved = True
                self.dirty = False
        return saved
Exemple #19
0
class MainWidget(QWidget):
    def __init__(self, parent: QWidget, model: Model) -> None:
        super().__init__(parent)

        logger.add(self.log)

        self.mainlayout = QVBoxLayout()
        self.setLayout(self.mainlayout)

        self.splitter = QSplitter(Qt.Vertical)

        self.stack = QStackedWidget()
        self.splitter.addWidget(self.stack)

        # mod list widget

        self.modlistwidget = QWidget()
        self.modlistlayout = QVBoxLayout()
        self.modlistlayout.setContentsMargins(0, 0, 0, 0)
        self.modlistwidget.setLayout(self.modlistlayout)
        self.stack.addWidget(self.modlistwidget)

        # search bar

        self.searchbar = QLineEdit()
        self.searchbar.setPlaceholderText('Search...')
        self.modlistlayout.addWidget(self.searchbar)

        # mod list

        self.modlist = ModList(self, model)
        self.modlistlayout.addWidget(self.modlist)

        self.searchbar.textChanged.connect(lambda e: self.modlist.setFilter(e))

        # welcome message

        welcomelayout = QVBoxLayout()
        welcomelayout.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
        welcomewidget = QWidget()
        welcomewidget.setLayout(welcomelayout)
        welcomewidget.dragEnterEvent = self.modlist.dragEnterEvent  # type: ignore
        welcomewidget.dragMoveEvent = self.modlist.dragMoveEvent  # type: ignore
        welcomewidget.dragLeaveEvent = self.modlist.dragLeaveEvent  # type: ignore
        welcomewidget.dropEvent = self.modlist.dropEvent  # type: ignore
        welcomewidget.setAcceptDrops(True)

        icon = QIcon(str(getRuntimePath('resources/icons/open-folder.ico')))
        iconpixmap = icon.pixmap(32, 32)
        icon = QLabel()
        icon.setPixmap(iconpixmap)
        icon.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
        icon.setContentsMargins(4, 4, 4, 4)
        welcomelayout.addWidget(icon)

        welcome = QLabel('''<p><font>
            No mod installed yet.
            Drag a mod into this area to get started!
            </font></p>''')
        welcome.setAttribute(Qt.WA_TransparentForMouseEvents)
        welcome.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
        welcomelayout.addWidget(welcome)

        self.stack.addWidget(welcomewidget)

        # output log

        self.output = QTextEdit(self)
        self.output.setTextInteractionFlags(Qt.NoTextInteraction)
        self.output.setReadOnly(True)
        self.output.setContextMenuPolicy(Qt.NoContextMenu)
        self.output.setPlaceholderText('Program output...')
        self.splitter.addWidget(self.output)

        # TODO: enhancement: add a launch game icon
        # TODO: enhancement: show indicator if scripts have to be merged

        self.splitter.setStretchFactor(0, 1)
        self.splitter.setStretchFactor(1, 0)
        self.mainlayout.addWidget(self.splitter)

        if len(model):
            self.stack.setCurrentIndex(0)
            self.splitter.setSizes([self.splitter.size().height(), 50])
        else:
            self.stack.setCurrentIndex(1)
            self.splitter.setSizes([self.splitter.size().height(), 0])
        model.updateCallbacks.append(self.modelUpdateEvent)

    def keyPressEvent(self, event: QKeyEvent) -> None:
        if event.key() == Qt.Key_Escape:
            self.modlist.setFocus()
            self.searchbar.setText('')
        elif event.matches(QKeySequence.Find):
            self.searchbar.setFocus()
        elif event.matches(QKeySequence.Paste):
            self.pasteEvent()
        super().keyPressEvent(event)

    def pasteEvent(self) -> None:
        clipboard = QApplication.clipboard().text().splitlines()
        if len(clipboard) == 1 and isValidNexusModsUrl(clipboard[0]):
            self.parentWidget().showDownloadModDialog()
        else:
            urls = [
                url for url in QApplication.clipboard().text().splitlines()
                if len(str(url.strip()))
            ]
            if all(
                    isValidModDownloadUrl(url) or isValidFileUrl(url)
                    for url in urls):
                asyncio.create_task(self.modlist.checkInstallFromURLs(urls))

    def modelUpdateEvent(self, model: Model) -> None:
        if len(model) > 0:
            if self.stack.currentIndex() != 0:
                self.stack.setCurrentIndex(0)
                self.repaint()
        else:
            if self.stack.currentIndex() != 1:
                self.stack.setCurrentIndex(1)
                self.repaint()

    def unhideOutput(self) -> None:
        if self.splitter.sizes()[1] < 10:
            self.splitter.setSizes([self.splitter.size().height(), 50])

    def unhideModList(self) -> None:
        if self.splitter.sizes()[0] < 10:
            self.splitter.setSizes([50, self.splitter.size().height()])

    def log(self, message: Any) -> None:
        # format log messages to user readable output
        settings = QSettings()

        record = message.record
        message = record['message']
        extra = record['extra']
        level = record['level'].name.lower()

        name = str(extra['name']
                   ) if 'name' in extra and extra['name'] is not None else ''
        path = str(extra['path']
                   ) if 'path' in extra and extra['path'] is not None else ''
        dots = bool(
            extra['dots']
        ) if 'dots' in extra and extra['dots'] is not None else False
        newline = bool(
            extra['newline']
        ) if 'newline' in extra and extra['newline'] is not None else False
        output = bool(
            extra['output']
        ) if 'output' in extra and extra['output'] is not None else bool(
            message)
        modlist = bool(
            extra['modlist']
        ) if 'modlist' in extra and extra['modlist'] is not None else False

        if level in ['debug'
                     ] and settings.value('debugOutput', 'False') != 'True':
            if newline:
                self.output.append(f'')
            return

        n = '<br>' if newline else ''
        d = '...' if dots else ''
        if len(name) and len(path):
            path = f' ({path})'

        if output:
            message = html.escape(message, quote=True)

            if level in ['success', 'error', 'warning']:
                message = f'<strong>{message}</strong>'
            if level in ['success']:
                message = f'<font color="#04c45e">{message}</font>'
            if level in ['error', 'critical']:
                message = f'<font color="#ee3b3b">{message}</font>'
            if level in ['warning']:
                message = f'<font color="#ff6500">{message}</font>'
            if level in ['debug', 'trace']:
                message = f'<font color="#aaa">{message}</font>'
                path = f'<font color="#aaa">{path}</font>' if path else ''
                d = f'<font color="#aaa">{d}</font>' if d else ''

            time = record['time'].astimezone(
                tz=None).strftime('%Y-%m-%d %H:%M:%S')
            message = f'<font color="#aaa">{time}</font> {message}'
            self.output.append(
                f'{n}{message.strip()}{" " if name or path else ""}{name}{path}{d}'
            )
        else:
            self.output.append(f'')

        self.output.verticalScrollBar().setValue(
            self.output.verticalScrollBar().maximum())
        self.output.repaint()

        if modlist:
            self.unhideModList()
        if settings.value('unhideOutput', 'True') == 'True' and output:
            self.unhideOutput()
class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.resize(1280, 720)
        self.central_widget = QWidget(MainWindow)

        self.splitter = QSplitter(self.central_widget)
        self.splitter.setChildrenCollapsible(False)
        self.splitter.setOpaqueResize(True)

        self.main_grid_layout = QGridLayout(self.central_widget)
        self.main_grid_layout.addWidget(self.splitter)
        self.main_grid_layout.setSizeConstraint(QLayout.SetDefaultConstraint)

        self.tab_widget = QTabWidget(self.central_widget)
        self.tab_widget.setMinimumSize(QSize(500, 0))
        self._set_up_component_tree_view()
        self._set_up_silx_view()
        self.splitter.addWidget(self.tab_widget)

        self._set_up_3d_view()

        MainWindow.setCentralWidget(self.central_widget)

        self._set_up_menus(MainWindow)
        self.tab_widget.setCurrentIndex(0)
        QMetaObject.connectSlotsByName(MainWindow)
        self.splitter.setStretchFactor(0, 0)
        self.splitter.setStretchFactor(1, 1)

    def _set_up_3d_view(self):
        self.sceneWidget = InstrumentView(self.splitter)
        self.sceneWidget.setMinimumSize(QSize(600, 0))
        self.splitter.addWidget(self.sceneWidget)

    def _set_up_silx_view(self):
        self.silx_tab = QWidget()
        self.silx_tab_layout = QGridLayout(self.silx_tab)
        self.tab_widget.addTab(self.silx_tab, "")

    def _set_up_component_tree_view(self):
        self.component_tree_view_tab = ComponentTreeViewTab(parent=self)
        self.tab_widget.addTab(self.component_tree_view_tab, "")

    def _set_up_menus(self, MainWindow):
        self.menu_bar = QMenuBar()
        self.menu_bar.setGeometry(QRect(0, 0, 1280, 720))
        self.file_menu = QMenu(self.menu_bar)
        MainWindow.setMenuBar(self.menu_bar)
        self.status_bar = QStatusBar(MainWindow)
        MainWindow.setStatusBar(self.status_bar)
        self.open_nexus_file_action = QAction(MainWindow)
        self.open_json_file_action = QAction(MainWindow)
        self.open_idf_file_action = QAction(MainWindow)
        self.export_to_nexus_file_action = QAction(MainWindow)
        self.export_to_filewriter_JSON_action = QAction(MainWindow)
        self.export_to_forwarder_JSON_action = QAction(MainWindow)
        self.file_menu.addAction(self.open_nexus_file_action)
        self.file_menu.addAction(self.open_json_file_action)
        self.file_menu.addAction(self.open_idf_file_action)
        self.file_menu.addAction(self.export_to_nexus_file_action)
        self.file_menu.addAction(self.export_to_filewriter_JSON_action)
        self.file_menu.addAction(self.export_to_forwarder_JSON_action)
        self.menu_bar.addAction(self.file_menu.menuAction())
        self._set_up_titles(MainWindow)

    def _set_up_titles(self, MainWindow):
        MainWindow.setWindowTitle("NeXus Constructor")
        self.tab_widget.setTabText(
            self.tab_widget.indexOf(self.component_tree_view_tab), "Components"
        )
        self.tab_widget.setTabText(
            self.tab_widget.indexOf(self.silx_tab), "NeXus File Layout"
        )
        self.file_menu.setTitle("File")
        self.open_nexus_file_action.setText("Open NeXus file")
        self.open_json_file_action.setText("Open Filewriter JSON file")

        self.open_idf_file_action.setText("Open Mantid IDF file")
        self.export_to_nexus_file_action.setText("Export to NeXus file")
        self.export_to_filewriter_JSON_action.setText("Export to Filewriter JSON")
        self.export_to_forwarder_JSON_action.setText("Export to Forwarder JSON")