def __init__(self, parent=None): super(MainWindow, self).__init__(parent) # Inicializa janela self.figure = plt.figure(figsize=(10, 6)) # Define figura e seu tamanho # Caracteristicas do mapa m = Basemap( resolution='i', # c, l, i, h, f or None projection='merc', lat_0=-22.525, lon_0=-48.865, llcrnrlon=-53.25, llcrnrlat=-25.1, urcrnrlon=-44.48, urcrnrlat=-19.5) m.drawmapboundary(fill_color='aqua') # Contorno m.fillcontinents(color='gray', lake_color='aqua') # Continente m.drawcoastlines() # Costa m.readshapefile('SP_Municipios/Sao_Paulo_Municipios', 'Sao_Paulo_Municipios') self.canvas = FigureCanvas(self.figure) self.setCentralWidget(self.canvas) simulParamDockWidget = QDockWidget('Simulação', self) simulParamDockWidget.setObjectName('simulParamDockWidget') simulParamDockWidget.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea) simulParamDockWidget.setFeatures(QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetMovable)
def addROI(self,roi = None): if self.roiwidget is None: self.roiwidget = ROIPlotWidget(roi_target = self.p1, view = self.view, parent = self) roiTab = QDockWidget("roi cam {0}".format(self.iCam), self) roiTab.setWidget(self.roiwidget) roiTab.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea | Qt.BottomDockWidgetArea | Qt.TopDockWidgetArea) roiTab.setFeatures(QDockWidget.DockWidgetMovable | QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetClosable) self.parent.addDockWidget(Qt.BottomDockWidgetArea ,roiTab) roiTab.setFloating(True) roiTab.resize(600,150) def closetab(ev): # This probably does not clean up memory... if not self.roiwidget is None: [self.p1.removeItem(r) for r in self.roiwidget.items()] del self.roiwidget self.roiwidget = None ev.accept() roiTab.closeEvent = closetab self.roiwidget.add_roi(roi)
class QtWindowCanvas(QMainWindow): '''generic app window to display a figure with a toolbar''' def __init__(self, bottom_dock=True, left_dock=True): # initialsie window QMainWindow.__init__(self) self.main_widget = QWidget(self) # add dock widget if bottom_dock: self.bottom_dock = QDockWidget() self.addDockWidget(Qt.BottomDockWidgetArea, self.bottom_dock) self.bottom_dock.setFeatures(QDockWidget.DockWidgetFloatable) if left_dock: self.left_dock = QDockWidget() self.addDockWidget(Qt.LeftDockWidgetArea, self.left_dock) self.left_dock.setFeatures(QDockWidget.DockWidgetFloatable) # define layout self.grid = QGridLayout(self.main_widget) # create figure on window self.canvas = MPLCanvas() self.grid.addWidget(self.canvas, 0, 0, 1, 1) # all rows # figure toolbar toolbar = NavigationToolbar2QT(self.canvas, self) self.grid.addWidget(toolbar, 1, 0, 1, 1) self.setCentralWidget(self.main_widget)
def __init__(self, src, dst): """ 打码界面 :param src: 验证码所在目录或url :param dst: 验证码输出目录 """ super().__init__() self.save = 0 self.passed = -1 self.img_queue = ImageQueue(src, dst) self.setGeometry(300, 300, 400, 200) self.setWindowTitle("打码器") self.et = QLineEdit() self.lbl = QLabel("hello, press enter to start!") self.et.setAlignment(Qt.AlignCenter) self.et.returnPressed.connect(self._submit) dock = QDockWidget('输入框') dock.setFeatures(QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetMovable) dock.setWidget(self.et) self.lbl.setAlignment(Qt.AlignCenter) self.setCentralWidget(self.lbl) self.addDockWidget(Qt.BottomDockWidgetArea, dock)
def init(self): self.pic = Picture(self) self.setCentralWidget(self.pic) self.panel = Panel(self.pic) self.dock = QDockWidget('info panel') self.dock.setWidget(self.panel) self.dock.setAllowedAreas(Qt.RightDockWidgetArea) self.addDockWidget(Qt.RightDockWidgetArea, self.dock) self.dock.setFeatures(QDockWidget.NoDockWidgetFeatures) self.dock.setFixedWidth(300) self.setWindowTitle('Untitled') dock = QDockWidget('command line', self) dock.setWidget(TwoLines()) dock.setAllowedAreas(Qt.BottomDockWidgetArea) self.addDockWidget(Qt.BottomDockWidgetArea, dock) dock.setFeatures(QDockWidget.NoDockWidgetFeatures) dock.setFixedHeight(60) dock.setFixedWidth(800) desktop = QApplication.desktop() self.setGeometry(300, 100, desktop.width(), desktop.height()) self.setFixedSize(1100, 705)
class JetTrackerView(QWidget): def __init__(self, context, signals, parent=None): super(JetTrackerView, self).__init__(parent) self.signals = signals self.context = context self.parent = parent self.mainLayout = QHBoxLayout() self.createGraphWidget() self.createDockWidgets() self.mainLayout.addWidget(self.controlsDock) self.mainLayout.addWidget(self.graphWidget) # self.parent.resizeDocks([self.controlsDock], [45], Qt.Horizontal) print(self.parent) self.setLayout(self.mainLayout) def createGraphWidget(self): self.graphWidget = GraphsWidget(context=self.context, signals=self.signals) self.graphWidget.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) def createDockWidgets(self): self.parent.setDockNestingEnabled(True) self.controlsDock = QDockWidget("Controls", self) self.controlsDock.setAllowedAreas(Qt.RightDockWidgetArea | Qt.BottomDockWidgetArea) self.controlsDock.setFeatures(QDockWidget.DockWidgetFloatable) self.controlsWidget = ControlsWidget(self.context, self.signals) self.controlsDock.setWidget(self.controlsWidget) self.controlsDock.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
def createTreeView(self): dockWidget = QDockWidget() dockWidget.setAllowedAreas(Qt.LeftDockWidgetArea) dockWidget.setFeatures(QDockWidget.NoDockWidgetFeatures) dockWidget.setTitleBarWidget(QWidget()) self.treeView = QTreeView() self.treeView.clicked.connect(self.treeItemClicked) self.treeModel = TreeModel() self.treeView.setModel(self.treeModel) self.logo = QLabel() logoPixmap = QPixmap(CMAKE_INSTALL_PREFIX + '/share/jderobot/resources/jderobot.png') self.logo.setPixmap(logoPixmap) self.upButton = QPushButton() self.upButton.setText('Up') self.upButton.clicked.connect(self.upButtonClicked) leftContainer = QWidget() leftLayout = QVBoxLayout() leftLayout.addWidget(self.treeView) leftLayout.addWidget(self.upButton) leftLayout.addWidget(self.logo) leftContainer.setLayout(leftLayout) dockWidget.setWidget(leftContainer) self.addDockWidget(Qt.LeftDockWidgetArea, dockWidget)
def sliceManager(var): sliceDock = QDockWidget('图像调节', var) sliceGroup = QGroupBox() vbox = QVBoxLayout() sliceHBox = QHBoxLayout() luminanceHBox = QHBoxLayout() contrastLabel = QLabel('对比度: ', var) luminanceLabel = QLabel('亮 度: ', var) var.contrastSlide = QSlider(Qt.Horizontal, var) var.luminanceSlide = QSlider(Qt.Horizontal, var) var.contrastSpin = QSpinBox(var) var.luminanceSpin = QSpinBox(var) var.contrastSlide.setFocusPolicy(Qt.NoFocus) var.contrastSlide.setSingleStep(1) var.contrastSlide.setMinimum(1) var.contrastSlide.setTickPosition(QSlider.TicksAbove) # 设置刻度信息 var.contrastSlide.setEnabled(False) # sliceSlide.setFixedSize(1, 100) var.luminanceSlide.setFocusPolicy(Qt.NoFocus) var.luminanceSlide.setSingleStep(1) var.luminanceSlide.setMinimum(1) var.luminanceSlide.setTickPosition(QSlider.TicksLeft) # 设置刻度信息 var.luminanceSlide.valueChanged.connect(var.luminanceSpin.setValue) var.luminanceSlide.setEnabled(False) var.contrastSpin.setSingleStep(1) # var.sliceSpin.setWrapping(True) #是否循环 var.contrastSpin.setValue(1) var.contrastSpin.setEnabled(False) var.luminanceSpin.setSingleStep(1) # var.luminanceSpin.setWrapping(True) var.luminanceSpin.setValue(1) var.luminanceSpin.setEnabled(False) var.luminanceSpin.valueChanged.connect(var.luminanceSlide.setValue) sliceHBox.addWidget(contrastLabel) sliceHBox.addWidget(var.contrastSlide) sliceHBox.addWidget(var.contrastSpin) luminanceHBox.addWidget(luminanceLabel) luminanceHBox.addWidget(var.luminanceSlide) luminanceHBox.addWidget(var.luminanceSpin) vbox.addLayout(sliceHBox) vbox.addLayout(luminanceHBox) vbox.addStretch() sliceGroup.setLayout(vbox) sliceDock.setFeatures(QDockWidget.NoDockWidgetFeatures) sliceDock.setWidget(sliceGroup) return sliceDock
def createWidgets(self): """Cette fonction permet la création de tous les widgets de la mainWindow""" #Création toolbar toolBar = self.addToolBar("Tools") #Création bar recherche self.lineEditSearch = QLineEdit() self.lineEditSearch.setPlaceholderText("Recherche") self.lineEditSearch.setStyleSheet("background-color:white") toolBar.addWidget(self.lineEditSearch) self.lineEditSearch.setMaximumWidth(300) #Création séparateur toolBar.addSeparator() #Création icon add contact self.actionAdd = QAction("Ajouter (Ctrl+P)",self) toolBar.addAction(self.actionAdd) self.actionAdd.setShortcut("Ctrl+P") self.actionAdd.setIcon(QIcon("Pictures/sign.png")) #Création icon delete contact self.actionDelete = QAction("supprimer (Ctrl+D)",self) toolBar.addAction(self.actionDelete) self.actionDelete.setShortcut("Ctrl+D") self.actionDelete.setIcon(QIcon("Pictures/contacts.png")) #Création icon quit self.actionQuitter = QAction("Quitter (Ctrl+Q)",self) toolBar.addAction(self.actionQuitter) self.actionQuitter.setShortcut("Ctrl+Q") self.actionQuitter.setIcon(QIcon("Pictures/arrows.png")) #Création widget central self.centralWidget = QWidget() self.centralWidget.setStyleSheet("background-color:white") self.setCentralWidget(self.centralWidget) #Création dockWidget left dockDisplay = QDockWidget("Répertoire") dockDisplay.setStyleSheet("background-color:white") dockDisplay.setFeatures(QDockWidget.DockWidgetFloatable) dockDisplay.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea) self.addDockWidget(Qt.LeftDockWidgetArea,dockDisplay) containDock = QWidget(dockDisplay) dockDisplay.setWidget(containDock) dockLayout = QVBoxLayout() displayWidget = QScrollArea() displayWidget.setWidgetResizable(1) dockLayout.addWidget(displayWidget) containDock.setLayout(dockLayout) #Ajouter la list au dockwidget self.listContact = QListWidget() displayWidget.setWidget(self.listContact)
class ToolsWidget: def __init__(self, parent, config): self.parent = parent self.config = config self.widget = QWidget(self.parent) self.widget.setGeometry(1200, 0, 400, 900) self.widget.setStyleSheet("background-color:#717171") self.dock = QDockWidget("Tools", self.parent) self.dock.setWidget(self.widget) self.dock.setFeatures(QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetMovable) self.tools_layout = QVBoxLayout(self.widget) self.tools_layout.setAlignment(Qt.AlignTop) self.tools_layout.setSpacing(15) self.controller = ToolsController(self.parent, self) self.address = AddressWidget(self.widget, self.controller) self.tools_layout.addWidget(self.address.get_address_widget()) self.buttons = ButtonsWidget(self.widget, self.controller) self.tools_layout.addWidget(self.buttons.get_buttons_widget()) self.slider_movement = SliderMovementWidget(self.widget, self.controller) self.tools_layout.addWidget(self.slider_movement.get_slider_widget()) self.slider_area = SliderCachedAreaWidget(self.widget, self.controller) self.tools_layout.addWidget(self.slider_area.get_slider_widget()) self.slider_history = SliderHistorySizeWidget(self.widget, self.controller) self.tools_layout.addWidget(self.slider_history.get_slider_widget()) self.slider_blurr = SliderBlurrWidget(self.widget, self.controller) self.tools_layout.addWidget(self.slider_blurr.get_slider_widget()) self.slider_dilate = SliderDilatedKernel(self.widget, self.controller) self.tools_layout.addWidget(self.slider_dilate.get_slider_widget()) self.slider_epsilon = SliderEpsilonWidget(self.widget, self.controller) self.tools_layout.addWidget(self.slider_epsilon.get_slider_widget()) self.slider_threshold = SliderPixelThresholdWidget( self.widget, self.controller) self.tools_layout.addWidget(self.slider_threshold.get_slider_widget()) # self.coordinates = CoordinatesWidget(self.widget, self.controller) # self.tools_layout.addWidget(self.coordinates.get_coordinates_widget()) # self.tools_layout.addWidget(self.coordinates.get_coordinates_button()) self.debug = DebugWidget(self.widget, self.controller) self.parent.enabled = False self.tools_layout.addWidget(self.debug.get_debug_widget()) def get_tools_area(self): return self.dock
def imageInforShow(var): imageInforDock = QDockWidget('图像信息', var) imageInforDock.setFeatures(QDockWidget.DockWidgetClosable) imageInforDock.setWidget(imageInfor(var)) return imageInforDock
def add_youtubedownloader(self): widget = YoutubeDownloaderGUI() dockwidget = QDockWidget(parent = self,) dockwidget.setWidget(widget) dockwidget.setObjectName("Youtube Downloader") dockwidget.setWindowTitle("Youtube Downloader") dockwidget.setFeatures(dockwidget.DockWidgetMovable | dockwidget.DockWidgetClosable) self.addDockWidget(Qt.TopDockWidgetArea, dockwidget)
def add_calc(self): widget = PyCalcCtrl() dockwidget = QDockWidget(parent = self,) dockwidget.setWidget(widget) dockwidget.setObjectName("Taschenrechner") dockwidget.setWindowTitle("Taschenrechner") dockwidget.setFeatures(dockwidget.DockWidgetMovable | dockwidget.DockWidgetClosable) self.addDockWidget(Qt.TopDockWidgetArea, dockwidget)
def initoptionspanel(self): label = QLabel('Filter') filtertype = QComboBox() filtertype.addItem('None') filtertype.addItem('Lowpass') filtertype.addItem('Highpass') filtertype.addItem('Bandreject') filtertype.addItem('Bandpass') filtertype.currentIndexChanged.connect(self.filtertypelistener) self.filterfunction = QComboBox() self.filterfunction.addItem('Ideal') self.filterfunction.addItem('Butterworth') self.filterfunction.addItem('Gaussian') self.filterfunction.currentIndexChanged.connect(self.filterfunctionlistener) self.filterfunction.setEnabled(False) self.filtercutoff = QDoubleSpinBox() self.filtercutoff.setValue(0.0) self.filtercutoff.setRange(0.0, 10000.0) self.filtercutoff.valueChanged.connect(self.filtercutofflistener) self.filtercutoff.setEnabled(False) self.filterbandwidth = QDoubleSpinBox() self.filterbandwidth.setValue(1.0) self.filterbandwidth.setRange(0.0, 10000.0) self.filterbandwidth.valueChanged.connect(self.filterbandwidthlistener) self.filterbandwidth.setEnabled(False) self.filterorder = QDoubleSpinBox() self.filterorder.setValue(1.0) self.filterorder.setRange(0.0, 10000.0) self.filterorder.valueChanged.connect(self.filterorderlistener) self.filterorder.setEnabled(False) loader = QMovie('loader.gif') loader.start() self.loadercontainer = QLabel() self.loadercontainer.setMovie(loader) self.loadercontainer.setVisible(False) formlayout = QFormLayout() formlayout.addRow('Type', filtertype) formlayout.addRow('Function', self.filterfunction) formlayout.addRow('Cut off', self.filtercutoff) formlayout.addRow('Bandwidth', self.filterbandwidth) formlayout.addRow('Order', self.filterorder) formlayout.addRow('', self.loadercontainer) filterbox = QGroupBox('Filter') filterbox.setLayout(formlayout) options = QDockWidget('Options') options.setFeatures(QDockWidget.DockWidgetFloatable) options.setFeatures(QDockWidget.DockWidgetMovable) options.setWidget(filterbox) self.addDockWidget(Qt.RightDockWidgetArea, options)
def init_file_tree(self, directory, title, action, filtered=False): widget = DirectoryDockWidget(directory, filtered=filtered, parent=self) widget.path_label.addAction(action, QLineEdit.LeadingPosition) widget.tree_view.activated.connect( partial(self.handle_directory_tree_view_activated, directory)) dock = QDockWidget(title, self) dock.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea) dock.setFeatures(QDockWidget.DockWidgetMovable) dock.setWidget(widget) self.addDockWidget(Qt.LeftDockWidgetArea, dock)
def addDock(self): dock1 = QDockWidget('DockWidget') dock1.setFeatures(QDockWidget.DockWidgetFloatable) dock1.setAllowedAreas(Qt.LeftDockWidgetArea) listwidget = QListWidget() listwidget.addItems(self.items) listwidget.currentRowChanged.connect(self.onDockListIndexChanged) dock1.setWidget(listwidget) self.addDockWidget(Qt.LeftDockWidgetArea, dock1)
def _createDock(self, widgetClass, widgetName, widgetArea, *param): """创建停靠组件""" widget = widgetClass(*param) dock = QDockWidget(widgetName, self) dock.setWidget(widget) dock.setObjectName(widgetName) dock.setFeatures(QDockWidget.NoDockWidgetFeatures) self.addDockWidget(widgetArea, dock) return widget, dock
def _createDock(self, widgetClass, widgetName, widgetArea, *param): """创建停靠组件""" widget = widgetClass(*param) dock = QDockWidget(widgetName, self) dock.setWidget(widget) dock.setObjectName(widgetName) dock.setFeatures(QDockWidget.NoDockWidgetFeatures) self.addDockWidget(widgetArea, dock) return widget, dock
def createDockStats(self): dock = QDockWidget('stats',self) dock.setAllowedAreas(Qt.TopDockWidgetArea) dock.setFeatures(dock.DockWidgetClosable|dock.DockWidgetVerticalTitleBar) self.statsui = StatsWin(dock,cur=self) self.statsui.setMaximumHeight(100) dock.setWidget(self.statsui) self.addDockWidget(Qt.TopDockWidgetArea, dock) a = dock.toggleViewAction() self.viewMenu.addAction(a) a.setEnabled(True)
class main_win(QMainWindow, Ui_MainWindow): def __init__(self): super(main_win, self).__init__() self.setupUi(self) self.my_setupUi() # 优化界面 # self.trigger_connection()#信号与槽连接 # self.view_dock_closeEvent()#重写dock关闭函数 def my_setupUi(self): self.tree.setColumnCount(1) # 设置列数 self.tree.header().hide() self.mdi = QMdiArea() self.tabWidget = QTabWidget() self.tabWidget.setTabsClosable(True) #self.mdi.setViewMode(QMdiArea.TabbedView) # 设置为Tab多页显示模式 #self.mdi.setTabsClosable(1) self.text_browser = QTextEdit( self) # QtextEditClick继承自QTextEdit,内置于信息输出视图 self.text_browser.setReadOnly(True) # 仅作为信息输出,设置“只读”属性 self.serial_info = QTextEdit( self) # QtextEditClick继承自QTextEdit,内置于信息输出视图 self.serial_info.setReadOnly(True) #self.loadFile(self.filename) # 1.3创建信息输出视图 self.dock_serial = QDockWidget('Serial monitor', self) # self.dock_connection.setText("connnnn") # self.dock_serial.setMinimumSize(600, 150) self.dock_serial.setWidget(self.serial_info) self.dockBuilt = QDockWidget('Built output', self) # self.dockBuilt.setFearures(DockWidgetClosable) self.dockBuilt.setFeatures(QDockWidget.DockWidgetClosable | QDockWidget.DockWidgetMovable) self.dockBuilt.setMinimumSize(600, 150) # 宽=600,高= 150 self.dockBuilt.setWidget(self.text_browser) self.tabifyDockWidget(self.dockBuilt, self.dock_serial) splitter1 = QSplitter(Qt.Vertical) splitter1.addWidget(self.mdi) # 多文档视图占布局右上 splitter1.addWidget(self.dockBuilt) # 信息输出视图占布局右下 # self.addDockWidget(Qt.LeftDockWidgetArea, self.dockProject) # 工程视图占布局左边 self.setCentralWidget(splitter1) self.tabifyDockWidget(self.dock_connection, self.dock_serial) self.tree.setIconSize(QSize(25, 25)) self.tree.setSelectionMode(QAbstractItemView.ExtendedSelection) self.sub = QMdiSubWindow() self.sub.setWidget(self.tabWidget) self.mdi.addSubWindow(self.sub) self.sub.showMaximized() self.sub.setWindowFlags(Qt.FramelessWindowHint) self.set_tree()
def __init__(self, parent=None): QMainWindow.__init__(self, parent) self.setWindowTitle("计算几何 测试") """ 菜单栏 """ newAct = QAction("&新建", self) newAct.setShortcuts(QKeySequence.New) newAct.setStatusTip("新建一个工程") newAct.triggered.connect(self.newProject) openAct = QAction("&打开", self) openAct.setShortcuts(QKeySequence.Open) openAct.setStatusTip("打开存在的工程") openAct.triggered.connect(self.openProject) fileMenu = self.menuBar().addMenu("&工程") fileMenu.addAction(newAct) fileMenu.addAction(openAct) """ 工具栏 """ fileToolBar = self.addToolBar("工程") fileToolBar.addAction(newAct) fileToolBar.addAction(openAct) fileToolBar.setAllowedAreas(Qt.TopToolBarArea | Qt.BottomToolBarArea) self.addToolBar(Qt.TopToolBarArea, fileToolBar) """ 中心画布 """ self.mCanvas = MainCanvas() self.setCentralWidget(self.mCanvas) """ 状态栏 """ self.mStatusBar = StatusBar() self.setStatusBar(self.mStatusBar) """ 控制(dock)框 """ self.mCtrlWidget = CtrlWidget() ctrlDock = QDockWidget("控制") self.addDockWidget(Qt.RightDockWidgetArea, ctrlDock) ctrlDock.setWidget(self.mCtrlWidget) ctrlDock.setFeatures(QDockWidget.NoDockWidgetFeatures) """ 绑定信号和槽 """ self.mCanvas.msCurrentChanged.connect(self.CurrentChanged) self.mCanvas.msMove.connect(self.mStatusBar.Move) self.mCtrlWidget.msRun.connect(self.Run)
def start_lexer(self): dock_name = QFileInfo(self.filename).fileName() token = QListWidget() error = QListWidget() sign = QListWidget() log = QListWidget() quaternary = QListWidget() self.docwidget[dock_name] = {"token": token, "error": error, "sign": sign, "log": log, 'quaternary': quaternary} token.itemDoubleClicked.connect(self.token_list_double_clicked_fun) error.itemDoubleClicked.connect(self.error_list_double_clicked_fun) self.lexer = Lexer(self.filename) try: self.lexer.sinOut.connect(self.show_toker_error_sign) self.lexer.start() except Exception as e: print("Start Lexer Error:", e) dock_token = QDockWidget(dock_name+"_Token") # 实例化dockwidget类 dock_token.setWidget(self.docwidget[dock_name]["token"]) # 带入的参数为一个QWidget窗体实例,将该窗体放入dock中 dock_token.setObjectName(dock_name) dock_token.setFeatures(dock_token.AllDockWidgetFeatures) # 设置dockwidget的各类属性 self.addDockWidget(Qt.RightDockWidgetArea, dock_token) # 设置dockwidget放置在QMainWindow中的位置,并且将dockwidget添加至QMainWindow中 dock_error = QDockWidget(dock_name+"_Error") dock_error.setWidget(self.docwidget[dock_name]["error"]) dock_error.setObjectName(dock_name) dock_error.setFeatures(dock_error.AllDockWidgetFeatures) self.addDockWidget(Qt.RightDockWidgetArea, dock_error) dock_sign = QDockWidget(dock_name+"_sign") dock_sign.setWidget(self.docwidget[dock_name]["sign"]) dock_sign.setObjectName(dock_name) dock_sign.setFeatures(dock_sign.AllDockWidgetFeatures) self.addDockWidget(Qt.RightDockWidgetArea, dock_sign) dock_log = QDockWidget(dock_name + "_log") dock_log.setWidget(self.docwidget[dock_name]["log"]) dock_log.setObjectName(dock_name) dock_log.setFeatures(dock_log.AllDockWidgetFeatures) self.addDockWidget(Qt.RightDockWidgetArea, dock_log) dock_quaternary = QDockWidget(dock_name + "_quaternary") dock_quaternary.setWidget(self.docwidget[dock_name]["quaternary"]) dock_quaternary.setObjectName(dock_name) dock_quaternary.setFeatures(dock_log.AllDockWidgetFeatures) self.addDockWidget(Qt.RightDockWidgetArea, dock_quaternary) self.tabifyDockWidget(dock_token, dock_error) self.tabifyDockWidget(dock_error, dock_sign) self.tabifyDockWidget(dock_sign, dock_log) self.tabifyDockWidget(dock_log, dock_quaternary) print('ui')
def initinformationpanel(self): self.mselabel = QLabel('No image selected') infoform = QFormLayout() infoform.addRow('MSE:', self.mselabel) imagebox = QGroupBox('Image') imagebox.setLayout(infoform) information = QDockWidget('Information') information.setFeatures(QDockWidget.DockWidgetFloatable) information.setFeatures(QDockWidget.DockWidgetMovable) information.setWidget(imagebox) self.addDockWidget(Qt.RightDockWidgetArea, information)
def show(var): fileDock = QDockWidget(var) var.fileDirectory = QListWidget(var) var.fileDirectory.verticalScrollBar() # 垂直滚动条 var.fileDirectory.horizontalScrollBar() # 水平滚动条 # var.fileDirectory.setFixedSize(500, 300) # var.fileDirectory.itemDoubleClicked.connect(lambda: fileDirectoryDoubleClicked(var)) fileDock.setFeatures(QDockWidget.NoDockWidgetFeatures) fileDock.setWidget(var.fileDirectory) # var.fileDirectory.setStyleSheet("QListWidget{ color:red; }") return fileDock
def __init_ui(self): self.create_menu() self.port_list = QListWidget(self) dock = QDockWidget(self.tr('Port list'), self) dock.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea) dock.setFeatures(QDockWidget.DockWidgetMovable) dock.setWidget(self.port_list) self.addDockWidget(Qt.LeftDockWidgetArea, dock) self.central_widget = QTabWidget(self) self.setCentralWidget(self.central_widget) self.setMinimumSize(1000, 700) self.setWindowTitle('TRex Panel') self.show()
def helpInforShow(var): helpInforDock = QDockWidget('帮助信息', var) helpContent = QTextEdit(var) helpContent.setFrameShape(QFrame.Panel | QFrame.Sunken) # 边框样式 helpContent.setAlignment(Qt.AlignVCenter | Qt.AlignLeft) # 内容显示样式 helpContent.setEnabled(False) helpContent.setFocusPolicy(Qt.NoFocus) helpContent.setLineWrapMode(QTextEdit.NoWrap) # 一行文本不换行 helpContent.verticalScrollBar() # 垂直滚动 helpContent.horizontalScrollBar() # 水平滚动 helpContent.setPlaceholderText('此处显示帮助文档') helpInforDock.setFeatures(QDockWidget.NoDockWidgetFeatures) helpInforDock.setWidget(helpContent) return helpInforDock
def addDock(self): dock1 = QDockWidget('Items') # dock1.setFeatures(QDockWidget.DockWidgetFloatable) # dock1.setFeatures(QDockWidget.DockWidgetClosable) # dock1.setFeatures(QDockWidget.DockWidgetMovable) dock1.setFeatures(QDockWidget.DockWidgetMovable | QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetClosable) # dock1.setFeatures(QDockWidget.DockWidgetVerticalTitleBar) # dock1.setFeatures(QDockWidget.NoDockWidgetFeatures) dock1.setAllowedAreas(Qt.RightDockWidgetArea | Qt.LeftDockWidgetArea) # 可停靠位置为左右 listwidget = QListWidget() listwidget.addItems(self.items) listwidget.currentRowChanged.connect( self.onDockListIndexChanged) # 当选择有变化时的动作 dock1.setWidget(listwidget) self.addDockWidget(Qt.LeftDockWidgetArea, dock1) # 初始显示位置
class Main(QMainWindow): def __init__(self): super(Main, self).__init__() self.tabw = QTabWidget(self) self.cw1 = MoveRename() self.tabw.addTab(self.cw1, 'Mover/Renombrar') self.cw2 = Falta() self.tabw.addTab(self.cw2, 'Falta') # self.cw3 = FTPGui() # self.tabw.addTab(self.cw3,'FTP') self.cw4 = FileGui() self.tabw.addTab(self.cw4, 'Sync') self.cw5 = About() self.tabw.addTab(self.cw5, 'About') self.tabw.setTabShape(QTabWidget.Triangular) self.tabw.setTabPosition(QTabWidget.West) self.setCentralWidget(self.tabw) self.logs = QTextEdit() self.logs.setReadOnly(True) self.logsdock = QDockWidget("Logs", self) self.logsdock.setAllowedAreas( Qt.BottomDockWidgetArea | Qt.TopDockWidgetArea) self.logsdock.setWidget(self.logs) self.logsdock.setFeatures(QDockWidget.DockWidgetMovable) self.addDockWidget(Qt.BottomDockWidgetArea, self.logsdock) self.cw1.logginn.connect(self.loggin) self.cw2.logginn.connect(self.loggin) # self.cw3.logginn.connect(self.loggin) self.cw4.logginn.connect(self.loggin) @pyqtSlot(str, str, int) def loggin(self, name, txt, level): if self.logs.document().lineCount() > 1000: self.logs.clear() txtt = logcolor(name + ': ', NAME) txtt += logcolor(txt, level) self.logs.append(txtt)
def histogramWin(self): if self.hist is None: histTab = QDockWidget("histogram cam {0}".format(self.iCam), self) widget = QWidget() layout = QGridLayout() widget.setLayout(layout) win = pg.GraphicsLayoutWidget() p1 = win.addPlot() p1.getViewBox().invertY(True) p1.hideAxis('left') p1.hideAxis('bottom') self.hist = pg.HistogramLUTItem() self.hist.axis.setPen('k') p1.addItem(self.hist) self.hist.setImageItem(self.view) layout.addWidget(win,0,0) histTab.setWidget(widget) histTab.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea | Qt.BottomDockWidgetArea | Qt.TopDockWidgetArea) histTab.setFeatures(QDockWidget.DockWidgetMovable | QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetClosable) self.parent.addDockWidget(Qt.BottomDockWidgetArea ,histTab) histTab.setFloating(True) histTab.resize(200,200) try: histstate = self.hist.saveState() except Exception as err: display('[ERROR] - could not save histogram state. "pip install pyqtgraph --upgrade" might solve it.') print(err) def closefun(ev): try: self.hist.restoreState(histstate) except Exception as err: print(err) pass self.hist = None ev.accept() histTab.closeEvent = closefun
class MainWindow(QMainWindow): def __init__(self, parent=None): QMainWindow.__init__(self, parent) # Main Window Toolbar self.tool_bar = QToolBar() self.addToolBar(QtCore.Qt.TopToolBarArea, self.tool_bar) self.database_open = QAction(self) database_open_ico = self.style().standardIcon(QStyle.SP_DirOpenIcon) self.database_open.setIcon(database_open_ico) self.database_open.setToolTip('Выбрать базу данных') self.database_open.triggered.connect(self.on_database_open) self.tool_bar.addAction(self.database_open) # Central widget - query table self.tdw = QDockWidget() self.tdw.setFeatures(self.tdw.NoDockWidgetFeatures) self.tdw_grid = QGridLayout() self.tdw_grid.setColumnStretch(2, 1) self.tdw_frame = QFrame() self.tdw_frame.setStyleSheet( "background-color: ghostwhite;" "border-width: 0.5px;" "border-style: solid;" "border-color: silver;") self.tdw_frame.setLayout(self.tdw_grid) self.tdw.setWidget(self.tdw_frame) # Bottom widget self.serv_mes = QDockWidget() self.serv_mes.setFixedSize(1400, 80) self.serv_mes.setFeatures(self.serv_mes.NoDockWidgetFeatures) self.listWidget = QListWidget() # Function of form opening def on_database_open(self): db_choose_win = DBChooseClass(self) db_choose_win.setWindowTitle('Форма выбора режима работы с программой') db_choose_win.show() screen = QDesktopWidget().screenGeometry() x = int((screen.width() - db_choose_win.width()) / 2) y = int((screen.height() - db_choose_win.height()) / 2) db_choose_win.move(x, y)
def createSubwindow(self, title, position, closeable=True, widget=None): area_classes = { "left": Qt.LeftDockWidgetArea, "right": Qt.RightDockWidgetArea, "top": Qt.TopDockWidgetArea, "bottom": Qt.BottomDockWidgetArea, } area = area_classes[position] window = QDockWidget(title, self) features = QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetMovable if closeable: features |= QDockWidget.DockWidgetClosable window.setFeatures(features) if widget is not None: window.setWidget(widget) self.addDockWidget(area, window) return window
def __init__(self, mainwin): te = QPlainTextEdit() hilighter = hilite.Highlighter(te.document()) qd = QDockWidget("Dae:Xgm") qd.setWidget(te) qd.setMinimumSize(480, 240) qd.setFeatures(QDockWidget.DockWidgetMovable | QDockWidget.DockWidgetVerticalTitleBar | QDockWidget.DockWidgetFloatable) qd.setAllowedAreas(Qt.LeftDockWidgetArea) qdss = "QWidget{background-color: rgb(64,64,128); color: rgb(160,160,192);}" qdss += "QDockWidget::title {background-color: rgb(32,32,48); color: rgb(255,0,0);}" qd.setStyleSheet(qdss) mainwin.addDockWidget(Qt.LeftDockWidgetArea, qd) if mainwin.prevDockWidget != None: mainwin.tabifyDockWidget(mainwin.prevDockWidget, qd) mainwin.prevDockWidget = qd self.stdout = "" self.stderr = "" def onSubProcStdout(): bytes = self.process.readAllStandardOutput() self.stdout += str(bytes, encoding='ascii') te.setPlainText(self.stdout + self.stderr) def onSubProcStderr(): bytes = self.process.readAllStandardError() self.stderr += str(bytes, encoding='ascii') te.setPlainText(self.stdout + self.stderr) def finished(text): print("process done...\n") self.process = QProcess() self.process.readyReadStandardError.connect(onSubProcStderr) self.process.readyReadStandardOutput.connect(onSubProcStdout) self.process.finished.connect(finished) self.process.start(cmd)
def __init__(self,mainwin): te = QPlainTextEdit() hilighter = hilite.Highlighter(te.document()) qd = QDockWidget("Dae:Xgm") qd.setWidget(te) qd.setMinimumSize(480,240) qd.setFeatures(QDockWidget.DockWidgetMovable|QDockWidget.DockWidgetVerticalTitleBar|QDockWidget.DockWidgetFloatable) qd.setAllowedAreas(Qt.LeftDockWidgetArea) qdss = "QWidget{background-color: rgb(64,64,128); color: rgb(160,160,192);}" qdss += "QDockWidget::title {background-color: rgb(32,32,48); color: rgb(255,0,0);}" qd.setStyleSheet(qdss) mainwin.addDockWidget(Qt.LeftDockWidgetArea,qd) if mainwin.prevDockWidget!=None: mainwin.tabifyDockWidget(mainwin.prevDockWidget,qd) mainwin.prevDockWidget = qd self.stdout = "" self.stderr = "" def onSubProcStdout(): bytes = self.process.readAllStandardOutput() self.stdout += str(bytes, encoding='ascii') te.setPlainText(self.stdout+self.stderr) def onSubProcStderr(): bytes = self.process.readAllStandardError() self.stderr += str(bytes, encoding='ascii') te.setPlainText(self.stdout+self.stderr) def finished(text): print( "process done...\n") self.process = QProcess() self.process.readyReadStandardError.connect(onSubProcStderr) self.process.readyReadStandardOutput.connect(onSubProcStdout); self.process.finished.connect(finished); self.process.start(cmd)
class Window(QMainWindow): """ Defines the look and characteristics of the application's main window. """ title = _("Mu {}").format(__version__) icon = "icon" timer = None usb_checker = None serial = None repl = None plotter = None _zoom_in = pyqtSignal(int) _zoom_out = pyqtSignal(int) close_serial = pyqtSignal() write_to_serial = pyqtSignal(bytes) data_received = pyqtSignal(bytes) def zoom_in(self): """ Handles zooming in. """ self._zoom_in.emit(2) def zoom_out(self): """ Handles zooming out. """ self._zoom_out.emit(2) def connect_zoom(self, widget): """ Connects a referenced widget to the zoom related signals. """ self._zoom_in.connect(widget.zoomIn) self._zoom_out.connect(widget.zoomOut) @property def current_tab(self): """ Returns the currently focussed tab. """ return self.tabs.currentWidget() def set_read_only(self, is_readonly): """ Set all tabs read-only. """ self.read_only_tabs = is_readonly for tab in self.widgets: tab.setReadOnly(is_readonly) def get_load_path(self, folder): """ Displays a dialog for selecting a file to load. Returns the selected path. Defaults to start in the referenced folder. """ path, _ = QFileDialog.getOpenFileName(self.widget, 'Open file', folder, '*.py *.PY *.hex') logger.debug('Getting load path: {}'.format(path)) return path def get_save_path(self, folder): """ Displays a dialog for selecting a file to save. Returns the selected path. Defaults to start in the referenced folder. """ path, _ = QFileDialog.getSaveFileName(self.widget, 'Save file', folder) logger.debug('Getting save path: {}'.format(path)) return path def get_microbit_path(self, folder): """ Displays a dialog for locating the location of the BBC micro:bit in the host computer's filesystem. Returns the selected path. Defaults to start in the referenced folder. """ path = QFileDialog.getExistingDirectory(self.widget, 'Locate BBC micro:bit', folder, QFileDialog.ShowDirsOnly) logger.debug('Getting micro:bit path: {}'.format(path)) return path def add_tab(self, path, text, api): """ Adds a tab with the referenced path and text to the editor. """ new_tab = EditorPane(path, text) new_tab.connect_margin(self.breakpoint_toggle) new_tab_index = self.tabs.addTab(new_tab, new_tab.label) new_tab.set_api(api) @new_tab.modificationChanged.connect def on_modified(): modified_tab_index = self.tabs.currentIndex() self.tabs.setTabText(modified_tab_index, new_tab.label) self.update_title(new_tab.label) self.tabs.setCurrentIndex(new_tab_index) self.connect_zoom(new_tab) self.set_theme(self.theme) new_tab.setFocus() if self.read_only_tabs: new_tab.setReadOnly(self.read_only_tabs) def focus_tab(self, tab): index = self.tabs.indexOf(tab) self.tabs.setCurrentIndex(index) tab.setFocus() @property def tab_count(self): """ Returns the number of active tabs. """ return self.tabs.count() @property def widgets(self): """ Returns a list of references to the widgets representing tabs in the editor. """ return [self.tabs.widget(i) for i in range(self.tab_count)] @property def modified(self): """ Returns a boolean indication if there are any modified tabs in the editor. """ for widget in self.widgets: if widget.isModified(): return True return False def on_serial_read(self): """ Called when the connected device is ready to send data via the serial connection. It reads all the available data, emits the data_received signal with the received bytes and, if appropriate, emits the tuple_received signal with the tuple created from the bytes received. """ data = bytes(self.serial.readAll()) # get all the available bytes. self.data_received.emit(data) def open_serial_link(self, port): """ Creates a new serial link instance. """ self.input_buffer = [] self.serial = QSerialPort() self.serial.setPortName(port) if self.serial.open(QIODevice.ReadWrite): self.serial.dataTerminalReady = True if not self.serial.isDataTerminalReady(): # Using pyserial as a 'hack' to open the port and set DTR # as QtSerial does not seem to work on some Windows :( # See issues #281 and #302 for details. self.serial.close() pyser = serial.Serial(port) # open serial port w/pyserial pyser.dtr = True pyser.close() self.serial.open(QIODevice.ReadWrite) self.serial.setBaudRate(115200) self.serial.readyRead.connect(self.on_serial_read) else: raise IOError("Cannot connect to device on port {}".format(port)) def close_serial_link(self): """ Close and clean up the currently open serial link. """ self.serial.close() self.serial = None def add_filesystem(self, home, file_manager): """ Adds the file system pane to the application. """ self.fs_pane = FileSystemPane(home) self.fs = QDockWidget(_('Filesystem on micro:bit')) self.fs.setWidget(self.fs_pane) self.fs.setFeatures(QDockWidget.DockWidgetMovable) self.fs.setAllowedAreas(Qt.BottomDockWidgetArea) self.addDockWidget(Qt.BottomDockWidgetArea, self.fs) self.fs_pane.setFocus() file_manager.on_list_files.connect(self.fs_pane.on_ls) self.fs_pane.list_files.connect(file_manager.ls) self.fs_pane.microbit_fs.put.connect(file_manager.put) self.fs_pane.microbit_fs.delete.connect(file_manager.delete) self.fs_pane.microbit_fs.list_files.connect(file_manager.ls) self.fs_pane.local_fs.get.connect(file_manager.get) self.fs_pane.local_fs.list_files.connect(file_manager.ls) file_manager.on_put_file.connect(self.fs_pane.microbit_fs.on_put) file_manager.on_delete_file.connect(self.fs_pane.microbit_fs.on_delete) file_manager.on_get_file.connect(self.fs_pane.local_fs.on_get) file_manager.on_list_fail.connect(self.fs_pane.on_ls_fail) file_manager.on_put_fail.connect(self.fs_pane.on_put_fail) file_manager.on_delete_fail.connect(self.fs_pane.on_delete_fail) file_manager.on_get_fail.connect(self.fs_pane.on_get_fail) self.connect_zoom(self.fs_pane) return self.fs_pane def add_micropython_repl(self, port, name): """ Adds a MicroPython based REPL pane to the application. """ if not self.serial: self.open_serial_link(port) # Send a Control-C / keyboard interrupt. self.serial.write(b'\x03') repl_pane = MicroPythonREPLPane(serial=self.serial, theme=self.theme) self.data_received.connect(repl_pane.process_bytes) self.add_repl(repl_pane, name) def add_micropython_plotter(self, port, name): """ Adds a plotter that reads data from a serial connection. """ if not self.serial: self.open_serial_link(port) plotter_pane = PlotterPane(theme=self.theme) self.data_received.connect(plotter_pane.process_bytes) self.add_plotter(plotter_pane, name) def add_jupyter_repl(self, kernel_manager, kernel_client): """ Adds a Jupyter based REPL pane to the application. """ kernel_manager.kernel.gui = 'qt4' kernel_client.start_channels() ipython_widget = JupyterREPLPane(theme=self.theme) ipython_widget.kernel_manager = kernel_manager ipython_widget.kernel_client = kernel_client self.add_repl(ipython_widget, _('Python3 (Jupyter)')) def add_repl(self, repl_pane, name): """ Adds the referenced REPL pane to the application. """ self.repl_pane = repl_pane self.repl = QDockWidget(_('{} REPL').format(name)) self.repl.setWidget(repl_pane) self.repl.setFeatures(QDockWidget.DockWidgetMovable) self.repl.setAllowedAreas(Qt.BottomDockWidgetArea | Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea) self.addDockWidget(Qt.BottomDockWidgetArea, self.repl) self.connect_zoom(self.repl_pane) self.repl_pane.set_theme(self.theme) self.repl_pane.setFocus() def add_plotter(self, plotter_pane, name): """ Adds the referenced plotter pane to the application. """ self.plotter_pane = plotter_pane self.plotter = QDockWidget(_('{} Plotter').format(name)) self.plotter.setWidget(plotter_pane) self.plotter.setFeatures(QDockWidget.DockWidgetMovable) self.plotter.setAllowedAreas(Qt.BottomDockWidgetArea | Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea) self.addDockWidget(Qt.BottomDockWidgetArea, self.plotter) self.plotter_pane.set_theme(self.theme) self.plotter_pane.setFocus() def add_python3_runner(self, script_name, working_directory, interactive=False, debugger=False, command_args=None, runner=None): """ Display console output for the referenced Python script. The script will be run within the workspace_path directory. If interactive is True (default is False) the Python process will run in interactive mode (dropping the user into the REPL when the script completes). If debugger is True (default is False) the script will be run within a debug runner session. The debugger overrides the interactive flag (you cannot run the debugger in interactive mode). If there is a list of command_args (the default is None) then these will be passed as further arguments into the command run in the new process. If runner is give, this is used as the command to start the Python process. """ self.process_runner = PythonProcessPane(self) self.runner = QDockWidget(_("Running: {}").format( os.path.basename(script_name))) self.runner.setWidget(self.process_runner) self.runner.setFeatures(QDockWidget.DockWidgetMovable) self.runner.setAllowedAreas(Qt.BottomDockWidgetArea | Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea) self.addDockWidget(Qt.BottomDockWidgetArea, self.runner) self.process_runner.start_process(script_name, working_directory, interactive, debugger, command_args, runner) self.process_runner.setFocus() self.connect_zoom(self.process_runner) return self.process_runner def add_debug_inspector(self): """ Display a debug inspector to view the call stack. """ self.debug_inspector = DebugInspector() self.debug_model = QStandardItemModel() self.debug_inspector.setModel(self.debug_model) self.debug_inspector.setUniformRowHeights(True) self.inspector = QDockWidget(_('Debug Inspector')) self.inspector.setWidget(self.debug_inspector) self.inspector.setFeatures(QDockWidget.DockWidgetMovable) self.inspector.setAllowedAreas(Qt.BottomDockWidgetArea | Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea) self.addDockWidget(Qt.RightDockWidgetArea, self.inspector) self.connect_zoom(self.debug_inspector) def update_debug_inspector(self, locals_dict): """ Given the contents of a dict representation of the locals in the current stack frame, update the debug inspector with the new values. """ excluded_names = ['__builtins__', '__debug_code__', '__debug_script__', ] names = sorted([x for x in locals_dict if x not in excluded_names]) self.debug_model.clear() self.debug_model.setHorizontalHeaderLabels([_('Name'), _('Value'), ]) for name in names: try: # DANGER! val = eval(locals_dict[name]) except Exception: val = None if isinstance(val, list): # Show a list consisting of rows of position/value list_item = QStandardItem(name) for i, i_val in enumerate(val): list_item.appendRow([ QStandardItem(str(i)), QStandardItem(repr(i_val)) ]) self.debug_model.appendRow([ list_item, QStandardItem(_('(A list of {} items.)').format(len(val))) ]) elif isinstance(val, dict): # Show a dict consisting of rows of key/value pairs. dict_item = QStandardItem(name) for k, k_val in val.items(): dict_item.appendRow([ QStandardItem(repr(k)), QStandardItem(repr(k_val)) ]) self.debug_model.appendRow([ dict_item, QStandardItem(_('(A dict of {} items.)').format(len(val))) ]) else: self.debug_model.appendRow([ QStandardItem(name), QStandardItem(locals_dict[name]), ]) def remove_filesystem(self): """ Removes the file system pane from the application. """ if hasattr(self, 'fs') and self.fs: self.fs_pane = None self.fs.setParent(None) self.fs.deleteLater() self.fs = None def remove_repl(self): """ Removes the REPL pane from the application. """ if self.repl: self.repl_pane = None self.repl.setParent(None) self.repl.deleteLater() self.repl = None if not self.plotter: self.serial = None def remove_plotter(self): """ Removes the plotter pane from the application. """ if self.plotter: self.plotter_pane = None self.plotter.setParent(None) self.plotter.deleteLater() self.plotter = None if not self.repl: self.serial = None def remove_python_runner(self): """ Removes the runner pane from the application. """ if hasattr(self, 'runner') and self.runner: self.process_runner = None self.runner.setParent(None) self.runner.deleteLater() self.runner = None def remove_debug_inspector(self): """ Removes the debug inspector pane from the application. """ if hasattr(self, 'inspector') and self.inspector: self.debug_inspector = None self.debug_model = None self.inspector.setParent(None) self.inspector.deleteLater() self.inspector = None def set_theme(self, theme): """ Sets the theme for the REPL and editor tabs. """ self.theme = theme if theme == 'contrast': self.setStyleSheet(CONTRAST_STYLE) new_theme = ContrastTheme new_icon = 'theme_day' elif theme == 'night': new_theme = NightTheme new_icon = 'theme_contrast' self.setStyleSheet(NIGHT_STYLE) else: self.setStyleSheet(DAY_STYLE) new_theme = DayTheme new_icon = 'theme' for widget in self.widgets: widget.set_theme(new_theme) self.button_bar.slots['theme'].setIcon(load_icon(new_icon)) if hasattr(self, 'repl') and self.repl: self.repl_pane.set_theme(theme) if hasattr(self, 'plotter') and self.plotter: self.plotter_pane.set_theme(theme) def show_logs(self, log, theme): """ Display the referenced content of the log. """ log_box = LogDisplay() log_box.setup(log, theme) log_box.exec() def show_message(self, message, information=None, icon=None): """ Displays a modal message to the user. If information is passed in this will be set as the additional informative text in the modal dialog. Since this mechanism will be used mainly for warning users that something is awry the default icon is set to "Warning". It's possible to override the icon to one of the following settings: NoIcon, Question, Information, Warning or Critical. """ message_box = QMessageBox(self) message_box.setText(message) message_box.setWindowTitle('Mu') if information: message_box.setInformativeText(information) if icon and hasattr(message_box, icon): message_box.setIcon(getattr(message_box, icon)) else: message_box.setIcon(message_box.Warning) logger.debug(message) logger.debug(information) message_box.exec() def show_confirmation(self, message, information=None, icon=None): """ Displays a modal message to the user to which they need to confirm or cancel. If information is passed in this will be set as the additional informative text in the modal dialog. Since this mechanism will be used mainly for warning users that something is awry the default icon is set to "Warning". It's possible to override the icon to one of the following settings: NoIcon, Question, Information, Warning or Critical. """ message_box = QMessageBox() message_box.setText(message) message_box.setWindowTitle(_('Mu')) if information: message_box.setInformativeText(information) if icon and hasattr(message_box, icon): message_box.setIcon(getattr(message_box, icon)) else: message_box.setIcon(message_box.Warning) message_box.setStandardButtons(message_box.Cancel | message_box.Ok) message_box.setDefaultButton(message_box.Cancel) logger.debug(message) logger.debug(information) return message_box.exec() def update_title(self, filename=None): """ Updates the title bar of the application. If a filename (representing the name of the file currently the focus of the editor) is supplied, append it to the end of the title. """ title = self.title if filename: title += ' - ' + filename self.setWindowTitle(title) def autosize_window(self): """ Makes the editor 80% of the width*height of the screen and centres it. """ screen = QDesktopWidget().screenGeometry() w = int(screen.width() * 0.8) h = int(screen.height() * 0.8) self.resize(w, h) size = self.geometry() self.move((screen.width() - size.width()) / 2, (screen.height() - size.height()) / 2) def reset_annotations(self): """ Resets the state of annotations on the current tab. """ self.current_tab.reset_annotations() def annotate_code(self, feedback, annotation_type): """ Given a list of annotations about the code in the current tab, add the annotations to the editor window so the user can make appropriate changes. """ self.current_tab.annotate_code(feedback, annotation_type) def show_annotations(self): """ Show the annotations added to the current tab. """ self.current_tab.show_annotations() def setup(self, breakpoint_toggle, theme): """ Sets up the window. Defines the various attributes of the window and defines how the user interface is laid out. """ self.theme = theme self.breakpoint_toggle = breakpoint_toggle # Give the window a default icon, title and minimum size. self.setWindowIcon(load_icon(self.icon)) self.update_title() self.read_only_tabs = False self.setMinimumSize(800, 400) self.widget = QWidget() widget_layout = QVBoxLayout() self.widget.setLayout(widget_layout) self.button_bar = ButtonBar(self.widget) self.tabs = FileTabs() self.tabs.setMovable(True) self.setCentralWidget(self.tabs) self.status_bar = StatusBar(parent=self) self.setStatusBar(self.status_bar) self.addToolBar(self.button_bar) self.show() self.autosize_window() def resizeEvent(self, resizeEvent): """ Respond to window getting too small for the button bar to fit well. """ size = resizeEvent.size() self.button_bar.set_responsive_mode(size.width(), size.height()) def select_mode(self, modes, current_mode, theme): """ Display the mode selector dialog and return the result. """ mode_select = ModeSelector() mode_select.setup(modes, current_mode, theme) mode_select.exec() try: return mode_select.get_mode() except Exception as ex: return None def change_mode(self, mode): """ Given a an object representing a mode, recreates the button bar with the expected functionality. """ self.button_bar.change_mode(mode) # Update the autocomplete / tooltip APIs for each tab to the new mode. api = mode.api() for widget in self.widgets: widget.set_api(api) def set_usb_checker(self, duration, callback): """ Sets up a timer that polls for USB changes via the "callback" every "duration" seconds. """ self.usb_checker = QTimer() self.usb_checker.timeout.connect(callback) self.usb_checker.start(duration * 1000) def set_timer(self, duration, callback): """ Set a repeating timer to call "callback" every "duration" seconds. """ self.timer = QTimer() self.timer.timeout.connect(callback) self.timer.start(duration * 1000) # Measured in milliseconds. def stop_timer(self): """ Stop the repeating timer. """ if self.timer: self.timer.stop() self.timer = None def connect_tab_rename(self, handler, shortcut): """ Connect the double-click event on a tab and the keyboard shortcut to the referenced handler (causing the Save As dialog). """ self.tabs.shortcut = QShortcut(QKeySequence(shortcut), self) self.tabs.shortcut.activated.connect(handler) self.tabs.tabBarDoubleClicked.connect(handler) def open_directory_from_os(self, path): """ Given the path to a directoy, open the OS's built in filesystem explorer for that path. Works with Windows, OSX and Linux. """ if sys.platform == 'win32': # Windows os.startfile(path) elif sys.platform == 'darwin': # OSX os.system('open "{}"'.format(path)) else: # Assume freedesktop.org on unix-y. os.system('xdg-open "{}"'.format(path))
class MainWindow(QMainWindow): def __init__(self, parent=None): super(MainWindow, self).__init__() self.setWindowTitle("RainbowBB") self.setParent(parent) self.initUI() def initUI(self): self.setStyleSheet("QCheckBox { background: palette(window); border-radius: 4px; padding: 2px; margin-right: 2px; }") self.toolBar = QToolBar(self) self.toolBar.setStyleSheet(stylesheet % (create_gradient("pastel"),)) self.toolBar.setMovable(False) self.toolBar.setContextMenuPolicy(Qt.CustomContextMenu) self.addToolBar(self.toolBar) self.reverseBox = QCheckBox("&Reverse", self) self.reverseBox.clicked.connect(lambda: self.updateGradient()) self.toolBar.addWidget(self.reverseBox) self.byWordBox = QCheckBox("By &word", self) self.toolBar.addWidget(self.byWordBox) self.bounceBox = QCheckBox("&Bounce", self) self.bounceBox.clicked.connect(lambda: self.updateGradient()) self.toolBar.addWidget(self.bounceBox) self.sizeList = QComboBox(self) self.sizeList.addItem("None") for num in range(1, 8): self.sizeList.addItem(str(num)) self.toolBar.addWidget(self.sizeList) self.cycleList = QComboBox(self) self.toolBar.addWidget(self.cycleList) self.cycleList.currentIndexChanged.connect(self.updateGradient) self.loadCycles() self.convertButton = QPushButton("&Convert", self) self.convertButton.clicked.connect(self.convert) self.toolBar.addWidget(self.convertButton) self.reloadButton = QPushButton("Reload", self) self.reloadButton.setShortcut("Alt+Shift+R") self.reloadButton.clicked.connect(self.loadCycles) self.toolBar.addWidget(self.reloadButton) self.inputDock = QDockWidget("Input", self) self.inputDock.setFeatures(QDockWidget.NoDockWidgetFeatures) self.inputDock.setContextMenuPolicy(Qt.CustomContextMenu) self.addDockWidget(Qt.LeftDockWidgetArea, self.inputDock) self.inputField = QTextEdit(self) self.inputField.setAcceptRichText(False) self.inputDock.setWidget(self.inputField) self.outputField = QTextEdit(self) self.outputField.setReadOnly(True) self.setCentralWidget(self.outputField) def updateGradient(self, index=None): if not index: index = self.cycleList.currentIndex() self.toolBar.setStyleSheet(stylesheet % (create_gradient(self.cycleList.itemText(index), self.reverseBox.isChecked(), self.bounceBox.isChecked()),)) def loadCycles(self): rainbowbb.load_cycles() self.cycleList.clear() self.cycleList.addItem("pastel") for cycle in sorted(list(rainbowbb.cycles.keys())): if cycle != "pastel": self.cycleList.addItem(cycle) def show(self): self.setVisible(True) self.inputField.setFocus() def convert(self): self.outputField.setPlainText(rainbowbb.size(rainbowbb.colorize(self.inputField.toPlainText(), self.cycleList.currentText(), self.reverseBox.isChecked(), not self.byWordBox.isChecked(), self.bounceBox.isChecked()), self.sizeList.currentText() if self.sizeList.currentText() != "None" else None))
class DocumentController(): """ Connects UI buttons to their corresponding actions in the model. """ ### INIT METHODS ### def __init__(self, document): """docstring for __init__""" # initialize variables self._document = document print("the doc", self._document) self._document.setController(self) self._active_part = None self._filename = None self._file_open_path = None # will be set in _readSettings self._has_no_associated_file = True self._path_view_instance = None self._slice_view_instance = None self._undo_stack = None self.win = None self.fileopendialog = None self.filesavedialog = None self.settings = QSettings() self._readSettings() # call other init methods self._initWindow() app().document_controllers.add(self) def _initWindow(self): """docstring for initWindow""" self.win = DocumentWindow(doc_ctrlr=self) # self.win.setWindowIcon(app().icon) app().documentWindowWasCreatedSignal.emit(self._document, self.win) self._connectWindowSignalsToSelf() self.win.show() app().active_document = self def _initMaya(self): """ Initialize Maya-related state. Delete Maya nodes if there is an old document left over from the same session. Set up the Maya window. """ # There will only be one document if (app().active_document and app().active_document.win and not app().active_document.win.close()): return del app().active_document app().active_document = self import maya.OpenMayaUI as OpenMayaUI import sip ptr = OpenMayaUI.MQtUtil.mainWindow() mayaWin = sip.wrapinstance(int(ptr), QMainWindow) self.windock = QDockWidget("cadnano") self.windock.setFeatures(QDockWidget.DockWidgetMovable | QDockWidget.DockWidgetFloatable) self.windock.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea) self.windock.setWidget(self.win) mayaWin.addDockWidget(Qt.DockWidgetArea(Qt.LeftDockWidgetArea), self.windock) self.windock.setVisible(True) def _connectWindowSignalsToSelf(self): """This method serves to group all the signal & slot connections made by DocumentController""" self.win.action_new.triggered.connect(self.actionNewSlot) self.win.action_open.triggered.connect(self.actionOpenSlot) self.win.action_close.triggered.connect(self.actionCloseSlot) self.win.action_save.triggered.connect(self.actionSaveSlot) self.win.action_save_as.triggered.connect(self.actionSaveAsSlot) self.win.action_SVG.triggered.connect(self.actionSVGSlot) self.win.action_autostaple.triggered.connect(self.actionAutostapleSlot) self.win.action_export_staples.triggered.connect(self.actionExportStaplesSlot) self.win.action_preferences.triggered.connect(self.actionPrefsSlot) self.win.action_modify.triggered.connect(self.actionModifySlot) self.win.action_new_honeycomb_part.triggered.connect(\ self.actionAddHoneycombPartSlot) self.win.action_new_square_part.triggered.connect(\ self.actionAddSquarePartSlot) self.win.closeEvent = self.windowCloseEventHandler self.win.action_about.triggered.connect(self.actionAboutSlot) self.win.action_cadnano_website.triggered.connect(self.actionCadnanoWebsiteSlot) self.win.action_feedback.triggered.connect(self.actionFeedbackSlot) self.win.action_filter_handle.triggered.connect(self.actionFilterHandleSlot) self.win.action_filter_endpoint.triggered.connect(self.actionFilterEndpointSlot) self.win.action_filter_strand.triggered.connect(self.actionFilterStrandSlot) self.win.action_filter_xover.triggered.connect(self.actionFilterXoverSlot) self.win.action_filter_scaf.triggered.connect(self.actionFilterScafSlot) self.win.action_filter_stap.triggered.connect(self.actionFilterStapSlot) self.win.action_renumber.triggered.connect(self.actionRenumberSlot) ### SLOTS ### def undoStackCleanChangedSlot(self): """The title changes to include [*] on modification.""" self.win.setWindowModified(not self.undoStack().isClean()) self.win.setWindowTitle(self.documentTitle()) def actionAboutSlot(self): """Displays the about cadnano dialog.""" from ui.dialogs.ui_about import Ui_About dialog = QDialog() dialog_about = Ui_About() # reusing this dialog, should rename dialog.setStyleSheet("QDialog { background-image: url(ui/dialogs/images/cadnano2-about.png); background-repeat: none; }") dialog_about.setupUi(dialog) dialog.exec_() filter_list = ["strand", "endpoint", "xover", "virtual_helix"] def actionFilterHandleSlot(self): """Disables all other selection filters when active.""" fH = self.win.action_filter_handle fE = self.win.action_filter_endpoint fS = self.win.action_filter_strand fX = self.win.action_filter_xover fH.setChecked(True) if fE.isChecked(): fE.setChecked(False) if fS.isChecked(): fS.setChecked(False) if fX.isChecked(): fX.setChecked(False) self._document.documentSelectionFilterChangedSignal.emit(["virtual_helix"]) def actionFilterEndpointSlot(self): """ Disables handle filters when activated. Remains checked if no other item-type filter is active. """ fH = self.win.action_filter_handle fE = self.win.action_filter_endpoint fS = self.win.action_filter_strand fX = self.win.action_filter_xover if fH.isChecked(): fH.setChecked(False) if not fS.isChecked() and not fX.isChecked(): fE.setChecked(True) self._strandFilterUpdate() # end def def actionFilterStrandSlot(self): """ Disables handle filters when activated. Remains checked if no other item-type filter is active. """ fH = self.win.action_filter_handle fE = self.win.action_filter_endpoint fS = self.win.action_filter_strand fX = self.win.action_filter_xover if fH.isChecked(): fH.setChecked(False) if not fE.isChecked() and not fX.isChecked(): fS.setChecked(True) self._strandFilterUpdate() # end def def actionFilterXoverSlot(self): """ Disables handle filters when activated. Remains checked if no other item-type filter is active. """ fH = self.win.action_filter_handle fE = self.win.action_filter_endpoint fS = self.win.action_filter_strand fX = self.win.action_filter_xover if fH.isChecked(): fH.setChecked(False) if not fE.isChecked() and not fS.isChecked(): fX.setChecked(True) self._strandFilterUpdate() # end def def actionFilterScafSlot(self): """Remains checked if no other strand-type filter is active.""" fSc = self.win.action_filter_scaf fSt = self.win.action_filter_stap if not fSc.isChecked() and not fSt.isChecked(): fSc.setChecked(True) self._strandFilterUpdate() def actionFilterStapSlot(self): """Remains checked if no other strand-type filter is active.""" fSc = self.win.action_filter_scaf fSt = self.win.action_filter_stap if not fSc.isChecked() and not fSt.isChecked(): fSt.setChecked(True) self._strandFilterUpdate() # end def def _strandFilterUpdate(self): win = self.win filter_list = [] if win.action_filter_endpoint.isChecked(): filter_list.append("endpoint") if win.action_filter_strand.isChecked(): filter_list.append("strand") if win.action_filter_xover.isChecked(): filter_list.append("xover") if win.action_filter_scaf.isChecked(): filter_list.append("scaffold") if win.action_filter_stap.isChecked(): filter_list.append("staple") self._document.documentSelectionFilterChangedSignal.emit(filter_list) # end def def actionNewSlot(self): """ 1. If document is has no parts, do nothing. 2. If document is dirty, call maybeSave and continue if it succeeds. 3. Create a new document and swap it into the existing ctrlr/window. """ # clear/reset the view! if len(self._document.parts()) == 0: return # no parts if self.maybeSave() == False: return # user canceled in maybe save else: # user did not cancel if self.filesavedialog != None: self.filesavedialog.finished.connect(self.newClickedCallback) else: # user did not save self.newClickedCallback() # finalize new def actionOpenSlot(self): """ 1. If document is untouched, proceed to open dialog. 2. If document is dirty, call maybesave and continue if it succeeds. Downstream, the file is selected in openAfterMaybeSave, and the selected file is actually opened in openAfterMaybeSaveCallback. """ if self.maybeSave() == False: return # user canceled in maybe save else: # user did not cancel if hasattr(self, "filesavedialog"): # user did save if self.filesavedialog != None: self.filesavedialog.finished.connect(self.openAfterMaybeSave) else: self.openAfterMaybeSave() # windows else: # user did not save self.openAfterMaybeSave() # finalize new def actionCloseSlot(self): """This will trigger a Window closeEvent.""" # if util.isWindows(): self.win.close() app().qApp.exit(0) def actionSaveSlot(self): """SaveAs if necessary, otherwise overwrite existing file.""" if self._has_no_associated_file: self.saveFileDialog() return self.writeDocumentToFile() def actionSaveAsSlot(self): """Open a save file dialog so user can choose a name.""" self.saveFileDialog() def actionSVGSlot(self): """docstring for actionSVGSlot""" fname = os.path.basename(str(self.filename())) if fname == None: directory = "." else: directory = QFileInfo(fname).path() fdialog = QFileDialog( self.win, "%s - Save As" % QApplication.applicationName(), directory, "%s (*.svg)" % QApplication.applicationName()) fdialog.setAcceptMode(QFileDialog.AcceptSave) fdialog.setWindowFlags(Qt.Sheet) fdialog.setWindowModality(Qt.WindowModal) self.svgsavedialog = fdialog self.svgsavedialog.filesSelected.connect(self.saveSVGDialogCallback) fdialog.open() class DummyChild(QGraphicsItem): def boundingRect(self): return QRect(200, 200) # self.parentObject().boundingRect() def paint(self, painter, option, widget=None): pass def saveSVGDialogCallback(self, selected): if isinstance(selected, (list, tuple)): fname = selected[0] else: fname = selected print("da fname", fname) if fname is None or os.path.isdir(fname): return False if not fname.lower().endswith(".svg"): fname += ".svg" if self.svgsavedialog != None: self.svgsavedialog.filesSelected.disconnect(self.saveSVGDialogCallback) del self.svgsavedialog # prevents hang self.svgsavedialog = None generator = QSvgGenerator() generator.setFileName(fname) generator.setSize(QSize(200, 200)) generator.setViewBox(QRect(0, 0, 2000, 2000)) painter = QPainter() # Render through scene # painter.begin(generator) # self.win.pathscene.render(painter) # painter.end() # Render item-by-item painter = QPainter() style_option = QStyleOptionGraphicsItem() q = [self.win.pathroot] painter.begin(generator) while q: graphics_item = q.pop() transform = graphics_item.itemTransform(self.win.sliceroot)[0] painter.setTransform(transform) if graphics_item.isVisible(): graphics_item.paint(painter, style_option, None) q.extend(graphics_item.childItems()) painter.end() def actionExportStaplesSlot(self): """ Triggered by clicking Export Staples button. Opens a file dialog to determine where the staples should be saved. The callback is exportStaplesCallback which collects the staple sequences and exports the file. """ # Validate that no staple oligos are loops. part = self.activePart() if part is None: return stap_loop_olgs = part.getStapleLoopOligos() if stap_loop_olgs: from ui.dialogs.ui_warning import Ui_Warning dialog = QDialog() dialogWarning = Ui_Warning() # reusing this dialog, should rename dialog.setStyleSheet("QDialog { background-image: url(ui/dialogs/images/cadnano2-about.png); background-repeat: none; }") dialogWarning.setupUi(dialog) locs = ", ".join([o.locString() for o in stap_loop_olgs]) msg = "Part contains staple loop(s) at %s.\n\nUse the break tool to introduce 5' & 3' ends before exporting. Loops have been colored red; use undo to revert." % locs dialogWarning.title.setText("Staple validation failed") dialogWarning.message.setText(msg) for o in stap_loop_olgs: o.applyColor(styles.stapColors[0].name()) dialog.exec_() return # Proceed with staple export. fname = self.filename() if fname == None: directory = "." else: directory = QFileInfo(fname).path() if util.isWindows(): # required for native looking file window fname = QFileDialog.getSaveFileName( self.win, "%s - Export As" % QApplication.applicationName(), directory, "(*.csv)") self.saveStaplesDialog = None self.exportStaplesCallback(fname) else: # access through non-blocking callback fdialog = QFileDialog( self.win, "%s - Export As" % QApplication.applicationName(), directory, "(*.csv)") fdialog.setAcceptMode(QFileDialog.AcceptSave) fdialog.setWindowFlags(Qt.Sheet) fdialog.setWindowModality(Qt.WindowModal) self.saveStaplesDialog = fdialog self.saveStaplesDialog.filesSelected.connect(self.exportStaplesCallback) fdialog.open() # end def def actionPrefsSlot(self): app().prefsClicked() def actionAutostapleSlot(self): part = self.activePart() if part: self.win.path_graphics_view.setViewportUpdateOn(False) part.autoStaple() self.win.path_graphics_view.setViewportUpdateOn(True) def actionModifySlot(self): """ Notifies that part root items that parts should respond to modifier selection signals. """ pass # uncomment for debugging # isChecked = self.win.actionModify.isChecked() # self.win.pathroot.setModifyState(isChecked) # self.win.sliceroot.setModifyState(isChecked) # if app().isInMaya(): # isChecked = self.win.actionModify.isChecked() # self.win.pathroot.setModifyState(isChecked) # self.win.sliceroot.setModifyState(isChecked) # self.win.solidroot.setModifyState(isChecked) def actionAddHoneycombPartSlot(self): """docstring for actionAddHoneycombPartSlot""" part = self._document.addHoneycombPart() self.setActivePart(part) def actionAddSquarePartSlot(self): """docstring for actionAddSquarePartSlot""" part = self._document.addSquarePart() self.setActivePart(part) def actionRenumberSlot(self): coordList = self.win.pathroot.getSelectedPartOrderedVHList() part = self.activePart() part.renumber(coordList) # end def ### ACCESSORS ### def document(self): return self._document def window(self): return self.win def setDocument(self, doc): """ Sets the controller's document, and informs the document that this is its controller. """ self._document = doc doc.setController(self) def activePart(self): if self._active_part == None: self._active_part = self._document.selectedPart() return self._active_part def setActivePart(self, part): self._active_part = part def undoStack(self): return self._document.undoStack() ### PRIVATE SUPPORT METHODS ### def newDocument(self, doc=None, fname=None): """Creates a new Document, reusing the DocumentController.""" if fname is not None and self._filename == fname: setReopen(True) self._document.resetViews() setBatch(True) self._document.removeAllParts() # clear out old parts setBatch(False) self._document.undoStack().clear() # reset undostack self._filename = fname if fname else "untitled.json" self._has_no_associated_file = fname == None self._active_part = None self.win.setWindowTitle(self.documentTitle() + '[*]') def saveFileDialog(self): fname = self.filename() if fname == None: directory = "." else: directory = QFileInfo(fname).path() if util.isWindows(): # required for native looking file window fname = QFileDialog.getSaveFileName( self.win, "%s - Save As" % QApplication.applicationName(), directory, "%s (*.json)" % QApplication.applicationName()) self.writeDocumentToFile(fname) else: # access through non-blocking callback fdialog = QFileDialog( self.win, "%s - Save As" % QApplication.applicationName(), directory, "%s (*.json)" % QApplication.applicationName()) fdialog.setAcceptMode(QFileDialog.AcceptSave) fdialog.setWindowFlags(Qt.Sheet) fdialog.setWindowModality(Qt.WindowModal) self.filesavedialog = fdialog self.filesavedialog.filesSelected.connect( self.saveFileDialogCallback) fdialog.open() # end def def _readSettings(self): self.settings.beginGroup("FileSystem") self._file_open_path = self.settings.value("openpath", QDir().homePath()) self.settings.endGroup() def _writeFileOpenPath(self, path): """docstring for _writePath""" self._file_open_path = path self.settings.beginGroup("FileSystem") self.settings.setValue("openpath", path) self.settings.endGroup() ### SLOT CALLBACKS ### def actionNewSlotCallback(self): """ Gets called on completion of filesavedialog after newClicked's maybeSave. Removes the dialog if necessary, but it was probably already removed by saveFileDialogCallback. """ if self.filesavedialog != None: self.filesavedialog.finished.disconnect(self.actionNewSlotCallback) del self.filesavedialog # prevents hang (?) self.filesavedialog = None self.newDocument() def exportStaplesCallback(self, selected): """Export all staple sequences to selected CSV file.""" if isinstance(selected, (list, tuple)): fname = selected[0] else: fname = selected if fname is None or os.path.isdir(fname): return False if not fname.lower().endswith(".csv"): fname += ".csv" if self.saveStaplesDialog != None: self.saveStaplesDialog.filesSelected.disconnect(self.exportStaplesCallback) # manual garbage collection to prevent hang (in osx) del self.saveStaplesDialog self.saveStaplesDialog = None # write the file output = self.activePart().getStapleSequences() with open(fname, 'w') as f: f.write(output) # end def def newClickedCallback(self): """ Gets called on completion of filesavedialog after newClicked's maybeSave. Removes the dialog if necessary, but it was probably already removed by saveFileDialogCallback. """ if self.filesavedialog != None: self.filesavedialog.finished.disconnect(self.newClickedCallback) del self.filesavedialog # prevents hang (?) self.filesavedialog = None self.newDocument() def openAfterMaybeSaveCallback(self, selected): """ Receives file selection info from the dialog created by openAfterMaybeSave, following user input. Extracts the file name and passes it to the decode method, which returns a new document doc, which is then set as the open document by newDocument. Calls finalizeImport and disconnects dialog signaling. """ if isinstance(selected, (list, tuple)): fname = selected[0] else: fname = selected if fname is None or os.path.isdir(fname): return False self._writeFileOpenPath(os.path.dirname(fname)) self.win.path_graphics_view.setViewportUpdateOn(False) self.win.slice_graphics_view.setViewportUpdateOn(False) self.newDocument(fname=fname) decodeFile(fname, document=self._document) self.win.path_graphics_view.setViewportUpdateOn(True) self.win.slice_graphics_view.setViewportUpdateOn(True) self.win.path_graphics_view.update() self.win.slice_graphics_view.update() if hasattr(self, "filesavedialog"): # user did save if self.fileopendialog != None: self.fileopendialog.filesSelected.disconnect(\ self.openAfterMaybeSaveCallback) # manual garbage collection to prevent hang (in osx) del self.fileopendialog self.fileopendialog = None def saveFileDialogCallback(self, selected): """If the user chose to save, write to that file.""" if isinstance(selected, (list, tuple)): fname = selected[0] else: fname = selected if fname is None or os.path.isdir(fname): return False if not fname.lower().endswith(".json"): fname += ".json" if self.filesavedialog != None: self.filesavedialog.filesSelected.disconnect( self.saveFileDialogCallback) del self.filesavedialog # prevents hang self.filesavedialog = None self.writeDocumentToFile(fname) self._writeFileOpenPath(os.path.dirname(fname)) ### EVENT HANDLERS ### def windowCloseEventHandler(self, event): """Intercept close events when user attempts to close the window.""" if self.maybeSave(): event.accept() # if app().isInMaya(): # self.windock.setVisible(False) # del self.windock # self.windock = None app().document_controllers.remove(self) else: event.ignore() self.actionCloseSlot() ### FILE INPUT ## def documentTitle(self): fname = os.path.basename(str(self.filename())) if not self.undoStack().isClean(): fname += '[*]' return fname def filename(self): return self._filename def setFilename(self, proposed_fname): if self._filename == proposed_fname: return True self._filename = proposed_fname self._has_no_associated_file = False self.win.setWindowTitle(self.documentTitle()) return True def openAfterMaybeSave(self): """ This is the method that initiates file opening. It is called by actionOpenSlot to spawn a QFileDialog and connect it to a callback method. """ path = self._file_open_path if util.isWindows(): # required for native looking file window#"/", fname = QFileDialog.getOpenFileName( None, "Open Document", path, "cadnano1 / cadnano2 Files (*.nno *.json *.cadnano)") self.filesavedialog = None self.openAfterMaybeSaveCallback(fname) else: # access through non-blocking callback fdialog = QFileDialog( self.win, "Open Document", path, "cadnano1 / cadnano2 Files (*.nno *.json *.cadnano)") fdialog.setAcceptMode(QFileDialog.AcceptOpen) fdialog.setWindowFlags(Qt.Sheet) fdialog.setWindowModality(Qt.WindowModal) self.fileopendialog = fdialog self.fileopendialog.filesSelected.connect(self.openAfterMaybeSaveCallback) fdialog.open() # end def ### FILE OUTPUT ### def maybeSave(self): """Save on quit, check if document changes have occured.""" if app().dontAskAndJustDiscardUnsavedChanges: return True if not self.undoStack().isClean(): # document dirty? savebox = QMessageBox(QMessageBox.Warning, "Application", "The document has been modified.\nDo you want to save your changes?", QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel, self.win, Qt.Dialog | Qt.MSWindowsFixedSizeDialogHint | Qt.Sheet) savebox.setWindowModality(Qt.WindowModal) save = savebox.button(QMessageBox.Save) discard = savebox.button(QMessageBox.Discard) cancel = savebox.button(QMessageBox.Cancel) save.setShortcut("Ctrl+S") discard.setShortcut(QKeySequence("D,Ctrl+D")) cancel.setShortcut(QKeySequence("C,Ctrl+C,.,Ctrl+.")) ret = savebox.exec_() del savebox # manual garbage collection to prevent hang (in osx) if ret == QMessageBox.Save: return self.actionSaveAsSlot() elif ret == QMessageBox.Cancel: return False return True def writeDocumentToFile(self, filename=None): if filename == None: assert(not self._has_no_associated_file) filename = self.filename() try: with open(filename, 'w') as f: helix_order_list = self.win.pathroot.getSelectedPartOrderedVHList() encode(self._document, helix_order_list, f) except IOError: flags = Qt.Dialog | Qt.MSWindowsFixedSizeDialogHint | Qt.Sheet errorbox = QMessageBox(QMessageBox.Critical, "cadnano", "Could not write to '%s'." % filename, QMessageBox.Ok, self.win, flags) errorbox.setWindowModality(Qt.WindowModal) errorbox.open() return False self.undoStack().setClean() self.setFilename(filename) return True def actionCadnanoWebsiteSlot(self): import webbrowser webbrowser.open("http://cadnano.org/") def actionFeedbackSlot(self): import webbrowser webbrowser.open("http://cadnano.org/feedback")
class MusicPlayer(QMainWindow): """MusicPlayer houses all of elements that directly interact with the main window.""" def __init__(self, parent=None): """Initialize the QMainWindow widget. The window title, window icon, and window size are initialized here as well as the following widgets: QMediaPlayer, QMediaPlaylist, QMediaContent, QMenuBar, QToolBar, QLabel, QPixmap, QSlider, QDockWidget, QListWidget, QWidget, and QVBoxLayout. The connect signals for relavant widgets are also initialized. """ super(MusicPlayer, self).__init__(parent) self.setWindowTitle('Mosaic') window_icon = utilities.resource_filename('mosaic.images', 'icon.png') self.setWindowIcon(QIcon(window_icon)) self.resize(defaults.Settings().window_size, defaults.Settings().window_size + 63) # Initiates Qt objects to be used by MusicPlayer self.player = QMediaPlayer() self.playlist = QMediaPlaylist() self.playlist_location = defaults.Settings().playlist_path self.content = QMediaContent() self.menu = self.menuBar() self.toolbar = QToolBar() self.art = QLabel() self.pixmap = QPixmap() self.slider = QSlider(Qt.Horizontal) self.duration_label = QLabel() self.playlist_dock = QDockWidget('Playlist', self) self.library_dock = QDockWidget('Media Library', self) self.playlist_view = QListWidget() self.library_view = library.MediaLibraryView() self.library_model = library.MediaLibraryModel() self.preferences = configuration.PreferencesDialog() self.widget = QWidget() self.layout = QVBoxLayout(self.widget) self.duration = 0 self.playlist_dock_state = None self.library_dock_state = None # Sets QWidget() as the central widget of the main window self.setCentralWidget(self.widget) self.layout.setContentsMargins(0, 0, 0, 0) self.art.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored) # Initiates the playlist dock widget and the library dock widget self.addDockWidget(defaults.Settings().dock_position, self.playlist_dock) self.playlist_dock.setWidget(self.playlist_view) self.playlist_dock.setVisible(defaults.Settings().playlist_on_start) self.playlist_dock.setFeatures(QDockWidget.DockWidgetClosable) self.addDockWidget(defaults.Settings().dock_position, self.library_dock) self.library_dock.setWidget(self.library_view) self.library_dock.setVisible(defaults.Settings().media_library_on_start) self.library_dock.setFeatures(QDockWidget.DockWidgetClosable) self.tabifyDockWidget(self.playlist_dock, self.library_dock) # Sets the range of the playback slider and sets the playback mode as looping self.slider.setRange(0, self.player.duration() / 1000) self.playlist.setPlaybackMode(QMediaPlaylist.Sequential) # OSX system menu bar causes conflicts with PyQt5 menu bar if sys.platform == 'darwin': self.menu.setNativeMenuBar(False) # Initiates Settings in the defaults module to give access to settings.toml defaults.Settings() # Signals that connect to other methods when they're called self.player.metaDataChanged.connect(self.display_meta_data) self.slider.sliderMoved.connect(self.seek) self.player.durationChanged.connect(self.song_duration) self.player.positionChanged.connect(self.song_position) self.player.stateChanged.connect(self.set_state) self.playlist_view.itemActivated.connect(self.activate_playlist_item) self.library_view.activated.connect(self.open_media_library) self.playlist.currentIndexChanged.connect(self.change_index) self.playlist.mediaInserted.connect(self.initialize_playlist) self.playlist_dock.visibilityChanged.connect(self.dock_visiblity_change) self.library_dock.visibilityChanged.connect(self.dock_visiblity_change) self.preferences.dialog_media_library.media_library_line.textChanged.connect(self.change_media_library_path) self.preferences.dialog_view_options.dropdown_box.currentIndexChanged.connect(self.change_window_size) self.art.mousePressEvent = self.press_playback # Creating the menu controls, media controls, and window size of the music player self.menu_controls() self.media_controls() self.load_saved_playlist() def menu_controls(self): """Initiate the menu bar and add it to the QMainWindow widget.""" self.file = self.menu.addMenu('File') self.edit = self.menu.addMenu('Edit') self.playback = self.menu.addMenu('Playback') self.view = self.menu.addMenu('View') self.help_ = self.menu.addMenu('Help') self.file_menu() self.edit_menu() self.playback_menu() self.view_menu() self.help_menu() def media_controls(self): """Create the bottom toolbar and controls used for media playback.""" self.addToolBar(Qt.BottomToolBarArea, self.toolbar) self.toolbar.setMovable(False) play_icon = utilities.resource_filename('mosaic.images', 'md_play.png') self.play_action = QAction(QIcon(play_icon), 'Play', self) self.play_action.triggered.connect(self.player.play) stop_icon = utilities.resource_filename('mosaic.images', 'md_stop.png') self.stop_action = QAction(QIcon(stop_icon), 'Stop', self) self.stop_action.triggered.connect(self.player.stop) previous_icon = utilities.resource_filename('mosaic.images', 'md_previous.png') self.previous_action = QAction(QIcon(previous_icon), 'Previous', self) self.previous_action.triggered.connect(self.previous) next_icon = utilities.resource_filename('mosaic.images', 'md_next.png') self.next_action = QAction(QIcon(next_icon), 'Next', self) self.next_action.triggered.connect(self.playlist.next) repeat_icon = utilities.resource_filename('mosaic.images', 'md_repeat_none.png') self.repeat_action = QAction(QIcon(repeat_icon), 'Repeat', self) self.repeat_action.setShortcut('R') self.repeat_action.triggered.connect(self.repeat_song) self.toolbar.addAction(self.play_action) self.toolbar.addAction(self.stop_action) self.toolbar.addAction(self.previous_action) self.toolbar.addAction(self.next_action) self.toolbar.addAction(self.repeat_action) self.toolbar.addWidget(self.slider) self.toolbar.addWidget(self.duration_label) def file_menu(self): """Add a file menu to the menu bar. The file menu houses the Open File, Open Multiple Files, Open Playlist, Open Directory, and Exit Application menu items. """ self.open_action = QAction('Open File', self) self.open_action.setShortcut('O') self.open_action.triggered.connect(self.open_file) self.open_multiple_files_action = QAction('Open Multiple Files', self) self.open_multiple_files_action.setShortcut('M') self.open_multiple_files_action.triggered.connect(self.open_multiple_files) self.open_playlist_action = QAction('Open Playlist', self) self.open_playlist_action.setShortcut('CTRL+P') self.open_playlist_action.triggered.connect(self.open_playlist) self.open_directory_action = QAction('Open Directory', self) self.open_directory_action.setShortcut('D') self.open_directory_action.triggered.connect(self.open_directory) self.save_playlist_action = QAction('Save Playlist', self) self.save_playlist_action.setShortcut('CTRL+S') self.save_playlist_action.triggered.connect(self.save_playlist) self.exit_action = QAction('Quit', self) self.exit_action.setShortcut('CTRL+Q') self.exit_action.triggered.connect(self.closeEvent) self.file.addAction(self.open_action) self.file.addAction(self.open_multiple_files_action) self.file.addAction(self.open_playlist_action) self.file.addAction(self.open_directory_action) self.file.addSeparator() self.file.addAction(self.save_playlist_action) self.file.addSeparator() self.file.addAction(self.exit_action) def edit_menu(self): """Add an edit menu to the menu bar. The edit menu houses the preferences item that opens a preferences dialog that allows the user to customize features of the music player. """ self.preferences_action = QAction('Preferences', self) self.preferences_action.setShortcut('CTRL+SHIFT+P') self.preferences_action.triggered.connect(lambda: self.preferences.exec_()) self.edit.addAction(self.preferences_action) def playback_menu(self): """Add a playback menu to the menu bar. The playback menu houses """ self.play_playback_action = QAction('Play', self) self.play_playback_action.setShortcut('P') self.play_playback_action.triggered.connect(self.player.play) self.stop_playback_action = QAction('Stop', self) self.stop_playback_action.setShortcut('S') self.stop_playback_action.triggered.connect(self.player.stop) self.previous_playback_action = QAction('Previous', self) self.previous_playback_action.setShortcut('B') self.previous_playback_action.triggered.connect(self.previous) self.next_playback_action = QAction('Next', self) self.next_playback_action.setShortcut('N') self.next_playback_action.triggered.connect(self.playlist.next) self.playback.addAction(self.play_playback_action) self.playback.addAction(self.stop_playback_action) self.playback.addAction(self.previous_playback_action) self.playback.addAction(self.next_playback_action) def view_menu(self): """Add a view menu to the menu bar. The view menu houses the Playlist, Media Library, Minimalist View, and Media Information menu items. The Playlist item toggles the playlist dock into and out of view. The Media Library items toggles the media library dock into and out of view. The Minimalist View item resizes the window and shows only the menu bar and player controls. The Media Information item opens a dialog that shows information relevant to the currently playing song. """ self.dock_action = self.playlist_dock.toggleViewAction() self.dock_action.setShortcut('CTRL+ALT+P') self.library_dock_action = self.library_dock.toggleViewAction() self.library_dock_action.setShortcut('CTRL+ALT+L') self.minimalist_view_action = QAction('Minimalist View', self) self.minimalist_view_action.setShortcut('CTRL+ALT+M') self.minimalist_view_action.setCheckable(True) self.minimalist_view_action.triggered.connect(self.minimalist_view) self.view_media_info_action = QAction('Media Information', self) self.view_media_info_action.setShortcut('CTRL+SHIFT+M') self.view_media_info_action.triggered.connect(self.media_information_dialog) self.view.addAction(self.dock_action) self.view.addAction(self.library_dock_action) self.view.addSeparator() self.view.addAction(self.minimalist_view_action) self.view.addSeparator() self.view.addAction(self.view_media_info_action) def help_menu(self): """Add a help menu to the menu bar. The help menu houses the about dialog that shows the user information related to the application. """ self.about_action = QAction('About', self) self.about_action.setShortcut('H') self.about_action.triggered.connect(lambda: about.AboutDialog().exec_()) self.help_.addAction(self.about_action) def open_file(self): """Open the selected file and add it to a new playlist.""" filename, success = QFileDialog.getOpenFileName(self, 'Open File', '', 'Audio (*.mp3 *.flac)', '', QFileDialog.ReadOnly) if success: file_info = QFileInfo(filename).fileName() playlist_item = QListWidgetItem(file_info) self.playlist.clear() self.playlist_view.clear() self.playlist.addMedia(QMediaContent(QUrl().fromLocalFile(filename))) self.player.setPlaylist(self.playlist) playlist_item.setToolTip(file_info) self.playlist_view.addItem(playlist_item) self.playlist_view.setCurrentRow(0) self.player.play() def open_multiple_files(self): """Open the selected files and add them to a new playlist.""" filenames, success = QFileDialog.getOpenFileNames(self, 'Open Multiple Files', '', 'Audio (*.mp3 *.flac)', '', QFileDialog.ReadOnly) if success: self.playlist.clear() self.playlist_view.clear() for file in natsort.natsorted(filenames, alg=natsort.ns.PATH): file_info = QFileInfo(file).fileName() playlist_item = QListWidgetItem(file_info) self.playlist.addMedia(QMediaContent(QUrl().fromLocalFile(file))) self.player.setPlaylist(self.playlist) playlist_item.setToolTip(file_info) self.playlist_view.addItem(playlist_item) self.playlist_view.setCurrentRow(0) self.player.play() def open_playlist(self): """Load an M3U or PLS file into a new playlist.""" playlist, success = QFileDialog.getOpenFileName(self, 'Open Playlist', '', 'Playlist (*.m3u *.pls)', '', QFileDialog.ReadOnly) if success: playlist = QUrl.fromLocalFile(playlist) self.playlist.clear() self.playlist_view.clear() self.playlist.load(playlist) self.player.setPlaylist(self.playlist) for song_index in range(self.playlist.mediaCount()): file_info = self.playlist.media(song_index).canonicalUrl().fileName() playlist_item = QListWidgetItem(file_info) playlist_item.setToolTip(file_info) self.playlist_view.addItem(playlist_item) self.playlist_view.setCurrentRow(0) self.player.play() def save_playlist(self): """Save the media in the playlist dock as a new M3U playlist.""" playlist, success = QFileDialog.getSaveFileName(self, 'Save Playlist', '', 'Playlist (*.m3u)', '') if success: saved_playlist = "{}.m3u" .format(playlist) self.playlist.save(QUrl().fromLocalFile(saved_playlist), "m3u") def load_saved_playlist(self): """Load the saved playlist if user setting permits.""" saved_playlist = "{}/.m3u" .format(self.playlist_location) if os.path.exists(saved_playlist): playlist = QUrl().fromLocalFile(saved_playlist) self.playlist.load(playlist) self.player.setPlaylist(self.playlist) for song_index in range(self.playlist.mediaCount()): file_info = self.playlist.media(song_index).canonicalUrl().fileName() playlist_item = QListWidgetItem(file_info) playlist_item.setToolTip(file_info) self.playlist_view.addItem(playlist_item) self.playlist_view.setCurrentRow(0) def open_directory(self): """Open the selected directory and add the files within to an empty playlist.""" directory = QFileDialog.getExistingDirectory(self, 'Open Directory', '', QFileDialog.ReadOnly) if directory: self.playlist.clear() self.playlist_view.clear() for dirpath, __, files in os.walk(directory): for filename in natsort.natsorted(files, alg=natsort.ns.PATH): file = os.path.join(dirpath, filename) if filename.endswith(('mp3', 'flac')): self.playlist.addMedia(QMediaContent(QUrl().fromLocalFile(file))) playlist_item = QListWidgetItem(filename) playlist_item.setToolTip(filename) self.playlist_view.addItem(playlist_item) self.player.setPlaylist(self.playlist) self.playlist_view.setCurrentRow(0) self.player.play() def open_media_library(self, index): """Open a directory or file from the media library into an empty playlist.""" self.playlist.clear() self.playlist_view.clear() if self.library_model.fileName(index).endswith(('mp3', 'flac')): self.playlist.addMedia(QMediaContent(QUrl().fromLocalFile(self.library_model.filePath(index)))) self.playlist_view.addItem(self.library_model.fileName(index)) elif self.library_model.isDir(index): directory = self.library_model.filePath(index) for dirpath, __, files in os.walk(directory): for filename in natsort.natsorted(files, alg=natsort.ns.PATH): file = os.path.join(dirpath, filename) if filename.endswith(('mp3', 'flac')): self.playlist.addMedia(QMediaContent(QUrl().fromLocalFile(file))) playlist_item = QListWidgetItem(filename) playlist_item.setToolTip(filename) self.playlist_view.addItem(playlist_item) self.player.setPlaylist(self.playlist) self.player.play() def display_meta_data(self): """Display the current song's metadata in the main window. If the current song contains metadata, its cover art is extracted and shown in the main window while the track number, artist, album, and track title are shown in the window title. """ if self.player.isMetaDataAvailable(): file_path = self.player.currentMedia().canonicalUrl().toLocalFile() (album, artist, title, track_number, *__, artwork) = metadata.metadata(file_path) try: self.pixmap.loadFromData(artwork) except TypeError: self.pixmap = QPixmap(artwork) meta_data = '{} - {} - {} - {}' .format(track_number, artist, album, title) self.setWindowTitle(meta_data) self.art.setScaledContents(True) self.art.setPixmap(self.pixmap) self.layout.addWidget(self.art) def initialize_playlist(self, start): """Display playlist and reset playback mode when media inserted into playlist.""" if start == 0: if self.library_dock.isVisible(): self.playlist_dock.setVisible(True) self.playlist_dock.show() self.playlist_dock.raise_() if self.playlist.playbackMode() != QMediaPlaylist.Sequential: self.playlist.setPlaybackMode(QMediaPlaylist.Sequential) repeat_icon = utilities.resource_filename('mosaic.images', 'md_repeat_none.png') self.repeat_action.setIcon(QIcon(repeat_icon)) def press_playback(self, event): """Change the playback of the player on cover art mouse event. When the cover art is clicked, the player will play the media if the player is either paused or stopped. If the media is playing, the media is set to pause. """ if event.button() == 1 and configuration.Playback().cover_art_playback.isChecked(): if (self.player.state() == QMediaPlayer.StoppedState or self.player.state() == QMediaPlayer.PausedState): self.player.play() elif self.player.state() == QMediaPlayer.PlayingState: self.player.pause() def seek(self, seconds): """Set the position of the song to the position dragged to by the user.""" self.player.setPosition(seconds * 1000) def song_duration(self, duration): """Set the slider to the duration of the currently played media.""" duration /= 1000 self.duration = duration self.slider.setMaximum(duration) def song_position(self, progress): """Move the horizontal slider in sync with the duration of the song. The progress is relayed to update_duration() in order to display the time label next to the slider. """ progress /= 1000 if not self.slider.isSliderDown(): self.slider.setValue(progress) self.update_duration(progress) def update_duration(self, current_duration): """Calculate the time played and the length of the song. Both of these times are sent to duration_label() in order to display the times on the toolbar. """ duration = self.duration if current_duration or duration: time_played = QTime((current_duration / 3600) % 60, (current_duration / 60) % 60, (current_duration % 60), (current_duration * 1000) % 1000) song_length = QTime((duration / 3600) % 60, (duration / 60) % 60, (duration % 60), (duration * 1000) % 1000) if duration > 3600: time_format = "hh:mm:ss" else: time_format = "mm:ss" time_display = "{} / {}" .format(time_played.toString(time_format), song_length.toString(time_format)) else: time_display = "" self.duration_label.setText(time_display) def set_state(self, state): """Change the icon in the toolbar in relation to the state of the player. The play icon changes to the pause icon when a song is playing and the pause icon changes back to the play icon when either paused or stopped. """ if self.player.state() == QMediaPlayer.PlayingState: pause_icon = utilities.resource_filename('mosaic.images', 'md_pause.png') self.play_action.setIcon(QIcon(pause_icon)) self.play_action.triggered.connect(self.player.pause) elif (self.player.state() == QMediaPlayer.PausedState or self.player.state() == QMediaPlayer.StoppedState): self.play_action.triggered.connect(self.player.play) play_icon = utilities.resource_filename('mosaic.images', 'md_play.png') self.play_action.setIcon(QIcon(play_icon)) def previous(self): """Move to the previous song in the playlist. Moves to the previous song in the playlist if the current song is less than five seconds in. Otherwise, restarts the current song. """ if self.player.position() <= 5000: self.playlist.previous() else: self.player.setPosition(0) def repeat_song(self): """Set the current media to repeat and change the repeat icon accordingly. There are four playback modes: repeat none, repeat all, repeat once, and shuffle. Clicking the repeat button cycles through each playback mode. """ if self.playlist.playbackMode() == QMediaPlaylist.Sequential: self.playlist.setPlaybackMode(QMediaPlaylist.Loop) repeat_on_icon = utilities.resource_filename('mosaic.images', 'md_repeat_all.png') self.repeat_action.setIcon(QIcon(repeat_on_icon)) elif self.playlist.playbackMode() == QMediaPlaylist.Loop: self.playlist.setPlaybackMode(QMediaPlaylist.CurrentItemInLoop) repeat_on_icon = utilities.resource_filename('mosaic.images', 'md_repeat_once.png') self.repeat_action.setIcon(QIcon(repeat_on_icon)) elif self.playlist.playbackMode() == QMediaPlaylist.CurrentItemInLoop: self.playlist.setPlaybackMode(QMediaPlaylist.Random) repeat_icon = utilities.resource_filename('mosaic.images', 'md_shuffle.png') self.repeat_action.setIcon(QIcon(repeat_icon)) elif self.playlist.playbackMode() == QMediaPlaylist.Random: self.playlist.setPlaybackMode(QMediaPlaylist.Sequential) repeat_icon = utilities.resource_filename('mosaic.images', 'md_repeat_none.png') self.repeat_action.setIcon(QIcon(repeat_icon)) def activate_playlist_item(self, item): """Set the active media to the playlist item dobule-clicked on by the user.""" current_index = self.playlist_view.row(item) if self.playlist.currentIndex() != current_index: self.playlist.setCurrentIndex(current_index) if self.player.state() != QMediaPlayer.PlayingState: self.player.play() def change_index(self, row): """Highlight the row in the playlist of the active media.""" self.playlist_view.setCurrentRow(row) def minimalist_view(self): """Resize the window to only show the menu bar and audio controls.""" if self.minimalist_view_action.isChecked(): if self.playlist_dock.isVisible(): self.playlist_dock_state = True if self.library_dock.isVisible(): self.library_dock_state = True self.library_dock.close() self.playlist_dock.close() QTimer.singleShot(10, lambda: self.resize(500, 0)) else: self.resize(defaults.Settings().window_size, defaults.Settings().window_size + 63) if self.library_dock_state: self.library_dock.setVisible(True) if self.playlist_dock_state: self.playlist_dock.setVisible(True) def dock_visiblity_change(self, visible): """Change the size of the main window when the docks are toggled.""" if visible and self.playlist_dock.isVisible() and not self.library_dock.isVisible(): self.resize(defaults.Settings().window_size + self.playlist_dock.width() + 6, self.height()) elif visible and not self.playlist_dock.isVisible() and self.library_dock.isVisible(): self.resize(defaults.Settings().window_size + self.library_dock.width() + 6, self.height()) elif visible and self.playlist_dock.isVisible() and self.library_dock.isVisible(): self.resize(defaults.Settings().window_size + self.library_dock.width() + 6, self.height()) elif (not visible and not self.playlist_dock.isVisible() and not self.library_dock.isVisible()): self.resize(defaults.Settings().window_size, defaults.Settings().window_size + 63) def media_information_dialog(self): """Show a dialog of the current song's metadata.""" if self.player.isMetaDataAvailable(): file_path = self.player.currentMedia().canonicalUrl().toLocalFile() else: file_path = None dialog = information.InformationDialog(file_path) dialog.exec_() def change_window_size(self): """Change the window size of the music player.""" self.playlist_dock.close() self.library_dock.close() self.resize(defaults.Settings().window_size, defaults.Settings().window_size + 63) def change_media_library_path(self, path): """Change the media library path to the new path selected in the preferences dialog.""" self.library_model.setRootPath(path) self.library_view.setModel(self.library_model) self.library_view.setRootIndex(self.library_model.index(path)) def closeEvent(self, event): """Override the PyQt close event in order to handle save playlist on close.""" playlist = "{}/.m3u" .format(self.playlist_location) if defaults.Settings().save_playlist_on_close: self.playlist.save(QUrl().fromLocalFile(playlist), "m3u") else: if os.path.exists(playlist): os.remove(playlist) QApplication.quit()
class MainWindow(QMainWindow, Ui_MainWindow): def __init__(self): super(MainWindow, self).__init__() self.setupUi(self) self.centralwidget.hide() self.parser = argparse.ArgumentParser("playground") self.parser.add_argument("-d", "--data-dir", type=str, help="data dir") self.parser.add_argument("-a", "--console-address", type=str, help="console address", default='localhost') self.parser.add_argument("-p", "--console-port", type=int, help="console port", default=2222) self.args = self.parser.parse_args() self.data_dir = self.args.data_dir self.console_port = self.args.console_port self.console_address = self.args.console_address self.project = CetechProject() self.api = QtConsoleAPI(self.console_address, self.console_port) self.setTabPosition(Qt.AllDockWidgetAreas, QTabWidget.North) self.script_editor_widget = ScriptEditor(project_manager=self.project, api=self.api) self.script_editor_dock_widget = QDockWidget(self) self.script_editor_dock_widget.setWindowTitle("Script editor") self.script_editor_dock_widget.hide() self.script_editor_dock_widget.setFeatures(QDockWidget.AllDockWidgetFeatures) self.script_editor_dock_widget.setWidget(self.script_editor_widget) self.addDockWidget(Qt.TopDockWidgetArea, self.script_editor_dock_widget) self.log_widget = LogWidget(self.api, self.script_editor_widget) self.log_dock_widget = QDockWidget(self) self.log_dock_widget.hide() self.log_dock_widget.setWindowTitle("Log") self.log_dock_widget.setWidget(self.log_widget) self.addDockWidget(Qt.BottomDockWidgetArea, self.log_dock_widget) self.assetb_widget = AssetBrowser() self.assetb_dock_widget = QDockWidget(self) self.assetb_dock_widget.hide() self.assetb_dock_widget.setWindowTitle("Asset browser") self.assetb_dock_widget.setFeatures(QDockWidget.AllDockWidgetFeatures) self.assetb_dock_widget.setWidget(self.assetb_widget) self.addDockWidget(Qt.LeftDockWidgetArea, self.assetb_dock_widget) self.recorded_event_widget = RecordEventWidget(api=self.api) self.recorded_event_dock_widget = QDockWidget(self) self.recorded_event_dock_widget.setWindowTitle("Recorded events") self.recorded_event_dock_widget.hide() self.recorded_event_dock_widget.setFeatures(QDockWidget.AllDockWidgetFeatures) self.recorded_event_dock_widget.setWidget(self.recorded_event_widget) self.addDockWidget(Qt.RightDockWidgetArea, self.recorded_event_dock_widget) #TODO bug #114 workaround. Disable create sub engine... if platform.system().lower() != 'darwin': self.ogl_widget = CetechWidget(self, self.api) self.ogl_dock = QDockWidget(self) self.ogl_dock.hide() self.ogl_dock.setWidget(self.ogl_widget) self.addDockWidget(Qt.TopDockWidgetArea, self.ogl_dock) self.tabifyDockWidget(self.assetb_dock_widget, self.log_dock_widget) self.assetb_widget.asset_clicked.connect(self.open_asset) self.file_watch = QFileSystemWatcher(self) self.file_watch.fileChanged.connect(self.file_changed) self.file_watch.directoryChanged.connect(self.dir_changed) self.build_file_watch = QFileSystemWatcher(self) self.build_file_watch.fileChanged.connect(self.build_file_changed) self.build_file_watch.directoryChanged.connect(self.build_dir_changed) def open_asset(self, path, ext): if self.script_editor_widget.support_ext(ext): self.script_editor_widget.open_file(path) self.script_editor_dock_widget.show() self.script_editor_dock_widget.focusWidget() def open_project(self, name, dir): self.project.open_project(name, dir) # self.project.run_cetech(build_type=CetechProject.BUILD_DEBUG, compile=True, continu=True, daemon=True) if platform.system().lower() == 'darwin': wid = None else: wid = self.ogl_widget.winId() self.project.run_cetech(build_type=CetechProject.BUILD_DEBUG, compile_=True, continue_=True, wid=wid) self.api.start(QThread.LowPriority) self.assetb_widget.open_project(self.project.project_dir) self.assetb_dock_widget.show() self.log_dock_widget.show() #TODO bug #114 workaround. Disable create sub engine... if platform.system().lower() != 'darwin': self.ogl_dock.show() self.watch_project_dir() def watch_project_dir(self): files = self.file_watch.files() directories = self.file_watch.directories() if len(files): self.file_watch.removePaths(files) if len(directories): self.file_watch.removePaths(directories) files = self.build_file_watch.files() directories = self.build_file_watch.directories() if len(files): self.build_file_watch.removePaths(files) if len(directories): self.build_file_watch.removePaths(directories) files = [] it = QDirIterator(self.project.source_dir, QDirIterator.Subdirectories) while it.hasNext(): files.append(it.next()) self.file_watch.addPaths(files) files = [] it = QDirIterator(self.project.build_dir, QDirIterator.Subdirectories) while it.hasNext(): files.append(it.next()) self.build_file_watch.addPaths(files) def file_changed(self, path): self.api.compile_all() def dir_changed(self, path): self.watch_project_dir() def build_file_changed(self, path): self.api.autocomplete_list() def build_dir_changed(self, path): pass def open_script_editor(self): self.script_editor_dock_widget.show() def open_recorded_events(self): self.recorded_event_dock_widget.show() def closeEvent(self, evnt): self.api.disconnect() self.project.killall_process() self.statusbar.showMessage("Disconnecting ...") while self.api.connected: self.api.tick() self.statusbar.showMessage("Disconnected") evnt.accept()