def add_vertical_splitter(self, layout): splitter = QSplitter() layout.addWidget(splitter) # ADD LEFT left_widget = QWidget(splitter) left = QVBoxLayout(left_widget) # NORMAL let = QLineEdit('Line Edit With Text') left.layout().addWidget(let) #PLACEHOLDER let = QLineEdit() let.setPlaceholderText('This is placeholder text...') left.layout().addWidget(let) # DISABLED let = QLineEdit('Line Edit Disabled') let.setEnabled(False) left.layout().addWidget(let) # ADD RIGHT right_widget = QWidget(splitter) right = QGridLayout(right_widget) # GROUP BOX grp = QGroupBox("Group Box") right.layout().addWidget(grp) grp_layout = QGridLayout(grp) btn = QPushButton('Set Style') btn.pressed.connect(self.set_style) grp_layout.addWidget(btn)
def SaveZeroPoint(offset: float, zeroPointManager: ZeroPointManager): dialog = QDialog() dialog.setWindowTitle("Save Zero Position") zeroPositionNameLineEdit = QLineEdit("Default Name: ") zeroPositionOffsetLineEdit = QLineEdit(str(offset)) zeroPositionOffsetLineEdit.setEnabled(False) buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) def createNewZeroPoint(): zeroPointManager.createZeroPoint( zeroPositionNameLineEdit.text(), float(zeroPositionOffsetLineEdit.text())) dialog.close() buttonBox.accepted.connect(createNewZeroPoint) buttonBox.rejected.connect(dialog.reject) layout = QFormLayout() layout.addRow(QLabel("Name: "), zeroPositionNameLineEdit) layout.addRow(QLabel("Offset: "), zeroPositionOffsetLineEdit) layout.addRow(buttonBox) dialog.setLayout(layout) return dialog
class NodesList_NodeWidget(QWidget): mouse_pressed = Signal() del_node_triggered = Signal() def __init__(self, node): super(NodesList_NodeWidget, self).__init__() self.node = node # UI layout = QHBoxLayout() self.name_line_edit = QLineEdit(node.title) self.name_line_edit.setEnabled(False) layout.addWidget(self.name_line_edit) self.setLayout(layout) def set_name(self, name): self.name_line_edit.setText(name) def set_selected(self, selected): if selected: self.name_line_edit.setStyleSheet( 'background: rgba(84, 169, 222, 200);') else: self.name_line_edit.setStyleSheet('') def mousePressEvent(self, event): if event.button() == Qt.LeftButton: self.mouse_pressed.emit() return def event(self, event): if event.type() == QEvent.ToolTip: self.setToolTip(self.node.content_widget.get_node_description()) return QWidget.event(self, event) def contextMenuEvent(self, event): menu: QMenu = QMenu(self) delete_action = QAction('delete') delete_action.triggered.connect(self.action_delete_triggered) actions = [delete_action] for a in actions: menu.addAction(a) menu.exec_(event.globalPos()) def action_delete_triggered(self): self.del_node_triggered.emit()
class SearchBar(QWidget): QueryLaunched = Signal(str) StopPressed = Signal() def __init__(self, parent=None): super().__init__(parent) self._query_edit = QLineEdit() self._query_edit.setClearButtonEnabled(True) self._query_edit.setPlaceholderText("Type you query here") self._query_edit.returnPressed.connect(self._HandleReturnPressed) self._query_edit.addAction(QIcon(icons.SEARCH), QLineEdit.LeadingPosition) self._kill_button = QToolButton() self._kill_button.setIcon(QIcon(icons.STOP)) self._kill_button.setAutoRaise(True) self._kill_button.setMinimumSize(31, 31) self._kill_button.setEnabled(False) self._kill_button.clicked.connect(self.StopPressed) layout = QHBoxLayout() layout.addWidget(self._kill_button) layout.addWidget(self._query_edit) layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) self.setFocusProxy(self._query_edit) def Clear(self): self._query_edit.clear() def SetStopEnabled(self, bool_): self._kill_button.setEnabled(bool_) def SetQueryEditEnabled(self, bool_): self._query_edit.setEnabled(bool_) def SetQuery(self, query): self._query_edit.setText(query) def LaunchQuery(self, query): self._query_edit.setText(query) self._HandleReturnPressed() def _HandleReturnPressed(self): query = " ".join(self._query_edit.text().split()) if query == "": return self.QueryLaunched.emit(query)
class PlotControls(QWidget): erasePlot = Signal(bool) def __init__(self): super().__init__() types_of_axes = ['Cartesiano', 'Logarítmico'] types_of_traces = ['Scatter', "Boxplot"] self.modify_title = QLineEdit() self.modify_x_axis_type = Dropdown(types_of_axes) self.modify_y_axis_type = Dropdown(types_of_axes) self.modify_x_axis_label = QLineEdit() self.modify_y_axis_label = QLineEdit() self.modify_lower_x_range = QLineEdit() self.modify_upper_x_range = QLineEdit() self.modify_lower_y_range = QLineEdit() self.modify_upper_y_range = QLineEdit() self.type_of_trace = Dropdown(types_of_traces) self.add_x_trace = QLineEdit() self.add_y_trace = QLineEdit() self.trace_name = QLineEdit() self.run_button = QPushButton('Confirmar alterações') self.erase_button = QPushButton('Apagar gráfico') self.erase_button.clicked.connect(lambda: self.erasePlot.emit(True)) self.type_of_trace.currentIndexChanged.connect(self.typeChanged) self.buildLayout() self.setStyleSheet('color:white; font-family: Bahnschrift SemiLight Condensed; font-size: 14px;') self.modify_title.setStyleSheet('background-color: white; color: black') self.modify_x_axis_type.setStyleSheet('background-color: white; color: black') self.modify_y_axis_type.setStyleSheet('background-color: white; color: black') self.modify_x_axis_label.setStyleSheet('background-color: white; color: black') self.modify_y_axis_label.setStyleSheet('background-color: white; color: black') self.modify_lower_x_range.setStyleSheet('background-color: white; color: black') self.modify_upper_x_range.setStyleSheet('background-color: white; color: black') self.modify_lower_y_range.setStyleSheet('background-color: white; color: black') self.modify_upper_y_range.setStyleSheet('background-color: white; color: black') self.type_of_trace.setStyleSheet('background-color: white; color: black') self.add_x_trace.setStyleSheet('background-color: white; color: black') self.add_y_trace.setStyleSheet('background-color: white; color: black') self.trace_name.setStyleSheet('background-color: white; color: black') self.run_button.setStyleSheet('background-color: white; color: black') self.erase_button.setStyleSheet('background-color: white; color: black') def buildLayout(self): layout = QFormLayout() layout.addRow('Título', self.modify_title) layout.addRow('Escala do eixo X', self.modify_x_axis_type) layout.addRow('Escala do eixo Y', self.modify_y_axis_type) layout.addRow('Rótulo do eixo X', self.modify_x_axis_label) layout.addRow('Rótulo do eixo Y', self.modify_y_axis_label) layout.addRow('Limite inferior do eixo X', self.modify_lower_x_range) layout.addRow('Limite superior do eixo X', self.modify_upper_x_range) layout.addRow('Limite inferior do eixo Y', self.modify_lower_y_range) layout.addRow('Limite superior do eixo Y', self.modify_upper_y_range) layout.addRow('Tipo de série', self.type_of_trace) layout.addRow('Adicionar série/box no gráfico (eixo x)', self.add_x_trace) layout.addRow('Adicionar série/box no gráfico (eixo y)', self.add_y_trace) layout.addRow('Nome da série', self.trace_name) layout.addWidget(self.run_button) layout.addWidget(self.erase_button) self.setLayout(layout) def fillFromJson(self, _json): # json is the standard json export from the plotly library assert (isinstance(_json, str)) j_obj = j.loads(_json) try: if 'title' in list(j_obj['layout'].keys()): self.modify_title.setText(str(j_obj['layout']['title']['text'])) if 'type' in list(j_obj['layout']['xaxis'].keys()): if j_obj['layout']['xaxis']['type'].lower() == 'log': self.modify_x_axis_type.setCurrentIndex(1) else: self.modify_y_axis_type.setCurrentIndex(0) if 'type' in list(j_obj['layout']['yaxis'].keys()): if j_obj['layout']['yaxis']['type'].lower() == 'log': self.modify_y_axis_type.setCurrentIndex(1) else: self.modify_y_axis_type.setCurrentIndex(0) if 'title' in list(j_obj['layout']['xaxis'].keys()): self.modify_x_axis_label.setText(str(j_obj['layout']['xaxis']['title']['text'])) if 'title' in list(j_obj['layout']['yaxis'].keys()): self.modify_y_axis_label.setText(str(j_obj['layout']['yaxis']['title']['text'])) if 'range' in list(j_obj['layout']['xaxis'].keys()): self.modify_lower_x_range.setText(str(j_obj['layout']['xaxis']['range'][0])) self.modify_upper_x_range.setText(str(j_obj['layout']['xaxis']['range'][1])) if 'range' in list(j_obj['layout']['yaxis'].keys()): self.modify_lower_y_range.setText(str(j_obj['layout']['yaxis']['range'][0])) self.modify_upper_y_range.setText(str(j_obj['layout']['yaxis']['range'][1])) except KeyError: if 'title' in list(j_obj['layout']['template']['layout'].keys()): self.modify_title.setText(str(j_obj['layout']['template']['layout']['title']['text'])) if 'type' in list(j_obj['layout']['template']['layout']['xaxis'].keys()): if j_obj['layout']['template']['layout']['xaxis']['type'].lower() == 'log': self.modify_x_axis_type.setCurrentIndex(1) else: self.modify_y_axis_type.setCurrentIndex(0) if 'type' in list(j_obj['layout']['template']['layout']['yaxis'].keys()): if j_obj['layout']['template']['layout']['yaxis']['type'].lower() == 'log': self.modify_y_axis_type.setCurrentIndex(1) else: self.modify_y_axis_type.setCurrentIndex(0) if 'title' in list(j_obj['layout']['template']['layout']['xaxis'].keys()): self.modify_x_axis_label.setText(str(j_obj['layout']['template']['layout']['xaxis']['title']['text'])) if 'title' in list(j_obj['layout']['template']['layout']['yaxis'].keys()): self.modify_y_axis_label.setText(str(j_obj['layout']['template']['layout']['yaxis']['title']['text'])) if 'range' in list(j_obj['layout']['template']['layout']['xaxis'].keys()): self.modify_lower_x_range.setText(str(j_obj['layout']['template']['layout']['xaxis']['range'][0])) self.modify_upper_x_range.setText(str(j_obj['layout']['template']['layout']['xaxis']['range'][1])) if 'range' in list(j_obj['layout']['template']['layout']['yaxis'].keys()): self.modify_lower_y_range.setText(str(j_obj['layout']['template']['layout']['yaxis']['range'][0])) self.modify_upper_y_range.setText(str(j_obj['layout']['template']['layout']['yaxis']['range'][1])) return def typeChanged(self, ind): currentType = self.type_of_trace.currentText() if currentType == "Boxplot": self.add_y_trace.setDisabled(True) self.add_y_trace.setStyleSheet('background-color: grey; color: black') else: self.add_y_trace.setEnabled(True) self.add_y_trace.setStyleSheet('background-color: white; color: black')
class Snippets(QDialog): def __init__(self, parent=None): super(Snippets, self).__init__(parent) # Create widgets self.setWindowModality(Qt.ApplicationModal) self.title = QLabel(self.tr("Snippet Editor")) self.saveButton = QPushButton(self.tr("Save")) self.closeButton = QPushButton(self.tr("Close")) self.clearHotkeyButton = QPushButton(self.tr("Clear Hotkey")) self.setWindowTitle(self.title.text()) self.newFolderButton = QPushButton("New Folder") self.deleteSnippetButton = QPushButton("Delete") self.newSnippetButton = QPushButton("New Snippet") self.edit = QPlainTextEdit() self.edit.setPlaceholderText("python code") self.resetting = False self.columns = 3 self.keySequenceEdit = QKeySequenceEdit(self) self.currentHotkey = QKeySequence() self.currentHotkeyLabel = QLabel("") self.currentFileLabel = QLabel() self.currentFile = "" self.snippetDescription = QLineEdit() self.snippetDescription.setPlaceholderText("optional description") #Set Editbox Size font = getMonospaceFont(self) self.edit.setFont(font) font = QFontMetrics(font) self.edit.setTabStopWidth(4 * font.width(' ')); #TODO, replace with settings API #Files self.files = QFileSystemModel() self.files.setRootPath(snippetPath) self.files.setNameFilters(["*.py"]) #Tree self.tree = QTreeView() self.tree.setModel(self.files) self.tree.setSortingEnabled(True) self.tree.hideColumn(2) self.tree.sortByColumn(0, Qt.AscendingOrder) self.tree.setRootIndex(self.files.index(snippetPath)) for x in range(self.columns): #self.tree.resizeColumnToContents(x) self.tree.header().setSectionResizeMode(x, QHeaderView.ResizeToContents) treeLayout = QVBoxLayout() treeLayout.addWidget(self.tree) treeButtons = QHBoxLayout() treeButtons.addWidget(self.newFolderButton) treeButtons.addWidget(self.newSnippetButton) treeButtons.addWidget(self.deleteSnippetButton) treeLayout.addLayout(treeButtons) treeWidget = QWidget() treeWidget.setLayout(treeLayout) # Create layout and add widgets buttons = QHBoxLayout() buttons.addWidget(self.clearHotkeyButton) buttons.addWidget(self.keySequenceEdit) buttons.addWidget(self.currentHotkeyLabel) buttons.addWidget(self.closeButton) buttons.addWidget(self.saveButton) description = QHBoxLayout() description.addWidget(QLabel(self.tr("Description: "))) description.addWidget(self.snippetDescription) vlayoutWidget = QWidget() vlayout = QVBoxLayout() vlayout.addLayout(description) vlayout.addWidget(self.edit) vlayout.addLayout(buttons) vlayoutWidget.setLayout(vlayout) hsplitter = QSplitter() hsplitter.addWidget(treeWidget) hsplitter.addWidget(vlayoutWidget) hlayout = QHBoxLayout() hlayout.addWidget(hsplitter) self.showNormal() #Fixes bug that maximized windows are "stuck" self.settings = QSettings("Vector35", "Snippet Editor") if self.settings.contains("ui/snippeteditor/geometry"): self.restoreGeometry(self.settings.value("ui/snippeteditor/geometry")) else: self.edit.setMinimumWidth(80 * font.averageCharWidth()) self.edit.setMinimumHeight(30 * font.lineSpacing()) # Set dialog layout self.setLayout(hlayout) # Add signals self.saveButton.clicked.connect(self.save) self.closeButton.clicked.connect(self.close) self.clearHotkeyButton.clicked.connect(self.clearHotkey) self.tree.selectionModel().selectionChanged.connect(self.selectFile) self.newSnippetButton.clicked.connect(self.newFileDialog) self.deleteSnippetButton.clicked.connect(self.deleteSnippet) self.newFolderButton.clicked.connect(self.newFolder) if self.settings.contains("ui/snippeteditor/selected"): selectedName = self.settings.value("ui/snippeteditor/selected") self.tree.selectionModel().select(self.files.index(selectedName), QItemSelectionModel.ClearAndSelect | QItemSelectionModel.Rows) if self.tree.selectionModel().hasSelection(): self.selectFile(self.tree.selectionModel().selection(), None) self.edit.setFocus() cursor = self.edit.textCursor() cursor.setPosition(self.edit.document().characterCount()-1) self.edit.setTextCursor(cursor) else: self.readOnly(True) else: self.readOnly(True) @staticmethod def registerAllSnippets(): for action in list(filter(lambda x: x.startswith("Snippets\\"), UIAction.getAllRegisteredActions())): if action == "Snippets\\Snippet Editor...": continue UIActionHandler.globalActions().unbindAction(action) Menu.mainMenu("Tools").removeAction(action) UIAction.unregisterAction(action) for snippet in includeWalk(snippetPath, ".py"): snippetKeys = None (snippetDescription, snippetKeys, snippetCode) = loadSnippetFromFile(snippet) if not snippetDescription: actionText = "Snippets\\" + os.path.basename(snippet).rstrip(".py") else: actionText = "Snippets\\" + snippetDescription if snippetCode: if snippetKeys == None: UIAction.registerAction(actionText) else: UIAction.registerAction(actionText, snippetKeys) UIActionHandler.globalActions().bindAction(actionText, UIAction(makeSnippetFunction(snippetCode))) Menu.mainMenu("Tools").addAction(actionText, actionText) def clearSelection(self): self.keySequenceEdit.clear() self.currentHotkey = QKeySequence() self.currentHotkeyLabel.setText("") self.currentFileLabel.setText("") self.snippetDescription.setText("") self.edit.setPlainText("") self.currentFile = "" def reject(self): self.settings.setValue("ui/snippeteditor/geometry", self.saveGeometry()) if self.snippetChanged(): question = QMessageBox.question(self, self.tr("Discard"), self.tr("You have unsaved changes, quit anyway?")) if question != QMessageBox.StandardButton.Yes: return self.accept() def newFolder(self): (folderName, ok) = QInputDialog.getText(self, self.tr("Folder Name"), self.tr("Folder Name: ")) if ok and folderName: index = self.tree.selectionModel().currentIndex() selection = self.files.filePath(index) if QFileInfo(selection).isDir(): QDir(selection).mkdir(folderName) else: QDir(snippetPath).mkdir(folderName) def selectFile(self, new, old): if (self.resetting): self.resetting = False return newSelection = self.files.filePath(new.indexes()[0]) self.settings.setValue("ui/snippeteditor/selected", newSelection) if QFileInfo(newSelection).isDir(): self.readOnly(True) self.tree.clearSelection() self.currentFile = "" return if old and old.length() > 0: oldSelection = self.files.filePath(old.indexes()[0]) if not QFileInfo(oldSelection).isDir() and self.snippetChanged(): question = QMessageBox.question(self, self.tr("Discard"), self.tr("Snippet changed. Discard changes?")) if question != QMessageBox.StandardButton.Yes: self.resetting = True self.tree.selectionModel().select(old, QItemSelectionModel.ClearAndSelect | QItemSelectionModel.Rows) return False self.currentFile = newSelection self.loadSnippet() def loadSnippet(self): self.currentFileLabel.setText(QFileInfo(self.currentFile).baseName()) (snippetDescription, snippetKeys, snippetCode) = loadSnippetFromFile(self.currentFile) self.snippetDescription.setText(snippetDescription) if snippetDescription else self.snippetDescription.setText("") self.keySequenceEdit.setKeySequence(snippetKeys) if snippetKeys else self.keySequenceEdit.setKeySequence(QKeySequence("")) self.edit.setPlainText(snippetCode) if snippetCode else self.edit.setPlainText("") self.readOnly(False) def newFileDialog(self): (snippetName, ok) = QInputDialog.getText(self, self.tr("Snippet Name"), self.tr("Snippet Name: ")) if ok and snippetName: if not snippetName.endswith(".py"): snippetName += ".py" index = self.tree.selectionModel().currentIndex() selection = self.files.filePath(index) if QFileInfo(selection).isDir(): path = os.path.join(selection, snippetName) else: path = os.path.join(snippetPath, snippetName) self.readOnly(False) open(path, "w").close() self.tree.setCurrentIndex(self.files.index(path)) log_debug("Snippet %s created." % snippetName) def readOnly(self, flag): self.keySequenceEdit.setEnabled(not flag) self.snippetDescription.setReadOnly(flag) self.edit.setReadOnly(flag) if flag: self.snippetDescription.setDisabled(True) self.edit.setDisabled(True) else: self.snippetDescription.setEnabled(True) self.edit.setEnabled(True) def deleteSnippet(self): selection = self.tree.selectedIndexes()[::self.columns][0] #treeview returns each selected element in the row snippetName = self.files.fileName(selection) question = QMessageBox.question(self, self.tr("Confirm"), self.tr("Confirm deletion: ") + snippetName) if (question == QMessageBox.StandardButton.Yes): log_debug("Deleting snippet %s." % snippetName) self.clearSelection() self.files.remove(selection) self.registerAllSnippets() def snippetChanged(self): if (self.currentFile == "" or QFileInfo(self.currentFile).isDir()): return False (snippetDescription, snippetKeys, snippetCode) = loadSnippetFromFile(self.currentFile) if snippetKeys == None and not self.keySequenceEdit.keySequence().isEmpty(): return True if snippetKeys != None and snippetKeys != self.keySequenceEdit.keySequence().toString(): return True return self.edit.toPlainText() != snippetCode or \ self.snippetDescription.text() != snippetDescription def save(self): log_debug("Saving snippet %s" % self.currentFile) outputSnippet = open(self.currentFile, "w") outputSnippet.write("#" + self.snippetDescription.text() + "\n") outputSnippet.write("#" + self.keySequenceEdit.keySequence().toString() + "\n") outputSnippet.write(self.edit.toPlainText()) outputSnippet.close() self.registerAllSnippets() def clearHotkey(self): self.keySequenceEdit.clear()
class Separate(QDialog): videoPath = '' duration = 60000 processToken = False voiceList = Signal(list) avgList = Signal(list) clrSep = Signal() tablePreset = Signal(list) autoFillToken = True autoSpanToken = True multipleThread = True def __init__(self): super().__init__() self.resize(800, 150) self.setWindowTitle('AI智能打轴 (测试版)') layout = QGridLayout() self.setLayout(layout) layout.addWidget(QLabel('前侧留白(ms)'), 0, 0, 1, 1) self.beforeEdit = QLineEdit('20') validator = QIntValidator() validator.setRange(0, 5000) self.beforeEdit.setValidator(validator) self.beforeEdit.setFixedWidth(50) layout.addWidget(self.beforeEdit, 0, 1, 1, 1) layout.addWidget(QLabel(''), 0, 2, 1, 1) layout.addWidget(QLabel('后侧留白(ms)'), 0, 3, 1, 1) self.afterEdit = QLineEdit('300') self.afterEdit.setValidator(validator) self.afterEdit.setFixedWidth(50) layout.addWidget(self.afterEdit, 0, 4, 1, 1) layout.addWidget(QLabel(''), 0, 5, 1, 1) self.autoFill = QPushButton('填充字符') self.autoFill.setStyleSheet('background-color:#3daee9') self.autoFill.clicked.connect(self.setAutoFill) layout.addWidget(self.autoFill, 0, 6, 1, 1) self.fillWord = QLineEdit('#AI自动识别#') layout.addWidget(self.fillWord, 0, 7, 1, 1) layout.addWidget(QLabel(''), 0, 8, 1, 1) self.autoSpan = QPushButton('自动合并') self.autoSpan.setStyleSheet('background-color:#3daee9') self.autoSpan.clicked.connect(self.setAutoSpan) layout.addWidget(self.autoSpan, 0, 9, 1, 1) self.multiCheck = QPushButton('启用多进程') self.multiCheck.setStyleSheet('background-color:#3daee9') self.multiCheck.clicked.connect(self.setMultipleThread) layout.addWidget(self.multiCheck, 0, 10, 1, 1) self.processBar = QProgressBar() layout.addWidget(self.processBar, 1, 0, 1, 10) self.checkButton = QPushButton('开始') self.checkButton.setFixedWidth(100) self.checkButton.clicked.connect(self.separateProcess) layout.addWidget(self.checkButton, 1, 10, 1, 1) def setDefault(self, videoPath, duration): self.videoPath = videoPath self.duration = duration def separateProcess(self): self.processToken = not self.processToken if self.videoPath: if self.processToken: self.processBar.setValue(0) self.checkButton.setText('初始化中') if not self.beforeEdit.text(): self.beforeEdit.setText('0') before = self.beforeEdit.text() if not self.afterEdit.text(): self.afterEdit.setText('0') after = self.afterEdit.text() if self.autoFillToken: try: fillWord = self.fillWord.text() except: fillWord = '' else: fillWord = '' self.sepProc = separateQThread(self.videoPath, self.duration, before, after, self.multipleThread) self.clrSep.emit() # 清空第一条字幕轴 self.sepProc.position.connect(self.setTitle) # 设置标题分析至第几分钟 self.sepProc.percent.connect(self.setProgressBar) # 设置滚动条进度 self.sepProc.voiceList.connect( self.sendVoiceList) # 二次传球给主界面标记表格 self.sepProc.avgList.connect( self.sendAvgList) # 平均音频响度 预留给后面画音频图 self.tablePreset.emit([fillWord, self.autoSpanToken]) # 自动填充 填充文本 自动合并 self.sepProc.finish.connect(self.sepFinished) self.sepProc.start() else: self.setWindowTitle('AI智能打轴 (测试版)') self.processBar.setValue(0) self.checkButton.setText('开始') self.checkButton.setStyleSheet('background-color:#31363b') # self.sepProc.separate._pool.terminate() # try: # p = psutil.Process(self.sepProc.p.pid) # for proc in p.children(True): # proc.kill() # except: # pass self.sepProc.terminate() self.sepProc.quit() self.sepProc.wait() def setTitle(self, pos): self.setWindowTitle('AI智能打轴 (已分析至第%s分钟)' % pos) def setProgressBar(self, percent): self.checkButton.setText('停止') self.checkButton.setStyleSheet('background-color:#3daee9') self.processBar.setValue(percent) def sendVoiceList(self, voiceList): self.voiceList.emit(voiceList) def sendAvgList(self, avgList): self.avgList.emit(avgList) def sepFinished(self, result): if result: self.processToken = not self.processToken self.setWindowTitle('AI智能打轴 (测试版)') self.processBar.setValue(100) self.checkButton.setText('开始') self.checkButton.setStyleSheet('background-color:#31363b') # self.sepProc.separate._pool.terminate() # try: # p = psutil.Process(self.sepProc.p.pid) # for proc in p.children(True): # proc.kill() # except: # pass self.sepProc.terminate() self.sepProc.quit() self.sepProc.wait() def setAutoFill(self): self.autoFillToken = not self.autoFillToken if self.autoFillToken: self.autoFill.setStyleSheet('background-color:#3daee9') self.fillWord.setEnabled(True) else: self.autoFill.setStyleSheet('background-color:#31363b') self.fillWord.setEnabled(False) def setAutoSpan(self): self.autoSpanToken = not self.autoSpanToken if self.autoSpanToken: self.autoSpan.setStyleSheet('background-color:#3daee9') else: self.autoSpan.setStyleSheet('background-color:#31363b') def setMultipleThread(self): self.multipleThread = not self.multipleThread if self.multipleThread: self.multiCheck.setStyleSheet('background-color:#3daee9') else: self.multiCheck.setStyleSheet('background-color:#31363b')
class SettingsEditionDialog(QDialog): languages = {"Français": "fr", "English": "en"} def __init__(self): QDialog.__init__(self) self.setWindowTitle(tr("btn_config")) self.setFixedSize(QSize(700, 670)) # Retrieve current settings self.settings = AssetManager.getInstance().config_to_dico( AssetManager.getInstance().get_config_parser()) self.__restart_needed = False self.__restore_required = False # Version self.lab_version = QLabel(self.settings['main']['version']) # Language self.combo_language = QComboBox() self.combo_language.addItems(list(self.languages.keys())) for lang in self.languages: # Look for the current language to select it if self.languages[lang] == self.settings['main']['language']: self.combo_language.setCurrentText(lang) break # CSV separator self.csv_sep_edit = QLineEdit() self.csv_sep_edit.setMaxLength(2) self.csv_sep_edit.setFixedWidth(25) self.csv_sep_edit.setAlignment(Qt.AlignCenter) self.csv_sep_edit.setText(self.settings['main']['csv_separator']) # BDD path self.btn_bdd_path = QPushButton(self.settings['main']['bdd_path']) self.btn_bdd_path.clicked.connect(self.choose_bdd_path) # Port self.wepapp_port = QSpinBox() self.wepapp_port.setMinimum(1024) self.wepapp_port.setMaximum(65535) self.wepapp_port.setValue(int(self.settings['webapp']['port'])) # Colors self.tile_color = ColorChooser(self.settings['colors']['tile']) self.hovered_tile_color = ColorChooser( self.settings['colors']['hovered_tile']) self.hovered_empty_tile_color = ColorChooser( self.settings['colors']['hovered_empty_tile']) self.dragged_tile_color = ColorChooser( self.settings['colors']['dragged_tile']) self.drag_selected_tile_color = ColorChooser( self.settings['colors']['drag_selected_tile']) self.selected_tile_color = ColorChooser( self.settings['colors']['selected_tile']) self.tile_text_color = ColorChooser( self.settings['colors']['tile_text']) self.room_bg_color = ColorChooser(self.settings['colors']['room_bg']) self.room_grid_color = ColorChooser( self.settings['colors']['room_grid']) self.main_bg_color = ColorChooser(self.settings['colors']['main_bg']) self.board_bg_color = ColorChooser(self.settings['colors']['board_bg']) self.attr_colors = "" # Chosen colors self.attributes_colors_chooser = AttrColorsChooser( self.settings['colors']['attr_colors'].split()) # Sizes (unmodifiable) self.unmodifiable = QLabel(tr("unmodifiable_data")) self.unmodifiable.setAlignment(Qt.AlignCenter) self.desk_size = QLineEdit(self.settings['size']['desk']) self.desk_size.setEnabled(False) self.desk_size.setFixedWidth(50) self.grid_rows = QLineEdit(self.settings['size']['default_room_rows']) self.grid_rows.setEnabled(False) self.grid_rows.setFixedWidth(50) self.grid_cols = QLineEdit( self.settings['size']['default_room_columns']) self.grid_cols.setEnabled(False) self.grid_cols.setFixedWidth(50) # --- Buttons --- # Confirm button self.ok_btn = QPushButton(tr("btn_save")) self.ok_btn.clicked.connect(self.accept) self.ok_btn.setFocus() # Cancel button self.cancel_btn = QPushButton(tr("btn_cancel")) self.cancel_btn.clicked.connect(self.reject) # Restore defaults button self.restore_btn = QPushButton(tr("btn_restore")) self.restore_btn.clicked.connect(self.__restore) self.__set_layout() def __set_layout(self) -> None: """ Sets the dialog layout """ # Main layout layout = QVBoxLayout() layout.setMargin(0) layout.addSpacing(5) # Main section main_layout = QFormLayout() main_layout.addRow(tr("app_version"), self.lab_version) main_layout.addRow(tr("language"), self.combo_language) main_layout.addRow(tr("csv_sep"), self.csv_sep_edit) main_layout.addRow(tr("bdd_path"), self.btn_bdd_path) # Web app widget_port = QWidget() layout_port = QHBoxLayout() layout_port.setMargin(0) layout_port.addWidget(self.wepapp_port) layout_port.addWidget(ShutDownToolTip()) widget_port.setLayout(layout_port) main_layout.addRow(tr("web_port"), widget_port) layout.addLayout(main_layout) Separator(self.width(), layout) # Colors colors_layout1 = QFormLayout() colors_layout1.addRow(tr("tile"), self.tile_color) colors_layout1.addRow(tr("hovered_tile"), self.hovered_tile_color) colors_layout1.addRow(tr("hovered_empty_tile"), self.hovered_empty_tile_color) colors_layout1.addRow(tr("dragged_tile"), self.dragged_tile_color) colors_layout1.addRow(tr("drag_selected_tile"), self.drag_selected_tile_color) colors_layout1.addRow(tr("selected_tile"), self.selected_tile_color) colors_layout2 = QFormLayout() colors_layout2.addRow(tr("tile_text"), self.tile_text_color) colors_layout2.addRow(tr("room_bg"), self.room_bg_color) colors_layout2.addRow(tr("room_grid"), self.room_grid_color) colors_layout2.addRow(tr("main_bg"), self.main_bg_color) colors_layout2.addRow(tr("board_bg"), self.board_bg_color) colors_layout = QHBoxLayout() colors_layout.setMargin(0) colors_layout.addLayout(colors_layout1) colors_layout.addLayout(colors_layout2) layout.addLayout(colors_layout) layout.addSpacing(15) colors_layout3 = QFormLayout() colors_layout3.setMargin(0) colors_layout3.addRow(tr("attr_colors"), self.attributes_colors_chooser) layout.addLayout(colors_layout3) Separator(self.width(), layout) # Unmodifiable data sizes_layout = QFormLayout() sizes_layout.setMargin(0) sizes_layout.addRow(tr("desk_size"), self.desk_size) sizes_layout.addRow(tr("grid_rows"), self.grid_rows) sizes_layout.addRow(tr("grid_cols"), self.grid_cols) layout.addWidget(self.unmodifiable, alignment=Qt.AlignCenter) layout.addSpacing(5) layout.addLayout(sizes_layout) Separator(self.width(), layout) # Buttons layout_buttons = QHBoxLayout() layout_buttons.addWidget(self.ok_btn) layout_buttons.addWidget(self.restore_btn) layout_buttons.addWidget(self.cancel_btn) layout.addLayout(layout_buttons) self.setLayout(layout) self.setStyleSheet(get_stylesheet("dialog2")) def __restore(self) -> None: """ Restore default parameters before closing dialog """ self.__restart_needed = True self.__restore_required = True self.accept() def __new_settings(self) -> dict: """ Retrieves the new settings to use """ settings = self.settings # Language language = self.languages[self.combo_language.currentText()] if language != settings['main']['language']: settings['main']['language'] = language self.__restart_needed = True # CSV separator settings['main']['csv_separator'] = self.csv_sep_edit.text() # BDD path if self.btn_bdd_path.text() != settings['main']['bdd_path']: if self.btn_bdd_path.text().endswith("sdc_db"): settings['main']['bdd_path'] = self.btn_bdd_path.text() else: settings['main']['bdd_path'] = "" self.__restart_needed = True # Port if str(self.wepapp_port.value()) != settings['webapp']['port']: settings['webapp']['port'] = str(self.wepapp_port.value()) # Colors settings['colors']['tile'] = self.tile_color.get_color() settings['colors']['hovered_tile'] = self.hovered_tile_color.get_color( ) settings['colors'][ 'hovered_empty_tile'] = self.hovered_empty_tile_color.get_color() settings['colors']['dragged_tile'] = self.dragged_tile_color.get_color( ) settings['colors'][ 'drag_selected_tile'] = self.drag_selected_tile_color.get_color() settings['colors'][ 'selected_tile'] = self.selected_tile_color.get_color() settings['colors']['tile_text'] = self.tile_text_color.get_color() settings['colors']['room_grid'] = self.room_grid_color.get_color() if self.room_bg_color.get_color() != settings['colors']['room_bg']: settings['colors']['room_bg'] = self.room_bg_color.get_color() self.__restart_needed = True if self.main_bg_color.get_color() != settings['colors']['main_bg']: settings['colors']['main_bg'] = self.main_bg_color.get_color() self.__restart_needed = True if self.board_bg_color.get_color() != settings['colors']['board_bg']: settings['colors']['board_bg'] = self.board_bg_color.get_color() self.__restart_needed = True settings['colors']['attr_colors'] = self.attr_colors return settings def new_config(self) -> ConfigParser: """ Retrieves the new config parser object """ conf = ConfigParser() conf.read_dict(self.__new_settings()) return conf def need_restart(self): return self.__restart_needed def restore_default(self) -> bool: return self.__restore_required def accept(self) -> None: """ Performs actions before calling parent's accept method """ self.attr_colors = self.attributes_colors_chooser.get_colors_to_str() super().accept() def choose_bdd_path(self) -> None: """ Opens a file chooser to select the bdd path. Then sets the name as button text. """ bdd_path = QFileDialog.getOpenFileName(self, tr("bdd_path"), self.btn_bdd_path.text())[0] if bdd_path: self.btn_bdd_path.setText(bdd_path)
class SearchBar(QWidget): def __init__(self): super(SearchBar, self).__init__() self.layout = QVBoxLayout() self.layout.setMargin(0) self.setStyleSheet( css('border: 1px solid {{color}};', color=colors.SECONDARY_COLOR)) self.searchbar = QLineEdit() self.searchbar.setPlaceholderText( 'Try searching for an artist or album') self.searchbar.textChanged.connect(self.set_keywords) self.searchbar.returnPressed.connect(self.search) self.searchbar.setStyleSheet( css(''' QLineEdit { padding: 10px; border-radius: 8px; background: {{backgroundColor}}; } ''', backgroundColor=colors.PLACEHOLDER_COLOR)) self.layout.addWidget(self.searchbar) self.setLayout(self.layout) def set_keywords(self, keywords): self.keywords = keywords def search(self): if self.searchbar.completer() and self.searchbar.completer().popup( ).isVisible(): # User did select an option from the dropdown menu. selected_suggestion = [ s for s in self.suggestions if s['label'] == self.keywords ] if len(selected_suggestion) > 0: self.searchbar.setCompleter(None) PageSignal.changed.emit( SongDetailPage(url=selected_suggestion[0]['url'])) else: # User did type something and then hit ENTER to search. self.thread = RunThread(self.get_search_suggestions, self.on_search_suggestions) def get_search_suggestions(self): if self.keywords: self.searchbar.setEnabled(False) logging.info( 'Getting search suggestions for keywords: "{}"'.format( self.keywords)) spider = CoreRadioSpider() self.suggestions = spider.get_search_suggestions(self.keywords) def on_search_suggestions(self): logging.info('Received search suggestions for keywords: "{}"'.format( self.keywords)) self.searchbar.setEnabled(True) self.searchbar.setFocus() if self.suggestions: suggestions = [ suggestion['label'] for suggestion in self.suggestions ] completer = QCompleter(suggestions) completer.setCaseSensitivity(Qt.CaseInsensitive) self.searchbar.setCompleter(completer) self.searchbar.completer().complete() self.searchbar.completer().popup().setStyleSheet( css( """ QListView { border: 1px solid {{borderColor}}; padding: 10px; background: {{backgroundColor}}; } QItemSelection { padding: 10px; } """, borderColor=colors.SECONDARY_COLOR, backgroundColor=colors.PLACEHOLDER_COLOR, ))
class VODCutter(QMainWindow): def __init__(self): QMainWindow.__init__(self) self.twitch_client_id = config.TWITCH_API_CLIENT_ID self.twitch_oauth_token = config.TWITCH_API_OAUTH_TOKEN self.twitch_interface = TwitchInterface( api_client_id=config.TWITCH_API_CLIENT_ID, api_oauth_token=config.TWITCH_API_OAUTH_TOKEN, browser_client_id=config.TWITCH_BROWSER_OAUTH_TOKEN, browser_oauth_token=config.TWITCH_BROWSER_OAUTH_TOKEN) self.vlc_interface = VLCInterface(config.VLC_PATH) self.loaded_video = None self.main_layout = QVBoxLayout() self.launch_vlc_btn = QPushButton("Launch VLC") self.info_layout = QGridLayout() self.file_picker_layout = QHBoxLayout() self.file_path_field = QLineEdit() self.file_browser_btn = QPushButton(text="...") self.file_picker_layout.addWidget(self.file_path_field) self.file_picker_layout.addWidget(self.file_browser_btn) vod_filepath_label = QLabel("VOD Filepath") id_twitch_label = QLabel("ID Twitch") created_at_label = QLabel("Created at") duration_label = QLabel("Duration") title_label = QLabel("Title") streamer_label = QLabel("Streamer") self.id_twitch_field = QLineEdit() self.created_at_field = QLineEdit() self.duration_field = QLineEdit() self.title_field = QLineEdit() self.streamer_field = QLineEdit() self.id_twitch_field.setEnabled(False) self.created_at_field.setEnabled(False) self.duration_field.setEnabled(False) self.title_field.setEnabled(False) self.streamer_field.setEnabled(False) self.info_layout.addWidget(vod_filepath_label, 0, 0) self.info_layout.addWidget(id_twitch_label, 1, 0) self.info_layout.addWidget(created_at_label, 2, 0) self.info_layout.addWidget(duration_label, 3, 0) self.info_layout.addWidget(title_label, 4, 0) self.info_layout.addWidget(streamer_label, 5, 0) self.info_layout.addLayout(self.file_picker_layout, 0, 1) self.info_layout.addWidget(self.id_twitch_field, 1, 1) self.info_layout.addWidget(self.created_at_field, 2, 1) self.info_layout.addWidget(self.duration_field, 3, 1) self.info_layout.addWidget(self.title_field, 4, 1) self.info_layout.addWidget(self.streamer_field, 5, 1) self.segments_create_btn = QPushButton("Import Chapters") self.download_thumbnails_btn = QPushButton("Download Thumbnails") self.download_chatlog_btn = QPushButton("Download Chat Log") self.segments_list = QListWidget() self.segments_add_btn = QPushButton(text="+") self.segments_delete_btn = QPushButton(text="-") self.jump_start_btn = QPushButton(text="Jump To Start") self.jump_end_btn = QPushButton(text="Jump To End") self.set_start_btn = QPushButton(text="Set Start") self.set_end_btn = QPushButton(text="Set End") self.split_btn = QPushButton(text="Split") self.process_selected_btn = QPushButton( text="Process Selected Segment") self.process_all_btn = QPushButton(text="Process All Segments") self.jump_layout = QHBoxLayout() self.jump_layout.addWidget(self.jump_start_btn) self.jump_layout.addWidget(self.jump_end_btn) self.set_layout = QHBoxLayout() self.set_layout.addWidget(self.set_start_btn) self.set_layout.addWidget(self.set_end_btn) self.main_layout.addWidget(self.launch_vlc_btn) self.main_layout.addLayout(self.file_picker_layout) self.main_layout.addLayout(self.info_layout) self.main_layout.addWidget(self.segments_create_btn) self.main_layout.addWidget(self.download_thumbnails_btn) self.main_layout.addWidget(self.download_chatlog_btn) self.main_layout.addWidget(self.segments_list) self.main_layout.addWidget(self.segments_add_btn) self.main_layout.addWidget(self.segments_delete_btn) self.main_layout.addLayout(self.jump_layout) self.main_layout.addLayout(self.set_layout) self.main_layout.addWidget(self.split_btn) self.main_layout.addWidget(self.process_selected_btn) self.main_layout.addWidget(self.process_all_btn) self.main_widget = QWidget() self.main_widget.setLayout(self.main_layout) self.setCentralWidget(self.main_widget) self.segments_list.itemDoubleClicked.connect( self.on_segments_list_doubleclick) self.jump_start_btn.clicked.connect(self.jump_to_segment_start) self.jump_end_btn.clicked.connect(self.jump_to_segment_end) self.set_start_btn.clicked.connect(self.set_segment_start) self.set_end_btn.clicked.connect(self.set_segment_end) self.download_thumbnails_btn.clicked.connect(self.download_thumbnails) self.segments_add_btn.clicked.connect(self.create_segment) self.segments_delete_btn.clicked.connect(self.delete_segment) self.split_btn.clicked.connect(self.split_selected_segment) self.launch_vlc_btn.clicked.connect(self.on_launch_vlc) self.file_path_field.returnPressed.connect(self.on_video_url_changed) self.file_browser_btn.clicked.connect(self.on_filebrowse_btn_click) self.process_selected_btn.clicked.connect( self.process_selected_segment) self.process_all_btn.clicked.connect(self.process_all_segments) def on_launch_vlc(self): self.vlc_interface.launch() def on_filebrowse_btn_click(self): filename = QFileDialog.getOpenFileName(self, "Select a video file") if filename[0]: self.set_video_file(filename[0]) def on_video_url_changed(self): self.set_video_file(self.file_path_field.text()) def on_segments_list_doubleclick(self, item): current_segment = item.get_segment() if current_segment: self.vlc_interface.set_current_time(int( current_segment.start_time)) def set_video_file(self, filepath=None): self.file_path_field.setText("" if filepath is None else filepath) if filepath: self.loaded_video = InputVideo() if re.search(r"^(?:/|[a-z]:[\\/])", filepath, re.I): file_url = "file://" + filepath self.loaded_video.is_local = True else: file_url = filepath if not self.loaded_video.is_local: streams = streamlink.streams(file_url) if streams: self.loaded_video.filepath = streams["best"].url else: self.loaded_video.filepath = file_url else: self.loaded_video.filepath = file_url try: self.update_twitch_metadatas() except requests.exceptions.ConnectionError: print("<!!> Can't connect to Twitch API.") try: self.vlc_interface.open_url(self.loaded_video.filepath) except requests.exceptions.ConnectionError: print("<!!> Can't connect to local VLC instance.") def get_twitch_id_from_filepath(self): filename = self.file_path_field.text() parsed_filename = re.search("([0-9]+)\.mp4$", filename, re.I) if parsed_filename: video_id = parsed_filename.group(1) return int(video_id) else: parsed_url = re.search("videos/([0-9]+)", filename, re.I) if parsed_url: video_id = parsed_url.group(1) return int(video_id) else: raise Exception( f"<!!> Can't find video Twitch id in video filename ({filename})" ) def create_segment_before(self, segment_obj): pass def create_segment_after(self, segment_obj): pass def update_twitch_metadatas(self): twitch_video_id = self.get_twitch_id_from_filepath() metadatas = self.twitch_interface.get_twitch_metadatas(twitch_video_id) self.loaded_video.metadatas = metadatas duration = parse_duration(metadatas["duration"]) self.id_twitch_field.setText(metadatas["id"]) self.created_at_field.setText(str(metadatas["created_at"])) self.duration_field.setText(format_time(duration.seconds)) self.title_field.setText(metadatas["title"]) self.streamer_field.setText(metadatas["user_login"]) for moment in self.twitch_interface.get_video_games_list( metadatas["id"]): s = Segment() s.name = f"{moment['description']} ({moment['type']})" s.start_time = moment['positionMilliseconds'] / 1000 s.end_time = (moment['positionMilliseconds'] + moment['durationMilliseconds']) / 1000 self.segments_list.addItem(SegmentListItem(s)) def create_segment(self): s = Segment() s.name = f"Segment {self.segments_list.count()}" s.start_time = 0 s.end_time = self.vlc_interface.get_duration() self.segments_list.addItem(SegmentListItem(s)) def delete_segment(self): for item in self.segments_list.selectedItems(): idx = self.segments_list.indexFromItem(item) item = self.segments_list.takeItem(idx.row()) del item def split_selected_segment(self): current_time = self.vlc_interface.get_current_time() for segment_item in self.segments_list.selectedItems(): current_segment = segment_item.get_segment() if current_segment: new_segment = segment_item.split( current_time, name="Splitted " + current_segment.name, split_mode=SPLIT_MODE.ABSOLUTE) self.segments_list.addItem(SegmentListItem(new_segment)) def get_selected_segments(self): return list( map(lambda item: item.get_segment(), self.segments_list.selectedItems())) def jump_to_segment_start(self): selected_segments = self.get_selected_segments() if selected_segments: self.vlc_interface.set_current_time( math.floor(selected_segments[0].start_time)) def jump_to_segment_end(self): selected_segments = self.get_selected_segments() if selected_segments: self.vlc_interface.set_current_time( math.floor(selected_segments[0].end_time)) def set_segment_start(self): current_time = self.vlc_interface.get_current_time() selected_segments = self.segments_list.selectedItems() if selected_segments: selected_segments[0].get_segment().start_time = current_time selected_segments[0].update() def set_segment_end(self): current_time = self.vlc_interface.get_current_time() selected_segments = self.segments_list.selectedItems() if selected_segments: selected_segments[0].get_segment().end_time = current_time selected_segments[0].update() def process_selected_segment(self): for segment in self.get_selected_segments(): self.process_segment(segment) def process_all_segments(self): for idx in range(self.segments_list.count()): segment_item = self.segments_list.item(idx) self.process_segment(segment_item.get_segment()) def process_segment(self, segment_obj): if not self.loaded_video: raise Exception("<!!> No video loaded") video_id = self.loaded_video.metadatas.get("id", None) created_at = self.loaded_video.metadatas.get("created_at", None) user_login = self.loaded_video.metadatas.get("user_login", None) if not (video_id and created_at and user_login): raise Exception("<!!> Missing video metadatas") created_at_timestamp = int(datetime.datetime.timestamp(created_at)) if self.loaded_video.is_local: cmd = f'ffmpeg -i "{self.loaded_video.filepath}" -ss {segment_obj.start_time} -to {segment_obj.end_time} -c:v copy -c:a copy "{user_login}_{created_at_timestamp}_{video_id}.mp4"' else: cmd = f'streamlink -f --hls-start-offset {format_time(segment_obj.start_time)} --hls-duration {format_time(segment_obj.end_time - segment_obj.start_time)} --player-passthrough hls "{self.loaded_video.filepath}" best -o "{user_login}_{created_at_timestamp}_{video_id}.mp4"' print(cmd) os.system(cmd) def download_thumbnails(self): twitch_video_id_str = self.id_twitch_field.text() if twitch_video_id_str: thumbnails_manifest_url = self.twitch_interface.get_video_thumbnails_manifest_url( int(twitch_video_id_str)) thumbnails_manifest, images_url_list = self.twitch_interface.get_thumbnails_url_from_manifest( thumbnails_manifest_url) for img in images_url_list: r = requests.get(images_url_list[img]) fp = open(img, "wb") fp.write(r.content) fp.close()
class PreparationWidget(QtWidgets.QWidget): def __init__(self): QtWidgets.QWidget.__init__(self) self.min_questions = 0 self.min_answers = 0 layout = QVBoxLayout() self.setLayout(layout) layout.addWidget(QLabel("Questions")) self.questions = QtWidgets.QListWidget() layout.addWidget(self.questions) self.question_textbox = QLineEdit() layout.addWidget(self.question_textbox) buttons_layout = QtWidgets.QHBoxLayout() icon = QtGui.QIcon.fromTheme('list-add') button = QPushButton(icon, "Add") button.clicked.connect(self.add_question) buttons_layout.addWidget(button) icon = QtGui.QIcon.fromTheme('list-remove') button = QPushButton(icon, 'Remove') button.clicked.connect(self.remove_question) buttons_layout.addWidget(button) layout.addLayout(buttons_layout) layout.addWidget(QLabel("Answers")) self.answers = QtWidgets.QListWidget() layout.addWidget(self.answers) self.answer_textbox = QLineEdit() layout.addWidget(self.answer_textbox) buttons_layout = QtWidgets.QHBoxLayout() icon = QtGui.QIcon.fromTheme('list-add') button = QPushButton(icon, "Add") button.clicked.connect(self.add_answer) buttons_layout.addWidget(button) icon = QtGui.QIcon.fromTheme('list-remove') button = QPushButton(icon, 'Remove') button.clicked.connect(self.remove_answer) buttons_layout.addWidget(button) icon = QtGui.QIcon.fromTheme('go-next') self.send_button = QPushButton(icon, "Send") self.send_button.clicked.connect(self.send_questions) buttons_layout.addWidget(self.send_button) layout.addLayout(buttons_layout) def set_num_players(self, num_players): self.min_questions = 3 self.min_answers = 3 * (num_players - 1) @QtCore.Slot() def add_question(self): text: str = self.question_textbox.text() if text: if not text.endswith('?'): text += '?' self.questions.addItem(text) self.question_textbox.clear() @QtCore.Slot() def remove_question(self): self.questions.takeItem(self.questions.currentRow()) @QtCore.Slot() def add_answer(self): text: str = self.answer_textbox.text() if text: self.answers.addItem(text) self.answer_textbox.clear() @QtCore.Slot() def remove_answer(self): self.answers.takeItem(self.questions.currentRow()) @QtCore.Slot() def send_questions(self): def callback(data): if data['status'] != 'ok': print(data) else: self.answer_textbox.setEnabled(False) self.question_textbox.setEnabled(False) self.send_button.setEnabled(False) questions = [self.questions.item(i).text() for i in range(self.questions.count())] answers = [self.answers.item(i). text() for i in range(self.answers.count())] if (len(questions) >= self.min_questions and len(answers) >= self.min_answers): sio.emit( "add-questions", (room_code, questions, answers), callback=callback )
class BlockView(QWidget): """Config widget for a single experiment block. In a model-view paradigm, this is a view, and block is a model. A new block can be set using setModel. """ statistics_type_to_name = { "max": "Min/Max", "meanstd": "Standardise" } statistics_name_to_type = {v: k for k, v in statistics_type_to_name.items()} def __init__(self, parent=None): super().__init__(parent) layout = QFormLayout() self.setLayout(layout) self._model = None # Block properties --------------------------------------------------------------------------------------------- self.duration = QWidget() self.duration.setContentsMargins(0, 0, 0, 0) ly = QHBoxLayout() ly.setContentsMargins(0, 0, 0, 0) self.duration.setLayout(ly) self.duration_base = QDoubleSpinBox() self.duration_base.setRange(0, 1000) self.duration_base.setValue(10) self.duration_deviation = QDoubleSpinBox() self.duration_deviation.setRange(0, 10) self.duration_deviation.setValue(0) self.duration_deviation.setSingleStep(0.1) self.duration_deviation.setSuffix(" s") self.duration_base.valueChanged.connect(self.duration_deviation.setMaximum) ly.addWidget(self.duration_base) ly.addWidget(QLabel("±")) ly.addWidget(self.duration_deviation) self.feedback_source = QLineEdit("All") self.feedback_type = QComboBox() self.feedback_type.addItem("Baseline") self.feedback_type.addItem("Feedback") self.mock_signal_path = QLineEdit() self.mock_signal_dataset = QLineEdit() self.mock_previous = QSpinBox() self.mock_previous_reverse = QCheckBox() self.mock_previous_random = QCheckBox() self.pause = QCheckBox() self.beep = QCheckBox() self.start_data_driven_filter_designer = QCheckBox() self.update_statistics = QCheckBox() self.update_statistics.stateChanged.connect(lambda state: self.statistics_type.setEnabled(bool(state))) self.statistics_type = QComboBox() self.statistics_type.setEnabled(False) for name in self.statistics_name_to_type: self.statistics_type.addItem(name) self.statistics_type.setCurrentText("Standardise") self.random_bound = QComboBox() self.random_bound.addItem("SimCircle") self.random_bound.addItem("RandomCircle") self.random_bound.addItem("Bar") self.video_path = QLineEdit() self.message = QLineEdit() self.feedback_type.currentTextChanged.connect(lambda ftype: self.message.setEnabled(ftype == "Baseline")) self.voiceover = QCheckBox() # Grouped properties ------------------------------------------------------------------------------------------- # Mock signal mock_signal_groupbox = QGroupBox("Mock signal") mock_signal_gblayout = QFormLayout() mock_signal_groupbox.setLayout(mock_signal_gblayout) mock_signal_gblayout.addRow("Mock signal file path", self.mock_signal_path) mock_signal_gblayout.addRow("Mock signal file dataset", self.mock_signal_dataset) mock_signal_gblayout.addRow("Mock previous", self.mock_previous) mock_signal_gblayout.addRow("Reverse mock previous", self.mock_previous_reverse) mock_signal_gblayout.addRow("Random mock previous", self.mock_previous_random) # After block actions after_block_groupbox = QGroupBox("After block actions") after_block_gblayout = QFormLayout() after_block_groupbox.setLayout(after_block_gblayout) after_block_gblayout.addRow("Start data driven filter designer", self.start_data_driven_filter_designer) after_block_gblayout.addRow("Pause", self.pause) after_block_gblayout.addRow("Beep", self.beep) after_block_gblayout.addRow("Update statistics", self.update_statistics) after_block_gblayout.addRow("Statistics type", self.statistics_type) # Adding properties to the widget ------------------------------------------------------------------------------ layout.addRow("Duration", self.duration) layout.addRow("Source", self.feedback_source) layout.addRow("FB Type", self.feedback_type) layout.addRow("Random bound", self.random_bound) layout.addRow("Video path", self.video_path) layout.addRow("Message for test subject", self.message) layout.addRow("Voiceover for message", self.voiceover) layout.addRow(mock_signal_groupbox) layout.addRow(after_block_groupbox) def model(self): return self._model def setModel(self, block, /): """Set the model block for this view. Data in the view will be updated to reflect the new block. """ self._model = block self.updateView() def updateModel(self): """Copy data from this view to the block model. A similarly named function in the block copies data the opposite way. Use one or the other depending on where data was changed. """ model = self.model() if model is None: return model.duration = self.duration_base.value() model.duration_deviation = self.duration_deviation.value() model.feedback_source = self.feedback_source.text() model.feedback_type = self.feedback_type.currentText() model.random_bound = self.random_bound.currentText() model.video_path = self.video_path.text() model.message = self.message.text() model.voiceover = self.voiceover.isChecked() model.mock_signal_path = self.mock_signal_path.text() model.mock_signal_dataset = self.mock_signal_dataset.text() model.mock_previous = self.mock_previous.value() model.mock_previous_reverse = self.mock_previous_reverse.isChecked() model.mock_previous_random = self.mock_previous_random.isChecked() model.start_data_driven_filter_designer = self.start_data_driven_filter_designer.isChecked() model.pause = self.pause.isChecked() model.beep = self.beep.isChecked() model.update_statistics = self.update_statistics.isChecked() model.statistics_type = self.statistics_name_to_type[self.statistics_type.currentText()] def updateView(self): model = self.model() if model is None: return self.duration_base.setValue(model.duration) self.duration_deviation.setValue(model.duration_deviation) self.feedback_source.setText(model.feedback_source) self.feedback_type.setCurrentText(model.feedback_type) self.mock_signal_path.setText(model.mock_signal_path) self.mock_signal_dataset.setText(model.mock_signal_dataset) self.mock_previous.setValue(model.mock_previous) self.mock_previous_reverse.setChecked(model.mock_previous_reverse) self.mock_previous_random.setChecked(model.mock_previous_random) self.pause.setChecked(model.pause) self.beep.setChecked(model.beep) self.start_data_driven_filter_designer.setChecked(model.start_data_driven_filter_designer) self.update_statistics.setChecked(model.update_statistics) self.statistics_type.setCurrentText(self.statistics_type_to_name[model.statistics_type]) self.random_bound.setCurrentText(model.random_bound) self.video_path.setText(model.video_path) self.message.setText(model.message) self.voiceover.setChecked(model.voiceover)
class MainWindow(QMainWindow): def __init__(self, vehicle_ctl: VehicleCtl, image_stream_server: ImageStreamServer): QMainWindow.__init__(self) self._vehicle_ctl = vehicle_ctl self._image_stream_server = image_stream_server # Our popup window for setting trim self._trim_window = None self.setMinimumSize(QSize(1000, 500)) self.setWindowTitle("Rotor Client") central_widget = QWidget() self.setCentralWidget(central_widget) # Need to allow the central widget to get focus so the key presses are caught correctly central_widget.setFocusPolicy(QtCore.Qt.ClickFocus) # Create all the buttons and widgets self.create_gui() # Create the image viewer self._image_viewer = ImageViewer(self._image_stream_server) # Connect all the push button signals self.add_gui_listeners() # Set the widgets in the grid layout self.add_widgets_to_screen(central_widget) # Give the central widget focus so the key presses work central_widget.setFocus() def game_controller_calibration_dialog(self): self._game_controller_config_window = GameControllerCalibrationDialog() self._game_controller_config_window.show() self._game_controller_config_window.calibration_complete_response = lambda calibration_data: self.game_controller_calibrated_from_window( calibration_data) def game_controller_calibrated_from_window(self, calibration_data): self._game_controller_config_window.close() config_handler = ConfigHandler.get_instance() config_handler.set_config_value('game_controller_calibration', calibration_data.to_json()) self.game_controller_calibrated(calibration_data) def game_controller_calibrated(self, calibration_data): logging.info("CONTROLLER WAS CALIBRATED! " + str(calibration_data.to_json())) self._game_controller = GameController(inputs.devices.gamepads[0], calibration_data) self._game_controller.add_event_response( 'ABS_HAT0X', self.game_controller_direction_pad_response) self._game_controller.add_event_response( 'ABS_RZ', self.game_controller_right_trigger_response) self._game_controller.add_event_response( 'ABS_Z', self.game_controller_left_trigger_response) self._game_controller.add_event_response( 'ABS_X', self.game_controller_left_stick_x) self._game_controller.add_event_response( 'BTN_EAST', self.game_controller_b_button_response) self._game_controller.add_event_response( 'BTN_TR', self.game_controller_right_bumper_response) self._game_controller.start() def game_controller_left_stick_x(self, state): self._vehicle_ctl.set_steering( state / self._game_controller.get_calibration().joystick_boundary) def game_controller_direction_pad_response(self, state): if state == -1: self.left_pressed() elif state == 1: self.right_pressed() else: self._vehicle_ctl.set_steering(0.0) def game_controller_b_button_response(self, state): if state == 1: self.backward_pressed() else: self.backward_released() def game_controller_right_bumper_response(self, state): if state == 0: self.change_gear() def game_controller_right_trigger_response(self, state): acc_value = state / self._game_controller.get_calibration( ).right_trigger_max if self._vehicle_ctl.get_gear() == Gear.DRIVE: self._vehicle_ctl.set_accelerator(acc_value) elif self._vehicle_ctl.get_gear() == Gear.REVERSE: acc_value *= -1 self._vehicle_ctl.set_accelerator(acc_value) def game_controller_left_trigger_response(self, state): acc_value = state / self._game_controller.get_calibration( ).right_trigger_max acc_value *= -1 if self._vehicle_ctl.get_gear() == Gear.DRIVE: self._vehicle_ctl.set_accelerator(acc_value) elif self._vehicle_ctl.get_gear() == Gear.REVERSE: acc_value *= -1 self._vehicle_ctl.set_accelerator(acc_value) def forward_pressed(self): if self._vehicle_ctl.get_gear() is Gear.REVERSE: self._vehicle_ctl.set_accelerator(-1.0) elif self._vehicle_ctl.get_gear() is Gear.DRIVE: self._vehicle_ctl.set_accelerator(1.0) def forward_released(self): self._vehicle_ctl.set_accelerator(0.0) def backward_pressed(self): if self._vehicle_ctl.get_gear() is Gear.REVERSE: self._vehicle_ctl.set_accelerator(1.0) elif self._vehicle_ctl.get_gear() is Gear.DRIVE: self._vehicle_ctl.set_accelerator(-1.0) def backward_released(self): self._vehicle_ctl.set_accelerator(0.0) def right_pressed(self): self._vehicle_ctl.set_steering(1.0) def right_released(self): self._vehicle_ctl.set_steering(0.0) def left_pressed(self): self._vehicle_ctl.set_steering(-1.0) def left_released(self): self._vehicle_ctl.set_steering(0.0) def show_trim_window(self): # Pull in the trim from the vehicle to populate the trim window trim = self._vehicle_ctl.get_trim() self._trim_window = TrimDialog(trim) self._trim_window.setGeometry(QtCore.QRect(100, 100, 400, 200)) self._trim_window.show() # After things have been trimmed, update our command so we can send updated trim values self._trim_window.trim_changed.connect(self.update_trim_from_dialog) def update_trim_from_dialog(self): trim = self._trim_window.get_trim() self._vehicle_ctl.send_trim(trim) def ip_changed(self, ip): port = self._sb_port.value() self._vehicle_ctl.set_endpoint(ip, port) def proxy_address_changed(self, address): self._vehicle_ctl.set_proxy(address, self._vehicle_ctl.vehicle_proxy_port()) def proxy_port_changed(self, port): self._vehicle_ctl.set_proxy(self._vehicle_ctl.vehicle_proxy_address(), port) def use_proxy_toggled(self, state): self._le_proxy_address.setEnabled(state) self._sb_proxy_port.setEnabled(state) if state: self._vehicle_ctl.enable_proxy() else: self._vehicle_ctl.disable_proxy() def port_changed(self, port): ip = self._le_ip.text() self._vehicle_ctl.set_endpoint(ip, port) def mode_changed(self, index): mode_int = self._cbo_mode.currentData() mode = Mode() mode.set_mode(mode_int) self._vehicle_ctl.set_mode(mode) def restart_stream(self): self._vehicle_ctl.restart_stream() def change_gear(self): self._vehicle_ctl.toggle_fw_bw() self._lbl_gear.setText('<b style="color: black;">' + self._vehicle_ctl.get_gear().value + "</b>") def keyPressEvent(self, e): if e.isAutoRepeat(): return super().keyReleaseEvent(e) if e.key() == QtCore.Qt.Key_Up or e.key() == QtCore.Qt.Key_W: self.forward_pressed() if e.key() == QtCore.Qt.Key_Left or e.key() == QtCore.Qt.Key_A: self.left_pressed() if e.key() == QtCore.Qt.Key_Down or e.key() == QtCore.Qt.Key_S: self.backward_pressed() if e.key() == QtCore.Qt.Key_Right or e.key() == QtCore.Qt.Key_D: self.right_pressed() return super().keyPressEvent(e) def keyReleaseEvent(self, e): if e.isAutoRepeat(): return super().keyReleaseEvent(e) if e.key() == QtCore.Qt.Key_Up or e.key() == QtCore.Qt.Key_W: self.forward_released() elif e.key() == QtCore.Qt.Key_Left or e.key() == QtCore.Qt.Key_A: self.left_released() elif e.key() == QtCore.Qt.Key_Down or e.key() == QtCore.Qt.Key_S: self.backward_released() elif e.key() == QtCore.Qt.Key_Right or e.key() == QtCore.Qt.Key_D: self.right_released() elif e.key() == QtCore.Qt.Key_R: self.change_gear() return super().keyReleaseEvent(e) def send_trim(self): self._vehicle_ctl.send_trim(self.trim) def create_gui(self): buttonHeight = 100 self._forward_btn = QPushButton("ACC", self) self._brake_btn = QPushButton("BRAKE", self) self._left_btn = QPushButton("LEFT", self) self._right_btn = QPushButton("RIGHT", self) self._forward_btn.setFixedHeight(buttonHeight) self._brake_btn.setFixedHeight(buttonHeight) self._left_btn.setFixedHeight(buttonHeight) self._right_btn.setFixedHeight(buttonHeight) self._trim_btn = QPushButton("Set Trim", self) self._trim_btn.clicked.connect(self.show_trim_window) self._le_ip = QLineEdit(self._vehicle_ctl.vehicle_ip(), self) self._le_ip.textChanged.connect(self.ip_changed) self._lbl_ip = QLabel("Ip:") self._sb_port = QSpinBox(self) self._sb_port.setMaximum(99999) self._sb_port.setValue(self._vehicle_ctl.vehicle_port()) self._sb_port.valueChanged.connect(self.port_changed) self._lbl_port = QLabel("Port:") self._lbl_mode = QLabel("Mode:") self._cbo_mode = QComboBox(self) self._lbl_proxy_address = QLabel("Proxy:") self._le_proxy_address = QLineEdit( self._vehicle_ctl.vehicle_proxy_address(), self) self._lbl_proxy_port = QLabel("Proxy Port:") self._lbl_gear = QLabel('<b style="color: black;">' + self._vehicle_ctl.get_gear().value + "</b>") f = self._lbl_gear.font() f.setPointSizeF(100) self._lbl_gear.setFont(f) self._lbl_gear.setAlignment(Qt.AlignCenter) self._btn_change_gear = QPushButton("Shift Gear") self._sb_proxy_port = QSpinBox(self) self._sb_proxy_port.setMaximum(99999) self._sb_proxy_port.setValue(self._vehicle_ctl.vehicle_proxy_port()) self._cbo_mode.addItem("NORMAL", int(ModeType.NORMAL)) self._cbo_mode.addItem("TRAIN", int(ModeType.TRAIN)) self._cbo_mode.addItem("AUTO", int(ModeType.AUTO)) self._btn_restart = QPushButton("Restart Stream") self._cb_proxy = QCheckBox() self._lbl_use_proxy = QLabel("Use Proxy") self._cb_proxy.setChecked(self._vehicle_ctl.is_using_proxy()) self._le_proxy_address.setEnabled(self._vehicle_ctl.is_using_proxy()) self._sb_proxy_port.setEnabled(self._vehicle_ctl.is_using_proxy()) def add_gui_listeners(self): self._forward_btn.pressed.connect(self.forward_pressed) self._forward_btn.released.connect(self.forward_released) self._brake_btn.pressed.connect(self.backward_pressed) self._brake_btn.released.connect(self.backward_released) self._right_btn.pressed.connect(self.right_pressed) self._right_btn.released.connect(self.right_released) self._left_btn.pressed.connect(self.left_pressed) self._left_btn.released.connect(self.left_released) self._cbo_mode.activated.connect(self.mode_changed) self._btn_restart.pressed.connect(self.restart_stream) self._cb_proxy.toggled.connect(self.use_proxy_toggled) self._le_proxy_address.textChanged.connect(self.proxy_address_changed) self._sb_proxy_port.valueChanged.connect(self.proxy_port_changed) self._btn_change_gear.released.connect(self.change_gear) def add_widgets_to_screen(self, cw): grid_layout = QGridLayout(cw) controls_layout = QGridLayout() controls_layout.setAlignment(Qt.AlignVCenter) grid_layout.addLayout(controls_layout, 0, 0, 2, 3) controls_layout.addWidget(self._forward_btn, 0, 1) controls_layout.addWidget(self._left_btn, 1, 0) controls_layout.addWidget(self._brake_btn, 1, 1) controls_layout.addWidget(self._right_btn, 1, 2) grid_layout.addWidget(self._lbl_ip, 2, 0) grid_layout.addWidget(self._le_ip, 2, 1, 1, 2) # Stretch the line edit into two cells grid_layout.addWidget(self._lbl_port, 3, 0) grid_layout.addWidget(self._sb_port, 3, 1, 1, 2) # Stretch the spinbox into two cells grid_layout.addWidget(self._lbl_use_proxy, 4, 0) grid_layout.addWidget(self._cb_proxy, 4, 1) grid_layout.addWidget(self._lbl_proxy_address, 5, 0) grid_layout.addWidget(self._le_proxy_address, 5, 1, 1, 2) grid_layout.addWidget(self._lbl_proxy_port, 6, 0) grid_layout.addWidget(self._sb_proxy_port, 6, 1, 1, 2) grid_layout.addWidget(self._lbl_mode, 7, 0) grid_layout.addWidget(self._cbo_mode, 7, 1, 1, 2) grid_layout.addWidget(self._image_viewer, 0, 3, 5, 1) grid_layout.addWidget(self._btn_restart, 5, 3) vehicle_layout = QVBoxLayout() grid_layout.addLayout(vehicle_layout, 0, 4) vehicle_layout.addWidget(self._lbl_gear) vehicle_layout.addWidget(self._btn_change_gear) vehicle_layout.addWidget(self._trim_btn)
class Window(QWidget): def __init__(self, parent=None): super(Window, self).__init__() self.path = None self.settings() self.create_widgets() self.create_layout() def settings(self): self.resize(300, 120) self.setWindowTitle('Mp3 Downloader') def create_widgets(self): self.edit_url = QLineEdit() self.edit_name = QLineEdit() self.btn_select_path = QPushButton('Select path', self) self.btn_select_path.clicked.connect(self.select_path) self.btn_download = QPushButton('Download mp3', self) self.btn_download.clicked.connect(self.download) def create_layout(self): self.layout = QFormLayout() self.layout.addRow('Nome:', self.edit_name) self.layout.addRow('Url:', self.edit_url) self.layout.addRow('Selecionar destino:', self.btn_select_path) self.layout.addRow(self.btn_download) self.setLayout(self.layout) def select_path(self): self.path = QFileDialog.getExistingDirectory(self, 'Selecionar Pasta') def download(self): if self.verify_fields(): self.manage_interface(False) self.thread_qt() def verify_fields(self): if self.path is None: return False else: strings = [self.edit_url, self.edit_name.text(), self.path] regex_validate = QRegExp('*.mp3') regex_validate.setPatternSyntax(QRegExp.Wildcard) emptys = 0 for string in strings: if len(string.split()) == 0: emptys += 1 if emptys == 0 and regex_validate.exactMatch( self.edit_url.text()): return True def thread_qt(self): url = self.edit_url.text() name = self.edit_name.text() path = self.edit_path.text() self.thre = DownloaderMusic() self.thre.finished.connect(self.downfin) self.thre.start() def manage_interface(self, state): self.btn_download.setEnabled(state) self.edit_name.setEnabled(state) self.edit_url.setEnabled(state) self.btn_select_path def downfin(self): self.notify_icon = QSystemTrayIcon() self.notify_icon.setVisible(True) self.notify_icon.showMessage( 'Download Finalizado', u'O download da sua música foi realizado com sucesso.', QSystemTrayIcon.Information, 3000) self.manage_interface(True)
class NodeInput(QWidget): def __init__(self, content_widget): super(NodeInput, self).__init__() self.content_widget = content_widget self.widget_type = '' # gets specified automatically when creating ui below (see self.widget_combo_box_changed) # create UI # create all layouts self.grid_layout = QGridLayout(self) # move buttons self.up_button = QPushButton(' < ') self.down_button = QPushButton(' > ') # type and label self.type_combo_box = QComboBox(self) self.type_combo_box.addItem('exec') self.type_combo_box.addItem('data') self.type_combo_box.currentTextChanged.connect( self.type_combo_box_changed) self.label_text_edit = QPlainTextEdit(self) self.label_text_edit.setPlaceholderText('Label') self.label_text_edit.setFixedWidth(self.type_combo_box.width()) # self.label_text_edit.setMinimumHeight(20) self.label_text_edit.setMaximumHeight(56) # widget self.widget_grid_layout = QGridLayout() self.widget_yes_no_group_box = QGroupBox(self) self.widget_yes_no_group_box.setLayout(QVBoxLayout()) self.widget_yes_radio_button = QRadioButton('Yes', self) self.widget_yes_radio_button.setChecked(True) self.widget_yes_radio_button.toggled.connect(self.widget_yes_set) self.widget_no_radio_button = QRadioButton('No', self) self.widget_yes_no_group_box.layout().addWidget( self.widget_yes_radio_button) self.widget_yes_no_group_box.layout().addWidget( self.widget_no_radio_button) self.widget_grid_layout.addWidget(self.widget_yes_no_group_box, 0, 0, 4, 1) self.widget_group_box = QGroupBox(self) self.widget_group_box.setLayout(QVBoxLayout()) self.widget_type_combo_box = QComboBox(self) self.widget_type_combo_box.addItem('std line edit') self.widget_type_combo_box.addItem('std spin box') self.widget_type_combo_box.addItem('custom widget') self.widget_type_combo_box.currentTextChanged.connect( self.widget_type_combo_box_changed) self.custom_widget_line_edit = QLineEdit() self.custom_widget_line_edit.setPlaceholderText('input widget name') self.custom_widget_line_edit.editingFinished.connect( self.widget_name_line_edit_edited) self.custom_widget_line_edit.setEnabled(False) self.widget_under_label_radio_button = QRadioButton( 'widget under label') self.widget_under_label_radio_button.setChecked(True) self.widget_besides_label_radio_button = QRadioButton( 'widget besides label') self.widget_group_box.layout().addWidget(self.widget_type_combo_box) self.widget_group_box.layout().addWidget(self.custom_widget_line_edit) self.widget_group_box.layout().addWidget( self.widget_under_label_radio_button) self.widget_group_box.layout().addWidget( self.widget_besides_label_radio_button) self.widget_grid_layout.addWidget(self.widget_group_box, 0, 3, 4, 1) # del button self.del_button = QPushButton(self) self.del_button.setText(' Del ') self.del_button.clicked.connect(self.delete_clicked) # create layout self.grid_layout.addWidget(self.up_button, 0, 0, 1, 1) self.grid_layout.addWidget(self.down_button, 3, 0, 1, 1) self.grid_layout.addWidget(self.type_combo_box, 0, 1) self.grid_layout.addWidget(self.label_text_edit, 1, 1, 3, 1) self.grid_layout.addLayout(self.widget_grid_layout, 0, 2, 4, 1) self.grid_layout.addWidget(self.del_button, 0, 4, 4, 1) def get_type(self): return self.type_combo_box.currentText() def get_label(self): return self.label_text_edit.toPlainText() def has_widget(self): return self.widget_yes_radio_button.isChecked() def set_has_widget(self, has_widget): if has_widget: self.widget_yes_radio_button.setChecked(True) self.widget_no_radio_button.setChecked(False) else: self.widget_yes_radio_button.setChecked(False) self.widget_no_radio_button.setChecked(True) def get_widget_type(self): return self.widget_type_combo_box.currentText() def set_widget_type(self, new_widget_type): self.widget_type_combo_box.setCurrentText(new_widget_type) def get_widget_name(self): return self.content_widget.prepare_class_name( self.custom_widget_line_edit.text()) def set_widget_name(self, name): self.custom_widget_line_edit.setText(name) def get_widget_pos(self): under = self.widget_under_label_radio_button # besides = self.widget_besides_label_radio_button return 'under' if under.isChecked() else 'besides' def set_widget_pos(self, pos): if pos == 'under': self.widget_under_label_radio_button.setChecked(True) self.widget_besides_label_radio_button.setChecked(False) elif pos == 'besides': self.widget_under_label_radio_button.setChecked(False) self.widget_besides_label_radio_button.setChecked(True) def widget_yes_set(self): if self.widget_yes_radio_button.isChecked(): self.widget_group_box.setEnabled(True) else: self.widget_group_box.setEnabled(False) def widget_name_line_edit_edited(self): self.custom_widget_line_edit.setText( self.content_widget.prepare_class_name( self.custom_widget_line_edit.text())) def widget_type_combo_box_changed(self, new_text): self.widget_type = new_text if new_text == 'custom widget': self.custom_widget_line_edit.setEnabled(True) else: self.custom_widget_line_edit.setEnabled(False) def set_type(self, new_type): self.type_combo_box.setCurrentText(new_type) def type_combo_box_changed(self, new_type): if new_type == 'data': self.widget_grid_layout.setEnabled(True) elif new_type == 'exec': self.widget_grid_layout.setEnabled(False) def set_label(self, new_label): self.label_text_edit.setPlainText(new_label) def delete_clicked(self): ret = QMessageBox.warning( self, 'Input', 'Do you really want to delete this input? All changes' 'will be lost.', QMessageBox.Yes, QMessageBox.No) if ret == QMessageBox.Yes: self.content_widget.delete_input(self)
class ButtonBox(QGroupBox): """ This code is to contain the overall controls which govern running experiments. """ def __init__(self, parent, size: QSize, log_handlers: [StreamHandler], lang: LangEnum): self.logger = getLogger(__name__) for h in log_handlers: self.logger.addHandler(h) self.logger.debug("Initializing") super().__init__(parent) self.setLayout(QVBoxLayout()) self.setMaximumSize(size) self._button_layout = QHBoxLayout() self._create_button = ClickAnimationButton() self._create_button.setFixedSize(60, 40) self._start_button = ClickAnimationButton() self._start_button.setFixedSize(120, 40) self._button_layout.addWidget(self._create_button) self._button_layout.addWidget(self._start_button) self._text_entry = QLineEdit() self.layout().addLayout(self._button_layout) self.layout().addWidget(self._text_entry) self._play_icon = QIcon(button_box_start_image_filepath) self._pause_icon = QIcon(button_box_pause_image_filepath) # self.prog_bar_label = QLabel() # self.prog_bar = QProgressBar() # self.prog_bar.setTextVisible(True) # self.prog_bar.setAlignment(Qt.AlignHCenter) # self.prog_bar.setMaximumHeight(12) # self.layout().addWidget(self.prog_bar_label) # self.layout().addWidget(self.prog_bar) self._start_button_state = 0 self._create_button_state = 0 self._set_button_states() self._strings = dict() self.set_lang(lang) # self.toggle_show_prog_bar(False) self.logger.debug("Initialized") def set_lang(self, lang: LangEnum) -> None: """ Set the language for this view object. :param lang: The enum for the language. :return None: """ self._strings = strings[lang] self._set_texts() self._set_tooltips() def get_condition_name(self) -> str: """ Return the text from the condition name text entry :return: The text from the text entry. """ return self._text_entry.text() def add_create_button_handler(self, func: classmethod) -> None: """ Add handler for the create button click event. :param func: The handler. :return: None. """ self.logger.debug("running") self._create_button.clicked.connect(func) self.logger.debug("done") def add_start_button_handler(self, func: classmethod) -> None: """ Add handler for the start button click event. :param func: The handler :return: None. """ self.logger.debug("running") self._start_button.clicked.connect(func) self.logger.debug("done") def set_condition_name_box_enabled(self, is_active: bool) -> None: """ Set whether this text entry is enabled. :param is_active: Whether this button is active. :return: None """ self.logger.debug("running") self._text_entry.setEnabled(is_active) self.logger.debug("done") def set_create_button_enabled(self, is_active: bool) -> None: """ Toggle whether this button is active. :param is_active: Whether this button is active. :return None: """ self._create_button.setEnabled(is_active) def set_create_button_state(self, button_state: int) -> None: """ Set create button state to given state. 0: Create. 1: End. :param button_state: The state to show on this button. :return: None. """ self.logger.debug("running") if button_state == 0: self._create_button.setText(self._strings[StringsEnum.CREATE]) self._create_button.setToolTip( self._strings[StringsEnum.CREATE_TT]) elif button_state == 1: self._create_button.setText(self._strings[StringsEnum.END]) self._create_button.setToolTip(self._strings[StringsEnum.END_TT]) self.logger.debug("done") def set_start_button_enabled(self, is_active: bool) -> None: """ Toggle whether this button is active. :param is_active: Whether this button is active. :return None: """ self._start_button.setEnabled(is_active) def set_start_button_state(self, button_state: int = 0) -> None: """ Set start button state to given state. 0: Start. 1: Pause. 2: Resume. :param button_state: The state to show on this button. :return: None. """ self.logger.debug("running") if button_state == 0: self._start_button.setIcon(self._play_icon) self._start_button.setIconSize(QSize(26, 26)) self._start_button.setToolTip(self._strings[StringsEnum.START_TT]) elif button_state == 1: self._start_button.setIcon(self._pause_icon) self._start_button.setIconSize(QSize(36, 36)) self._start_button.setToolTip(self._strings[StringsEnum.PAUSE_TT]) elif button_state == 2: self._start_button.setIcon(self._play_icon) self._start_button.setIconSize(QSize(26, 26)) self._start_button.setToolTip(self._strings[StringsEnum.RESUME_TT]) self.logger.debug("done") def toggle_show_prog_bar(self, is_visible: bool) -> None: """ Toggle showing the progress bar. :param is_visible: Whether or not to show the progress bar. :return: None. """ pass # if is_visible: # self.prog_bar.show() # self.prog_bar_label.show() # else: # self.prog_bar.hide() # self.prog_bar_label.hide() def update_prog_bar_value(self, value: int) -> None: """ Update the progress bar to the given value :param value: The value to use when updating the progress bar. :return: None. """ pass # self.prog_bar.setValue(value) def _set_texts(self) -> None: """ Set the texts of this view item. :return: None. """ self.logger.debug("running") self.setTitle(self._strings[StringsEnum.TITLE]) self._text_entry.setPlaceholderText( self._strings[StringsEnum.COND_NAME_SHADOW]) if self._create_button_state == 0: self._create_button.setText(self._strings[StringsEnum.CREATE]) elif self._create_button_state == 1: self._create_button.setText(self._strings[StringsEnum.END]) if self._start_button_state == 0 or self._start_button_state == 2: self._start_button.setIcon(self._play_icon) self._start_button.setIconSize(QSize(32, 32)) elif self._start_button_state == 1: self._start_button.setIcon(self._pause_icon) self._start_button.setIconSize(QSize(36, 36)) # self.prog_bar_label.setText(button_box_prog_bar_label) # self.prog_bar.setValue(0) self.logger.debug("done") def _set_button_states(self) -> None: """ Set default button states. :return: None. """ self.logger.debug("running") self._start_button.setEnabled(False) self.logger.debug("done") def _set_tooltips(self) -> None: """ Set the text for the tooltips in this view item. :return: None. """ self.logger.debug("running") if self._create_button_state == 0: self._create_button.setToolTip( self._strings[StringsEnum.CREATE_TT]) if self._create_button_state == 1: self._create_button.setToolTip(self._strings[StringsEnum.END_TT]) if self._start_button_state == 0: self._start_button.setToolTip(self._strings[StringsEnum.START_TT]) elif self._start_button_state == 1: self._start_button.setToolTip(self._strings[StringsEnum.PAUSE_TT]) elif self._start_button_state == 2: self._start_button.setToolTip(self._strings[StringsEnum.RESUME_TT]) self.logger.debug("done")
class ContinuousCriteriaPage(EnableNextOnBackMixin, QWizardPage): def __init__(self, parent): super().__init__(parent) self.parent_wizard = weakref.proxy(parent) self.setTitle('Continuous criteria') # Radio button, if yes then ask for inputs self.yes = QRadioButton( '&Yes, there are criteria that needs to be calculated') no = QRadioButton( 'N&o, I will manually give a rating for every choice and criteria') no.setChecked(True) self.registerField('yes', self.yes) self.yes.toggled.connect(self.toggled) group = QButtonGroup(self) group.addButton(self.yes) group.addButton(no) # Duplicated from AbstractMultiInputPage self.line_edit = QLineEdit() self.list_widget = QListWidget() self.add_button = QPushButton('&Add criterion') self.delete_button = QPushButton('&Delete') self.line_edit.setDisabled(True) self.list_widget.setDisabled(True) self.add_button.setDisabled(True) self.delete_button.setDisabled(True) self.line_edit.returnPressed.connect(self.add_item) self.add_button.clicked.connect(self.add_item) self.delete_button.clicked.connect(self.delete_item) grid = QGridLayout(self) grid.addWidget(self.yes, 0, 0) grid.addWidget(no, 1, 0) grid.addWidget(self.line_edit, 2, 0) grid.addWidget(self.add_button, 2, 1) grid.addWidget(self.list_widget, 3, 0) grid.addWidget(self.delete_button, 3, 1, Qt.AlignTop) self.setLayout(grid) def initializePage(self): for criterion in self.parent_wizard.main_parent.matrix.continuous_criteria: self.list_widget.addItem(QListWidgetItem(criterion)) if self.list_widget.count() != 0: self.yes.setChecked(True) self.parent_wizard.next_button.setEnabled(True) def toggled(self, checked: bool): if checked: self.line_edit.setEnabled(True) self.list_widget.setEnabled(True) self.add_button.setEnabled(True) self.parent_wizard.next_button.setDisabled(True) else: self.line_edit.setDisabled(True) self.list_widget.setDisabled(True) self.parent_wizard.next_button.setEnabled(True) def add_item(self): # Duplicated if not (name := self.line_edit.text()): return item = QListWidgetItem(name) self.list_widget.addItem(item) self.line_edit.clear() self.line_edit.setFocus() self.parent_wizard.next_button.setEnabled(True) self.delete_button.setEnabled(True) self.parent_wizard.main_parent.line_edit_cc_tab.setText(name) self.parent_wizard.main_parent.matrix.add_continuous_criterion( name, weight=float('nan')) self.parent_wizard.main_parent.add_continuous_criteria()
class App(QWidget): def __init__(self, bk, prefs): super().__init__() self.bk = bk self.prefs = prefs self.update = False # Install translator for the DOCXImport plugin dialog. # Use the Sigil language setting unless manually overridden. plugin_translator = QTranslator() if prefs['language_override'] is not None: print('Plugin preferences language override in effect') qmf = '{}_{}'.format(bk._w.plugin_name.lower(), prefs['language_override']) else: qmf = '{}_{}'.format(bk._w.plugin_name.lower(), bk.sigil_ui_lang) print( qmf, os.path.join(bk._w.plugin_dir, bk._w.plugin_name, 'translations')) plugin_translator.load( qmf, os.path.join(bk._w.plugin_dir, bk._w.plugin_name, 'translations')) print(QCoreApplication.instance().installTranslator(plugin_translator)) self._ok_to_close = False self.FTYPE_MAP = { 'smap': { 'title': _translate('App', 'Select custom style-map file'), 'defaultextension': '.txt', 'filetypes': 'Text Files (*.txt);;All files (*.*)', }, 'css': { 'title': _translate('App', 'Select custom CSS file'), 'defaultextension': '.css', 'filetypes': 'CSS Files (*.css)', }, 'docx': { 'title': _translate('App', 'Select DOCX file'), 'defaultextension': '.docx', 'filetypes': 'DOCX Files (*.docx)', }, } # Check online github files for newer version if self.prefs['check_for_updates']: self.update, self.newversion = self.check_for_update() self.initUI() def initUI(self): main_layout = QVBoxLayout(self) self.setWindowTitle('DOCXImport') self.upd_layout = QVBoxLayout() self.update_label = QLabel() self.update_label.setAlignment(Qt.AlignCenter) self.upd_layout.addWidget(self.update_label) self.get_update_button = QPushButton() self.get_update_button.clicked.connect(self.get_update) self.upd_layout.addWidget(self.get_update_button) main_layout.addLayout(self.upd_layout) if not self.update: self.update_label.hide() self.get_update_button.hide() self.details_grid = QGridLayout() self.epub2_select = QRadioButton() self.epub2_select.setText('EPUB2') self.epubType = QButtonGroup() self.epubType.addButton(self.epub2_select) self.details_grid.addWidget(self.epub2_select, 0, 0, 1, 1) self.checkbox_get_updates = QCheckBox() self.details_grid.addWidget(self.checkbox_get_updates, 0, 1, 1, 1) self.epub3_select = QRadioButton() self.epub3_select.setText('EPUB3') self.epubType.addButton(self.epub3_select) self.details_grid.addWidget(self.epub3_select, 1, 0, 1, 1) main_layout.addLayout(self.details_grid) self.checkbox_get_updates.setChecked(self.prefs['check_for_updates']) if self.prefs['epub_version'] == '2.0': self.epub2_select.setChecked(True) elif self.prefs['epub_version'] == '3.0': self.epub3_select.setChecked(True) else: self.epub2_select.setChecked(True) self.groupBox = QGroupBox() self.groupBox.setTitle('') self.verticalLayout_2 = QVBoxLayout(self.groupBox) self.docx_grid = QGridLayout() self.docx_label = QLabel() self.docx_grid.addWidget(self.docx_label, 0, 0, 1, 1) self.docx_path = QLineEdit() self.docx_grid.addWidget(self.docx_path, 1, 0, 1, 1) self.choose_docx_button = QPushButton() self.choose_docx_button.setText('...') self.docx_grid.addWidget(self.choose_docx_button, 1, 1, 1, 1) self.verticalLayout_2.addLayout(self.docx_grid) self.choose_docx_button.clicked.connect( lambda: self.fileChooser('docx', self.docx_path)) if len(self.prefs['lastDocxPath']): self.docx_path.setText(self.prefs['lastDocxPath']) self.docx_path.setEnabled(False) self.smap_grid = QGridLayout() self.checkbox_smap = QCheckBox(self.groupBox) self.smap_grid.addWidget(self.checkbox_smap, 0, 0, 1, 1) self.cust_smap_path = QLineEdit(self.groupBox) self.smap_grid.addWidget(self.cust_smap_path, 1, 0, 1, 1) self.choose_smap_button = QPushButton(self.groupBox) self.choose_smap_button.setText('...') self.smap_grid.addWidget(self.choose_smap_button, 1, 1, 1, 1) self.verticalLayout_2.addLayout(self.smap_grid) self.checkbox_smap.setChecked(self.prefs['useSmap']) self.checkbox_smap.stateChanged.connect(lambda: self.chkBoxActions( self.checkbox_smap, self.choose_smap_button)) self.choose_smap_button.clicked.connect( lambda: self.fileChooser('smap', self.cust_smap_path, self. checkbox_smap, self.choose_smap_button)) if len(self.prefs['useSmapPath']): self.cust_smap_path.setText(self.prefs['useSmapPath']) self.cust_smap_path.setEnabled(False) self.chkBoxActions(self.checkbox_smap, self.choose_smap_button) self.css_grid = QGridLayout() self.checkbox_css = QCheckBox(self.groupBox) self.css_grid.addWidget(self.checkbox_css, 0, 0, 1, 1) self.cust_css_path = QLineEdit(self.groupBox) self.css_grid.addWidget(self.cust_css_path, 1, 0, 1, 1) self.choose_css_button = QPushButton(self.groupBox) self.choose_css_button.setText('...') self.css_grid.addWidget(self.choose_css_button, 1, 1, 1, 1) self.verticalLayout_2.addLayout(self.css_grid) self.checkbox_css.setChecked(self.prefs['useCss']) self.checkbox_css.stateChanged.connect(lambda: self.chkBoxActions( self.checkbox_css, self.choose_css_button)) self.choose_css_button.clicked.connect( lambda: self.fileChooser('css', self.cust_css_path, self. checkbox_css, self.choose_css_button)) if len(self.prefs['useCssPath']): self.cust_css_path.setText(self.prefs['useCssPath']) self.cust_css_path.setEnabled(False) self.chkBoxActions(self.checkbox_css, self.choose_css_button) main_layout.addWidget(self.groupBox) self.checkbox_debug = QCheckBox() main_layout.addWidget(self.checkbox_debug) self.checkbox_debug.setChecked(self.prefs['debug']) spacerItem = QSpacerItem(20, 15, QSizePolicy.Minimum, QSizePolicy.Expanding) main_layout.addItem(spacerItem) button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) button_box.accepted.connect(self._ok_clicked) button_box.rejected.connect(self._cancel_clicked) main_layout.addWidget(button_box) self.retranslateUi(self) if self.prefs['qt_geometry'] is not None: try: self.restoreGeometry( QByteArray.fromHex( self.prefs['qt_geometry'].encode('ascii'))) except: pass self.show() def retranslateUi(self, App): self.update_label.setText(_translate('App', 'Plugin Update Available')) self.get_update_button.setText(_translate('App', 'Go to download page')) self.checkbox_get_updates.setText( _translate('App', 'Check for plugin updates')) self.docx_label.setText(_translate('App', 'DOCX File to import')) self.checkbox_smap.setText(_translate('App', 'Use Custom Style Map')) self.checkbox_css.setText(_translate('App', 'Use Custom CSS')) self.checkbox_debug.setText( _translate('App', 'Debug Mode (change takes effect next plugin run)')) def fileChooser(self, ftype, qlineedit, qcheck=None, qbutton=None): options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog title = self.FTYPE_MAP[ftype]['title'] startfolder = self.prefs['lastDir'][ftype] ffilter = self.FTYPE_MAP[ftype]['filetypes'] inpath, _ = QFileDialog.getOpenFileName(self, title, startfolder, ffilter, options=options) if len(inpath): qlineedit.setEnabled(True) qlineedit.setText(os.path.normpath(inpath)) self.prefs['lastDir'][ftype] = os.path.dirname(inpath) qlineedit.setEnabled(False) else: if qcheck is not None: qcheck.setChecked(False) if qbutton is not None: qbutton.setEnabled(False) def chkBoxActions(self, chk, btn): btn.setEnabled(chk.isChecked()) def cmdDo(self): global _DETAILS self.prefs['qt_geometry'] = self.saveGeometry().toHex().data().decode( 'ascii') self.prefs['check_for_updates'] = self.checkbox_get_updates.isChecked() self.prefs['epub_version'] = self.epubType.checkedButton().text( )[-1] + '.0' self.prefs['debug'] = self.checkbox_debug.isChecked() _DETAILS['vers'] = self.epubType.checkedButton().text()[-1] + '.0' self.prefs['useSmap'] = self.checkbox_smap.isChecked() if self.checkbox_smap.isChecked(): if len(self.cust_smap_path.text()): self.prefs['useSmapPath'] = self.cust_smap_path.text() _DETAILS['smap'] = (self.checkbox_smap.isChecked(), self.cust_smap_path.text()) else: # Message box that no file is selected return self.prefs['useCss'] = self.checkbox_css.isChecked() if self.checkbox_css.isChecked(): if len(self.cust_css_path.text()): self.prefs['useCssPath'] = self.cust_css_path.text() _DETAILS['css'] = (self.checkbox_css.isChecked(), self.cust_css_path.text()) else: # Message box that no file is selected return if len(self.docx_path.text()): self.prefs['lastDocxPath'] = self.docx_path.text() _DETAILS['docx'] = self.docx_path.text() else: # Message box that no file is selected return def check_for_update(self): '''Use updatecheck.py to check for newer versions of the plugin''' chk = UpdateChecker(self.prefs['last_time_checked'], self.bk._w) update_available, online_version, time = chk.update_info() # update preferences with latest date/time/version self.prefs['last_time_checked'] = time if online_version is not None: self.prefs['last_online_version'] = online_version if update_available: return (True, online_version) return (False, online_version) def get_update(self): url = DOWNLOAD_PAGE if self.update: latest = '/tag/v{}'.format(self.newversion) url = url + latest webbrowser.open_new_tab(url) def _ok_clicked(self): self._ok_to_close = True self.cmdDo() self.bk.savePrefs(self.prefs) QCoreApplication.instance().quit() def _cancel_clicked(self): self._ok_to_close = True '''Close aborting any changes''' self.prefs['qt_geometry'] = self.saveGeometry().toHex().data().decode( 'ascii') self.prefs['check_for_updates'] = self.checkbox_get_updates.isChecked() self.prefs['debug'] = self.checkbox_debug.isChecked() self.bk.savePrefs(self.prefs) QCoreApplication.instance().quit() def closeEvent(self, event): if self._ok_to_close: event.accept() # let the window close else: self._cancel_clicked()
class RightSide: def __init__(self, font): self._font = font self.layout = QVBoxLayout() self.stdout_info = QTextEdit() self.stdout_info.setFixedWidth(800) self.stdout_info.moveCursor(QtGui.QTextCursor.Start) self.stdout_info.ensureCursorVisible() self.stdout_info.setLineWrapColumnOrWidth(500) self.stdout_info.setLineWrapMode(QTextEdit.FixedPixelWidth) self.layout.addWidget(self.stdout_info) self._set_media_player() self._midi_path = os.path.abspath( os.path.join(str(Path(__file__).parent.parent.parent), 'results')) self._midi_file = None self.midi_player = MidiPlayer() self._toggle_pause = True self._already_playing = False self._play_default_stylesheet = None self._pause_default_stylesheet = None self._stop_default_stylesheet = None self.end_signal = 'NO END.' self.player_timer_thread = threading.Thread( target=self._update_media_player_timer) self.player_timer_thread.start() def update_stdout_text_window(self, msg): cursor = self.stdout_info.textCursor() cursor.movePosition(QtGui.QTextCursor.End) cursor.insertText(msg) self.stdout_info.setTextCursor(cursor) self.stdout_info.ensureCursorVisible() def _set_media_player(self): self._resources_path = os.path.abspath( os.path.join(str(Path(__file__).parent.parent.parent), 'resources', 'gui')) self._media_box = QHBoxLayout() self._play_button = QPushButton('PLAY') self._play_icon = QtGui.QPixmap( os.path.join(self._resources_path, 'play.png')) self._play_button.setIcon(self._play_icon) self._play_default_stylesheet = self._play_button.styleSheet() self._play_button.setEnabled(False) self._play_button.clicked.connect(lambda c: self._play_midi()) self._pause_button = QPushButton('PAUSE') self._pause_icon = QtGui.QPixmap( os.path.join(self._resources_path, 'pause.png')) self._pause_button.setIcon(self._pause_icon) self._pause_default_stylesheet = self._pause_button.styleSheet() self._pause_button.setEnabled(False) self._pause_button.clicked.connect(lambda c: self._pause()) self._stop_button = QPushButton('STOP') self._stop_icon = QtGui.QPixmap( os.path.join(self._resources_path, 'stop.png')) self._stop_button.setIcon(self._stop_icon) self._stop_button.setEnabled(False) self._stop_button.clicked.connect(lambda c: self._stop()) self._stop_button.setStyleSheet( "QPushButton:pressed { background-color: red }") self._player_timer = QLineEdit('--/-- sec.') self._player_timer.setFixedWidth(200) self._player_timer.setEnabled(False) self._media_box.addWidget(self._play_button) self._media_box.addWidget(self._pause_button) self._media_box.addWidget(self._stop_button) self._media_box.addWidget(self._player_timer) self.layout.addLayout(self._media_box) def update_media_player(self, msg): self._midi_file = os.path.join(self._midi_path, msg[:-4] + '.mid') self.midi_player.load(self._midi_file) self._play_button.setEnabled(True) self._pause_button.setEnabled(True) self._stop_button.setEnabled(True) def _play_midi(self): self._play_button.setStyleSheet("background-color: green") self._pause_button.setStyleSheet(self._pause_default_stylesheet) self._toggle_pause = True if self._already_playing is False: self.midi_player.play() self._already_playing = True def _pause(self): self._play_button.setStyleSheet(self._play_default_stylesheet) self._pause_button.setStyleSheet("background-color: green") if self._toggle_pause is True: self.midi_player.pause() self._already_playing = False else: self.midi_player.unpause() self._already_playing = True self._toggle_pause = not self._toggle_pause def _stop(self): self._play_button.setStyleSheet(self._play_default_stylesheet) self._pause_button.setStyleSheet(self._pause_default_stylesheet) self._toggle_pause = True self.midi_player.stop() self._already_playing = False def _update_media_player_timer(self): while True: if self.end_signal == 'End.': break total = self.midi_player.song_duration if total != 0: current = self.midi_player.current_runtime if int(current) > math.floor(total): current = total output = f'{current}/{total} sec.' else: output = '--/-- sec.' self._player_timer.setText(output)
class VOGTab(QWidget): """ This code is for helping the user interact with the configurations of the VOG device. """ def __init__(self, device, ch): self.logger = logging.getLogger(__name__) self.logger.addHandler(ch) self.logger.debug("Initializing") try: super().__init__() except Exception as e: self.logger.exception( "Error making VOGTab, passed parent is invalid") return self.setLayout(QVBoxLayout(self)) self.setGeometry(QRect(0, 0, 200, 500)) self.setMaximumHeight(500) self.layout().addWidget(EasyFrame(line=True)) """ Set configuration value display area""" self.__config_frame = EasyFrame() self.__config_horiz_layout = QHBoxLayout(self.__config_frame) self.__config_label = QLabel(self.__config_frame) self.__config_label.setAlignment(Qt.AlignCenter) self.__config_horiz_layout.addWidget(self.__config_label) self.__config_val_line_edit = QLineEdit(self.__config_frame) self.__config_val_line_edit.setAlignment(Qt.AlignCenter) self.__config_horiz_layout.addWidget(self.__config_val_line_edit) self.layout().addWidget(self.__config_frame) self.layout().addWidget(EasyFrame(line=True)) """ Set preset button selection area. """ self.__presets_frame = EasyFrame() self.__presets_vert_layout = QVBoxLayout(self.__presets_frame) self.__nhtsa_button = ClickAnimationButton(self.__presets_frame) self.__presets_vert_layout.addWidget(self.__nhtsa_button) self.__eblindfold_button = ClickAnimationButton(self.__presets_frame) self.__presets_vert_layout.addWidget(self.__eblindfold_button) self.__direct_control_button = ClickAnimationButton( self.__presets_frame) self.__presets_vert_layout.addWidget(self.__direct_control_button) self.layout().addWidget(self.__presets_frame) self.layout().addWidget(EasyFrame(line=True)) """ Set open duration, close duration, and debounce time settings display area. """ self.__input_box_frame = EasyFrame() self.__input_box_grid_layout = QGridLayout(self.__input_box_frame) self.__input_box_grid_layout.setContentsMargins(0, 6, 0, 6) self.__open_dur_label = QLabel(self.__input_box_frame) self.__input_box_grid_layout.addWidget(self.__open_dur_label, 0, 0, 1, 1) self.__open_dur_line_edit = QLineEdit(self.__input_box_frame) self.__open_dur_line_edit.setFixedWidth(80) self.__input_box_grid_layout.addWidget(self.__open_dur_line_edit, 0, 1, 1, 1) self.__open_inf_check_box = QCheckBox(self.__input_box_frame) self.__input_box_grid_layout.addWidget(self.__open_inf_check_box, 0, 2, 1, 1) self.__close_dur_label = QLabel(self.__input_box_frame) self.__input_box_grid_layout.addWidget(self.__close_dur_label, 1, 0, 1, 1) self.__close_dur_line_edit = QLineEdit(self.__input_box_frame) self.__close_dur_line_edit.setFixedWidth(80) self.__input_box_grid_layout.addWidget(self.__close_dur_line_edit, 1, 1, 1, 1) self.__close_inf_check_box = QCheckBox(self.__input_box_frame) self.__input_box_grid_layout.addWidget(self.__close_inf_check_box, 1, 2, 1, 1) self.__debounce_label = QLabel(self.__input_box_frame) self.__input_box_grid_layout.addWidget(self.__debounce_label, 2, 0, 1, 1) self.__debounce_time_line_edit = QLineEdit(self.__input_box_frame) self.__debounce_time_line_edit.setFixedWidth(80) self.__input_box_grid_layout.addWidget(self.__debounce_time_line_edit, 2, 1, 1, 1) self.layout().addWidget(self.__input_box_frame) self.layout().addWidget(EasyFrame(line=True)) """ Set button mode setting display area. """ self.__button_mode_frame = EasyFrame() self.__button_mode_horiz_layout = QHBoxLayout(self.__button_mode_frame) self.__button_mode_label = QLabel(self.__button_mode_frame) self.__button_mode_horiz_layout.addWidget(self.__button_mode_label) self.__button_mode_selector = QComboBox(self.__button_mode_frame) self.__button_mode_selector.addItem("") self.__button_mode_selector.addItem("") self.__button_mode_horiz_layout.addWidget(self.__button_mode_selector) self.layout().addWidget(self.__button_mode_frame) self.layout().addWidget(EasyFrame(line=True)) """ Set upload button selection area. """ self.__upload_settings_button = ClickAnimationButton() self.layout().addWidget(self.__upload_settings_button) self.layout().addWidget(EasyFrame(line=True)) """ Set manual control selection area. """ self.__manual_control_button = ClickAnimationButton() self.layout().addWidget(self.__manual_control_button) self.layout().addWidget(EasyFrame(line=True)) self.__graph_buttons = [] self.device_info = device self.__index = 0 self.__set_texts() self.__set_tooltips() self.logger.debug("Initialized") def add_manual_control_handler(self, func): self.logger.debug("running") self.__manual_control_button.clicked.connect(func) self.logger.debug("done") def add_nhtsa_button_handler(self, func): self.logger.debug("running") self.__nhtsa_button.clicked.connect(func) self.logger.debug("done") def add_eblind_button_handler(self, func): self.logger.debug("running") self.__eblindfold_button.clicked.connect(func) self.logger.debug("done") def add_direct_control_button_handler(self, func): self.logger.debug("running") self.__direct_control_button.clicked.connect(func) self.logger.debug("done") def add_upload_button_handler(self, func): self.logger.debug("running") self.__upload_settings_button.clicked.connect(func) self.logger.debug("done") def add_open_inf_handler(self, func): self.logger.debug("running") self.__open_inf_check_box.toggled.connect(func) self.logger.debug("done") def add_close_inf_handler(self, func): self.logger.debug("running") self.__close_inf_check_box.toggled.connect(func) self.logger.debug("done") def add_open_entry_changed_handler(self, func): self.logger.debug("running") self.__open_dur_line_edit.textChanged.connect(func) self.logger.debug("done") def add_close_entry_changed_handler(self, func): self.logger.debug("running") self.__close_dur_line_edit.textChanged.connect(func) self.logger.debug("done") def add_debounce_entry_changed_handler(self, func): self.logger.debug("running") self.__debounce_time_line_edit.textChanged.connect(func) self.logger.debug("done") def add_button_mode_entry_changed_handler(self, func): self.logger.debug("running") self.__button_mode_selector.currentIndexChanged.connect(func) self.logger.debug("done") def add_config_val_changed_handler(self, func): self.logger.debug("running") self.__config_val_line_edit.textChanged.connect(func) self.logger.debug("done") def set_upload_button_activity(self, is_active): """ Set upload button to enabled or disabled depending on is_active bool. """ self.logger.debug("running") self.__upload_settings_button.setEnabled(is_active) self.logger.debug("done") def set_config_value(self, value): """ Set display value of config.txt. """ self.logger.debug("running") self.__config_val_line_edit.setText(value) self.logger.debug("done") def get_config_value(self): return self.__config_val_line_edit.text() def get_open_val(self): return self.__open_dur_line_edit.text() def set_open_val(self, val): """ Set display value of open duration. """ self.logger.debug("running") self.__open_dur_line_edit.setText(str(val)) self.logger.debug("done") def set_open_val_error(self, is_error): """ Set display of error in open duration line edit. """ self.logger.debug("running") if is_error: self.__open_dur_line_edit.setStyleSheet(tab_line_edit_error_style) else: self.__open_dur_line_edit.setStyleSheet( tab_line_edit_compliant_style) self.logger.debug("done") def set_close_val_error(self, is_error): """ Set display of error in close duration line edit. """ self.logger.debug("running") if is_error: self.__close_dur_line_edit.setStyleSheet(tab_line_edit_error_style) else: self.__close_dur_line_edit.setStyleSheet( tab_line_edit_compliant_style) self.logger.debug("done") def set_debounce_val_error(self, is_error): """ Set display of error in debounce line edit. """ self.logger.debug("running") if is_error: self.__debounce_time_line_edit.setStyleSheet( tab_line_edit_error_style) else: self.__debounce_time_line_edit.setStyleSheet( tab_line_edit_compliant_style) self.logger.debug("done") def set_open_val_entry_activity(self, is_active): """ Set open value line edit to enabled or disabled depending on is_active bool. """ self.logger.debug("running") self.__open_dur_line_edit.setEnabled(is_active) self.logger.debug("done") def get_open_inf(self): return self.__open_inf_check_box.isChecked() def set_open_inf(self, is_checked): """ Set open infinity checkbox state to is_checked. """ self.logger.debug("running") self.__open_inf_check_box.setChecked(is_checked) self.logger.debug("done") def get_close_val(self): return self.__close_dur_line_edit.text() def set_close_val(self, val): """ Set display value of close duration. """ self.logger.debug("running") self.__close_dur_line_edit.setText(str(val)) self.logger.debug("done") def set_close_val_entry_activity(self, is_active): """ Set close value line edit to enabled or disabled depending on is_active bool. """ self.logger.debug("running") self.__close_dur_line_edit.setEnabled(is_active) self.logger.debug("done") def get_close_inf(self): return self.__close_inf_check_box.isChecked() def set_close_inf(self, is_checked): """ Set close infinity checkbox state to is_checked. """ self.logger.debug("running") self.__close_inf_check_box.setChecked(is_checked) self.logger.debug("done") def get_debounce_val(self): return self.__debounce_time_line_edit.text() def set_debounce_val(self, val): """ Set debounce display value. """ self.logger.debug("running") self.__debounce_time_line_edit.setText(str(val)) self.logger.debug("done") def get_button_mode(self): return self.__button_mode_selector.currentIndex() def set_button_mode(self, val): """ Set display value of button mode. """ self.logger.debug("running") self.__button_mode_selector.setCurrentIndex(int(val)) self.logger.debug("done") def get_name(self): return self.device_info def __set_texts(self): self.logger.debug("running") self.__config_label.setText("Current configuration:") self.__config_val_line_edit.setText("DIRECT CONTROL") self.__nhtsa_button.setText("NHTSA") self.__eblindfold_button.setText("eBlindfold") self.__direct_control_button.setText("Direct Control") self.__open_dur_label.setText("Open Duration") self.__open_inf_check_box.setText("INF") self.__close_dur_label.setText("Close Duration") self.__close_inf_check_box.setText("INF") self.__debounce_label.setText("Debounce Time") self.__button_mode_label.setText("Button Mode") self.__button_mode_selector.setItemText(0, "Hold") self.__button_mode_selector.setItemText(1, "Click") self.__upload_settings_button.setText("Upload settings") self.__manual_control_button.setText("Toggle Lens") self.logger.debug("done") def __set_tooltips(self): self.logger.debug("running") self.__config_label.setToolTip("Current device configuration") self.__config_val_line_edit.setToolTip("Enter custom config name here") self.__config_val_line_edit.setPlaceholderText("Custom config name") self.__nhtsa_button.setToolTip("Set Device to NHTSA standard") self.__eblindfold_button.setToolTip("Set Device to eBlindfold mode") self.__direct_control_button.setToolTip( "Set Device to Direct Control mode") self.__button_mode_label.setToolTip("CHANGEME") self.__open_dur_label.setToolTip("Range: " + str(vog_min_open_close) + "-" + str(vog_max_open_close)) self.__close_dur_label.setToolTip("Range: " + str(vog_min_open_close) + "-" + str(vog_max_open_close)) self.__debounce_label.setToolTip("Range: " + str(vog_debounce_min) + "-" + str(vog_debounce_max)) self.__open_inf_check_box.setToolTip("Set to manual switching") self.__close_inf_check_box.setToolTip("Set to manual switching") self.__upload_settings_button.setToolTip( "Upload current configuration to device") self.__manual_control_button.setToolTip( "Manually open or close the lens") self.logger.debug("done")
class WidgetConfig(QGroupBox): def __init__(self): super(WidgetConfig, self).__init__() HEIGHT = 40 grid = QGridLayout() # 使用默认摄像头复选框 self.check_camera = QCheckBox('Use default camera') self.check_camera.setChecked(False) self.check_camera.stateChanged.connect(self.slot_check_camera) grid.addWidget(self.check_camera, 0, 0, 1, 3) # 一行三列 # 选择视频文件 label_video = QLabel('Detect File') self.line_video = QLineEdit() if 'video' in GLOBAL.config: self.line_video.setText(GLOBAL.config['video']) self.line_video.setFixedHeight(HEIGHT) self.line_video.setEnabled(False) self.line_video.editingFinished.connect( lambda: GLOBAL.record_config({'video': self.line_video.text()})) self.btn_video = QPushButton('Choose') self.btn_video.setFixedHeight(HEIGHT) self.btn_video.setEnabled(False) self.btn_video.clicked.connect(self.choose_video_file) self.slot_check_camera() grid.addWidget(label_video, 1, 0) grid.addWidget(self.line_video, 1, 1) grid.addWidget(self.btn_video, 1, 2) # 选择权重文件 label_weights = QLabel('Weights File') self.line_weights = QLineEdit() if 'weights' in GLOBAL.config: self.line_weights.setText(GLOBAL.config['weights']) self.line_weights.setFixedHeight(HEIGHT) self.line_weights.editingFinished.connect(lambda: GLOBAL.record_config( {'weights': self.line_weights.text()})) self.btn_weights = QPushButton('Choose') self.btn_weights.setFixedHeight(HEIGHT) self.btn_weights.clicked.connect(self.choose_weights_file) grid.addWidget(label_weights, 2, 0) grid.addWidget(self.line_weights, 2, 1) grid.addWidget(self.btn_weights, 2, 2) # 是否使用GPU label_device = QLabel('CUDA device') self.line_device = QLineEdit('gpu') if 'device' in GLOBAL.config: self.line_device.setText(GLOBAL.config['device']) else: self.line_device.setText('cpu') self.line_device.setPlaceholderText('cpu or 0 or 0,1,2,3') self.line_device.setFixedHeight(HEIGHT) self.line_device.editingFinished.connect( lambda: GLOBAL.record_config({'device': self.line_device.text()})) grid.addWidget(label_device, 3, 0) grid.addWidget(self.line_device, 3, 1, 1, 2) # 设置图像大小 label_size = QLabel('Img Size') self.combo_size = QComboBox() self.combo_size.setFixedHeight(HEIGHT) self.combo_size.setStyleSheet( 'QAbstractItemView::item {height: 40px;}') self.combo_size.setView(QListView()) self.combo_size.addItem('320', 320) self.combo_size.addItem('416', 416) self.combo_size.addItem('480', 480) self.combo_size.addItem('544', 544) self.combo_size.addItem('640', 640) self.combo_size.setCurrentIndex(2) self.combo_size.currentIndexChanged.connect( lambda: GLOBAL.record_config( {'img_size': self.combo_size.currentData()})) grid.addWidget(label_size, 4, 0) grid.addWidget(self.combo_size, 4, 1, 1, 2) #choose net camera label_stream = QLabel('NetVedioStream') self.combo_stream = QComboBox() self.combo_stream.setFixedHeight(HEIGHT) self.combo_stream.setStyleSheet( 'QAbstractItemView::item {height: 40px;}') self.combo_stream.setView(QListView()) self.combo_stream.addItem('rtsp://*****:*****@192.168.0.65/', 'rtsp://*****:*****@192.168.0.65/') self.combo_stream.addItem('rtsp://*****:*****@192.168.0.66/', 'rtsp://*****:*****@192.168.0.66/') self.combo_stream.addItem('rtsp://*****:*****@192.168.0.67/', 'rtsp://*****:*****@192.168.0.67/') self.combo_stream.addItem('rtsp://*****:*****@192.168.0.68/', 'rtsp://*****:*****@192.168.0.68/') self.combo_stream.addItem('rtsp://*****:*****@192.168.0.65/', 'rtsp://*****:*****@192.168.0.65/') self.combo_stream.setCurrentIndex(0) self.combo_stream.currentIndexChanged.connect( lambda: GLOBAL.record_config( {'netstreamvedio': self.combo_stream.currentData()})) grid.addWidget(label_stream, 5, 0) grid.addWidget(self.combo_stream, 5, 1, 1, 2) # 设置置信度阈值 label_conf = QLabel('Confidence') self.spin_conf = QDoubleSpinBox() self.spin_conf.setFixedHeight(HEIGHT) self.spin_conf.setDecimals(1) self.spin_conf.setRange(0.1, 0.9) self.spin_conf.setSingleStep(0.1) if 'conf_thresh' in GLOBAL.config: self.spin_conf.setValue(GLOBAL.config['conf_thresh']) else: self.spin_conf.setValue(0.4) # 默认值 GLOBAL.record_config({'conf_thresh': 0.4}) self.spin_conf.valueChanged.connect(lambda: GLOBAL.record_config( {'conf_thresh': round(self.spin_conf.value(), 1)})) grid.addWidget(label_conf, 6, 0) grid.addWidget(self.spin_conf, 6, 1, 1, 2) # 设置IOU阈值 label_iou = QLabel('IOU') self.spin_iou = QDoubleSpinBox() self.spin_iou.setFixedHeight(HEIGHT) self.spin_iou.setDecimals(1) self.spin_iou.setRange(0.1, 0.9) self.spin_iou.setSingleStep(0.1) if 'iou_thresh' in GLOBAL.config: self.spin_iou.setValue(GLOBAL.config['iou_thresh']) else: self.spin_iou.setValue(0.5) # 默认值 GLOBAL.record_config({'iou_thresh': 0.5}) self.spin_iou.valueChanged.connect(lambda: GLOBAL.record_config( {'iou_thresh': round(self.spin_iou.value(), 1)})) grid.addWidget(label_iou, 7, 0) grid.addWidget(self.spin_iou, 7, 1, 1, 2) # class-agnostic NMS self.check_agnostic = QCheckBox('Agnostic') if 'agnostic' in GLOBAL.config: self.check_agnostic.setChecked(GLOBAL.config['agnostic']) else: self.check_agnostic.setChecked(True) self.check_agnostic.stateChanged.connect(lambda: GLOBAL.record_config( {'agnostic': self.check_agnostic.isChecked()})) grid.addWidget(self.check_agnostic, 8, 0, 1, 3) # 一行三列 # augmented inference self.check_augment = QCheckBox('Augment') if 'augment' in GLOBAL.config: self.check_augment.setChecked(GLOBAL.config['augment']) else: self.check_augment.setChecked(True) self.check_augment.stateChanged.connect(lambda: GLOBAL.record_config( {'augment': self.check_augment.isChecked()})) grid.addWidget(self.check_augment, 9, 0, 1, 3) # 一行三列 self.setLayout(grid) # 设置布局 def slot_check_camera(self): check = self.check_camera.isChecked() GLOBAL.record_config({'use_camera': check}) # 保存配置 if check: self.line_video.setEnabled(False) self.btn_video.setEnabled(False) else: self.line_video.setEnabled(True) self.btn_video.setEnabled(True) def choose_weights_file(self): """从系统中选择权重文件""" file = QFileDialog.getOpenFileName( self, "Pre-trained YOLOv5 Weights", "./", "Weights Files (*.pt);;All Files (*)") if file[0] != '': self.line_weights.setText(file[0]) GLOBAL.record_config({'weights': file[0]}) def choose_video_file(self): """从系统中选择视频文件""" file = QFileDialog.getOpenFileName(self, "Video Files", "./", "Video Files (*)") if file[0] != '': self.line_video.setText(file[0]) GLOBAL.record_config({'video': file[0]}) def save_config(self): """保存当前的配置到配置文件""" config = { 'use_camera': self.check_camera.isChecked(), 'video': self.line_video.text(), 'weights': self.line_weights.text(), 'device': self.line_device.text(), 'img_size': self.combo_size.currentData(), 'conf_thresh': round(self.spin_conf.value(), 1), 'iou_thresh': round(self.spin_iou.value(), 1), 'agnostic': self.check_agnostic.isChecked(), 'augment': self.check_augment.isChecked(), 'netstreamvedio': self.combo_stream.currentData() } GLOBAL.record_config(config)
class LimitOptionsView(QWidget): """View which displays options for limiting they type of files to work with. Attributes: layout (QVBoxLayout): Main layout for view. frame (QFrame): Frame around limit options. frame_layout (QHBoxLayout): Layout associated with frame. title (QLabel): Title associated with view. limit_type_cb (QCheckBox): CheckBox which controls if view should be limited by file type. limit_type (QLineEdit): File type to limit to. search_cb (QCheckBox): CheckBox which controls if the view should limit by a search word. search (QLineEdit): Word to search for when renaming. """ def __init__(self): super(LimitOptionsView, self).__init__() self.layout = QVBoxLayout() self.title = QLabel(prefs.TITLE) self.frame_layout = QHBoxLayout() self.frame = QFrame() self.limit_type_cb = QCheckBox(prefs.LIMIT) self.limit_type = QLineEdit(prefs.LIMIT_DEFAULT) self.search_cb = QCheckBox(prefs.SEARCH) self.search = QLineEdit(prefs.SEARCH_DEFAULT) self._configure() def _configure(self) -> None: """Configure LimitOptionsView.""" self.frame.setLayout(self.frame_layout) self.layout.setAlignment(Qt.AlignLeft) self.limit_type_cb.setToolTip(prefs.LIMIT_TOOLTIP) self.search_cb.setToolTip(prefs.SEARCH_TOOLTIP) self.frame_layout.addWidget(self.limit_type_cb) self.frame_layout.addWidget(self.limit_type) self.frame_layout.addSpacerItem(QSpacerItem(*prefs.ITEM_SPACING)) self.frame_layout.addWidget(self.search_cb) self.frame_layout.addWidget(self.search) self.layout.addWidget(self.title) self.layout.addWidget(self.frame) self.setLayout(self.layout) def disable_limit_type(self) -> None: """Disable limit type functionality.""" self.limit_type.setDisabled(True) def disable_search(self) -> None: """Disable search functionality.""" self.search.setDisabled(True) def enable_limit_type(self) -> None: """Enable limit type functionality.""" self.limit_type.setEnabled(True) def enable_search(self) -> None: """Enable limit type functionality.""" self.limit_type.setEnabled(True) def get_limit_type(self) -> str: """Return the limit type.""" return str(self.limit_type.text()) def get_do_limit_type(self) -> bool: """Return if end user wants to limit the file type.""" return self.limit_type_cb.isChecked() def get_search(self) -> str: """Return the search value.""" return str(self.search.text()) def get_do_search(self) -> bool: """Return if the end user wants to limit files by a search.""" return self.search_cb.isChecked() def set_disabled(self) -> None: """Disable View.""" self.setDisabled(True) def set_enable(self) -> None: """Enable View.""" self.setEnabled(True) def set_limit_type(self, value: str) -> None: """Set the value in the limit type.""" self.limit_type.setText(value) def set_limit_type_style(self, style: str) -> None: """Set the style applied to limit type.""" self.limit_type.setStyleSheet(style) def set_search(self, value: str) -> None: """Set the value in the search.""" self.search.setText(value) def set_search_style(self, style: str) -> None: """Set the style applied to search.""" self.search.setStyleSheet(style)
class MuxSettingTab(QWidget): tab_clicked_signal = Signal() start_muxing_signal = Signal() update_task_bar_progress_signal = Signal(int) update_task_bar_paused_signal = Signal() update_task_bar_clear_signal = Signal() def __init__(self): super().__init__() self.create_widgets() self.setup_widgets() self.connect_signals() def connect_signals(self): self.tab_clicked_signal.connect(self.tab_clicked) self.destination_path_button.clicked.connect(self.open_select_destination_folder_dialog) self.only_keep_those_audios_checkBox.stateChanged.connect( self.only_keep_those_audios_multi_choose_comboBox.check_box_state_changed) self.only_keep_those_subtitles_checkBox.stateChanged.connect( self.only_keep_those_subtitles_multi_choose_comboBox.check_box_state_changed) self.make_this_audio_default_checkBox.disable_combo_box.connect(self.disable_make_this_audio_default_comboBox) self.make_this_subtitle_default_checkBox.disable_combo_box.connect( self.disable_make_this_subtitle_default_comboBox) self.control_queue_button.add_to_queue_clicked_signal.connect(self.add_to_queue_button_clicked) self.control_queue_button.start_multiplexing_clicked_signal.connect(self.start_multiplexing_button_clicked) self.control_queue_button.pause_multiplexing_clicked_signal.connect(self.pause_multiplexing_button_clicked) self.clear_job_queue_button.clicked.connect(self.clear_job_queue_button_clicked) self.only_keep_those_audios_multi_choose_comboBox.closeList.connect(self.only_keep_those_audios_close_list) self.only_keep_those_subtitles_multi_choose_comboBox.closeList.connect( self.only_keep_those_subtitles_close_list) self.make_this_audio_default_comboBox.currentTextChanged.connect( self.make_this_audio_default_comboBox_text_changed) self.make_this_subtitle_default_comboBox.currentTextChanged.connect( self.make_this_subtitle_default_comboBox_text_changed) self.abort_on_errors_checkBox.stateChanged.connect(self.abort_on_errors_state_changed) self.keep_log_file_checkBox.stateChanged.connect(self.keep_log_file_state_changed) self.job_queue_layout.update_task_bar_progress_signal.connect(self.update_task_bar_progress) self.job_queue_layout.paused_done_signal.connect(self.paused_done) self.job_queue_layout.cancel_done_signal.connect(self.cancel_done) self.job_queue_layout.finished_all_jobs_signal.connect(self.finished_all_jobs) self.job_queue_layout.pause_from_error_occurred_signal.connect(self.pause_multiplexing_button_clicked) def setup_widgets(self): self.setup_mux_setting_groupBox() self.setup_job_queue_groupBox() self.setup_destination_path_label() self.setup_destination_path_lineEdit() self.setup_destination_path_button() self.setup_abort_on_errors_checkBox() self.setup_discard_old_attachments_checkBox() self.setup_keep_log_file_checkBox() self.setup_clear_job_queue_button() self.setup_tool_tip_hint() self.setup_layouts() def setup_layouts(self): self.setup_MainLayout() self.mux_setting_groupBox.setLayout(self.mux_setting_layout) self.job_queue_groupBox.setLayout(self.job_queue_layout) self.setup_mux_tools_layout_first_row() self.setup_mux_tools_layout_second_row() self.setup_mux_setting_layout() self.setLayout(self.MainLayout) # noinspection PyAttributeOutsideInit def create_widgets(self): self.MainLayout = QVBoxLayout() self.mux_setting_groupBox = QGroupBox(self) self.job_queue_groupBox = QGroupBox(self) self.mux_setting_layout = QGridLayout() self.job_queue_layout = JobQueueLayout() self.destination_path_label = QLabel() self.destination_path_lineEdit = QLineEdit() self.destination_path_button = QPushButton() self.only_keep_those_audios_checkBox = OnlyKeepThoseAudiosCheckBox() self.only_keep_those_subtitles_checkBox = OnlyKeepThoseSubtitlesCheckBox() self.only_keep_those_audios_multi_choose_comboBox = AudioTracksCheckableComboBox() self.only_keep_those_subtitles_multi_choose_comboBox = SubtitleTracksCheckableComboBox() self.make_this_audio_default_checkBox = MakeThisAudioDefaultCheckBox() self.make_this_subtitle_default_checkBox = MakeThisSubtitleDefaultCheckBox() self.make_this_audio_default_comboBox = MakeThisTrackDefaultComboBox() self.make_this_subtitle_default_comboBox = MakeThisTrackDefaultComboBox() self.abort_on_errors_checkBox = QCheckBox() self.discard_old_attachments_checkBox = QCheckBox() self.keep_log_file_checkBox = QCheckBox() self.control_queue_button = ControlQueueButton() self.clear_job_queue_button = QPushButton() self.mux_tools_layout_first_row = QHBoxLayout() self.mux_tools_layout_second_row = QHBoxLayout() self.job_queue_tools_layout = QHBoxLayout() def setup_mux_setting_layout(self): self.mux_setting_layout.addWidget(self.destination_path_label, 0, 0) self.mux_setting_layout.addWidget(self.destination_path_lineEdit, 0, 1) self.mux_setting_layout.addWidget(self.destination_path_button, 0, 2) self.mux_setting_layout.addWidget(self.only_keep_those_audios_checkBox, 1, 0) self.mux_setting_layout.addWidget(self.only_keep_those_subtitles_checkBox, 2, 0) self.mux_setting_layout.addLayout(self.mux_tools_layout_first_row, 1, 1) self.mux_setting_layout.addLayout(self.mux_tools_layout_second_row, 2, 1) def setup_mux_tools_layout_first_row(self): self.mux_tools_layout_first_row.addWidget(self.only_keep_those_audios_multi_choose_comboBox, 2) self.mux_tools_layout_first_row.addWidget(self.make_this_audio_default_checkBox, 1) self.mux_tools_layout_first_row.addWidget(self.make_this_audio_default_comboBox, 2) self.mux_tools_layout_first_row.addWidget(self.abort_on_errors_checkBox, 1) self.mux_tools_layout_first_row.addWidget(self.keep_log_file_checkBox) def setup_mux_tools_layout_second_row(self): self.mux_tools_layout_second_row.addWidget(self.only_keep_those_subtitles_multi_choose_comboBox, 2) self.mux_tools_layout_second_row.addWidget(self.make_this_subtitle_default_checkBox, 1) self.mux_tools_layout_second_row.addWidget(self.make_this_subtitle_default_comboBox, 2) self.mux_tools_layout_second_row.addWidget(self.control_queue_button, 1) self.mux_tools_layout_second_row.addWidget(self.clear_job_queue_button, 1) def setup_clear_job_queue_button(self): self.clear_job_queue_button.setText("Clear All") self.clear_job_queue_button.setIcon(GlobalFiles.CleanIcon) self.clear_job_queue_button.setDisabled(True) def setup_keep_log_file_checkBox(self): self.keep_log_file_checkBox.setText("Keep Log File") self.keep_log_file_checkBox.setToolTip("log file will located in the source folder after finished muxing") def setup_discard_old_attachments_checkBox(self): self.discard_old_attachments_checkBox.setText("Discard Old Attachments ") def setup_abort_on_errors_checkBox(self): self.abort_on_errors_checkBox.setText("Abort On Errors") self.abort_on_errors_checkBox.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Preferred) def setup_destination_path_button(self): self.destination_path_button.setIcon(GlobalFiles.SelectFolderIcon) def setup_destination_path_lineEdit(self): self.destination_path_lineEdit.setPlaceholderText("Enter Destination Folder Path") self.destination_path_lineEdit.setClearButtonEnabled(True) def setup_destination_path_label(self): self.destination_path_label.setText("Videos Destination Folder :") def setup_MainLayout(self): self.MainLayout.addWidget(self.mux_setting_groupBox) self.MainLayout.addWidget(self.job_queue_groupBox) def setup_job_queue_groupBox(self): self.job_queue_groupBox.setTitle("Job Queue") def setup_mux_setting_groupBox(self): self.mux_setting_groupBox.setTitle("Mux Setting") def paintEvent(self, event: QPaintEvent): self.update_widgets_size() super().paintEvent(event) def resizeEvent(self, event: QResizeEvent): self.job_queue_layout.update_layout() super().resizeEvent(event) def update_widgets_size(self): self.only_keep_those_subtitles_multi_choose_comboBox.resize( self.only_keep_those_audios_multi_choose_comboBox.width(), self.only_keep_those_audios_multi_choose_comboBox.height(), ) self.make_this_subtitle_default_checkBox.resize( self.make_this_audio_default_checkBox.width(), self.make_this_audio_default_checkBox.height(), ) self.make_this_subtitle_default_checkBox.move( self.make_this_audio_default_checkBox.x(), self.make_this_subtitle_default_checkBox.y(), ) self.make_this_subtitle_default_comboBox.resize( self.make_this_audio_default_comboBox.width(), self.make_this_audio_default_comboBox.height(), ) self.make_this_subtitle_default_comboBox.move( self.make_this_audio_default_comboBox.x(), self.make_this_subtitle_default_comboBox.y(), ) self.control_queue_button.move( self.abort_on_errors_checkBox.x(), self.control_queue_button.y(), ) self.clear_job_queue_button.move( self.control_queue_button.x() + self.control_queue_button.width() + 5, self.clear_job_queue_button.y(), ) def open_select_destination_folder_dialog(self): temp_folder_path = QFileDialog.getExistingDirectory(self, caption="Choose Destination Folder", dir=GlobalSetting.LAST_DIRECTORY_PATH, ) if temp_folder_path == "" or temp_folder_path.isspace(): return elif Path(temp_folder_path) == Path(GlobalSetting.VIDEO_SOURCE_PATH): invalid_dialog = InvalidPathDialog( error_message="Source and destination videos can't be in the same folder") invalid_dialog.execute() return else: self.destination_path_lineEdit.setText(str(Path(temp_folder_path))) GlobalSetting.LAST_DIRECTORY_PATH = self.destination_path_lineEdit.text() GlobalSetting.DESTINATION_FOLDER_PATH = self.destination_path_lineEdit.text() def check_destination_path(self): temp_destination_path = self.destination_path_lineEdit.text() try: if temp_destination_path == "" or temp_destination_path.isspace(): temp_destination_path = "[Empty Path]" raise Exception( "[WinError 998] Empty path is Not a valid path : " + temp_destination_path) # check if system is windows so path must have # SOME_LETTER:\ if os.name == 'nt': if temp_destination_path[1:3] != ":\\" and self.destination_path_lineEdit.text()[ 1:3] != ":/": raise Exception("[WinError 999] Not a valid path : " + temp_destination_path) makedirs(temp_destination_path, exist_ok=True) ## test if i can write into this path: test_file_name = str(time.time()) + ".txt" test_file_name_absolute = os.path.join(Path(temp_destination_path), Path(test_file_name)) try: with open(test_file_name_absolute, 'w+') as test_file: test_file.write("Test") os.remove(test_file_name_absolute) except Exception as e: write_to_log_file(e) invaild_dialog = InvalidPathDialog(window_title="Permission Denied", error_message="MKV Muxing Batch GUI lacks write " "permissions on Destination folder") invaild_dialog.execute() self.destination_path_lineEdit.setText(GlobalSetting.DESTINATION_FOLDER_PATH) return False except Exception as e: write_to_log_file(e) error_message = "" if temp_destination_path == "[Empty Path]": error_message = "Enter a valid destination path" else: error_message = temp_destination_path + "\nisn't a valid path!" invalid_dialog = InvalidPathDialog(error_message=error_message) invalid_dialog.execute() self.destination_path_lineEdit.setText(GlobalSetting.DESTINATION_FOLDER_PATH) return False if Path(temp_destination_path) == Path(GlobalSetting.VIDEO_SOURCE_PATH): invalid_dialog = InvalidPathDialog( error_message="Source and destination videos can't be in the same folder") invalid_dialog.execute() self.destination_path_lineEdit.setText(GlobalSetting.DESTINATION_FOLDER_PATH) return False GlobalSetting.DESTINATION_FOLDER_PATH = temp_destination_path return True def setup_tool_tip_hint(self): self.only_keep_those_subtitles_multi_choose_comboBox.set_tool_tip_hint() self.only_keep_those_audios_multi_choose_comboBox.set_tool_tip_hint() self.make_this_subtitle_default_checkBox.set_tool_tip_hint_no_check() self.make_this_audio_default_checkBox.set_tool_tip_hint_no_check() def add_to_queue_button_clicked(self): self.job_queue_layout.setup_queue() self.enable_muxing_setting() if not GlobalSetting.JOB_QUEUE_EMPTY: self.disable_editable_widgets() self.control_queue_button.set_state_start_multiplexing() self.clear_job_queue_button.setDisabled(False) change_global_LogFilePath() else: self.enable_editable_widgets() self.setup_enable_options_for_mkv_only_options() def tab_clicked(self): self.job_queue_layout.show_necessary_table_columns() self.setup_enable_options_for_mkv_only_options() def setup_enable_options_for_mkv_only_options(self): if GlobalSetting.JOB_QUEUE_EMPTY: if GlobalSetting.VIDEO_SOURCE_MKV_ONLY: self.only_keep_those_audios_checkBox.setEnabled(True) self.only_keep_those_subtitles_checkBox.setEnabled(True) self.make_this_audio_default_checkBox.setEnabled(True) self.make_this_subtitle_default_checkBox.setEnabled(True) self.only_keep_those_audios_checkBox.setToolTip("") self.only_keep_those_subtitles_checkBox.setToolTip("") self.make_this_audio_default_comboBox.setToolTip("") self.make_this_subtitle_default_comboBox.setToolTip("") self.setup_tool_tip_hint() else: self.only_keep_those_subtitles_checkBox.setCheckState(Qt.Unchecked) self.only_keep_those_audios_checkBox.setCheckState(Qt.Unchecked) self.make_this_audio_default_checkBox.setCheckState(Qt.Unchecked) self.make_this_subtitle_default_checkBox.setCheckState(Qt.Unchecked) self.only_keep_those_audios_checkBox.setEnabled(False) self.only_keep_those_subtitles_checkBox.setEnabled(False) self.make_this_audio_default_checkBox.setEnabled(False) self.make_this_subtitle_default_checkBox.setEnabled(False) self.only_keep_those_audios_checkBox.setToolTip("<b>[Disabled]</b> Only works when video files " "are Mkv only") self.only_keep_those_subtitles_checkBox.setToolTip("<b>[Disabled]</b> Only works when video files " "are Mkv only") self.make_this_audio_default_checkBox.setToolTip("<b>[Disabled]</b> Only works when video files " "are Mkv only") self.make_this_subtitle_default_checkBox.setToolTip("<b>[Disabled]</b> Only works when video files " "are Mkv only") self.make_this_audio_default_comboBox.setToolTip("<b>[Disabled]</b> Only works when video files " "are Mkv only") self.make_this_subtitle_default_comboBox.setToolTip("<b>[Disabled]</b> Only works when video files " "are Mkv only") self.only_keep_those_audios_multi_choose_comboBox.setToolTip( "<b>[Disabled]</b> Only works when video files " "are Mkv only") self.only_keep_those_subtitles_multi_choose_comboBox.setToolTip( "<b>[Disabled]</b> Only works when video files " "are Mkv only") def clear_job_queue_button_clicked(self): self.job_queue_layout.clear_queue() self.control_queue_button.set_state_add_to_queue() self.clear_job_queue_button.setDisabled(True) self.control_queue_button.setDisabled(False) self.enable_editable_widgets() self.enable_muxing_setting() self.setup_enable_options_for_mkv_only_options() self.update_task_bar_clear_signal.emit() def disable_editable_widgets(self): self.only_keep_those_subtitles_checkBox.setEnabled(False) self.only_keep_those_subtitles_multi_choose_comboBox.setEnabled(False) self.only_keep_those_audios_checkBox.setEnabled(False) self.only_keep_those_audios_multi_choose_comboBox.setEnabled(False) self.make_this_subtitle_default_checkBox.setEnabled(False) self.make_this_subtitle_default_comboBox.setEnabled(False) self.make_this_audio_default_checkBox.setEnabled(False) self.make_this_audio_default_comboBox.setEnabled(False) def enable_editable_widgets(self): self.only_keep_those_subtitles_checkBox.setEnabled(True) self.only_keep_those_subtitles_multi_choose_comboBox.setEnabled( self.only_keep_those_subtitles_checkBox.isChecked()) self.only_keep_those_audios_checkBox.setEnabled(True) self.only_keep_those_audios_multi_choose_comboBox.setEnabled(self.only_keep_those_audios_checkBox.isChecked()) self.make_this_subtitle_default_checkBox.setEnabled(True) self.make_this_subtitle_default_comboBox.setEnabled(self.make_this_subtitle_default_checkBox.isChecked()) self.make_this_audio_default_checkBox.setEnabled(True) self.make_this_audio_default_comboBox.setEnabled(self.make_this_audio_default_checkBox.isChecked()) def only_keep_those_audios_close_list(self): GlobalSetting.MUX_SETTING_ONLY_KEEP_THOSE_AUDIOS_LANGUAGES = self.only_keep_those_audios_multi_choose_comboBox.languages GlobalSetting.MUX_SETTING_ONLY_KEEP_THOSE_AUDIOS_TRACKS = self.only_keep_those_audios_multi_choose_comboBox.tracks def only_keep_those_subtitles_close_list(self): GlobalSetting.MUX_SETTING_ONLY_KEEP_THOSE_SUBTITLES_LANGUAGES = self.only_keep_those_subtitles_multi_choose_comboBox.languages GlobalSetting.MUX_SETTING_ONLY_KEEP_THOSE_SUBTITLES_TRACKS = self.only_keep_those_subtitles_multi_choose_comboBox.tracks def disable_make_this_subtitle_default_comboBox(self, state): self.make_this_subtitle_default_comboBox.setDisabled(state) if state: self.make_this_subtitle_default_comboBox.setCurrentIndex(-1) def disable_make_this_audio_default_comboBox(self, state): self.make_this_audio_default_comboBox.setDisabled(state) if state: self.make_this_audio_default_comboBox.setCurrentIndex(-1) def make_this_audio_default_comboBox_text_changed(self): GlobalSetting.MUX_SETTING_MAKE_THIS_AUDIO_DEFAULT_TRACK = str( self.make_this_audio_default_comboBox.currentText()) def make_this_subtitle_default_comboBox_text_changed(self): GlobalSetting.MUX_SETTING_MAKE_THIS_SUBTITLE_DEFAULT_TRACK = str( self.make_this_subtitle_default_comboBox.currentText()) def update_task_bar_progress(self, new_progress): self.update_task_bar_progress_signal.emit(new_progress) def enable_muxing_setting(self): self.destination_path_lineEdit.setEnabled(True) self.destination_path_button.setEnabled(True) self.abort_on_errors_checkBox.setEnabled(True) self.keep_log_file_checkBox.setEnabled(True) def disable_muxing_setting(self): self.destination_path_lineEdit.setEnabled(False) self.destination_path_button.setEnabled(False) self.abort_on_errors_checkBox.setEnabled(False) self.keep_log_file_checkBox.setEnabled(False) @staticmethod def abort_on_errors_state_changed(state): GlobalSetting.MUX_SETTING_ABORT_ON_ERRORS = bool(state) @staticmethod def keep_log_file_state_changed(state): GlobalSetting.MUX_SETTING_KEEP_LOG_FILE = bool(state) def start_multiplexing_button_clicked(self): at_least_one_muxing_setting_has_been_selected = check_if_at_least_one_muxing_setting_has_been_selected() if at_least_one_muxing_setting_has_been_selected: destination_path_valid = self.check_destination_path() if destination_path_valid: self.setup_log_file() self.control_queue_button.set_state_pause_multiplexing() self.disable_muxing_setting() self.job_queue_layout.start_muxing() self.start_muxing_signal.emit() self.clear_job_queue_button.setDisabled(True) def pause_multiplexing_button_clicked(self): self.job_queue_layout.pause_muxing() self.control_queue_button.setDisabled(True) self.control_queue_button.set_state_pausing_multiplexing() def paused_done(self): self.control_queue_button.set_state_resume_multiplexing() self.clear_job_queue_button.setDisabled(False) self.control_queue_button.setDisabled(False) self.update_task_bar_paused_signal.emit() def cancel_done(self): self.disable_editable_widgets() self.enable_muxing_setting() self.control_queue_button.set_state_start_multiplexing() self.clear_job_queue_button.setDisabled(False) change_global_LogFilePath() def finished_all_jobs(self): self.enable_editable_widgets() self.enable_muxing_setting() self.setup_enable_options_for_mkv_only_options() self.control_queue_button.set_state_start_multiplexing() self.control_queue_button.setDisabled(True) self.clear_job_queue_button.setDisabled(False) self.update_task_bar_clear_signal.emit() GlobalSetting.JOB_QUEUE_EMPTY = True check_if_want_to_keep_log_file() def setup_log_file(self): if self.control_queue_button.state == "START": open(GlobalFiles.LogFilePath, 'w+').close()
class Form(QDialog): def __init__(self, parent=None): super(Form, self).__init__(parent) self.setWindowTitle('RetroUFO') # Create widgets self.chkboxPlatformDetect = QCheckBox('Platform Auto-Detect') self.chkboxPlatformDetect.setChecked(True) self.chkboxPlatformDetect.stateChanged.connect(self.auto_detect) self.cmbboxPlatform = QComboBox() self.cmbboxPlatform.setEnabled(False) self.cmbboxPlatform.setEditable(False) self.cmbboxPlatform.addItem('Linux') self.cmbboxPlatform.addItem('macOS') self.cmbboxPlatform.addItem('Windows') self.cmbboxArchitecture = QComboBox() self.cmbboxArchitecture.setEnabled(False) self.cmbboxArchitecture.setEditable(False) self.cmbboxArchitecture.addItem('x86') self.cmbboxArchitecture.addItem('x86_64') self.chkboxLocationDetect = QCheckBox('Core Location Auto-Detect') self.chkboxLocationDetect.setChecked(True) self.chkboxLocationDetect.stateChanged.connect(self.auto_location) self.leditCoreLocation = QLineEdit('') self.leditCoreLocation.setEnabled(False) self.btnCoreLocation = QPushButton('...') self.btnCoreLocation.setEnabled(False) self.btnCoreLocation.clicked.connect(self.choose_location) self.teditLog = QTextEdit() self.teditLog.setReadOnly(True) self.tcsrLog = QTextCursor(self.teditLog.document()) self.chkboxKeepDownload = QCheckBox('Keep Downloaded Cores') self.chkboxKeepDownload.setChecked(False) self.btnGrabCores = QPushButton('Grab Cores') self.btnGrabCores.clicked.connect(self.grab_cores) # Create layout and add widgets self.formLayout = QVBoxLayout() self.formLayout.addWidget(self.chkboxPlatformDetect) self.formLayout.addWidget(self.cmbboxPlatform) self.formLayout.addWidget(self.cmbboxArchitecture) self.formLayout.addWidget(self.chkboxLocationDetect) self.formLayout.addWidget(self.leditCoreLocation) self.formLayout.addWidget(self.btnCoreLocation) self.formLayout.addWidget(self.teditLog) self.formLayout.addWidget(self.chkboxKeepDownload) self.formLayout.addWidget(self.btnGrabCores) # Set dialog layout self.setLayout(self.formLayout) def auto_detect(self): if self.chkboxPlatformDetect.isChecked(): self.cmbboxPlatform.setEnabled(False) self.cmbboxArchitecture.setEnabled(False) else: self.cmbboxPlatform.setEnabled(True) self.cmbboxArchitecture.setEnabled(True) def auto_location(self): if self.chkboxLocationDetect.isChecked(): self.leditCoreLocation.setEnabled(False) self.btnCoreLocation.setEnabled(False) else: self.leditCoreLocation.setEnabled(True) self.btnCoreLocation.setEnabled(True) def choose_location(self): directory = QFileDialog.getExistingDirectory(self, 'Choose Target Location', os.path.expanduser('~')) self.leditCoreLocation.insert(directory) def update_log(self, _info): self.teditLog.insertPlainText('{}\n'.format(_info)) # Auto scrolling on log UI self.teditLog.moveCursor(QTextCursor.End) def lock_ui(self, _lock): # Cycle through each widget and disable it except for log UI widgets = (self.formLayout.itemAt(i).widget() for i in range(self.formLayout.count())) for widget in widgets: if isinstance(widget, QTextEdit): pass else: widget.setDisabled(_lock) # Have to run these to make sure only the correct things unlock after grab thread self.auto_detect() self.auto_location() def grab_cores(self): """ Where the magic happens """ if not self.chkboxKeepDownload.isChecked(): self.clean_up() target_platform = self.get_platform() architecture = self.get_architecture() location = self.get_location() self.grab = GrabThread(target_platform, architecture, location) self.grab.add_to_log.connect(self.update_log) self.grab.lock.connect(self.lock_ui) self.grab.start() def get_platform(self): """ Gets the Platform and Architecture if not supplied """ if not self.chkboxPlatformDetect.isChecked(): if self.cmbboxPlatform.currentText() == 'macOS': return 'apple/osx' # macOS else: return self.cmbboxPlatform.currentText().lower() else: if platform.system() == 'Linux': return 'linux' elif platform.system() == 'Darwin': # macOS return 'apple/osx' elif platform.system( ) == 'Windows' or 'MSYS_NT' in platform.system( ): # Checks for MSYS environment as well return 'windows' else: msgBox = QMessageBox.warning( self, 'Error', 'Platform not found or supported!', QMessageBox.Ok) msgBox.exec_() def get_architecture(self): """ Gets the Platform and Architecture if not supplied """ if '64' in platform.architecture()[0]: return 'x86_64' elif '32' in platform.architecture()[0]: return 'x86' else: msgBox = QMessageBox.warning( self, 'Error', 'Architecture not found or supported', QMessageBox.Ok) msgBox.exec_() def get_location(self): if not self.chkboxLocationDetect.isChecked(): return self.leditCoreLocation.text() else: return CORE_LOCATION[self.get_platform()] def clean_up(self): """ Removes all the downloaded files """ if os.path.isdir('cores'): rmtree('cores/')
class BrowserWin(QWidget): def __init__(self, *args, **kwargs): super(BrowserWin, self).__init__(*args, **kwargs) # parent Maya window self.setParent(mainWindow) self.setWindowFlags(Qt.Window) # Window settings self.setWindowTitle('AC_AssetBrowser') # Build window self.mainLayout = QVBoxLayout() self.btnLayout = QHBoxLayout() self.radioLayout = QHBoxLayout() # radio buttons load import self.radioLabel = QLabel("Action: ") self.importRadioBtn = QRadioButton("Import File") self.openRadioBtn = QRadioButton("Open File") self.saveRadioBtn = QRadioButton("Save File") # Find asset directories to load from and populate the drop down self.fileType = QComboBox() self.__populate_list(self.fileType) self.curr_cat = self.fileType.currentText() # list of assets in self.list self.fileList = QListWidget() self.fileList.setSelectionMode(QAbstractItemView.ExtendedSelection) self.__populate_list(self.fileList, directory=os.path.join(DIRECTORY, self.curr_cat)) self.fileName = QLineEdit() self.loadBtn = QPushButton("Load Asset") self.publishBtn = QPushButton("Publish") self.closeBtn = QPushButton("Close") # Add widgets to layouts self.radioLayout.addWidget(self.radioLabel) self.radioLayout.addWidget(self.importRadioBtn) self.radioLayout.addWidget(self.openRadioBtn) self.radioLayout.addWidget(self.saveRadioBtn) self.mainLayout.addLayout(self.radioLayout) self.mainLayout.addWidget(self.fileType) self.mainLayout.addWidget(self.fileList) self.mainLayout.addWidget(self.fileName) self.btnLayout.addWidget(self.loadBtn) self.btnLayout.addWidget(self.publishBtn) self.btnLayout.addWidget(self.closeBtn) self.mainLayout.addLayout(self.btnLayout) self.setLayout(self.mainLayout) # Set state of widgets self.importRadioBtn.toggle() self.fileName.setPlaceholderText("file_name") self.fileName.setEnabled(False) self.publishBtn.setEnabled(False) # Signals self.fileType.currentIndexChanged.connect(self.selectionChanged) self.loadBtn.clicked.connect(self.loadBtnCmd) self.publishBtn.clicked.connect(self.publishBtnCmd) self.closeBtn.clicked.connect(self.closeBtnCmd) self.importRadioBtn.toggled.connect(self.onImportToggled) self.openRadioBtn.toggled.connect(self.onOpenToggled) self.saveRadioBtn.toggled.connect(self.onSaveToggled) def __populate_list(self, destination, directory=DIRECTORY): _dirs = os.listdir(directory) _items = [_dir for _dir in _dirs] return destination.addItems(_items) def selectionChanged(self): self.curr_cat = self.fileType.currentText() self.fileList.clear() self.__populate_list(self.fileList, directory=os.path.join(DIRECTORY, self.curr_cat)) def loadBtnCmd(self): if self.importRadioBtn.isChecked(): selected_files = self.fileList.selectedItems() for _file in selected_files: asset_file = os.path.join(DIRECTORY, self.curr_cat, _file.text()) cmds.file(asset_file, i=True) elif self.openRadioBtn.isChecked(): selected_file = self.fileList.currentItem() asset_file = os.path.join(DIRECTORY, self.curr_cat, selected_file.text()) cmds.file(asset_file, o=True, force=True) else: print("Did you mean to publish this asset?") def publishBtnCmd(self): if self.saveRadioBtn.isChecked() and self.fileName.text() is not None: path_to_save = os.path.join(DIRECTORY, self.curr_cat, self.fileName.text()) cmds.file(rn="{}.ma".format(path_to_save)) cmds.file(save=True) self.fileList.clear() self.__populate_list(self.fileList, directory=os.path.join( DIRECTORY, self.curr_cat)) def closeBtnCmd(self): self.close() def onSaveToggled(self): items = self.fileList.selectedItems() for item in items: item.setSelected(False) self.fileName.setEnabled(not self.fileName.isEnabled()) self.publishBtn.setEnabled(not self.publishBtn.isEnabled()) def onImportToggled(self): if self.importRadioBtn.isChecked(): self.fileList.setSelectionMode(QAbstractItemView.ExtendedSelection) def onOpenToggled(self): if self.openRadioBtn.isChecked(): items = self.fileList.selectedItems() items.pop() for item in items: item.setSelected(False) self.fileList.setSelectionMode(QAbstractItemView.SingleSelection)
class VideoDeck(QWidget): def __init__(self, vlc_instance=None): QWidget.__init__(self) self.layout = QHBoxLayout() self.setAcceptDrops(True) self.loaded_video = None self.vlc_instance = vlc_instance self.file_picker_field = FilePicker() self.info_layout = QGridLayout() vod_filepath_label = QLabel("VOD Filepath") id_twitch_label = QLabel("ID Twitch") created_at_label = QLabel("Created at") duration_label = QLabel("Duration") title_label = QLabel("Title") streamer_label = QLabel("Streamer") self.id_twitch_field = QLineEdit() self.created_at_field = QLineEdit() self.duration_field = QLineEdit() self.title_field = QLineEdit() self.streamer_field = QLineEdit() self.id_twitch_field.setEnabled(False) self.created_at_field.setEnabled(False) self.duration_field.setEnabled(False) self.title_field.setEnabled(False) self.streamer_field.setEnabled(False) self.info_layout.addWidget(vod_filepath_label, 0, 0) self.info_layout.addWidget(id_twitch_label, 1, 0) self.info_layout.addWidget(created_at_label, 2, 0) self.info_layout.addWidget(duration_label, 3, 0) self.info_layout.addWidget(title_label, 4, 0) self.info_layout.addWidget(streamer_label, 5, 0) self.info_layout.addWidget(self.file_picker_field, 0, 1) self.info_layout.addWidget(self.id_twitch_field, 1, 1) self.info_layout.addWidget(self.created_at_field, 2, 1) self.info_layout.addWidget(self.duration_field, 3, 1) self.info_layout.addWidget(self.title_field, 4, 1) self.info_layout.addWidget(self.streamer_field, 5, 1) self.layout.addLayout(self.info_layout) self.file_picker_field.changed.connect(self.on_video_url_changed) self.setLayout(self.layout) def load_video_url(self, url=None): self.file_picker_field.file_path_field.setText( "" if url is None else url) if url: self.loaded_video = InputVideo() if re.search(r"^(?:/|[a-z]:[\\/])", url, re.I): video_url = "file://" + url self.loaded_video.is_local = True elif url.lower().startswith("file://"): video_url = url self.loaded_video.is_local = True else: video_url = url def find_suitable_stream(streams): best_stream = streams.get("best", None) if best_stream: if type(best_stream) is MuxedStream: return best_stream.substreams[0].url else: return best_stream.url else: raise Exception(f"<!!> Can't find best stream") if not self.loaded_video.is_local: try: streams = streamlink.streams(video_url) except streamlink.exceptions.PluginError as e: print(f"<!!> Error while loading video {video_url} : {e}") return if streams: self.loaded_video.video_url = find_suitable_stream( streams) #streams["best"] else: self.loaded_video.video_url = video_url else: self.loaded_video.video_url = video_url if "twitch.tv" in video_url: try: self.loaded_video.metadatas["service"] = "twitch" self.update_twitch_metadatas() except requests.exceptions.ConnectionError: print("<!!> Can't connect to Twitch API.") elif "youtube.com" in video_url: try: self.loaded_video.metadatas["service"] = "youtube" self.update_youtube_metadatas() except requests.exceptions.ConnectionError: print("<!!> Can't connect to Youtube API.") try: self.vlc_instance.open_url(self.loaded_video.video_url) except requests.exceptions.ConnectionError: print("<!!> Can't connect to local VLC instance.") def seek(self, time): self.vlc_instance.set_current_time(time) def get_service_metadatas(self): pass def get_youtube_id_from_url(self): url = self.file_picker_field.file_path_field.text() # Ressource pour plus tard : https://webapps.stackexchange.com/questions/54443/format-for-id-of-youtube-video parsed_url = re.search("v=([0-9A-Za-z_-]+)", url, re.I) if parsed_url: video_id = parsed_url.group(1) return video_id else: raise Exception( f"<!!> Can't find video Youtube id in video url ({url})") def get_twitch_id_from_url(self): filename = self.file_picker_field.file_path_field.text() parsed_filename = re.search("([0-9]+)\.mp4$", filename, re.I) if parsed_filename: video_id = parsed_filename.group(1) return int(video_id) else: parsed_url = re.search("videos/([0-9]+)", filename, re.I) if parsed_url: video_id = parsed_url.group(1) return int(video_id) else: raise Exception( f"<!!> Can't find video Twitch id in video filename ({filename})" ) def update_youtube_metadatas(self): self.loaded_video.metadatas["id"] = self.get_youtube_id_from_url() self.id_twitch_field.setText(self.loaded_video.metadatas["id"]) def update_twitch_metadatas(self): twitch_video_id = self.get_twitch_id_from_url() metadatas = self.topLevelWidget( ).twitch_interface.get_twitch_metadatas(twitch_video_id) self.loaded_video.metadatas = metadatas duration = parse_duration(metadatas["duration"]) self.id_twitch_field.setText(metadatas["id"]) self.created_at_field.setText(str(metadatas["created_at"])) self.duration_field.setText(format_time(duration.seconds)) self.title_field.setText(metadatas["title"]) self.streamer_field.setText(metadatas["user_login"]) def on_video_url_changed(self): self.load_video_url(self.file_picker_field.file_path_field.text()) def dragEnterEvent(self, event: PySide2.QtGui.QDragEnterEvent) -> None: if event.mimeData().hasUrls: event.accept() else: event.ignore() def dragMoveEvent(self, event): if event.mimeData().hasUrls: event.setDropAction(Qt.CopyAction) event.accept() else: event.ignore() def dropEvent(self, event: PySide2.QtGui.QDropEvent) -> None: if event.mimeData().hasUrls: event.setDropAction(Qt.CopyAction) event.accept() if len(event.mimeData().urls()) > 0: url = event.mimeData().urls()[0] self.load_video_url(url.url()) else: event.ignore()
class LayoutDialog(QMainWindow): def __init__(self, parent): super().__init__(parent) self.setWindowTitle("Layout for " + parent.name) self.setWindowFlags(QtCore.Qt.Window | QtCore.Qt.CustomizeWindowHint | QtCore.Qt.WindowTitleHint | QtCore.Qt.WindowCloseButtonHint) self.resize(600, 600) self.parent = parent self.onlyInt = QtGui.QIntValidator() all_fonts = [ "Arial", "Balto", "Courier New", "Droid Sans", "Droid Serif", "Droid Sans Mono", "Gravitas One", "Old Standard TT", "Open Sans", "Overpass", "PT Sans Narrow", "Raleway", "Times New Roman" ] self.bt_uplayout = QPushButton('Update layout') self.bt_uplayout.setIcon(self.style().standardIcon( QStyle.SP_BrowserReload)) self.bt_uplayout.clicked.connect(self.layout_update) self.hbox = QHBoxLayout() self.hbox.addWidget(self.bt_uplayout) self.hbox.addWidget(QWidget()) self.hbox.addStretch() # Overal Layout parameters self.lbl_layhover = QLabel('hovermode:') self.combo_layhover = QComboBox() self.combo_layhover.addItem('closest') self.combo_layhover.addItem('x') self.combo_layhover.addItem('y') self.combo_layhover.addItem('False') self.chk_layautosize = QCheckBox('autosize') self.chk_layautosize.setChecked(True) self.chk_layautosize.stateChanged.connect(self.toggle_enable_fields) self.lbl_laywidth = QLabel('width:') self.lin_laywidth = QLineEdit('700') self.lin_laywidth.setValidator(self.onlyInt) self.lbl_layheight = QLabel('height:') self.lin_layheight = QLineEdit('450') self.lin_layheight.setValidator(self.onlyInt) self.lbl_layfont = QLabel('font:') self.combo_layfont = QComboBox() for ft in all_fonts: self.combo_layfont.addItem(ft) self.lin_layfont = QLineEdit('10') self.lin_layfont.setValidator(self.onlyInt) self.lbl_layfontc = QLabel('font color (r,g,b,a):') self.btn_layfontc = QPushButton('Pick') self.btn_layfontc.clicked.connect( lambda: self.choose_color(target='layout_font')) self.lin_layfontr = QLineEdit('0') self.lin_layfontr.setValidator(self.onlyInt) self.lin_layfontg = QLineEdit('0') self.lin_layfontg.setValidator(self.onlyInt) self.lin_layfontb = QLineEdit('0') self.lin_layfontb.setValidator(self.onlyInt) self.lin_layfonta = QLineEdit('255') self.lin_layfonta.setValidator(self.onlyInt) self.lbl_laypaperc = QLabel('paper color (r,g,b,a):') self.btn_laypaperc = QPushButton('Pick') self.btn_laypaperc.clicked.connect( lambda: self.choose_color(target='layout_paper')) self.lin_laypaperr = QLineEdit('255') self.lin_laypaperr.setValidator(self.onlyInt) self.lin_laypaperg = QLineEdit('255') self.lin_laypaperg.setValidator(self.onlyInt) self.lin_laypaperb = QLineEdit('255') self.lin_laypaperb.setValidator(self.onlyInt) self.lin_laypapera = QLineEdit('255') self.lin_laypapera.setValidator(self.onlyInt) self.lbl_layplotc = QLabel('plot_bg color (r,g,b,a):') self.btn_layplotc = QPushButton('Pick') self.btn_layplotc.clicked.connect( lambda: self.choose_color(target='layout_plot')) self.lin_layplotr = QLineEdit('255') self.lin_layplotr.setValidator(self.onlyInt) self.lin_layplotg = QLineEdit('255') self.lin_layplotg.setValidator(self.onlyInt) self.lin_layplotb = QLineEdit('255') self.lin_layplotb.setValidator(self.onlyInt) self.lin_layplota = QLineEdit('255') self.lin_layplota.setValidator(self.onlyInt) self.chk_legend = QCheckBox('show legend') self.chk_legend.setChecked(True) self.general_grid = QGridLayout() self.general_grid.setColumnStretch(7, 1) self.general_grid.addWidget(self.lbl_layhover, 0, 0, 1, 1) self.general_grid.addWidget(self.combo_layhover, 0, 1, 1, 1) self.general_grid.addWidget(self.chk_layautosize, 1, 0, 1, 1) self.general_grid.addWidget(self.lbl_laywidth, 2, 0, 1, 1) self.general_grid.addWidget(self.lin_laywidth, 2, 1, 1, 1) self.general_grid.addWidget(self.lbl_layheight, 3, 0, 1, 1) self.general_grid.addWidget(self.lin_layheight, 3, 1, 1, 1) self.general_grid.addWidget(self.lbl_layfont, 4, 0, 1, 1) self.general_grid.addWidget(self.lin_layfont, 4, 1, 1, 1) self.general_grid.addWidget(self.combo_layfont, 4, 2, 1, 2) self.general_grid.addWidget(self.lbl_layfontc, 5, 0, 1, 1) self.general_grid.addWidget(self.lin_layfontr, 5, 1, 1, 1) self.general_grid.addWidget(self.lin_layfontg, 5, 2, 1, 1) self.general_grid.addWidget(self.lin_layfontb, 5, 3, 1, 1) self.general_grid.addWidget(self.lin_layfonta, 5, 4, 1, 1) self.general_grid.addWidget(self.btn_layfontc, 5, 5, 1, 1) self.general_grid.addWidget(self.lbl_laypaperc, 6, 0, 1, 1) self.general_grid.addWidget(self.lin_laypaperr, 6, 1, 1, 1) self.general_grid.addWidget(self.lin_laypaperg, 6, 2, 1, 1) self.general_grid.addWidget(self.lin_laypaperb, 6, 3, 1, 1) self.general_grid.addWidget(self.lin_laypapera, 6, 4, 1, 1) self.general_grid.addWidget(self.btn_laypaperc, 6, 5, 1, 1) self.general_grid.addWidget(self.lbl_layplotc, 7, 0, 1, 1) self.general_grid.addWidget(self.lin_layplotr, 7, 1, 1, 1) self.general_grid.addWidget(self.lin_layplotg, 7, 2, 1, 1) self.general_grid.addWidget(self.lin_layplotb, 7, 3, 1, 1) self.general_grid.addWidget(self.lin_layplota, 7, 4, 1, 1) self.general_grid.addWidget(self.btn_layplotc, 7, 5, 1, 1) self.general_grid.addWidget(self.chk_legend, 8, 0, 1, 1) self.general_grid.addWidget(QWidget(), 9, 0, 1, 7) self.general_group = CollapsibleBox(title='General', parent=self) self.general_group.setContentLayout(self.general_grid) # Title parameters self.lbl_titletext = QLabel('text:') self.lin_titletext = QLineEdit('') self.lbl_titlefont = QLabel('font:') self.combo_titlefont = QComboBox() for ft in all_fonts: self.combo_titlefont.addItem(ft) self.lin_titlefont = QLineEdit('18') self.lin_titlefont.setValidator(self.onlyInt) self.lbl_titlec = QLabel('color (r,g,b,a):') self.btn_titlec = QPushButton('Pick') self.btn_titlec.clicked.connect( lambda: self.choose_color(target='title')) self.lin_titler = QLineEdit('0') self.lin_titler.setValidator(self.onlyInt) self.lin_titleg = QLineEdit('0') self.lin_titleg.setValidator(self.onlyInt) self.lin_titleb = QLineEdit('0') self.lin_titleb.setValidator(self.onlyInt) self.lin_titlea = QLineEdit('255') self.lin_titlea.setValidator(self.onlyInt) self.title_grid = QGridLayout() self.title_grid.setColumnStretch(7, 1) self.title_grid.addWidget(self.lbl_titletext, 0, 0, 1, 1) self.title_grid.addWidget(self.lin_titletext, 0, 1, 1, 3) self.title_grid.addWidget(self.lbl_titlefont, 1, 0, 1, 1) self.title_grid.addWidget(self.lin_titlefont, 1, 1, 1, 1) self.title_grid.addWidget(self.combo_titlefont, 1, 2, 1, 2) self.title_grid.addWidget(self.lbl_titlec, 2, 0, 1, 1) self.title_grid.addWidget(self.lin_titler, 2, 1, 1, 1) self.title_grid.addWidget(self.lin_titleg, 2, 2, 1, 1) self.title_grid.addWidget(self.lin_titleb, 2, 3, 1, 1) self.title_grid.addWidget(self.lin_titlea, 2, 4, 1, 1) self.title_grid.addWidget(self.btn_titlec, 2, 5, 1, 1) self.title_group = CollapsibleBox(title='Title', parent=self) self.title_group.setContentLayout(self.title_grid) # X Axis parameters self.chk_xvisible = QCheckBox('visible') self.chk_xvisible.setChecked(True) self.lbl_xc = QLabel('color (r,g,b,a):') self.btn_xc = QPushButton('Pick') self.btn_xc.clicked.connect(lambda: self.choose_color(target='xaxis')) self.lin_xr = QLineEdit('255') self.lin_xr.setValidator(self.onlyInt) self.lin_xg = QLineEdit('255') self.lin_xg.setValidator(self.onlyInt) self.lin_xb = QLineEdit('255') self.lin_xb.setValidator(self.onlyInt) self.lin_xa = QLineEdit('255') self.lin_xa.setValidator(self.onlyInt) self.lbl_xtitletext = QLabel('text:') self.lin_xtitletext = QLineEdit('') self.lbl_xtitlefont = QLabel('font:') self.combo_xtitlefont = QComboBox() for ft in all_fonts: self.combo_xtitlefont.addItem(ft) self.lin_xtitlefont = QLineEdit('10') self.lin_xtitlefont.setValidator(self.onlyInt) self.lbl_xtitlec = QLabel('font color (r,g,b,a):') self.btn_xtitlec = QPushButton('Pick') self.btn_xtitlec.clicked.connect( lambda: self.choose_color(target='xaxis_title')) self.lin_xtitler = QLineEdit('27') self.lin_xtitler.setValidator(self.onlyInt) self.lin_xtitleg = QLineEdit('27') self.lin_xtitleg.setValidator(self.onlyInt) self.lin_xtitleb = QLineEdit('27') self.lin_xtitleb.setValidator(self.onlyInt) self.lin_xtitlea = QLineEdit('255') self.lin_xtitlea.setValidator(self.onlyInt) self.lbl_xtype = QLabel('type:') self.combo_xtype = QComboBox() self.combo_xtype.addItem("-") self.combo_xtype.addItem("linear") self.combo_xtype.addItem("log") self.combo_xtype.addItem("date") self.combo_xtype.addItem("category") self.combo_xtype.addItem("multicategory") self.chk_xautorange = QCheckBox('autorange') self.chk_xautorange.setChecked(True) self.lbl_xnticks = QLabel('nticks:') self.lin_xnticks = QLineEdit('4') self.lin_xnticks.setValidator(self.onlyInt) self.lbl_xticks = QLabel('ticks:') self.combo_xticks = QComboBox() self.combo_xticks.addItem("inside") self.combo_xticks.addItem("outside") self.combo_xticks.addItem("") self.lbl_xticklen = QLabel('tick length:') self.lin_xticklen = QLineEdit('5') self.lin_xticklen.setValidator(self.onlyInt) self.lbl_xtickwid = QLabel('tick width:') self.lin_xtickwid = QLineEdit('1') self.lin_xtickwid.setValidator(self.onlyInt) self.lbl_xtickc = QLabel('tick color (r,g,b,a):') self.btn_xtickc = QPushButton('Pick') self.btn_xtickc.clicked.connect( lambda: self.choose_color(target='xaxis_tick')) self.lin_xtickr = QLineEdit('27') self.lin_xtickr.setValidator(self.onlyInt) self.lin_xtickg = QLineEdit('27') self.lin_xtickg.setValidator(self.onlyInt) self.lin_xtickb = QLineEdit('27') self.lin_xtickb.setValidator(self.onlyInt) self.lin_xticka = QLineEdit('255') self.lin_xticka.setValidator(self.onlyInt) self.chk_xshowticklabels = QCheckBox('show tick labels') self.chk_xshowticklabels.setChecked(True) self.lbl_xtickangle = QLabel('tick angle:') self.chk_xtickangle = QCheckBox('auto') self.chk_xtickangle.setChecked(True) self.chk_xtickangle.stateChanged.connect(self.toggle_enable_fields) self.lin_xtickangle = QLineEdit('0') self.lin_xtickangle.setValidator(self.onlyInt) self.lbl_xtickprefix = QLabel('tick prefix:') self.lin_xtickprefix = QLineEdit('') self.combo_xshowtickprefix = QComboBox() self.combo_xshowtickprefix.addItem("all") self.combo_xshowtickprefix.addItem("first") self.combo_xshowtickprefix.addItem("last") self.combo_xshowtickprefix.addItem("none") self.lbl_xticksufix = QLabel('tick sufix:') self.lin_xticksufix = QLineEdit('') self.combo_xshowticksufix = QComboBox() self.combo_xshowticksufix.addItem("all") self.combo_xshowticksufix.addItem("first") self.combo_xshowticksufix.addItem("last") self.combo_xshowticksufix.addItem("none") self.lbl_xexponent = QLabel('exponent:') self.combo_xexponent = QComboBox() self.combo_xexponent.addItem("B") self.combo_xexponent.addItem("e") self.combo_xexponent.addItem("E") self.combo_xexponent.addItem("power") self.combo_xexponent.addItem("SI") self.combo_xexponent.addItem("none") self.combo_xshowexponent = QComboBox() self.combo_xshowexponent.addItem("all") self.combo_xshowexponent.addItem("first") self.combo_xshowexponent.addItem("last") self.combo_xshowexponent.addItem("none") self.lbl_xtickformat = QLabel('tick format:') self.lin_xtickformat = QLineEdit('') self.chk_xshowline = QCheckBox('show line') self.chk_xshowline.setChecked(False) self.chk_xshowline.stateChanged.connect(self.toggle_enable_fields) self.lbl_xlinewid = QLabel('line width:') self.lin_xlinewid = QLineEdit('1') self.lin_xlinewid.setValidator(self.onlyInt) self.lbl_xlinec = QLabel('line color (r,g,b,a):') self.btn_xlinec = QPushButton('Pick') self.btn_xlinec.clicked.connect( lambda: self.choose_color(target='xaxis_line')) self.lin_xliner = QLineEdit('27') self.lin_xliner.setValidator(self.onlyInt) self.lin_xlineg = QLineEdit('27') self.lin_xlineg.setValidator(self.onlyInt) self.lin_xlineb = QLineEdit('27') self.lin_xlineb.setValidator(self.onlyInt) self.lin_xlinea = QLineEdit('255') self.lin_xlinea.setValidator(self.onlyInt) self.chk_xshowgrid = QCheckBox('show grid') self.chk_xshowgrid.setChecked(False) self.chk_xshowgrid.stateChanged.connect(self.toggle_enable_fields) self.lbl_xgridwid = QLabel('grid width:') self.lin_xgridwid = QLineEdit('1') self.lin_xgridwid.setValidator(self.onlyInt) self.lbl_xgridc = QLabel('grid color (r,g,b,a):') self.btn_xgridc = QPushButton('Pick') self.btn_xgridc.clicked.connect( lambda: self.choose_color(target='xaxis_grid')) self.lin_xgridr = QLineEdit('238') self.lin_xgridr.setValidator(self.onlyInt) self.lin_xgridg = QLineEdit('238') self.lin_xgridg.setValidator(self.onlyInt) self.lin_xgridb = QLineEdit('238') self.lin_xgridb.setValidator(self.onlyInt) self.lin_xgrida = QLineEdit('255') self.lin_xgrida.setValidator(self.onlyInt) self.chk_xzeroline = QCheckBox('show zero-line') self.chk_xzeroline.setChecked(False) self.chk_xzeroline.stateChanged.connect(self.toggle_enable_fields) self.lbl_xzerolinewid = QLabel('zero-line width:') self.lin_xzerolinewid = QLineEdit('1') self.lin_xzerolinewid.setValidator(self.onlyInt) self.lbl_xzerolinec = QLabel('zero-line color (r,g,b,a):') self.btn_xzerolinec = QPushButton('Pick') self.btn_xzerolinec.clicked.connect( lambda: self.choose_color(target='xaxis_zeroline')) self.lin_xzeroliner = QLineEdit('68') self.lin_xzeroliner.setValidator(self.onlyInt) self.lin_xzerolineg = QLineEdit('68') self.lin_xzerolineg.setValidator(self.onlyInt) self.lin_xzerolineb = QLineEdit('68') self.lin_xzerolineb.setValidator(self.onlyInt) self.lin_xzerolinea = QLineEdit('255') self.lin_xzerolinea.setValidator(self.onlyInt) self.lbl_xside = QLabel('side:') self.combo_xside = QComboBox() self.combo_xside.addItem("bottom") self.combo_xside.addItem("top") self.xaxis_grid = QGridLayout() self.xaxis_grid.setColumnStretch(7, 1) self.xaxis_grid.addWidget(self.chk_xvisible, 0, 0, 1, 1) self.xaxis_grid.addWidget(self.lbl_xc, 1, 0, 1, 1) self.xaxis_grid.addWidget(self.lin_xr, 1, 1, 1, 1) self.xaxis_grid.addWidget(self.lin_xg, 1, 2, 1, 1) self.xaxis_grid.addWidget(self.lin_xb, 1, 3, 1, 1) self.xaxis_grid.addWidget(self.lin_xa, 1, 4, 1, 1) self.xaxis_grid.addWidget(self.btn_xc, 1, 5, 1, 1) self.xaxis_grid.addWidget(self.lbl_xtitletext, 2, 0, 1, 1) self.xaxis_grid.addWidget(self.lin_xtitletext, 2, 1, 1, 3) self.xaxis_grid.addWidget(self.lbl_xtitlefont, 3, 0, 1, 1) self.xaxis_grid.addWidget(self.lin_xtitlefont, 3, 1, 1, 1) self.xaxis_grid.addWidget(self.combo_xtitlefont, 3, 2, 1, 2) self.xaxis_grid.addWidget(self.lbl_xtitlec, 4, 0, 1, 1) self.xaxis_grid.addWidget(self.lin_xtitler, 4, 1, 1, 1) self.xaxis_grid.addWidget(self.lin_xtitleg, 4, 2, 1, 1) self.xaxis_grid.addWidget(self.lin_xtitleb, 4, 3, 1, 1) self.xaxis_grid.addWidget(self.lin_xtitlea, 4, 4, 1, 1) self.xaxis_grid.addWidget(self.btn_xtitlec, 4, 5, 1, 1) self.xaxis_grid.addWidget(self.lbl_xtype, 5, 0, 1, 1) self.xaxis_grid.addWidget(self.combo_xtype, 5, 1, 1, 2) self.xaxis_grid.addWidget(self.chk_xautorange, 6, 0, 1, 1) self.xaxis_grid.addWidget(self.lbl_xnticks, 7, 0, 1, 1) self.xaxis_grid.addWidget(self.lin_xnticks, 7, 1, 1, 1) self.xaxis_grid.addWidget(self.lbl_xticks, 8, 0, 1, 1) self.xaxis_grid.addWidget(self.combo_xticks, 8, 1, 1, 2) self.xaxis_grid.addWidget(self.lbl_xticklen, 9, 0, 1, 1) self.xaxis_grid.addWidget(self.lin_xticklen, 9, 1, 1, 1) self.xaxis_grid.addWidget(self.lbl_xtickwid, 10, 0, 1, 1) self.xaxis_grid.addWidget(self.lin_xtickwid, 10, 1, 1, 1) self.xaxis_grid.addWidget(self.lbl_xtickc, 11, 0, 1, 1) self.xaxis_grid.addWidget(self.lin_xtickr, 11, 1, 1, 1) self.xaxis_grid.addWidget(self.lin_xtickg, 11, 2, 1, 1) self.xaxis_grid.addWidget(self.lin_xtickb, 11, 3, 1, 1) self.xaxis_grid.addWidget(self.lin_xticka, 11, 4, 1, 1) self.xaxis_grid.addWidget(self.btn_xtickc, 11, 5, 1, 1) self.xaxis_grid.addWidget(self.chk_xshowticklabels, 12, 0, 1, 1) self.xaxis_grid.addWidget(self.lbl_xtickangle, 13, 0, 1, 1) self.xaxis_grid.addWidget(self.chk_xtickangle, 13, 1, 1, 1) self.xaxis_grid.addWidget(self.lin_xtickangle, 13, 2, 1, 1) self.xaxis_grid.addWidget(self.lbl_xtickprefix, 14, 0, 1, 1) self.xaxis_grid.addWidget(self.lin_xtickprefix, 14, 1, 1, 1) self.xaxis_grid.addWidget(self.combo_xshowtickprefix, 14, 2, 1, 1) self.xaxis_grid.addWidget(self.lbl_xticksufix, 15, 0, 1, 1) self.xaxis_grid.addWidget(self.lin_xticksufix, 15, 1, 1, 1) self.xaxis_grid.addWidget(self.combo_xshowticksufix, 15, 2, 1, 1) self.xaxis_grid.addWidget(self.lbl_xexponent, 16, 0, 1, 1) self.xaxis_grid.addWidget(self.combo_xexponent, 16, 1, 1, 1) self.xaxis_grid.addWidget(self.combo_xshowexponent, 16, 2, 1, 1) self.xaxis_grid.addWidget(self.lbl_xtickformat, 17, 0, 1, 1) self.xaxis_grid.addWidget(self.lin_xtickformat, 17, 1, 1, 1) self.xaxis_grid.addWidget(self.chk_xshowline, 18, 0, 1, 1) self.xaxis_grid.addWidget(self.lbl_xlinewid, 19, 0, 1, 1) self.xaxis_grid.addWidget(self.lin_xlinewid, 19, 1, 1, 1) self.xaxis_grid.addWidget(self.lbl_xlinec, 20, 0, 1, 1) self.xaxis_grid.addWidget(self.lin_xliner, 20, 1, 1, 1) self.xaxis_grid.addWidget(self.lin_xlineg, 20, 2, 1, 1) self.xaxis_grid.addWidget(self.lin_xlineb, 20, 3, 1, 1) self.xaxis_grid.addWidget(self.lin_xlinea, 20, 4, 1, 1) self.xaxis_grid.addWidget(self.btn_xlinec, 20, 5, 1, 1) self.xaxis_grid.addWidget(self.chk_xshowgrid, 21, 0, 1, 1) self.xaxis_grid.addWidget(self.lbl_xgridwid, 22, 0, 1, 1) self.xaxis_grid.addWidget(self.lin_xgridwid, 22, 1, 1, 1) self.xaxis_grid.addWidget(self.lbl_xgridc, 23, 0, 1, 1) self.xaxis_grid.addWidget(self.lin_xgridr, 23, 1, 1, 1) self.xaxis_grid.addWidget(self.lin_xgridg, 23, 2, 1, 1) self.xaxis_grid.addWidget(self.lin_xgridb, 23, 3, 1, 1) self.xaxis_grid.addWidget(self.lin_xgrida, 23, 4, 1, 1) self.xaxis_grid.addWidget(self.btn_xgridc, 23, 5, 1, 1) self.xaxis_grid.addWidget(self.chk_xzeroline, 24, 0, 1, 1) self.xaxis_grid.addWidget(self.lbl_xzerolinewid, 25, 0, 1, 1) self.xaxis_grid.addWidget(self.lin_xzerolinewid, 25, 1, 1, 1) self.xaxis_grid.addWidget(self.lbl_xzerolinec, 26, 0, 1, 1) self.xaxis_grid.addWidget(self.lin_xzeroliner, 26, 1, 1, 1) self.xaxis_grid.addWidget(self.lin_xzerolineg, 26, 2, 1, 1) self.xaxis_grid.addWidget(self.lin_xzerolineb, 26, 3, 1, 1) self.xaxis_grid.addWidget(self.lin_xzerolinea, 26, 4, 1, 1) self.xaxis_grid.addWidget(self.btn_xzerolinec, 26, 5, 1, 1) self.xaxis_grid.addWidget(self.lbl_xside, 27, 0, 1, 1) self.xaxis_grid.addWidget(self.combo_xside, 27, 1, 1, 1) self.xaxis_group = CollapsibleBox(title='X Axis', parent=self) self.xaxis_group.setContentLayout(self.xaxis_grid) # Y Axis parameters self.lbl_ytitle = QLabel('y title') self.lin_ytitle = QLineEdit('') self.yaxis_grid = QGridLayout() self.yaxis_grid.setColumnStretch(7, 1) self.yaxis_grid.addWidget(self.lbl_ytitle, 0, 0, 1, 1) self.yaxis_grid.addWidget(self.lin_ytitle, 0, 1, 1, 2) self.yaxis_group = CollapsibleBox(title='Y Axis', parent=self) self.yaxis_group.setContentLayout(self.yaxis_grid) # Main window layout self.vbox1 = QVBoxLayout() self.vbox1.addWidget(self.general_group) self.vbox1.addWidget(self.title_group) self.vbox1.addWidget(self.xaxis_group) self.vbox1.addWidget(self.yaxis_group) self.vbox1.addStretch() scroll_aux = QWidget() scroll_aux.setLayout(self.vbox1) scroll = QScrollArea() scroll.setWidget(scroll_aux) scroll.setWidgetResizable(True) self.vbox2 = QVBoxLayout() self.vbox2.addLayout(self.hbox) self.vbox2.addWidget(scroll) centralw = QWidget() centralw.setLayout(self.vbox2) self.setCentralWidget(centralw) self.show() self.init_attributes() self.toggle_enable_fields() #self.general_group.toggle_button.click() #self.title_group.toggle_button.click() self.xaxis_group.toggle_button.click() #self.yaxis_group.toggle_button.click() def toggle_enable_fields(self): # General self.lin_laywidth.setEnabled(not self.chk_layautosize.isChecked()) self.lin_layheight.setEnabled(not self.chk_layautosize.isChecked()) # X axis self.lin_xtickangle.setEnabled(not self.chk_xtickangle.isChecked()) self.lin_xlinewid.setEnabled(self.chk_xshowline.isChecked()) self.btn_xlinec.setEnabled(self.chk_xshowline.isChecked()) self.lin_xliner.setEnabled(self.chk_xshowline.isChecked()) self.lin_xlineg.setEnabled(self.chk_xshowline.isChecked()) self.lin_xlineb.setEnabled(self.chk_xshowline.isChecked()) self.lin_xlinea.setEnabled(self.chk_xshowline.isChecked()) self.lin_xgridwid.setEnabled(self.chk_xshowgrid.isChecked()) self.btn_xgridc.setEnabled(self.chk_xshowgrid.isChecked()) self.lin_xgridr.setEnabled(self.chk_xshowgrid.isChecked()) self.lin_xgridg.setEnabled(self.chk_xshowgrid.isChecked()) self.lin_xgridb.setEnabled(self.chk_xshowgrid.isChecked()) self.lin_xgrida.setEnabled(self.chk_xshowgrid.isChecked()) self.lin_xzerolinewid.setEnabled(self.chk_xzeroline.isChecked()) self.btn_xzerolinec.setEnabled(self.chk_xzeroline.isChecked()) self.lin_xzeroliner.setEnabled(self.chk_xzeroline.isChecked()) self.lin_xzerolineg.setEnabled(self.chk_xzeroline.isChecked()) self.lin_xzerolineb.setEnabled(self.chk_xzeroline.isChecked()) self.lin_xzerolinea.setEnabled(self.chk_xzeroline.isChecked()) def choose_color(self, target): color = QColorDialog.getColor() if color.isValid(): if target == 'title': self.lin_titler.setText(str(color.red())) self.lin_titleg.setText(str(color.green())) self.lin_titleb.setText(str(color.blue())) elif target == 'layout_font': self.lin_layfontr.setText(str(color.red())) self.lin_layfontg.setText(str(color.green())) self.lin_layfontb.setText(str(color.blue())) elif target == 'layout_paper': self.lin_laypaperr.setText(str(color.red())) self.lin_laypaperg.setText(str(color.green())) self.lin_laypaperb.setText(str(color.blue())) elif target == 'layout_plot': self.lin_layplotr.setText(str(color.red())) self.lin_layplotg.setText(str(color.green())) self.lin_layplotb.setText(str(color.blue())) elif target == 'xaxis': self.lin_xr.setText(str(color.red())) self.lin_xg.setText(str(color.green())) self.lin_xb.setText(str(color.blue())) elif target == 'xaxis_title': self.lin_xtitler.setText(str(color.red())) self.lin_xtitleg.setText(str(color.green())) self.lin_xtitleb.setText(str(color.blue())) elif target == 'xaxis_tick': self.lin_xtickr.setText(str(color.red())) self.lin_xtickg.setText(str(color.green())) self.lin_xtickb.setText(str(color.blue())) elif target == 'xaxis_line': self.lin_xliner.setText(str(color.red())) self.lin_xlineg.setText(str(color.green())) self.lin_xlineb.setText(str(color.blue())) elif target == 'xaxis_grid': self.lin_xgridr.setText(str(color.red())) self.lin_xgridg.setText(str(color.green())) self.lin_xgridb.setText(str(color.blue())) elif target == 'xaxis_zeroline': self.lin_xzeroliner.setText(str(color.red())) self.lin_xzerolineg.setText(str(color.green())) self.lin_xzerolineb.setText(str(color.blue())) def layout_update(self): """Reads fields and updates parent's layout""" changes = AutoDictionary() # General if str(self.combo_layhover.currentText()) == 'False': changes['hovermode'] = False else: changes['hovermode'] = str(self.combo_layhover.currentText()) changes['autosize'] = self.chk_layautosize.isChecked() changes['width'] = int(self.lin_laywidth.text() ) if self.lin_laywidth.isEnabled() else None changes['height'] = int(self.lin_layheight.text() ) if self.lin_layheight.isEnabled() else None changes['font']['family'] = str(self.combo_layfont.currentText()) changes['font']['size'] = int(self.lin_layfont.text()) r = str(self.lin_layfontr.text()) g = str(self.lin_layfontg.text()) b = str(self.lin_layfontb.text()) a = str(self.lin_layfonta.text()) changes['font'][ 'color'] = 'rgb(' + r + ',' + g + ',' + b + ',' + a + ')' r = str(self.lin_laypaperr.text()) g = str(self.lin_laypaperg.text()) b = str(self.lin_laypaperb.text()) a = str(self.lin_laypapera.text()) changes[ 'paper_bgcolor'] = 'rgb(' + r + ',' + g + ',' + b + ',' + a + ')' r = str(self.lin_layplotr.text()) g = str(self.lin_layplotg.text()) b = str(self.lin_layplotb.text()) a = str(self.lin_layplota.text()) changes[ 'plot_bgcolor'] = 'rgb(' + r + ',' + g + ',' + b + ',' + a + ')' changes['showlegend'] = self.chk_legend.isChecked() # Title changes['title']['text'] = str(self.lin_titletext.text()) changes['title']['font']['family'] = str( self.combo_titlefont.currentText()) changes['title']['font']['size'] = int(self.lin_titlefont.text()) r = str(self.lin_titler.text()) g = str(self.lin_titleg.text()) b = str(self.lin_titleb.text()) a = str(self.lin_titlea.text()) changes['title']['font'][ 'color'] = 'rgb(' + r + ',' + g + ',' + b + ',' + a + ')' # X axis changes['xaxis']['visible'] = self.chk_xvisible.isChecked() r = str(self.lin_xr.text()) g = str(self.lin_xg.text()) b = str(self.lin_xb.text()) a = str(self.lin_xa.text()) changes['xaxis'][ 'color'] = 'rgb(' + r + ',' + g + ',' + b + ',' + a + ')' #changes['xaxis']['title']['text'] = str(self.lin_xtitletext.text()) changes['xaxis']['title']['font']['family'] = str( self.combo_xtitlefont.currentText()) changes['xaxis']['title']['font']['size'] = int( self.lin_xtitlefont.text()) r = str(self.lin_xtitler.text()) g = str(self.lin_xtitleg.text()) b = str(self.lin_xtitleb.text()) a = str(self.lin_xtitlea.text()) changes['xaxis']['title']['font'][ 'color'] = 'rgb(' + r + ',' + g + ',' + b + ',' + a + ')' changes['xaxis']['type'] = str(self.combo_xtype.currentText()) changes['xaxis']['autorange'] = self.chk_xautorange.isChecked() changes['xaxis']['nticks'] = int(self.lin_xnticks.text()) changes['xaxis']['ticks'] = str(self.combo_xticks.currentText()) changes['xaxis']['ticklen'] = int(self.lin_xticklen.text()) changes['xaxis']['tickwidth'] = int(self.lin_xtickwid.text()) r = str(self.lin_xtickr.text()) g = str(self.lin_xtickg.text()) b = str(self.lin_xtickb.text()) a = str(self.lin_xticka.text()) changes['xaxis'][ 'tickcolor'] = 'rgb(' + r + ',' + g + ',' + b + ',' + a + ')' changes['xaxis'][ 'showticklabels'] = self.chk_xshowticklabels.isChecked() changes['xaxis'][ 'tickangle'] = None if self.chk_xtickangle.isChecked else int( self.lin_xtickangle.text()) changes['xaxis']['tickprefix'] = str(self.lin_xtickprefix.text()) changes['xaxis']['showtickprefix'] = str( self.combo_xshowtickprefix.currentText()) changes['xaxis']['ticksuffix'] = str(self.lin_xticksufix.text()) changes['xaxis']['showticksuffix'] = str( self.combo_xshowticksufix.currentText()) changes['xaxis']['showexponent'] = str( self.combo_xshowexponent.currentText()) changes['xaxis']['exponentformat'] = str( self.combo_xexponent.currentText()) changes['xaxis']['tickformat'] = str(self.lin_xtickformat.text()) changes['xaxis']['showline'] = self.chk_xshowline.isChecked() changes['xaxis']['linewidth'] = int(self.lin_xlinewid.text()) r = str(self.lin_xliner.text()) g = str(self.lin_xlineg.text()) b = str(self.lin_xlineb.text()) a = str(self.lin_xlinea.text()) changes['xaxis'][ 'linecolor'] = 'rgb(' + r + ',' + g + ',' + b + ',' + a + ')' changes['xaxis']['showgrid'] = self.chk_xshowgrid.isChecked() changes['xaxis']['gridwidth'] = int(self.lin_xgridwid.text()) r = str(self.lin_xgridr.text()) g = str(self.lin_xgridg.text()) b = str(self.lin_xgridb.text()) a = str(self.lin_xgrida.text()) changes['xaxis'][ 'gridcolor'] = 'rgb(' + r + ',' + g + ',' + b + ',' + a + ')' changes['xaxis']['zeroline'] = self.chk_xzeroline.isChecked() changes['xaxis']['zerolinewidth'] = int(self.lin_xzerolinewid.text()) r = str(self.lin_xzeroliner.text()) g = str(self.lin_xzerolineg.text()) b = str(self.lin_xzerolineb.text()) a = str(self.lin_xzerolinea.text()) changes['xaxis'][ 'zerolinecolor'] = 'rgb(' + r + ',' + g + ',' + b + ',' + a + ')' changes['xaxis']['side'] = str(self.combo_xside.currentText()) # Run layout update self.parent.layout_update(changes=changes) def init_attributes(self): pass
class VODSync(QMainWindow): def __init__(self): QMainWindow.__init__(self) self.twitch_interface = TwitchInterface( api_client_id=config.TWITCH_API_CLIENT_ID, api_oauth_token=config.TWITCH_API_OAUTH_TOKEN, browser_client_id=config.TWITCH_BROWSER_OAUTH_TOKEN, browser_oauth_token=config.TWITCH_BROWSER_OAUTH_TOKEN) self.loaded_videos = [] self.video_decks = [] self.corrected_time = None self.main_layout = QVBoxLayout() self.launch_vlc_btn = QPushButton("Launch VLC") self.playlist_widget = PlaylistWidget() self.sync_btn = QPushButton(text="SYNC") self.match_btn = QPushButton(text="MATCH") self.decks_layout = QHBoxLayout() self.main_layout.addWidget(self.launch_vlc_btn) self.main_layout.addWidget(self.playlist_widget) self.main_layout.addWidget(self.sync_btn) self.main_layout.addLayout(self.decks_layout) self.main_layout.addWidget(self.match_btn) match_infos_layout = QGridLayout() timecode_source_label = QLabel("Timecode Video Source") timecode_target_label = QLabel("Timecode Video Target") target_start_time_label = QLabel("Resulting VOD Start Time") self.timecode_source_field = QLineEdit() self.timecode_target_field = QLineEdit() self.target_start_time_field = QLineEdit() self.timecode_source_field.setEnabled(False) self.timecode_target_field.setEnabled(False) self.target_start_time_field.setEnabled(False) match_infos_layout.addWidget(timecode_source_label, 0, 0) match_infos_layout.addWidget(timecode_target_label, 1, 0) match_infos_layout.addWidget(target_start_time_label, 2, 0) match_infos_layout.addWidget(self.timecode_source_field, 0, 1) match_infos_layout.addWidget(self.timecode_target_field, 1, 1) match_infos_layout.addWidget(self.target_start_time_field, 2, 1) self.main_layout.addLayout(match_infos_layout) self.export_btn = QPushButton(text="EXPORT") self.main_layout.addWidget(self.export_btn) self.main_widget = QWidget() self.main_widget.setLayout(self.main_layout) self.setCentralWidget(self.main_widget) self.sync_btn.clicked.connect(self.sync_from_playlist_item) self.match_btn.clicked.connect(self.match) self.export_btn.clicked.connect(self.export_metadatas) self.launch_vlc_btn.clicked.connect(self.on_launch_vlc) self.playlist_widget.itemPlayed.connect(self.on_playlist_item_played) self.add_video_deck(8080) self.add_video_deck(8081) def get_loaded_video(self, idx): if idx < 0 or idx >= len(self.loaded_videos): raise IndexError(f"<!!> Unknown loaded video index: {idx}") return self.loaded_videos[idx] def get_vlc_instance(self, idx): if idx < 0 or idx >= len(self.vlc_instances): raise IndexError(f"<!!> Unknown loaded video index: {idx}") return self.vlc_instances[idx] def add_video_deck(self, vlc_port=8080): new_deck = VideoDeck(VLCInterface(config.VLC_PATH, port=vlc_port)) self.video_decks.append(new_deck) self.decks_layout.addWidget(new_deck) def export_metadatas(self, fixed_created_at): time_offset = abs(self.video_decks[0].vlc_instance.get_current_time() - self.video_decks[1].vlc_instance.get_current_time()) created_at = self.video_decks[0].loaded_video.metadatas.get( "created_at") corrected_time = created_at + datetime.timedelta(seconds=time_offset) fixed_metadatas = dict(self.video_decks[0].loaded_video.metadatas) fixed_metadatas["created_at"] = corrected_time.isoformat() fixed_metadatas["permanent_id"] = { "service": self.video_decks[1].loaded_video.metadatas["service"], "id": self.video_decks[1].loaded_video.metadatas["id"] } print(fixed_metadatas) def match(self): if len(self.video_decks) < 2: raise Exception( f"Not enough decks opened ({len(self.video_decks)})") time_offset = abs(self.video_decks[0].vlc_instance.get_current_time() - self.video_decks[1].vlc_instance.get_current_time()) created_at = self.video_decks[0].loaded_video.metadatas.get( "created_at") self.corrected_time = created_at + datetime.timedelta( seconds=time_offset) self.timecode_source_field.setText( str(self.video_decks[0].vlc_instance.get_current_time())) self.timecode_target_field.setText( str(self.video_decks[1].vlc_instance.get_current_time())) self.target_start_time_field.setText(str(self.corrected_time)) print(created_at) print(time_offset) print(self.corrected_time) def sync_from_playlist_item(self): for i, item in enumerate( self.playlist_widget.playlist_list.selectedItems()): if item.__class__ is PlaylistItemWidget: for i, m in enumerate(item.playlist_item.media_list): self.video_decks[i].seek(m["time"]) def on_launch_vlc(self): for deck in self.video_decks: deck.vlc_instance.launch() def on_playlist_item_played(self, playlist_item): for i, media_info in enumerate(playlist_item): if i >= len(self.video_decks): print( "<!> Not enough decks to load all the playlist item videos!" ) break self.video_decks[i].load_video_url(media_info["url"])
class SubtitleInfoDialog(QDialog): def __init__(self, subtitle_name="Test", subtitle_delay=0.0, subtitle_language=Default_Subtitle_Language, subtitle_track_name="Test", subtitle_set_default=False, subtitle_set_forced=False, subtitle_default_value_delay=0.0, subtitle_default_value_language=Default_Subtitle_Language, subtitle_default_value_track_name="Test", subtitle_default_value_set_default=False, subtitle_default_value_set_forced=False, subtitle_set_default_disabled=False, subtitle_set_forced_disabled=False, disable_edit=False, parent=None): super().__init__(parent) self.window_title = "Subtitle Info" self.state = "no" self.messageIcon = QLabel() self.disable_edit = disable_edit self.current_subtitle_language = str(subtitle_language) self.current_subtitle_delay = str(subtitle_delay) self.current_subtitle_track_name = str(subtitle_track_name) self.current_subtitle_set_default = subtitle_set_default self.current_subtitle_set_forced = subtitle_set_forced self.default_subtitle_language = str(subtitle_default_value_language) self.default_subtitle_delay = str(subtitle_default_value_delay) self.default_subtitle_track_name = str( subtitle_default_value_track_name) self.default_subtitle_set_default = subtitle_default_value_set_default self.default_subtitle_set_forced = subtitle_default_value_set_forced self.subtitle_set_default_disabled = subtitle_set_default_disabled self.subtitle_set_forced_disabled = subtitle_set_forced_disabled self.subtitle_name_label = QLabel("Subtitle Name:") self.subtitle_name_value = QLabel(str(subtitle_name)) self.subtitle_delay_label = QLabel("Subtitle Delay:") self.subtitle_delay_spin = QDoubleSpinBox() self.setup_subtitle_delay_spin() self.subtitle_language_label = QLabel("Subtitle Language:") self.subtitle_language_comboBox = QComboBox() self.setup_subtitle_language_comboBox() self.subtitle_track_name_label = QLabel("Subtitle Track Name:") self.subtitle_track_name_lineEdit = QLineEdit() self.setup_subtitle_track_name_lineEdit() self.subtitle_set_forced_label = QLabel("Subtitle Forced State:") self.subtitle_set_forced_checkBox = QCheckBox() self.setup_subtitle_set_forced_checkBox() self.subtitle_set_default_label = QLabel("Subtitle Default State:") self.subtitle_set_default_checkBox = QCheckBox() self.setup_subtitle_set_default_checkBox() self.yes_button = QPushButton("OK") self.no_button = QPushButton("Cancel") self.reset_button = QPushButton("Reset To Default") self.buttons_layout = QHBoxLayout() self.subtitle_delay_layout = QHBoxLayout() self.subtitle_language_layout = QHBoxLayout() self.subtitle_track_name_layout = QHBoxLayout() self.subtitle_set_default_layout = QHBoxLayout() self.subtitle_set_forced_layout = QHBoxLayout() self.buttons_layout.addWidget(QLabel(""), stretch=3) self.buttons_layout.addWidget(self.reset_button, stretch=2) self.buttons_layout.addWidget(self.yes_button, stretch=2) self.buttons_layout.addWidget(self.no_button, stretch=2) self.buttons_layout.addWidget(QLabel(""), stretch=3) self.subtitle_setting_layout = QGridLayout() self.subtitle_changeble_setting_layout = QFormLayout() self.subtitle_changeble_setting_layout.addRow(self.subtitle_name_label, self.subtitle_name_value) self.subtitle_changeble_setting_layout.addRow( self.subtitle_track_name_label, self.subtitle_track_name_lineEdit) self.subtitle_changeble_setting_layout.addRow( self.subtitle_language_label, self.subtitle_language_comboBox) self.subtitle_changeble_setting_layout.addRow( self.subtitle_delay_label, self.subtitle_delay_spin) self.subtitle_changeble_setting_layout.addRow( self.subtitle_set_default_label, self.subtitle_set_default_checkBox) self.subtitle_changeble_setting_layout.addRow( self.subtitle_set_forced_label, self.subtitle_set_forced_checkBox) self.subtitle_setting_layout.addLayout( self.subtitle_changeble_setting_layout, 0, 0, 5, 2) self.subtitle_setting_layout.addWidget(self.messageIcon, 0, 3, 5, -1) self.main_layout = QGridLayout() self.main_layout.addLayout(self.subtitle_setting_layout, 0, 0, 2, 3) self.main_layout.addLayout(self.buttons_layout, 2, 0, 1, -1) self.main_layout.setContentsMargins(20, 20, 20, 20) self.setLayout(self.main_layout) self.setup_ui() self.signal_connect() def setup_ui(self): self.disable_question_mark_window() self.messageIcon.setPixmap( QtGui.QPixmap(GlobalFiles.SubtitleIconPath).scaledToHeight(100)) self.set_dialog_values() self.set_default_buttons() if self.subtitle_set_default_disabled: self.subtitle_set_default_disable() if self.subtitle_set_forced_disabled: self.subtitle_set_forced_disable() if self.disable_edit: self.subtitle_track_name_lineEdit.setEnabled(False) self.subtitle_language_comboBox.setEnabled(False) self.subtitle_delay_spin.setEnabled(False) self.subtitle_set_default_checkBox.setEnabled(False) self.subtitle_set_forced_checkBox.setEnabled(False) self.reset_button.setEnabled(False) self.setup_tool_tip_hint_subtitle_set_default() self.setup_tool_tip_hint_subtitle_set_forced() def signal_connect(self): self.subtitle_track_name_lineEdit.textEdited.connect( self.update_current_subtitle_track_name) self.subtitle_delay_spin.editingFinished.connect( self.update_current_subtitle_delay) self.subtitle_language_comboBox.currentTextChanged.connect( self.update_current_subtitle_language) self.subtitle_set_default_checkBox.stateChanged.connect( self.update_current_subtitle_set_default) self.subtitle_set_forced_checkBox.stateChanged.connect( self.update_current_subtitle_set_forced) self.yes_button.clicked.connect(self.click_yes) self.no_button.clicked.connect(self.click_no) self.reset_button.clicked.connect(self.reset_subtitle_setting) def click_yes(self): self.state = "yes" self.close() def click_no(self): self.close() def set_dialog_values(self): self.setWindowTitle(self.window_title) self.setWindowIcon(GlobalFiles.InfoSettingIcon) def disable_question_mark_window(self): self.setWindowFlag(Qt.WindowContextHelpButtonHint, on=False) def increase_message_font_size(self, value): message_font = self.message.font() message_font.setPointSize(self.message.fontInfo().pointSize() + value) self.message.setFont(message_font) def set_default_buttons(self): self.yes_button.setDefault(True) self.yes_button.setFocus() def showEvent(self, a0: QtGui.QShowEvent) -> None: super().showEvent(a0) self.setFixedSize(self.size()) def setup_subtitle_track_name_lineEdit(self): self.subtitle_track_name_lineEdit.setClearButtonEnabled(True) self.subtitle_track_name_lineEdit.setText( self.current_subtitle_track_name) def setup_subtitle_language_comboBox(self): self.subtitle_language_comboBox.addItems(AllSubtitlesLanguages) self.subtitle_language_comboBox.setCurrentIndex( AllSubtitlesLanguages.index(self.current_subtitle_language)) self.subtitle_language_comboBox.setMaxVisibleItems(8) self.subtitle_language_comboBox.setStyleSheet( "QComboBox { combobox-popup: 0; }") def setup_subtitle_delay_spin(self): # self.subtitle_delay_spin.setMaximumWidth(screen_size.width() // 16) self.subtitle_delay_spin.setDecimals(3) self.subtitle_delay_spin.setMinimum(-9999.0) self.subtitle_delay_spin.setMaximum(9999.0) self.subtitle_delay_spin.setSingleStep(0.5) self.subtitle_delay_spin.setValue(float(self.current_subtitle_delay)) def setup_subtitle_set_default_checkBox(self): self.subtitle_set_default_checkBox.setText("Set Default") self.subtitle_set_default_checkBox.setChecked( bool(self.current_subtitle_set_default)) def setup_subtitle_set_forced_checkBox(self): self.subtitle_set_forced_checkBox.setText("Set Forced") self.subtitle_set_forced_checkBox.setChecked( bool(self.current_subtitle_set_forced)) def update_current_subtitle_track_name(self): self.current_subtitle_track_name = str( self.subtitle_track_name_lineEdit.text()) def update_current_subtitle_delay(self): self.current_subtitle_delay = round(self.subtitle_delay_spin.value(), 5) def update_current_subtitle_language(self): self.current_subtitle_language = str( self.subtitle_language_comboBox.currentText()) def update_current_subtitle_set_default(self): self.current_subtitle_set_default = ( self.subtitle_set_default_checkBox.checkState() == Qt.Checked) def update_current_subtitle_set_forced(self): self.current_subtitle_set_forced = ( self.subtitle_set_forced_checkBox.checkState() == Qt.Checked) def reset_subtitle_setting(self): self.current_subtitle_language = self.default_subtitle_language self.current_subtitle_delay = self.default_subtitle_delay self.current_subtitle_track_name = self.default_subtitle_track_name self.current_subtitle_set_default = self.default_subtitle_set_default self.current_subtitle_set_forced = self.default_subtitle_set_forced self.subtitle_language_comboBox.setCurrentIndex( AllSubtitlesLanguages.index(self.current_subtitle_language)) self.subtitle_delay_spin.setValue(float(self.current_subtitle_delay)) self.subtitle_track_name_lineEdit.setText( self.current_subtitle_track_name) self.subtitle_set_default_checkBox.setChecked( bool(self.current_subtitle_set_default)) self.subtitle_set_forced_checkBox.setChecked( bool(self.current_subtitle_set_forced)) def subtitle_set_default_disable(self): self.subtitle_set_default_checkBox.setDisabled(True) def subtitle_set_forced_disable(self): self.subtitle_set_forced_checkBox.setDisabled(True) def setup_tool_tip_hint_subtitle_set_default(self): if self.subtitle_set_default_checkBox.isEnabled(): self.subtitle_set_default_checkBox.setToolTip( "<nobr>set this subtitle to be the default subtitle track " "when play") self.subtitle_set_default_checkBox.setToolTipDuration(12000) else: self.subtitle_set_default_checkBox.setToolTip( "<nobr>set this subtitle to be the default subtitle track when play<br><b>Disabled</b> because " "option " "<b>make this subtitle default</b> is enabled on mux setting tab " ) self.subtitle_set_default_checkBox.setToolTipDuration(12000) def setup_tool_tip_hint_subtitle_set_forced(self): if self.subtitle_set_forced_checkBox.isEnabled(): self.subtitle_set_forced_checkBox.setToolTip( "<nobr>set this subtitle to be the forced subtitle track when " "play") self.subtitle_set_forced_checkBox.setToolTipDuration(12000) else: self.subtitle_set_forced_checkBox.setToolTip( "<nobr>set this subtitle to be the forced subtitle track when play<br><b>Disabled</b> because " "option " "<b>make this subtitle default and forced</b> is enabled on mux setting tab " ) self.subtitle_set_forced_checkBox.setToolTipDuration(12000) def execute(self): self.exec_()
class AdapterSettingsDialog(QDialog): def __init__(self, parent, data): assert type(data) == BinaryView self.bv = data QDialog.__init__(self, parent) debug_state = binjaplug.get_state(self.bv) self.setWindowTitle("Debug Adapter Settings") self.setMinimumSize(UIContext.getScaledWindowSize(400, 130)) self.setAttribute(Qt.WA_DeleteOnClose) layout = QVBoxLayout() layout.setSpacing(0) titleLabel = QLabel("Adapter Settings") titleLayout = QHBoxLayout() titleLayout.setContentsMargins(0, 0, 0, 0) titleLayout.addWidget(titleLabel) self.adapterEntry = QPushButton(self) self.adapterMenu = QMenu(self) for adapter in DebugAdapter.ADAPTER_TYPE: if not DebugAdapter.ADAPTER_TYPE.can_use(adapter): continue def select_adapter(adapter): return lambda: self.selectAdapter(adapter) self.adapterMenu.addAction(adapter.name, select_adapter(adapter)) if adapter == debug_state.adapter_type: self.adapterEntry.setText(adapter.name) self.adapterEntry.setMenu(self.adapterMenu) self.argumentsEntry = QLineEdit(self) self.addressEntry = QLineEdit(self) self.portEntry = QLineEdit(self) self.formLayout = QFormLayout() self.formLayout.addRow("Adapter Type", self.adapterEntry) self.formLayout.addRow("Command Line Arguments", self.argumentsEntry) self.formLayout.addRow("Address", self.addressEntry) self.formLayout.addRow("Port", self.portEntry) buttonLayout = QHBoxLayout() buttonLayout.setContentsMargins(0, 0, 0, 0) self.cancelButton = QPushButton("Cancel") self.cancelButton.clicked.connect(lambda: self.reject()) self.acceptButton = QPushButton("Accept") self.acceptButton.clicked.connect(lambda: self.accept()) self.acceptButton.setDefault(True) buttonLayout.addStretch(1) buttonLayout.addWidget(self.cancelButton) buttonLayout.addWidget(self.acceptButton) layout.addLayout(titleLayout) layout.addSpacing(10) layout.addLayout(self.formLayout) layout.addStretch(1) layout.addSpacing(10) layout.addLayout(buttonLayout) self.setLayout(layout) self.addressEntry.setText(debug_state.remote_host) self.portEntry.setText(str(debug_state.remote_port)) self.addressEntry.textEdited.connect(lambda: self.apply()) self.portEntry.textEdited.connect(lambda: self.apply()) self.argumentsEntry.setText(' '.join( shlex.quote(arg) for arg in debug_state.command_line_args)) self.argumentsEntry.textEdited.connect(lambda: self.updateArguments()) self.accepted.connect(lambda: self.apply()) def selectAdapter(self, adapter): self.bv.store_metadata('debugger.adapter_type', adapter.value) debug_state = binjaplug.get_state(self.bv) debug_state.adapter_type = adapter self.adapterEntry.setText(adapter.name) if DebugAdapter.ADAPTER_TYPE.use_exec(adapter): self.argumentsEntry.setEnabled(True) self.addressEntry.setEnabled(False) self.portEntry.setEnabled(False) elif DebugAdapter.ADAPTER_TYPE.use_connect(adapter): self.argumentsEntry.setEnabled(False) self.addressEntry.setEnabled(True) self.portEntry.setEnabled(True) def apply(self): debug_state = binjaplug.get_state(self.bv) arguments = shlex.split(self.argumentsEntry.text()) debug_state.command_line_args = arguments self.bv.store_metadata('debugger.command_line_args', arguments) address = self.addressEntry.text() port = int(self.portEntry.text()) debug_state.remote_host = address debug_state.remote_port = port self.bv.store_metadata('debugger.remote_host', address) self.bv.store_metadata('debugger.remote_port', port) def updateArguments(self): try: arguments = shlex.split(self.argumentsEntry.text()) self.acceptButton.setEnabled(True) except: self.acceptButton.setEnabled(False)