def __init__(self): super().__init__() self.setWindowTitle("My App") label = QLabel("Hello!") label.setAlignment(Qt.AlignCenter) self.setCentralWidget(label) toolbar = QToolBar("My main toolbar") toolbar.setIconSize(QSize(16, 16)) self.addToolBar(toolbar) button_action = QAction(QIcon("bug.png"), "Your button", self) button_action.setStatusTip("This is your button") button_action.triggered.connect(self.onMyToolBarButtonClick) button_action.setCheckable(True) toolbar.addAction(button_action) toolbar.addSeparator() button_action2 = QAction(QIcon("bug.png"), "Your button2", self) button_action2.setStatusTip("This is your button2") button_action2.triggered.connect(self.onMyToolBarButtonClick) button_action2.setCheckable(True) toolbar.addAction(button_action2) toolbar.addWidget(QLabel("Hello")) toolbar.addWidget(QCheckBox()) self.setStatusBar(QStatusBar(self))
def __init__(self): super().__init__() self.setWindowTitle("My App") label = QLabel("Hello!") # The `Qt` namespace has a lot of attributes to customize # widgets. See: http://doc.qt.io/qt-5/qt.html label.setAlignment(Qt.AlignCenter) # Set the central widget of the Window. Widget will expand # to take up all the space in the window by default. self.setCentralWidget(label) toolbar = QToolBar("My main toolbar") toolbar.setIconSize(QSize(16, 16)) self.addToolBar(toolbar) button_action = QAction(QIcon("bug.png"), "&Your button", self) button_action.setStatusTip("This is your button") button_action.triggered.connect(self.onMyToolBarButtonClick) button_action.setCheckable(True) # You can enter keyboard shortcuts using key names (e.g. Ctrl+p) # Qt.namespace identifiers (e.g. Qt.CTRL + Qt.Key_P) # or system agnostic identifiers (e.g. QKeySequence.Print) button_action.setShortcut(QKeySequence("Ctrl+p")) toolbar.addAction(button_action) toolbar.addSeparator() button_action2 = QAction(QIcon("bug.png"), "Your &button2", self) button_action2.setStatusTip("This is your button2") button_action2.triggered.connect(self.onMyToolBarButtonClick) button_action2.setCheckable(True) toolbar.addAction(button_action) toolbar.addWidget(QLabel("Hello")) toolbar.addWidget(QCheckBox()) self.setStatusBar(QStatusBar(self)) menu = self.menuBar() file_menu = menu.addMenu("&File") file_menu.addAction(button_action) file_menu.addSeparator() file_submenu = file_menu.addMenu("Submenu") file_submenu.addAction(button_action2)
def _add_tool_bar_items( tool_bar: QToolBar, items: List[Union[str, QAction]], ) -> None: for item in items: if item == _TOOL_BAR_SEPARATOR: tool_bar.addSeparator() elif item == _TOOL_BAR_SPACER: spacer = QWidget(tool_bar) spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) tool_bar.addWidget(spacer) elif isinstance(item, QAction): tool_bar.addAction(item)
def createToolBar(self): #Ok """ Criar barra de ferramentas para editor de fotos """ tool_bar = QToolBar("Barra de Ferramentas do Editor de Fotos") tool_bar.setIconSize(QSize(24, 24)) self.addToolBar(tool_bar) tool_bar.addAction(self.abre_act) tool_bar.addAction(self.salv_act) tool_bar.addAction(self.prnt_act) tool_bar.addAction(self.limp_act) tool_bar.addSeparator() tool_bar.addAction(self.sair_act)
class MainWindow(QWidget): def __init__(self, parent=None): super().__init__(parent) self.setWindowTitle("AxiGUI") self._config_dialog = ConfigDialog() self._plot_control = PlotControlWidget() # setup toolbar self._toolbar = QToolBar() self._toolbar.setIconSize(QSize(64, 64)) load_act = self._toolbar.addAction(QIcon("images/icons_open.png"), "Load") load_act.triggered.connect(lambda: self.load_svg()) config_act = self._toolbar.addAction( QIcon("images/icons_settings.png"), "Config") config_act.triggered.connect(lambda: self._config_dialog.exec_()) self._toolbar.addSeparator() self._plot_control.add_actions(self._toolbar) empty = QWidget() empty.setSizePolicy( QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)) self._toolbar.addWidget(empty) quit_act = self._toolbar.addAction(QIcon("images/icons_exit.png"), "Quit") quit_act.triggered.connect(lambda: QCoreApplication.quit()) # setup layout layout = QVBoxLayout() layout.setSpacing(0) layout.setMargin(0) layout.addWidget(self._toolbar) layout.addWidget(self._plot_control) self.setLayout(layout) def load_svg(self): # TODO: remember last folder opened in the session path = QFileDialog.getOpenFileName(self, "Choose SVG file:", "/Users/hhip/Drive/axidraw", "SVG (*.svg)") if path[0]: self._plot_control.load_svg(path[0])
def qtoolbar(self): toolbar = QToolBar(self.name, self.window) for action in self.actions: if isinstance(action, ToolbarSplitter): toolbar.addSeparator() else: if action.icon is not None: act = QAction(action.icon, action.name, toolbar) else: act = QAction(action.name, toolbar) if action.triggered is not None: act.triggered.connect(action.triggered) if action.tooltip: act.setToolTip(action.tooltip) toolbar.addAction(act) toolbar.setIconSize(QSize(16, 16)) return toolbar
class Ui_FE14ChapterEditor(QMainWindow): def __init__(self, parent=None): super().__init__(parent) self.toolbar = QToolBar() self.addToolBar(self.toolbar) self.add_chapter_action = QAction("Add Chapter") self.hide_selector_action = QAction("Toggle Selection Pane") self.toolbar.addAction(self.add_chapter_action) self.toolbar.addSeparator() self.toolbar.addAction(self.hide_selector_action) self.selector_layout = QVBoxLayout() self.chapter_search_bar = QLineEdit() self.chapter_search_bar.setPlaceholderText("Search...") self.chapter_list_view = QListView() self.selector_layout.addWidget(self.chapter_search_bar) self.selector_layout.addWidget(self.chapter_list_view) self.selector_widget = QWidget() self.selector_widget.setLayout(self.selector_layout) self.selector_widget.setFixedWidth(225) self.config_tab = FE14ChapterConfigTab() self.map_tab = FE14MapEditor() self.characters_tab = FE14CharacterEditor(is_person=True) self.conversation_tab = FE14ConversationEditor() self.tab_widget = QTabWidget() self.tab_widget.addTab(self.config_tab, "Config") self.tab_widget.addTab(self.map_tab, "Map") self.tab_widget.addTab(self.characters_tab, "Characters") self.tab_widget.addTab(self.conversation_tab, "Text") self.main_layout = QHBoxLayout() self.main_widget = QWidget() self.visual_splitter = QFrame() self.visual_splitter.setFrameShape(QFrame.VLine) self.visual_splitter.setFrameShadow(QFrame.Sunken) self.main_widget.setLayout(self.main_layout) self.main_layout.addWidget(self.selector_widget) self.main_layout.addWidget(self.visual_splitter) self.main_layout.addWidget(self.tab_widget) self.setCentralWidget(self.main_widget)
class IccMainWindow(QMainWindow): def __init__(self, environment): QMainWindow.__init__(self) self.setWindowTitle("ImmoControlCenter " + environment) self._menubar: QMenuBar = None self._viewsMenu: QMenu = None self._submenuShowTableContent: QMenu = None self._toolbar: QToolBar = None self._sdLetzteBuchung: SmartDateEdit = SmartDateEdit(self) self._leLetzteBuchung: QLineEdit = QLineEdit(self) # Summen self._idSumMiete = self._createSumDisplay("Summe aller Bruttomieten") self._idSummeSonstAus = self._createSumDisplay( "Summe aller sonstigen Ausgaben") self._idSummeHGV = self._createSumDisplay( "Summe aller Hausgeld-Vorauszahlungen") self._idSaldo = self._createSumDisplay( "Bruttomieten minus Ausgaben minus HG-Vorauszahlungen") self._summenfont = QFont("Times New Roman", 16, weight=QFont.Bold) self._summenartfont = QFont("Times New Roman", 9) # give others access to sum fields via Singleton SumFieldsAccess: self._sumfieldsAccess = SumFieldsProvider( self._idSumMiete, self._idSummeSonstAus, self._idSummeHGV, self._idSaldo, self.onSumFieldsProvidingFailed) self._actionCallbackFnc = None #callback function for all action callbacks self._shutdownCallback = None # callback function for shutdown action self._createUI() def onSumFieldsProvidingFailed(self, msg: str): self.showException(msg) def _createUI(self): self._menubar = QMenuBar(self) self._toolBar = QToolBar(self) self._createImmoCenterMenu() self._createMietobjektMenu() self._createMietverhaeltnisMenu() self._createZahlungenMenu() self._createAbrechnungenMenu() self._createAnlageVMenu() self._createExtrasMenu() self._createSqlMenu() self._createShowViewsMenu() self._toolBar.addSeparator() lbl = QLabel(self, text="Letzte verarbeitete Buchung: ") self._toolBar.addWidget(lbl) self._sdLetzteBuchung.setToolTip( "Freier Eintrag der Kenndaten der letzten Buchung,\n " "um beim nächsten Anwendungsstart gezielt weiterarbeiten zu können." ) self._sdLetzteBuchung.setMaximumWidth(90) self._toolBar.addWidget(self._sdLetzteBuchung) dummy = QWidget() dummy.setFixedWidth(5) self._toolBar.addWidget(dummy) self._leLetzteBuchung.setToolTip( "Freier Eintrag der Kenndaten der letzten Buchung,\n " "um beim nächsten Anwendungsstart gezielt weiterarbeiten zu können." ) # self._leLetzteBuchung.setMaximumWidth( 300 ) self._toolBar.addWidget(self._leLetzteBuchung) dummy = QWidget() dummy.setFixedWidth(30) #dummy.setSizePolicy( QSizePolicy.Expanding, QSizePolicy.Preferred ) self._toolBar.addWidget(dummy) self._addSumFields() self.setMenuBar(self._menubar) self.addToolBar(QtCore.Qt.TopToolBarArea, self._toolBar) def _createImmoCenterMenu(self): # Menü "ImmoCenter" menu = QtWidgets.QMenu(self._menubar, title="ImmoCenter") self._menubar.addMenu(menu) # Menüpunkt "Alle Änderungen speichern" action = QAction(self, text="Alle Änderungen speichern") action.setShortcut(QKeySequence("Ctrl+Shift+s")) action.triggered.connect(self.onSaveAll) menu.addAction(action) menu.addSeparator() # Menü "Datenbank zum Server exportieren" action = QAction(self, text="Datenbank zum Server exportieren") action.triggered.connect(self.onExportDatabaseToServer) menu.addAction(action) # Menü "Datenbank vom Server importieren" action = QAction(self, text="Datenbank vom Server importieren") action.triggered.connect(self.onImportDatabaseFromServer) menu.addAction(action) menu.addSeparator() # Menüpunkt "Folgejahr einrichten" action = QAction(self, text="Folgejahr einrichten") action.triggered.connect(self.onFolgejahrEinrichten) menu.addAction(action) menu.addSeparator() # Menüpunkt "Ende" action = QAction(self, text="Ende") action.triggered.connect(self.onExit) action.setShortcut("Alt+F4") menu.addAction(action) def _createMietobjektMenu(self): menu = QtWidgets.QMenu(self._menubar, title="Mietobjekt") self._menubar.addMenu(menu) # Menüpunkt "Wohnungsstammdaten..." action = QAction(self, text="Objektstammdaten...") action.triggered.connect(self.onViewObjektStammdaten) menu.addAction(action) # # Menüpunkt "Mietverhältnis..." # action = QAction( self, text="Mietverhältnis..." ) # action.triggered.connect( self.onViewMietverhaeltnis ) # menu.addAction( action ) menu.addSeparator() # action = QAction( self, text="Mieterwechsel..." ) # action.triggered.connect( self.onMieterwechsel ) # menu.addAction( action ) action = QAction(self, text="Verwalterwechsel...") action.triggered.connect(self.onVerwalterwechsel) menu.addAction(action) def _createMietverhaeltnisMenu(self): menu = QtWidgets.QMenu(self._menubar, title="Mietverhältnis") self._menubar.addMenu(menu) # Menüpunkt "Mietverhältnis..." action = QAction(self, text="Mietverhältnis anschauen und ändern...") action.triggered.connect(self.onViewMietverhaeltnis) menu.addAction(action) menu.addSeparator() action = QAction(self, text="Mieterwechsel...") action.triggered.connect(self.onMieterwechsel) menu.addAction(action) def _createZahlungenMenu(self): menu = QtWidgets.QMenu(self._menubar, title="Ist- und Sollzahlungen") self._menubar.addMenu(menu) # Menüpunkt "Mietzahlungen..." action = QAction(self, text="Mietzahlungen...") action.triggered.connect(self.onViewMietzahlungen) menu.addAction(action) # Menüpunkt "HG-Vorauszahlungen..." action = QAction(self, text="HG-Vorauszahlungen...") action.triggered.connect(self.onViewHGVorauszahlungen) menu.addAction(action) # Menüpunkt "Rechnungen, Abgaben, Gebühren..." action = QAction(self, text="Rechnungen, Abgaben, Gebühren...") action.triggered.connect(self.onViewRechnungen) menu.addAction(action) menu.addSeparator() # Menüpunkt "Offene Posten" action = QAction(self, text="Offene Posten") action.triggered.connect(self.onViewOffenePosten) menu.addAction(action) menu.addSeparator() # Menüpunkt "Soll-Miete..." action = QAction(self, text="Soll-Miete...") action.triggered.connect(self.onViewSollMiete) menu.addAction(action) # Menüpunkt "Soll-Hausgeld..." action = QAction(self, text="Soll-Hausgeld...") action.triggered.connect(self.onViewSollHausgeld) menu.addAction(action) menu.addSeparator() def _createAbrechnungenMenu(self): menu = QtWidgets.QMenu(self._menubar, title="Abrechnungen") self._menubar.addMenu(menu) action = QAction(self, text="Nebenkostenabrechnung...") action.triggered.connect(self.onViewNebenkostenabrechnung) menu.addAction(action) action = QAction(self, text="Hausgeldabrechnung...") action.triggered.connect(self.onViewHausgeldabrechnung) menu.addAction(action) def _createAnlageVMenu(self): menu = QtWidgets.QMenu(self._menubar, title="AnlageV") self._menubar.addMenu(menu) action = QAction(self, text="Anlagen V: Objektauswahl, Vorschau, Druck...") action.triggered.connect(self.onViewAnlageV) menu.addAction(action) # action = QAction( self, text="Anlagen V drucken..." ) # action.triggered.connect( self.onViewHausgeldabrechnung ) # menu.addAction( action ) def _createExtrasMenu(self): menu = QtWidgets.QMenu(self._menubar, title="Extras") self._menubar.addMenu(menu) action = QAction(self, text="Geschäftsreise...") action.triggered.connect(self.onGeschaeftsreise) menu.addAction(action) action = QAction(self, text="Notizen...") action.triggered.connect(self.onNotizen) menu.addAction(action) menu.addSeparator() action = QAction(self, text="Sammelabgabenbescheid aufsplitten...") action.triggered.connect(self.onSammelabgabe) menu.addAction(action) menu.addSeparator() action = QAction(self, text="Renditevergleich...") action.triggered.connect(self.onRenditeVergleich) menu.addAction(action) menu.addSeparator() action = QAction(self, text="Exportiere aktive Tabelle in Calc") action.triggered.connect(self.onExportActiveTableView) menu.addAction(action) def _createSqlMenu(self): # Menü "ImmoCenter" menu = QtWidgets.QMenu(self._menubar, title="SQL") self._menubar.addMenu(menu) # Menüpunkt "Neue Abfrage action = QAction(self, text="Neue Datenbankabfrage") action.setShortcut(QKeySequence("Ctrl+n")) icon = QtGui.QIcon("../images/sql.xpm") action.setIcon(icon) action.triggered.connect(self.onNewSql) menu.addAction(action) #self._toolBar.addAction( action ) #Menüpunkt "Ganze Tabelle anzeigen" self._submenuShowTableContent = QtWidgets.QMenu( menu, title="Ganze Tabelle anzeigen") menu.addMenu(self._submenuShowTableContent) def _createShowViewsMenu(self): menu = QtWidgets.QMenu(self._menubar, title="Views") self._menubar.addMenu(menu) self._viewsMenu = menu def _addSumFields(self): self._toolBar.addWidget(self._createSumLabel()) self._toolBar.addWidget(self._createSumArtLabel("Miete", 30)) self._toolBar.addWidget(self._idSumMiete) self._toolBar.addWidget(self._createLabel("-", 20)) self._toolBar.addWidget(self._createSumLabel()) self._toolBar.addWidget(self._createSumArtLabel("Ausgaben", 50)) self._toolBar.addWidget(self._idSummeSonstAus) self._toolBar.addWidget(self._createLabel("-", 20)) self._toolBar.addWidget(self._createSumLabel()) self._toolBar.addWidget(self._createSumArtLabel("HGV", 40)) self._toolBar.addWidget(self._idSummeHGV) self._toolBar.addWidget(self._createLabel("=", 20)) self._toolBar.addWidget(self._idSaldo) self._toolBar.addWidget(self._createSpacer(20)) def _createSumDisplay(self, tooltip: str) -> IntDisplay: display = IntDisplay(self) display.setMaximumWidth(70) display.setEnabled(False) display.setToolTip(tooltip) return display def _createSumLabel(self) -> QLabel: lbl = QLabel(self, text="∑") lbl.setFont(self._summenfont) lbl.setMaximumWidth(15) return lbl def _createSumArtLabel(self, sumart: str, width: int) -> QLabel: lbl = QLabel(self, text=sumart) lbl.setFont(self._summenartfont) lbl.setMaximumWidth(width) return lbl def _createLabel(self, text: str, width: int) -> QLabel: lbl = QLabel(self, text=text) lbl.setMinimumWidth(width) lbl.setMaximumWidth(width) lbl.setAlignment(Qt.AlignCenter) return lbl def _createSpacer(self, width: int) -> QWidget: spacer = QWidget(self) spacer.setMinimumWidth(width) spacer.setMaximumWidth(width) return spacer def canShutdown(self) -> bool: if self._shutdownCallback: return self._shutdownCallback() def setLetzteBuchung(self, datum: str, text: str) -> None: try: y, m, d = getDateParts(datum) self._sdLetzteBuchung.setDate(y, m, d) except: pass self._leLetzteBuchung.setText(text) def setTabellenAuswahl(self, tables: List[str]) -> None: """ Fügt dem SubMenu "Ganze Tabelle anzeigen" soviele Tabellen-Namen hinzu wie in <tables> enthalten. :param tables: :return: """ n = len(tables) actions = [QAction(self._submenuShowTableContent) for i in range(n)] for i in range(n): act = actions[i] act.setText(tables[i]) #act.triggered.connect( lambda action=act: self.onShowTableContent(action) ) --> funktioniert nicht act.triggered.connect(partial(self.onShowTableContent, act)) #txt = act.text() #act.triggered.connect( lambda table=txt: self.showTableContent.emit( txt ) ) --> funktioniert nicht self._submenuShowTableContent.addAction(act) def getLetzteBuchung(self) -> Dict: """ :return: dictionary with keys "date" and "text" """ d = dict() d["datum"] = self._sdLetzteBuchung.getDate() d["text"] = self._leLetzteBuchung.text() return d def setShutdownCallback(self, callbackFnc) -> None: self._shutdownCallback = callbackFnc def setActionCallback(self, callbackFnc) -> None: self._actionCallbackFnc = callbackFnc def addOpenedDialog(self, name: str, data: Any): """ Fügt dem Views-Menü eine gerade geöffnete View hinzu :param name: :param data: :return: """ action = QAction(self._viewsMenu, text=name) action.setData(data) self._viewsMenu.addAction(action) #action.triggered.connect( lambda name=name, data=data: self.bringDialogToFront.emit( name, data ) ) action.triggered.connect(partial(self.onShowDialog, action)) def getOpenedDialogs(self) -> List[IccDialog]: return [a.data() for a in self._viewsMenu.actions()] def removeClosedDialog(self, name: str, data: Any): """ Entfernt den Eintrag <name> aus dem Views-Menü. :param name: Name der zu entfernenden View (entspricht dem Text des Menüpunktes) :param data: Wird zur Identifikation der View verwendet. :return: """ for a in self._viewsMenu.actions(): if a.data() == data: self._viewsMenu.removeAction(a) break return def doCallback(self, action: MainWindowAction, arg=None): if self._actionCallbackFnc: if arg: self._actionCallbackFnc(action, arg) else: self._actionCallbackFnc(action) def onNewWindow(self): self.doCallback(MainWindowAction.NEW_WINDOW) def onMieterwechsel(self): self.doCallback(MainWindowAction.MIETERWECHSEL) def onVerwalterwechsel(self): pass # def onChangeSollmiete( self ): # pass # # def onChangeSollhausgeld( self ): # pass # def onSaveActiveView( self ): # self.doCallback( MainWindowAction.SAVE_ACTIVE_VIEW ) def onSaveAll(self): self.doCallback(MainWindowAction.SAVE_ALL) def onExportDatabaseToServer(self): self.doCallback(MainWindowAction.EXPORT_DB_TO_SERVER) def onImportDatabaseFromServer(self): self.doCallback(MainWindowAction.IMPORT_DB_FROM_SERVER) def onFolgejahrEinrichten(self): self.doCallback(MainWindowAction.FOLGEJAHR) def onPrintActiveView(self): self.doCallback(MainWindowAction.PRINT_ACTIVE_VIEW) def onExit(self): self.doCallback(MainWindowAction.EXIT) def onViewMietzahlungen(self): self.doCallback(MainWindowAction.OPEN_MIETE_VIEW) def onViewHGVorauszahlungen(self): self.doCallback(MainWindowAction.OPEN_HGV_VIEW) def onViewSollMiete(self): self.doCallback(MainWindowAction.OPEN_SOLL_MIETE_VIEW) def onViewSollHausgeld(self): self.doCallback(MainWindowAction.OPEN_SOLL_HG_VIEW) def onViewNebenkostenabrechnung(self): self.doCallback(MainWindowAction.OPEN_NKA_VIEW) def onViewHausgeldabrechnung(self): self.doCallback(MainWindowAction.OPEN_HGA_VIEW) def onViewAnlageV(self): self.doCallback(MainWindowAction.OPEN_ANLAGEV_VIEW) def onExportActiveTableView(self): self.doCallback(MainWindowAction.EXPORT_CSV) def onNotizen(self): self.doCallback(MainWindowAction.NOTIZEN) def onSammelabgabe(self): self.doCallback(MainWindowAction.SAMMELABGABE_DETAIL) def onGeschaeftsreise(self): self.doCallback(MainWindowAction.OPEN_GESCHAEFTSREISE_VIEW) def onRenditeVergleich(self): self.doCallback(MainWindowAction.RENDITE_VIEW) def onViewRechnungen(self): self.doCallback(MainWindowAction.OPEN_SONST_EIN_AUS_VIEW) def onViewOffenePosten(self): self.doCallback(MainWindowAction.OPEN_OFFENE_POSTEN_VIEW) def onViewObjektStammdaten(self): self.doCallback(MainWindowAction.OPEN_OBJEKT_STAMMDATEN_VIEW) def onViewMietverhaeltnis(self): self.doCallback(MainWindowAction.OPEN_MIETVERH_VIEW) def onNewSql(self): pass def onShowTableContent(self, action): self.doCallback(MainWindowAction.SHOW_TABLE_CONTENT, action.text()) def onShowDialog(self, action): self.doCallback(MainWindowAction.BRING_DIALOG_TO_FRONT, action.data()) def showException(self, exception: str, moretext: str = None): print(exception) msg = QtWidgets.QMessageBox() msg.setIcon(QMessageBox.Critical) msg.setText(exception) if moretext: msg.setInformativeText(moretext) msg.setWindowTitle("Error") msg.exec_() def showInfo(self, title, msg): box = InfoBox(title, msg, "", "OK") box.exec_()
def initUI(self): # ---------------- # Create toolbar toolbar = QToolBar() self.addToolBar(toolbar) # Add buttons to toolbar btn_before: QToolButton = QToolButton() btn_before.setIcon(QIcon(self.icons.LEFT)) btn_before.setStyleSheet("QToolButton {margin: 0 5px;}") btn_before.setStatusTip('goto previous PARAMETER') btn_before.clicked.connect(self.prev_chart) toolbar.addWidget(btn_before) # Add buttons to toolbar btn_after: QToolButton = QToolButton() btn_after.setIcon(QIcon(self.icons.RIGHT)) btn_after.setStyleSheet("QToolButton {margin: 0 5px;}") btn_after.setStatusTip('go to next PARAMETER') btn_after.clicked.connect(self.next_chart) toolbar.addWidget(btn_after) toolbar.addSeparator() self.check_update = QCheckBox('Hide Spec Limit(s)', self) self.check_update.setStyleSheet("QCheckBox {margin: 0 5px;}") self.checkbox_state() self.check_update.stateChanged.connect(self.update_status) toolbar.addWidget(self.check_update) # spacer to expand spacer: QWidget = QWidget() spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) toolbar.addWidget(spacer) # ComboBox to choose PowerPoint format self.ppt_format = bwidget.BComboBox(self) self.ppt_format.setText('PPT Format') self.ppt_format.addItems(['Default', 'Custom']) self.ppt_format.currentIndexChanged(self.selectionComboChange) toolbar.addWidget(self.ppt_format) toolbar.addSeparator() self.check_all_slides = QCheckBox('All parameters', self) toolbar.addWidget(self.check_all_slides) # PowerPoint but_ppt: QToolButton = QToolButton() but_ppt.setIcon(QIcon(self.icons.PPT)) but_ppt.setStatusTip('generate PowerPoint slide(s)') but_ppt.clicked.connect(self.OnPPT) toolbar.addWidget(but_ppt) # ------------ # Status Bar self.statusbar = QStatusBar() self.setStatusBar(self.statusbar) self.create_chart() self.show()
def __init__(self): super().__init__() self.browser = QWebEngineView() self.browser.setUrl(QUrl("http://google.com")) self.setCentralWidget(self.browser) # tag::navigationSignals[] self.browser.urlChanged.connect(self.update_urlbar) self.browser.loadFinished.connect(self.update_title) # end::navigationSignals[] # tag::navigation1[] navtb = QToolBar("Navigation") navtb.setIconSize(QSize(16, 16)) self.addToolBar(navtb) back_btn = QAction(QIcon(os.path.join("icons", "arrow-180.png")), "Back", self) back_btn.setStatusTip("Back to previous page") back_btn.triggered.connect(self.browser.back) navtb.addAction(back_btn) # end::navigation1[] # tag::navigation2[] next_btn = QAction(QIcon(os.path.join("icons", "arrow-000.png")), "Forward", self) next_btn.setStatusTip("Forward to next page") next_btn.triggered.connect(self.browser.forward) navtb.addAction(next_btn) reload_btn = QAction( QIcon(os.path.join("icons", "arrow-circle-315.png")), "Reload", self) reload_btn.setStatusTip("Reload page") reload_btn.triggered.connect(self.browser.reload) navtb.addAction(reload_btn) home_btn = QAction(QIcon(os.path.join("icons", "home.png")), "Home", self) home_btn.setStatusTip("Go home") home_btn.triggered.connect(self.navigate_home) navtb.addAction(home_btn) # end::navigation2[] navtb.addSeparator() # tag::navigation3[] self.httpsicon = QLabel() # Yes, really! self.httpsicon.setPixmap( QPixmap(os.path.join("icons", "lock-nossl.png"))) navtb.addWidget(self.httpsicon) self.urlbar = QLineEdit() self.urlbar.returnPressed.connect(self.navigate_to_url) navtb.addWidget(self.urlbar) stop_btn = QAction(QIcon(os.path.join("icons", "cross-circle.png")), "Stop", self) stop_btn.setStatusTip("Stop loading current page") stop_btn.triggered.connect(self.browser.stop) navtb.addAction(stop_btn) # end::navigation3[] self.menuBar().setNativeMenuBar(False) self.statusBar() # tag::menuFile[] file_menu = self.menuBar().addMenu("&File") open_file_action = QAction( QIcon(os.path.join("icons", "disk--arrow.png")), "Open file...", self) open_file_action.setStatusTip("Open from file") open_file_action.triggered.connect(self.open_file) file_menu.addAction(open_file_action) save_file_action = QAction( QIcon(os.path.join("icons", "disk--pencil.png")), "Save Page As...", self) save_file_action.setStatusTip("Save current page to file") save_file_action.triggered.connect(self.save_file) file_menu.addAction(save_file_action) # end::menuFile[] # tag::menuPrint[] print_action = QAction(QIcon(os.path.join("icons", "printer.png")), "Print...", self) print_action.setStatusTip("Print current page") print_action.triggered.connect(self.print_page) file_menu.addAction(print_action) # Create our system printer instance. self.printer = QPrinter() # end::menuPrint[] # tag::menuHelp[] help_menu = self.menuBar().addMenu("&Help") about_action = QAction( QIcon(os.path.join("icons", "question.png")), "About Mozzarella Ashbadger", self, ) about_action.setStatusTip( "Find out more about Mozzarella Ashbadger") # Hungry! about_action.triggered.connect(self.about) help_menu.addAction(about_action) navigate_mozzarella_action = QAction( QIcon(os.path.join("icons", "lifebuoy.png")), "Mozzarella Ashbadger Homepage", self, ) navigate_mozzarella_action.setStatusTip( "Go to Mozzarella Ashbadger Homepage") navigate_mozzarella_action.triggered.connect(self.navigate_mozzarella) help_menu.addAction(navigate_mozzarella_action) # end::menuHelp[] self.show() self.setWindowIcon(QIcon(os.path.join("icons", "ma-icon-64.png")))
class USBFrame(QWidget): # --- Init methods --- def __init__(self, config): """ USB control frame :param config: application configuration file """ QWidget.__init__(self) self.setFixedSize(QSize(600, 200)) self.config = config self.setWindowTitle("DigiQt - USB Control") self.sig_button_pressed = None # signal configured by serialControler self.sig_firmware_update = None # # Firmware update output self.out = ConsoleOutput() # Buttons self.to_dr_btn = ToDigiruleButton(config) self.to_dr_btn.to_digirule = lambda: self.sig_button_pressed.emit(0) self.from_dr_btn = FromDigiruleButton(config) self.from_dr_btn.from_digirule = lambda: self.sig_button_pressed.emit(1 ) # Firmware self.firmware_btn = FirmwareUpdate(config) self.firmware_btn.firmware_update = self.firmware_update # Port selection self.lab_port = QLabel("Port:") self.usb_combo = UsbPortCombo() self.refresh_btn = RefreshPortButton(config) self.refresh_btn.on_refresh = lambda: self.sig_button_pressed.emit(2) self._init_tool_bar() self._set_layout() self._set_stylesheet() def _init_tool_bar(self): """ Creates the main toolbar with all its content """ self.toolbar = QToolBar() self.toolbar.setFixedHeight(70) self.toolbar.addWidget(self.to_dr_btn) self.toolbar.addWidget(self.from_dr_btn) self.toolbar.addSeparator() self.toolbar.addWidget(self.firmware_btn) self.toolbar.addSeparator() self.toolbar.addWidget(self.lab_port) self.toolbar.addWidget(self.usb_combo) self.toolbar.addWidget(self.refresh_btn) def _set_layout(self): """ Creates this Widget's Layout """ box = QGridLayout() box.setContentsMargins(0, 0, 0, 0) box.addWidget(self.toolbar, 0, 0) box.addWidget(self.out, 1, 0) self.setLayout(box) def _set_stylesheet(self): self.toolbar.setStyleSheet(style.get_stylesheet("qtoolbar")) self.setStyleSheet(style.get_stylesheet("common")) self.lab_port.setStyleSheet( "background-color: transparent; color: #75BA6D; font-weight: bold;" ) self.out.setStyleSheet("background-color: #505050; color: white;") def firmware_update(self): dlg = QFileDialog() dlg.setWindowTitle("Choose a digirule Firmware") dlg.setFileMode(QFileDialog.AnyFile) dlg.setNameFilter("HEX files (*.hex)") if dlg.exec_(): file_path = dlg.selectedFiles()[0] # Call the controller method for update self.sig_firmware_update.emit(file_path) # --- Close handler --- def closeEvent(self, event): """ Event called upon a red-cross click. """ self.on_close() def on_close(self): """ Reroute this method in the Main Frame in order to Updates the execution frame's open editor icon and tooltip """ pass
class MainWindow(QMainWindow): def __init__(self, path_to_rom=""): super(MainWindow, self).__init__() self.setWindowIcon(icon("foundry.ico")) file_menu = QMenu("File") open_rom_action = file_menu.addAction("&Open ROM") open_rom_action.triggered.connect(self.on_open_rom) self.open_m3l_action = file_menu.addAction("&Open M3L") self.open_m3l_action.triggered.connect(self.on_open_m3l) file_menu.addSeparator() self.save_rom_action = file_menu.addAction("&Save ROM") self.save_rom_action.triggered.connect(self.on_save_rom) self.save_rom_as_action = file_menu.addAction("&Save ROM as ...") self.save_rom_as_action.triggered.connect(self.on_save_rom_as) """ file_menu.AppendSeparator() """ self.save_m3l_action = file_menu.addAction("&Save M3L") self.save_m3l_action.triggered.connect(self.on_save_m3l) """ file_menu.Append(ID_SAVE_LEVEL_TO, "&Save Level to", "") file_menu.AppendSeparator() file_menu.Append(ID_APPLY_IPS_PATCH, "&Apply IPS Patch", "") file_menu.AppendSeparator() file_menu.Append(ID_ROM_PRESET, "&ROM Preset", "") """ file_menu.addSeparator() settings_action = file_menu.addAction("&Settings") settings_action.triggered.connect(show_settings) file_menu.addSeparator() exit_action = file_menu.addAction("&Exit") exit_action.triggered.connect(lambda _: self.close()) self.menuBar().addMenu(file_menu) """ edit_menu = wx.Menu() edit_menu.Append(ID_EDIT_LEVEL, "&Edit Level", "") edit_menu.Append(ID_EDIT_OBJ_DEFS, "&Edit Object Definitions", "") edit_menu.Append(ID_EDIT_PALETTE, "&Edit Palette", "") edit_menu.Append(ID_EDIT_GRAPHICS, "&Edit Graphics", "") edit_menu.Append(ID_EDIT_MISC, "&Edit Miscellaneous", "") edit_menu.AppendSeparator() edit_menu.Append(ID_FREE_FORM_MODE, "&Free form Mode", "") edit_menu.Append(ID_LIMIT_SIZE, "&Limit Size", "") """ self.level_menu = QMenu("Level") self.select_level_action = self.level_menu.addAction("&Select Level") self.select_level_action.triggered.connect(self.open_level_selector) self.reload_action = self.level_menu.addAction("&Reload Level") self.reload_action.triggered.connect(self.reload_level) self.level_menu.addSeparator() self.edit_header_action = self.level_menu.addAction("&Edit Header") self.edit_header_action.triggered.connect(self.on_header_editor) self.edit_autoscroll = self.level_menu.addAction("Edit Autoscrolling") self.edit_autoscroll.triggered.connect(self.on_edit_autoscroll) self.menuBar().addMenu(self.level_menu) self.object_menu = QMenu("Objects") view_blocks_action = self.object_menu.addAction("&View Blocks") view_blocks_action.triggered.connect(self.on_block_viewer) view_objects_action = self.object_menu.addAction("&View Objects") view_objects_action.triggered.connect(self.on_object_viewer) self.object_menu.addSeparator() view_palettes_action = self.object_menu.addAction( "View Object Palettes") view_palettes_action.triggered.connect(self.on_palette_viewer) self.menuBar().addMenu(self.object_menu) self.view_menu = QMenu("View") self.view_menu.triggered.connect(self.on_menu) action = self.view_menu.addAction("Mario") action.setProperty(ID_PROP, ID_MARIO) action.setCheckable(True) action.setChecked(SETTINGS["draw_mario"]) action = self.view_menu.addAction("&Jumps on objects") action.setProperty(ID_PROP, ID_JUMP_OBJECTS) action.setCheckable(True) action.setChecked(SETTINGS["draw_jump_on_objects"]) action = self.view_menu.addAction("Items in blocks") action.setProperty(ID_PROP, ID_ITEM_BLOCKS) action.setCheckable(True) action.setChecked(SETTINGS["draw_items_in_blocks"]) action = self.view_menu.addAction("Invisible items") action.setProperty(ID_PROP, ID_INVISIBLE_ITEMS) action.setCheckable(True) action.setChecked(SETTINGS["draw_invisible_items"]) action = self.view_menu.addAction("Autoscroll Path") action.setProperty(ID_PROP, ID_AUTOSCROLL) action.setCheckable(True) action.setChecked(SETTINGS["draw_autoscroll"]) self.view_menu.addSeparator() action = self.view_menu.addAction("Jump Zones") action.setProperty(ID_PROP, ID_JUMPS) action.setCheckable(True) action.setChecked(SETTINGS["draw_jumps"]) action = self.view_menu.addAction("&Grid lines") action.setProperty(ID_PROP, ID_GRID_LINES) action.setCheckable(True) action.setChecked(SETTINGS["draw_grid"]) action = self.view_menu.addAction("Resize Type") action.setProperty(ID_PROP, ID_RESIZE_TYPE) action.setCheckable(True) action.setChecked(SETTINGS["draw_expansion"]) self.view_menu.addSeparator() action = self.view_menu.addAction("&Block Transparency") action.setProperty(ID_PROP, ID_TRANSPARENCY) action.setCheckable(True) action.setChecked(SETTINGS["block_transparency"]) self.view_menu.addSeparator() self.view_menu.addAction( "&Save Screenshot of Level").triggered.connect(self.on_screenshot) """ self.view_menu.Append(ID_BACKGROUND_FLOOR, "&Background & Floor", "") self.view_menu.Append(ID_TOOLBAR, "&Toolbar", "") self.view_menu.AppendSeparator() self.view_menu.Append(ID_ZOOM, "&Zoom", "") self.view_menu.AppendSeparator() self.view_menu.Append(ID_USE_ROM_GRAPHICS, "&Use ROM Graphics", "") self.view_menu.Append(ID_PALETTE, "&Palette", "") self.view_menu.AppendSeparator() self.view_menu.Append(ID_MORE, "&More", "") """ self.menuBar().addMenu(self.view_menu) help_menu = QMenu("Help") """ help_menu.Append(ID_ENEMY_COMPATIBILITY, "&Enemy Compatibility", "") help_menu.Append(ID_TROUBLESHOOTING, "&Troubleshooting", "") help_menu.AppendSeparator() help_menu.Append(ID_PROGRAM_WEBSITE, "&Program Website", "") help_menu.Append(ID_MAKE_A_DONATION, "&Make a Donation", "") help_menu.AppendSeparator() """ update_action = help_menu.addAction("Check for updates") update_action.triggered.connect(self.on_check_for_update) help_menu.addSeparator() video_action = help_menu.addAction("Feature Video on YouTube") video_action.triggered.connect(lambda: open_url(feature_video_link)) github_action = help_menu.addAction("Github Repository") github_action.triggered.connect(lambda: open_url(github_link)) discord_action = help_menu.addAction("SMB3 Rom Hacking Discord") discord_action.triggered.connect(lambda: open_url(discord_link)) help_menu.addSeparator() about_action = help_menu.addAction("&About") about_action.triggered.connect(self.on_about) self.menuBar().addMenu(help_menu) self.block_viewer = None self.object_viewer = None self.level_ref = LevelRef() self.level_ref.data_changed.connect(self._on_level_data_changed) self.context_menu = ContextMenu(self.level_ref) self.context_menu.triggered.connect(self.on_menu) self.level_view = LevelView(self, self.level_ref, self.context_menu) self.scroll_panel = QScrollArea() self.scroll_panel.setWidgetResizable(True) self.scroll_panel.setWidget(self.level_view) self.setCentralWidget(self.scroll_panel) self.spinner_panel = SpinnerPanel(self, self.level_ref) self.spinner_panel.zoom_in_triggered.connect(self.level_view.zoom_in) self.spinner_panel.zoom_out_triggered.connect(self.level_view.zoom_out) self.spinner_panel.object_change.connect(self.on_spin) self.object_list = ObjectList(self, self.level_ref, self.context_menu) self.object_dropdown = ObjectDropdown(self) self.object_dropdown.object_selected.connect( self._on_placeable_object_selected) self.level_size_bar = LevelSizeBar(self, self.level_ref) self.enemy_size_bar = EnemySizeBar(self, self.level_ref) self.jump_list = JumpList(self, self.level_ref) self.jump_list.add_jump.connect(self.on_jump_added) self.jump_list.edit_jump.connect(self.on_jump_edit) self.jump_list.remove_jump.connect(self.on_jump_removed) splitter = QSplitter(self) splitter.setOrientation(Qt.Vertical) splitter.addWidget(self.object_list) splitter.setStretchFactor(0, 1) splitter.addWidget(self.jump_list) splitter.setChildrenCollapsible(False) level_toolbar = QToolBar("Level Info Toolbar", self) level_toolbar.setContextMenuPolicy(Qt.PreventContextMenu) level_toolbar.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum) level_toolbar.setOrientation(Qt.Horizontal) level_toolbar.setFloatable(False) level_toolbar.addWidget(self.spinner_panel) level_toolbar.addWidget(self.object_dropdown) level_toolbar.addWidget(self.level_size_bar) level_toolbar.addWidget(self.enemy_size_bar) level_toolbar.addWidget(splitter) level_toolbar.setAllowedAreas(Qt.LeftToolBarArea | Qt.RightToolBarArea) self.addToolBar(Qt.RightToolBarArea, level_toolbar) self.object_toolbar = ObjectToolBar(self) self.object_toolbar.object_selected.connect( self._on_placeable_object_selected) object_toolbar = QToolBar("Object Toolbar", self) object_toolbar.setContextMenuPolicy(Qt.PreventContextMenu) object_toolbar.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum) object_toolbar.setFloatable(False) object_toolbar.addWidget(self.object_toolbar) object_toolbar.setAllowedAreas(Qt.LeftToolBarArea | Qt.RightToolBarArea) self.addToolBar(Qt.LeftToolBarArea, object_toolbar) self.menu_toolbar = QToolBar("Menu Toolbar", self) self.menu_toolbar.setOrientation(Qt.Horizontal) self.menu_toolbar.setIconSize(QSize(20, 20)) self.menu_toolbar.addAction( icon("settings.svg"), "Editor Settings").triggered.connect(show_settings) self.menu_toolbar.addSeparator() self.menu_toolbar.addAction( icon("folder.svg"), "Open ROM").triggered.connect(self.on_open_rom) self.menu_toolbar.addAction( icon("save.svg"), "Save Level").triggered.connect(self.on_save_rom) self.menu_toolbar.addSeparator() self.undo_action = self.menu_toolbar.addAction(icon("rotate-ccw.svg"), "Undo Action") self.undo_action.triggered.connect(self.level_ref.undo) self.undo_action.setEnabled(False) self.redo_action = self.menu_toolbar.addAction(icon("rotate-cw.svg"), "Redo Action") self.redo_action.triggered.connect(self.level_ref.redo) self.redo_action.setEnabled(False) self.menu_toolbar.addSeparator() play_action = self.menu_toolbar.addAction(icon("play-circle.svg"), "Play Level") play_action.triggered.connect(self.on_play) play_action.setWhatsThis( "Opens an emulator with the current Level set to 1-1.\nSee Settings." ) self.menu_toolbar.addSeparator() self.menu_toolbar.addAction(icon("zoom-out.svg"), "Zoom Out").triggered.connect( self.level_view.zoom_out) self.menu_toolbar.addAction(icon("zoom-in.svg"), "Zoom In").triggered.connect( self.level_view.zoom_in) self.menu_toolbar.addSeparator() header_action = self.menu_toolbar.addAction(icon("tool.svg"), "Edit Level Header") header_action.triggered.connect(self.on_header_editor) header_action.setWhatsThis( "<b>Header Editor</b><br/>" "Many configurations regarding the level are done in its header, like the length of " "the timer, or where and how Mario enters the level.<br/>") self.jump_destination_action = self.menu_toolbar.addAction( icon("arrow-right-circle.svg"), "Go to Jump Destination") self.jump_destination_action.triggered.connect( self._go_to_jump_destination) self.jump_destination_action.setWhatsThis( "Opens the level, that can be reached from this one, e.g. by entering a pipe." ) self.menu_toolbar.addSeparator() whats_this_action = QWhatsThis.createAction() whats_this_action.setWhatsThis( "Click on parts of the editor, to receive help information.") whats_this_action.setIcon(icon("help-circle.svg")) whats_this_action.setText("Starts 'What's this?' mode") self.menu_toolbar.addAction(whats_this_action) self.menu_toolbar.addSeparator() self.warning_list = WarningList(self, self.level_ref) warning_action = self.menu_toolbar.addAction( icon("alert-triangle.svg"), "Warning Panel") warning_action.setWhatsThis("Shows a list of warnings.") warning_action.triggered.connect(self.warning_list.show) warning_action.setDisabled(True) self.warning_list.warnings_updated.connect(warning_action.setEnabled) self.addToolBar(Qt.TopToolBarArea, self.menu_toolbar) self.status_bar = ObjectStatusBar(self, self.level_ref) self.setStatusBar(self.status_bar) self.delete_shortcut = QShortcut(QKeySequence(Qt.Key_Delete), self, self.remove_selected_objects) QShortcut(QKeySequence(Qt.CTRL + Qt.Key_X), self, self._cut_objects) QShortcut(QKeySequence(Qt.CTRL + Qt.Key_C), self, self._copy_objects) QShortcut(QKeySequence(Qt.CTRL + Qt.Key_V), self, self._paste_objects) QShortcut(QKeySequence(Qt.CTRL + Qt.Key_Z), self, self.level_ref.undo) QShortcut(QKeySequence(Qt.CTRL + Qt.Key_Y), self, self.level_ref.redo) QShortcut(QKeySequence(Qt.CTRL + Qt.SHIFT + Qt.Key_Z), self, self.level_ref.redo) QShortcut(QKeySequence(Qt.CTRL + Qt.Key_Plus), self, self.level_view.zoom_in) QShortcut(QKeySequence(Qt.CTRL + Qt.Key_Minus), self, self.level_view.zoom_out) QShortcut(QKeySequence(Qt.CTRL + Qt.Key_A), self, self.level_view.select_all) self.on_open_rom(path_to_rom) self.showMaximized() def _on_level_data_changed(self): self.undo_action.setEnabled(self.level_ref.undo_stack.undo_available) self.redo_action.setEnabled(self.level_ref.undo_stack.redo_available) self.jump_destination_action.setEnabled( self.level_ref.level.has_next_area) def _go_to_jump_destination(self): if not self.safe_to_change(): return level_address = self.level_ref.level.next_area_objects enemy_address = self.level_ref.level.next_area_enemies + 1 object_set = self.level_ref.level.next_area_object_set world, level = world_and_level_for_level_address(level_address) self.update_level(f"Level {world}-{level}", level_address, enemy_address, object_set) def on_play(self): """ Copies the ROM, including the current level, to a temporary directory, saves the current level as level 1-1 and opens the rom in an emulator. """ temp_dir = pathlib.Path(tempfile.gettempdir()) / "smb3foundry" temp_dir.mkdir(parents=True, exist_ok=True) path_to_temp_rom = temp_dir / "instaplay.rom" ROM().save_to(path_to_temp_rom) if not self._put_current_level_to_level_1_1(path_to_temp_rom): return if not self._set_default_powerup(path_to_temp_rom): return arguments = SETTINGS["instaplay_arguments"].replace( "%f", str(path_to_temp_rom)) arguments = shlex.split(arguments, posix=False) emu_path = pathlib.Path(SETTINGS["instaplay_emulator"]) if emu_path.is_absolute(): if emu_path.exists(): emulator = str(emu_path) else: QMessageBox.critical( self, "Emulator not found", f"Check it under File > Settings.\nFile {emu_path} not found." ) return else: emulator = SETTINGS["instaplay_emulator"] try: subprocess.run([emulator, *arguments]) except Exception as e: QMessageBox.critical(self, "Emulator command failed.", f"Check it under File > Settings.\n{str(e)}") def _open_rom(self, path_to_rom): with open(path_to_rom, "rb") as smb3_rom: data = smb3_rom.read() rom = SMB3Rom(bytearray(data)) return rom def _put_current_level_to_level_1_1(self, path_to_rom) -> bool: rom = self._open_rom(path_to_rom) # load world-1 data world_1 = SMB3World.from_world_number(rom, 1) # find position of "level 1" tile in world map for position in world_1.gen_positions(): if position.tile() == TILE_LEVEL_1: break else: QMessageBox.critical( self, "Couldn't place level", "Could not find a level 1 tile in World 1 to put your level at." ) return False if not self.level_ref.level.attached_to_rom: QMessageBox.critical( self, "Couldn't place level", "The Level is not part of the rom yet (M3L?). Try saving it into the ROM first.", ) return False # write level and enemy data of current level (layout_address, layout_bytes), (enemy_address, enemy_bytes) = self.level_ref.level.to_bytes() rom.write(layout_address, layout_bytes) rom.write(enemy_address, enemy_bytes) # replace level information with that of current level object_set_number = self.level_ref.object_set_number world_1.replace_level_at_position( (layout_address, enemy_address - 1, object_set_number), position) # save rom rom.save_to(path_to_rom) return True def _set_default_powerup(self, path_to_rom) -> bool: rom = self._open_rom(path_to_rom) *_, powerup, hasPWing = POWERUPS[SETTINGS["default_powerup"]] rom.write(Title_PrepForWorldMap + 0x1, bytes([powerup])) nop = 0xEA rts = 0x60 lda = 0xA9 staAbsolute = 0x8D # If a P-wing powerup is selected, another variable needs to be set with the P-wing value # This piece of code overwrites a part of Title_DebugMenu if hasPWing: Map_Power_DispHigh = 0x03 Map_Power_DispLow = 0xF3 # We need to start one byte before Title_DebugMenu to remove the RTS of Title_PrepForWorldMap # The assembly code below reads as follows: # LDA 0x08 # STA $03F3 # RTS rom.write( Title_DebugMenu - 0x1, bytes([ lda, 0x8, staAbsolute, Map_Power_DispLow, Map_Power_DispHigh, # The RTS to get out of the now extended Title_PrepForWorldMap rts, ]), ) # Remove code that resets the powerup value by replacing it with no-operations # Otherwise this code would copy the value of the normal powerup here # (So if the powerup would be Raccoon Mario, Map_Power_Disp would also be # set as Raccoon Mario instead of P-wing Map_Power_DispResetLocation = 0x3C5A2 rom.write(Map_Power_DispResetLocation, bytes([nop, nop, nop])) rom.save_to(path_to_rom) return True def on_screenshot(self, _) -> bool: if self.level_view is None: return False recommended_file = f"{os.path.expanduser('~')}/{ROM.name} - {self.level_view.level_ref.name}.png" pathname, _ = QFileDialog.getSaveFileName(self, caption="Save Screenshot", dir=recommended_file, filter=IMG_FILE_FILTER) if not pathname: return False # Proceed loading the file chosen by the user self.level_view.make_screenshot().save(pathname) return True def update_title(self): if self.level_view.level_ref is not None and ROM is not None: title = f"{self.level_view.level_ref.name} - {ROM.name}" else: title = "SMB3Foundry" self.setWindowTitle(title) def on_open_rom(self, path_to_rom="") -> bool: if not self.safe_to_change(): return False if not path_to_rom: # otherwise ask the user what new file to open path_to_rom, _ = QFileDialog.getOpenFileName( self, caption="Open ROM", filter=ROM_FILE_FILTER) if not path_to_rom: self._enable_disable_gui_elements() return False # Proceed loading the file chosen by the user try: ROM.load_from_file(path_to_rom) return self.open_level_selector(None) except IOError as exp: QMessageBox.warning(self, type(exp).__name__, f"Cannot open file '{path_to_rom}'.") return False finally: self._enable_disable_gui_elements() def on_open_m3l(self, _) -> bool: if not self.safe_to_change(): return False # otherwise ask the user what new file to open pathname, _ = QFileDialog.getOpenFileName(self, caption="Open M3L file", filter=M3L_FILE_FILTER) if not pathname: return False # Proceed loading the file chosen by the user try: with open(pathname, "rb") as m3l_file: self.level_view.from_m3l(bytearray(m3l_file.read())) except IOError as exp: QMessageBox.warning(self, type(exp).__name__, f"Cannot open file '{pathname}'.") return False self.level_view.level_ref.name = os.path.basename(pathname) self.update_gui_for_level() return True def safe_to_change(self) -> bool: if not self.level_ref: return True if self.level_ref.level.changed: answer = QMessageBox.question( self, "Please confirm", "Current content has not been saved! Proceed?", QMessageBox.No | QMessageBox.Yes, QMessageBox.No, ) return answer == QMessageBox.Yes else: return True def on_save_rom(self, _): self.save_rom(False) def on_save_rom_as(self, _): self.save_rom(True) def save_rom(self, is_save_as): safe_to_save, reason, additional_info = self.level_view.level_safe_to_save( ) if not safe_to_save: answer = QMessageBox.warning( self, reason, f"{additional_info}\n\nDo you want to proceed?", QMessageBox.No | QMessageBox.Yes, QMessageBox.No, ) if answer == QMessageBox.No: return if not self.level_ref.attached_to_rom: QMessageBox.information( self, "Importing M3L into ROM", "Please select the positions in the ROM you want the level objects and enemies/items to be stored.", QMessageBox.Ok, ) level_selector = LevelSelector(self) answer = level_selector.exec_() if answer == QMessageBox.Accepted: self.level_view.level_ref.attach_to_rom( level_selector.object_data_offset, level_selector.enemy_data_offset) if is_save_as: # if we save to another rom, don't consider the level # attached (to the current rom) self.level_view.level_ref.attached_to_rom = False else: return if is_save_as: pathname, _ = QFileDialog.getSaveFileName(self, caption="Save ROM as", filter=ROM_FILE_FILTER) if not pathname: return # the user changed their mind else: pathname = ROM.path level = self.level_ref.level for offset, data in level.to_bytes(): ROM().bulk_write(data, offset) try: ROM().save_to_file(pathname) except IOError as exp: QMessageBox.warning(self, f"{type(exp).__name__}", f"Cannot save ROM data to file '{pathname}'.") self.update_title() if not is_save_as: level.changed = False def on_save_m3l(self, _): suggested_file = self.level_view.level_ref.name if not suggested_file.endswith(".m3l"): suggested_file += ".m3l" pathname, _ = QFileDialog.getSaveFileName(self, caption="Save M3L as", filter=M3L_FILE_FILTER) if not pathname: return level = self.level_view.level_ref try: with open(pathname, "wb") as m3l_file: m3l_file.write(level.to_m3l()) except IOError as exp: QMessageBox.warning(self, type(exp).__name__, f"Couldn't save level to '{pathname}'.") def on_check_for_update(self): self.setCursor(Qt.WaitCursor) current_version = get_current_version_name() try: latest_version = get_latest_version_name() except ValueError as ve: QMessageBox.critical(self, "Error while checking for updates", f"Error: {ve}") return if current_version != latest_version: latest_release_url = f"{releases_link}/tag/{latest_version}" go_to_github_button = QPushButton(icon("external-link.svg"), "Go to latest release") go_to_github_button.clicked.connect( lambda: open_url(latest_release_url)) info_box = QMessageBox( QMessageBox.Information, "New release available", f"New Version {latest_version} is available.") info_box.addButton(QMessageBox.Cancel) info_box.addButton(go_to_github_button, QMessageBox.AcceptRole) info_box.exec_() else: QMessageBox.information( self, "No newer release", f"Version {current_version} is up to date.") self.setCursor(Qt.ArrowCursor) def on_menu(self, action: QAction): item_id = action.property(ID_PROP) if item_id in CHECKABLE_MENU_ITEMS: self.on_menu_item_checked(action) self.level_view.update() # if setting a checkbox, keep the menu open menu_of_action: QMenu = self.sender() menu_of_action.exec_() elif item_id in self.context_menu.get_all_menu_item_ids(): x, y = self.context_menu.get_position() if item_id == CMAction.REMOVE: self.remove_selected_objects() elif item_id == CMAction.ADD_OBJECT: selected_object = self.object_dropdown.currentIndex() if selected_object != -1: self.place_object_from_dropdown((x, y)) else: self.create_object_at(x, y) elif item_id == CMAction.CUT: self._cut_objects() elif item_id == CMAction.COPY: self._copy_objects() elif item_id == CMAction.PASTE: self._paste_objects(x, y) elif item_id == CMAction.FOREGROUND: self.bring_objects_to_foreground() elif item_id == CMAction.BACKGROUND: self.bring_objects_to_background() self.level_view.update() def reload_level(self): if not self.safe_to_change(): return level_name = self.level_view.level_ref.name object_data = self.level_view.level_ref.header_offset enemy_data = self.level_view.level_ref.enemy_offset object_set = self.level_view.level_ref.object_set_number self.update_level(level_name, object_data, enemy_data, object_set) def _on_placeable_object_selected(self, level_object: Union[LevelObject, EnemyObject]): if self.sender() is self.object_toolbar: self.object_dropdown.select_object(level_object) else: self.object_toolbar.select_object(level_object) @undoable def bring_objects_to_foreground(self): self.level_ref.level.bring_to_foreground( self.level_ref.selected_objects) @undoable def bring_objects_to_background(self): self.level_ref.level.bring_to_background( self.level_ref.selected_objects) @undoable def create_object_at(self, x, y): self.level_view.create_object_at(x, y) @undoable def create_enemy_at(self, x, y): self.level_view.create_enemy_at(x, y) def _cut_objects(self): self._copy_objects() self.remove_selected_objects() def _copy_objects(self): selected_objects = self.level_view.get_selected_objects().copy() if selected_objects: self.context_menu.set_copied_objects(selected_objects) @undoable def _paste_objects(self, x=None, y=None): self.level_view.paste_objects_at( self.context_menu.get_copied_objects(), x, y) @undoable def remove_selected_objects(self): self.level_view.remove_selected_objects() self.level_view.update() self.spinner_panel.disable_all() def on_menu_item_checked(self, action: QAction): item_id = action.property(ID_PROP) checked = action.isChecked() if item_id == ID_GRID_LINES: self.level_view.draw_grid = checked elif item_id == ID_TRANSPARENCY: self.level_view.transparency = checked elif item_id == ID_JUMPS: self.level_view.draw_jumps = checked elif item_id == ID_MARIO: self.level_view.draw_mario = checked elif item_id == ID_RESIZE_TYPE: self.level_view.draw_expansions = checked elif item_id == ID_JUMP_OBJECTS: self.level_view.draw_jumps_on_objects = checked elif item_id == ID_ITEM_BLOCKS: self.level_view.draw_items_in_blocks = checked elif item_id == ID_INVISIBLE_ITEMS: self.level_view.draw_invisible_items = checked elif item_id == ID_AUTOSCROLL: self.level_view.draw_autoscroll = checked SETTINGS["draw_mario"] = self.level_view.draw_mario SETTINGS["draw_jumps"] = self.level_view.draw_jumps SETTINGS["draw_grid"] = self.level_view.draw_grid SETTINGS["draw_expansion"] = self.level_view.draw_expansions SETTINGS[ "draw_jump_on_objects"] = self.level_view.draw_jumps_on_objects SETTINGS["draw_items_in_blocks"] = self.level_view.draw_items_in_blocks SETTINGS["draw_invisible_items"] = self.level_view.draw_invisible_items SETTINGS["draw_autoscroll"] = self.level_view.draw_autoscroll SETTINGS["block_transparency"] = self.level_view.transparency save_settings() @undoable def on_spin(self, _): selected_objects = self.level_ref.selected_objects if len(selected_objects) != 1: logging.error(selected_objects, RuntimeWarning) return selected_object = selected_objects[0] obj_type = self.spinner_panel.get_type() if isinstance(selected_object, LevelObject): domain = self.spinner_panel.get_domain() if selected_object.is_4byte: length = self.spinner_panel.get_length() else: length = None self.level_view.replace_object(selected_object, domain, obj_type, length) else: self.level_view.replace_enemy(selected_object, obj_type) self.level_ref.data_changed.emit() def fill_object_list(self): self.object_list.Clear() self.object_list.SetItems(self.level_view.get_object_names()) def open_level_selector(self, _): if not self.safe_to_change(): return level_selector = LevelSelector(self) level_was_selected = level_selector.exec_() == QDialog.Accepted if level_was_selected: self.update_level( level_selector.level_name, level_selector.object_data_offset, level_selector.enemy_data_offset, level_selector.object_set, ) return level_was_selected def on_block_viewer(self, _): if self.block_viewer is None: self.block_viewer = BlockViewer(parent=self) if self.level_ref.level is not None: self.block_viewer.object_set = self.level_ref.object_set.number self.block_viewer.palette_group = self.level_ref.object_palette_index self.block_viewer.show() def on_object_viewer(self, _): if self.object_viewer is None: self.object_viewer = ObjectViewer(parent=self) if self.level_ref.level is not None: object_set = self.level_ref.object_set.number graphics_set = self.level_ref.graphic_set self.object_viewer.set_object_and_graphic_set( object_set, graphics_set) if len(self.level_view.get_selected_objects()) == 1: selected_object = self.level_view.get_selected_objects()[0] if isinstance(selected_object, LevelObject): self.object_viewer.set_object(selected_object.domain, selected_object.obj_index, selected_object.length) self.object_viewer.show() def on_palette_viewer(self, _): PaletteViewer(self, self.level_ref).exec_() def on_edit_autoscroll(self, _): AutoScrollEditor(self, self.level_ref).exec_() def on_header_editor(self, _): HeaderEditor(self, self.level_ref).exec_() def update_level(self, level_name: str, object_data_offset: int, enemy_data_offset: int, object_set: int): try: self.level_ref.load_level(level_name, object_data_offset, enemy_data_offset, object_set) except IndexError: QMessageBox.critical( self, "Please confirm", "Failed loading level. The level offsets don't match.") return self.update_gui_for_level() def update_gui_for_level(self): self._enable_disable_gui_elements() self.update_title() self.jump_list.update() is_a_world_map = isinstance(self.level_ref.level, WorldMap) self.save_m3l_action.setEnabled(not is_a_world_map) self.edit_header_action.setEnabled(not is_a_world_map) if is_a_world_map: self.object_dropdown.Clear() self.object_dropdown.setEnabled(False) self.jump_list.setEnabled(False) self.jump_list.Clear() else: self.object_dropdown.setEnabled(True) self.object_dropdown.set_object_set( self.level_ref.object_set_number, self.level_ref.graphic_set) self.jump_list.setEnabled(True) self.object_toolbar.set_object_set(self.level_ref.object_set_number, self.level_ref.graphic_set) self.level_view.update() def _enable_disable_gui_elements(self): rom_elements = [ # entries in file menu self.open_m3l_action, self.save_rom_action, self.save_rom_as_action, # entry in level menu self.select_level_action, ] level_elements = [ # entry in file menu self.save_m3l_action, # top toolbar self.menu_toolbar, # other gui elements self.level_view, self.spinner_panel, self.object_toolbar, self.level_size_bar, self.enemy_size_bar, self.object_list, self.jump_list, self.object_toolbar, ] level_elements.extend(self.level_menu.actions()) level_elements.remove(self.select_level_action) level_elements.extend(self.object_menu.actions()) level_elements.extend(self.view_menu.actions()) for gui_element in rom_elements: gui_element.setEnabled(ROM.is_loaded()) for gui_element in level_elements: gui_element.setEnabled(ROM.is_loaded() and self.level_ref.level is not None) def on_jump_edit(self): index = self.jump_list.currentIndex().row() updated_jump = JumpEditor.edit_jump( self, self.level_view.level_ref.jumps[index]) self.on_jump_edited(updated_jump) @undoable def on_jump_added(self): self.level_view.add_jump() @undoable def on_jump_removed(self): self.level_view.remove_jump(self.jump_list.currentIndex().row()) @undoable def on_jump_edited(self, jump): index = self.jump_list.currentIndex().row() assert index >= 0 if isinstance(self.level_ref.level, Level): self.level_view.level_ref.jumps[index] = jump self.jump_list.item(index).setText(str(jump)) def on_jump_list_change(self, event): self.jump_list.set_jumps(event) def mouseReleaseEvent(self, event: QMouseEvent): if event.button() == Qt.MiddleButton: pos = self.level_view.mapFromGlobal(self.mapToGlobal( event.pos())).toTuple() self.place_object_from_dropdown(pos) @undoable def place_object_from_dropdown(self, pos: Tuple[int, int]) -> None: # the dropdown is synchronized with the toolbar, so it doesn't matter where to take it from level_object = self.object_dropdown.currentData(Qt.UserRole) self.object_toolbar.add_recent_object(level_object) if isinstance(level_object, LevelObject): self.level_view.create_object_at(*pos, level_object.domain, level_object.obj_index) elif isinstance(level_object, EnemyObject): self.level_view.add_enemy(level_object.obj_index, *pos, -1) def on_about(self, _): about = AboutDialog(self) about.show() def closeEvent(self, event: QCloseEvent): if not self.safe_to_change(): event.ignore() return super(MainWindow, self).closeEvent(event)
class ExecutionFrame(QWidget): # --- Init methods --- def __init__(self, config, sig_update_config): """ Main application frame. Contains the MenuBar, main toolbar, DR canvas and status bar. :param config: application configuration file """ QWidget.__init__(self) self.config = config self.is_quitting = False app_version = self.config.get('main', 'APP_VERSION') self.setWindowTitle("DigiQt - Emulator for Digirule - " + str(app_version)) window_width = int(self.config.get('main', 'WINDOW_WIDTH')) self.setFixedSize(window_width, 320) self.current_digirule_model = self.config.get('digirule', 'DR_MODEL') sliderbar_width = 200 bottom_widget_height = 26 self.statusbar = StatusBar(window_width - sliderbar_width, bottom_widget_height, config) self.dr_canvas = DRCanvas(self.statusbar.sig_temp_message, window_width, self.current_digirule_model, config) self.slider = SpeedSlider(sliderbar_width, bottom_widget_height, config) # Buttons open/hide frames self.editor_frame = EditorFrame(config, self.statusbar.sig_temp_message) self.open_editor_btn = OpenEditorButton(self.editor_frame, config) self.editor_frame.on_close = lambda: self.open_editor_btn.show_editor_frame( False) self.ram_frame = RAMFrame(config) self.open_ram_btn = OpenRamButton(self.ram_frame, config) self.ram_frame.on_close = lambda: self.open_ram_btn.show_ram_frame( False) self.monitor_frame = TerminalFrame(config) self.open_monitor_btn = OpenTerminalButton(self.monitor_frame, config) self.monitor_frame.on_close = lambda: self.open_monitor_btn.show_terminal_frame( False) self.usb_frame = USBFrame(config) self.open_usb_btn = OpenUSBButton(self.usb_frame, config) self.usb_frame.on_close = lambda: self.open_usb_btn.show_usb_frame( False) self.open_monitor_btn.is_opened = lambda b: self.open_usb_btn.setEnabled( not b) self.open_usb_btn.is_opened = lambda b: self.open_monitor_btn.setEnabled( not b) self.symbol_frame = SymbolViewFrame(config) self.open_symbol_btn = OpenSymbolButton(self.symbol_frame, config) self.symbol_frame.on_close = lambda: self.open_symbol_btn.show_symbol_frame( False) self.symbol_frame.place_search_text = self.editor_frame.do_search self.about_frame = AboutFrame(self.config) self.open_about_btn = AboutButton(self.about_frame, config) self.about_frame.on_close = lambda: self.open_about_btn.show_about_frame( False) self._init_tool_bar() self._set_layout() self._set_stylesheets() self.sig_update_config = sig_update_config def _init_tool_bar(self): """ Creates the main toolbar with all its content """ self.toolbar = QToolBar() self.toolbar.setFixedHeight(70) # Open/hide buttons self.toolbar.addWidget(self.open_editor_btn) self.toolbar.addWidget(self.open_ram_btn) self.toolbar.addWidget(self.open_usb_btn) self.toolbar.addWidget(self.open_monitor_btn) self.toolbar.addWidget(self.open_symbol_btn) # Digirule model selection self.toolbar.addSeparator() self.digimodel_dropdown = DigiruleModelDropdown( self.on_digimodel_dropdown_changed) self.toolbar.addWidget(self.digimodel_dropdown) # Empty space to align the about button to the right spacer = QWidget() spacer.setStyleSheet("background-color: transparent;") spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.toolbar.addWidget(spacer) # About button self.toolbar.addWidget(self.open_about_btn) def _set_layout(self): """ Creates this Widget's Layout """ box = QVBoxLayout() box.setContentsMargins(0, 0, 0, 0) box.addWidget(self.toolbar) box.setAlignment(self.toolbar, Qt.AlignTop) box.addWidget(self.dr_canvas) box.setAlignment(self.dr_canvas, Qt.AlignTop) bottom_box = QHBoxLayout() bottom_box.setContentsMargins(0, 0, 0, 0) bottom_box.addWidget(self.statusbar) bottom_box.addWidget(self.slider) box.addLayout(bottom_box) box.setAlignment(bottom_box, Qt.AlignBottom) self.setLayout(box) def _set_stylesheets(self): self.toolbar.setStyleSheet(style.get_stylesheet("qtoolbar")) # Execution Frame self.setStyleSheet(style.get_stylesheet("common")) # --- Callbacks methods --- def on_digimodel_dropdown_changed(self): """ Handles the Digirule's model-combo-box-selection-changed process. Calls the canvas redraw. """ self.sig_update_config.emit( self.digimodel_dropdown.get_digirule_model()) self.dr_canvas.digirule_changed(self.config.get( 'digirule', 'DR_MODEL')) # --- Close handler --- def do_quit(self): pass def closeEvent(self, event): """ Event called upon a red-cross click """ if self.ask_quit_confirmation(): self.is_quitting = True self.do_quit() # Reset status bar self.statusbar.sig_persistent_message.emit("") # Call the secondary frames close methods as well self.editor_frame.on_close() self.ram_frame.on_close() self.monitor_frame.on_close() self.usb_frame.on_close() self.symbol_frame.on_close() self.about_frame.on_close() event.accept() else: event.ignore() def ask_quit_confirmation(self): """ Asks a quit confirmation message :return: True if the user wants to quit the app """ return DialogQuitConfirmation().exec_()
class MainWindow(QMainWindow): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) #window setup resolution = QDesktopWidget().screenGeometry() self.screen_w = resolution.width() self.screen_h = resolution.height() self.setGeometry(0, 0, 650, 550) self.setWindowTitle('MARS_v1_8') self.setWindowIcon(QIcon('icons/mouse.png')) self.queue = Queue() self.queue_list = [] self.str_proc = '' self.fname = '' #center window qr = self.frameGeometry() cp = QDesktopWidget().availableGeometry().center() qr.moveCenter(cp) self.move(qr.topLeft()) #adjust size self.resize(self.screen_w / 2, self.screen_h / 2) self.Menu() self.Layout() central_widget = QWidget() central_widget.setLayout(self.main_layout) self.setCentralWidget(central_widget) def Menu(self): #this creates an action exit, a shortcut and status tip exitAction = QAction(QIcon('icons/exit.png'), '&Exit', self) exitAction.setShortcut('Ctrl+Q') exitAction.setStatusTip('Exit application') exitAction.triggered.connect(self.close) openFile = QAction(QIcon('icons/open.png'), '&Open', self) openFile.setShortcut('Ctrl+O') openFile.setStatusTip('Open new File') openFile.triggered.connect(self.browse) runAction = QAction(QIcon('icons/run.png'), '&Run', self) runAction.setShortcut('Ctrl+R') runAction.setStatusTip('Run Mars') runAction.triggered.connect(self.run_event) resetAction = QAction(QIcon('icons/reset.png'), '&Reset', self) resetAction.setShortcut('Ctrl+X') resetAction.setStatusTip('Reset Mars') resetAction.triggered.connect(self.reset) #create status bar to show tooltip statusbar = QStatusBar(self) self.setStatusBar(statusbar) #create menu self.menu_File = QMenu('&File', self) self.menuBar().addMenu(self.menu_File) self.menu_File.addAction(openFile) self.menu_File.addAction(runAction) self.menu_File.addAction(resetAction) self.menu_File.addSeparator() self.menu_File.addAction(exitAction) #create toolbar self.toolbar = QToolBar("Toolbar", self) self.toolbar.addAction(openFile) self.toolbar.addAction(runAction) self.toolbar.addAction(resetAction) self.toolbar.addSeparator() # self.toolbar.move(5, 5) self.toolbar2 = QToolBar("ToolbarExit", self) self.toolbar2.addAction(exitAction) self.toto = QFrame(self) self.toto.setFrameShape(QFrame.HLine) self.toto.setFrameShadow(QFrame.Sunken) self.toto.setLineWidth(2) def Layout(self): #LAYOUT self.select_video = QLabel(self) self.select_video.setText("Folder Selected:") self.select_video.setVisible(False) self.browse_btn = QPushButton("Browse", self) self.browse_btn.setStatusTip(" Browse Folder") # self.browse_btn.setStyleSheet("background-color: rgb(186, 186, 186); border-radius: 15px;border-style: solid;border-width: 2px;border-color: black;"); self.browse_btn.clicked.connect(self.browse) self.VideoName = QLabel(self) self.todo = QLabel(self) self.todo.setText("What do you want to do?") self.todo.setVisible(False) ## Various checkboxes for activities to perform within MARS. self.doPose = False self.pose_chbox = QCheckBox('[Pose]', self) self.pose_chbox.stateChanged.connect(self.checkDoPose) self.pose_chbox.setVisible(False) self.doFeats = False self.feat_chbox = QCheckBox('[Features]', self) self.feat_chbox.stateChanged.connect(self.checkDoFeat) self.feat_chbox.setVisible(False) self.doActions = False self.actions_chbox = QCheckBox('[Classify Actions]', self) self.actions_chbox.stateChanged.connect(self.checkDoActions) self.actions_chbox.setVisible(False) # self.ddlist_label = QLabel(self) # self.ddlist_label.setText("Classifier:") # self.ddlist_label.move(200, 150) # self.ddlist_label.resize(150, 30) # self.ddlist_label.setVisible(False) # # self.ddlist = QComboBox(self) # self.ddlist.setVisible(False) # self.ddlist.setStatusTip('Choose the classifier you\'d like to use.') # self.ddlist.move(220, 120) # self.ddlist.resize(150, 50) # self.ddlist.setSizeAdjustPolicy(QComboBox.AdjustToContents) self.doVideo = False self.video_chbox = QCheckBox('[Produce Video]', self) self.video_chbox.stateChanged.connect(self.checkDoVideo) self.video_chbox.setVisible(False) self.doOverwrite = False self.overwrite_chbox = QCheckBox('[Overwrite]', self) self.overwrite_chbox.setStyleSheet("background-color: #ff7a7a") self.overwrite_chbox.stateChanged.connect(self.checkDoOverwrite) self.overwrite_chbox.setVisible(False) ## Checkboxes that pick which view(s) to use, as well as the internal values they represent. self.doTop = False self.top_chbox = QCheckBox('[Top]', self) self.top_chbox.stateChanged.connect(self.checkDoTop) self.top_chbox.setVisible(False) self.doToppcf = False # self.toppcf_chbox = QCheckBox('[Top (w/ Front pixel features)]', self) # self.toppcf_chbox.stateChanged.connect(self.checkDoToppcf) # self.toppcf_chbox.setVisible(False) self.doFront = False self.front_chbox = QCheckBox('[Front]', self) self.front_chbox.stateChanged.connect(self.checkDoFront) self.front_chbox.setVisible(False) # Button to run MARS. self.run_mars = QPushButton("[Run MARS]", self) self.run_mars.setVisible(False) self.run_mars.setStatusTip('Run detection and actions classification') self.run_mars.setStyleSheet( "background-color: rgb(142, 229, 171); border-radius: 15px;") self.run_mars.clicked.connect(self.run_event) # Button to reset the form for MARS. self.reset_btn = QPushButton("[Reset]", self) self.reset_btn.setVisible(False) self.reset_btn.setStatusTip('Reset buttons') self.reset_btn.setStyleSheet( "background-color: rgb(229, 200, 142);border-radius: 15px") self.reset_btn.clicked.connect(self.reset) # Button for adding things to queue. self.add2queue_btn = QPushButton("[Enqueue]", self) self.add2queue_btn.setVisible(False) self.add2queue_btn.setStyleSheet( "background-color: rgb(216,191,216);border-radius: 50px") self.add2queue_btn.clicked.connect(self.addToQueue) self.progress = QLabel(self) self.progress.setVisible(True) # Progress bar above the global progress, shows the progress on the current task. self.progbar = QProgressBar(self) self.progbar.setStyleSheet( "background-color: #FFA07A; border: 3px solid #000000;") self.progbar.setVisible(True) self.progbar.setAlignment(QtCore.Qt.AlignCenter) # Label for progress bar. self.progbar_label = QLabel(self) self.progbar_label.setText("Current Task Progress:") # Big progress bar at the bottom. Global progress. self.big_progbar = QProgressBar(self) self.big_progbar.setVisible(True) self.big_progbar.setStyleSheet( "background-color: #add8e6; border: 3px solid #FFFFFF;") self.big_progbar.setAlignment(QtCore.Qt.AlignCenter) # Label for big progress bar. self.big_progbar_label = QLabel(self) self.big_progbar_label.setText("Global Video Progress:") # Layout for the browsing span. self.button_layout = QHBoxLayout() self.button_layout.addWidget(self.browse_btn) self.button_layout.addWidget(self.select_video) self.button_layout.addWidget(self.VideoName) self.button_layout.addWidget(self.add2queue_btn) self.button_layout.addStretch(0.5) # Layout for the menu at the top. self.menu_layout = QHBoxLayout() self.menu_layout.addWidget(self.toolbar) self.menu_layout.addStretch() self.menu_layout.addWidget(self.toolbar2) # Layout for the view selection (Top, Toppcf, Front) self.view_layout = QHBoxLayout() self.view_layout.addWidget(self.top_chbox) # self.view_layout.addWidget(self.toppcf_chbox) self.view_layout.addWidget(self.front_chbox) self.view_layout.addStretch() # Layout for the checkboxes. self.chbox_layout = QHBoxLayout() self.chbox_layout.setSpacing(10) self.chbox_layout.addWidget(self.pose_chbox) self.chbox_layout.addWidget(self.feat_chbox) self.chbox_layout.addWidget(self.actions_chbox) self.chbox_layout.addWidget(self.video_chbox) self.chbox_layout.addWidget(self.overwrite_chbox) self.chbox_layout.addStretch(1) # Layout for the activity buttons, RUN and RESET. self.active_layout = QHBoxLayout() self.active_layout.addWidget(self.run_mars, stretch=2) self.active_layout.addWidget(self.reset_btn, stretch=1) # # Layout for the task progress bar. # self.task_progbar_layout = QtGui.QHBoxLayout() # self.task_progbar_layout.addWidget(self.progbar_label) # self.task_progbar_layout.addWidget(self.progbar, stretch=1) # # # Layout for the global progress bar. # self.global_progbar_layout = QtGui.QHBoxLayout() # self.global_progbar_layout.addWidget(self.big_progbar_label) # self.global_progbar_layout.addWidget(self.big_progbar) # Layout for the labels, to get ther vertically-aligned. self.progbar_label_layout = QVBoxLayout() self.progbar_label_layout.addWidget(self.progbar_label) self.progbar_label_layout.addWidget(self.big_progbar_label) # Layout for the progress bars themselves, to get them vertically-aligned. self.progbar_bar_layout = QVBoxLayout() self.progbar_bar_layout.addWidget(self.progbar) self.progbar_bar_layout.addWidget(self.big_progbar) # Layout for the combined progress bars and labels. self.progbar_layout = QHBoxLayout() self.progbar_layout.addLayout(self.progbar_label_layout) self.progbar_layout.addLayout(self.progbar_bar_layout, stretch=1) # This layout puts everything on the screen. self.main_layout = QVBoxLayout() self.main_layout.addLayout(self.menu_layout) self.main_layout.addWidget(self.toto) self.main_layout.addLayout(self.button_layout) self.main_layout.addWidget(self.todo) self.main_layout.addLayout(self.view_layout) self.main_layout.addLayout(self.chbox_layout) self.main_layout.addLayout(self.active_layout) self.main_layout.addWidget(self.progress) self.main_layout.addStretch() self.main_layout.addLayout(self.progbar_layout) # self.main_layout.addLayout(self.task_progbar_layout) # self.main_layout.addLayout(self.global_progbar_layout) def addToQueue(self): self.queue.put(self.fname) self.queue_list.append(self.fname) barMsg = self.fname + " added to the list!\n" msg = barMsg self.updateProgess(barMsg, msg) def browse(self): # sender = self.sender() dialog = QFileDialog() dialog.setFileMode(QFileDialog.Directory) dialog.setOption(QFileDialog.ShowDirsOnly) if os.path.exists(self.fname): dir_to_use = self.fname else: dir_to_use = os.path.curdir self.fname = dialog.getExistingDirectory(self, 'Choose Directory', dir_to_use) self.statusBar().showMessage(self.fname + ' selected ') if os.path.exists(self.fname) and os.path.isdir( self.fname) and self.fname != '': files = os.listdir(self.fname) seq_files = [ f for f in files if f.endswith('.seq') or f.endswith('.avi') or f.endswith('.mp4') or f.endswith('.mpg') ] self.vid_name = self.fname.split('/')[-1] #if len(seq_files) >= 2: self.VideoName.setText(self.fname) self.todo.setVisible(True) self.select_video.setVisible(True) self.add2queue_btn.setVisible(True) # self.ddlist_label.setVisible(True) # self.ddlist.setVisible(True) self.pose_chbox.setVisible(True) self.feat_chbox.setVisible(True) self.actions_chbox.setVisible(True) self.video_chbox.setVisible(True) self.front_chbox.setVisible(True) self.top_chbox.setVisible(True) # self.toppcf_chbox.setVisible(True) self.run_mars.setVisible(True) self.reset_btn.setVisible(True) self.overwrite_chbox.setVisible(True) #else: # QMessageBox.information(self, "Not all needed files exists", "Select a folder containing .seq files!") else: QMessageBox.information( self, " Wrong file selected", "No compatible movie files found! Supported formats: .seq, .avi, .mp4, .mpg" ) self.fname = dir_to_use def checkDoPose(self, state): self.doPose = (state == QtCore.Qt.Checked) def checkDoFeat(self, state): self.doFeats = (state == QtCore.Qt.Checked) def checkDoActions(self, state): self.doActions = (state == QtCore.Qt.Checked) def checkDoVideo(self, state): self.doVideo = (state == QtCore.Qt.Checked) def checkDoOverwrite(self, state): self.doOverwrite = (state == QtCore.Qt.Checked) def checkDoTop(self, state): self.doTop = (state == QtCore.Qt.Checked) # if self.doTop: # self.ddlist.addItem("top mlp") # self.ddlist.addItem("top xgb") # self.ddlist.addItem("top mlp wnd") # self.ddlist.addItem("top xgb wnd") # else: # self.ddlist.clear() def checkDoToppcf(self, state): self.doToppcf = (state == QtCore.Qt.Checked) # if self.doToppcf: # self.ddlist.addItem("top pcf mlp") # self.ddlist.addItem("top pcf xgb") # self.ddlist.addItem("top pcf mlp wnd") # self.ddlist.addItem("top pcf xgb wnd") # else: # self.ddlist.clear() def checkDoFront(self, state): self.doFront = (state == QtCore.Qt.Checked) # if self.doFront: # self.ddlist.addItem("topfront mlp") # self.ddlist.addItem("topfront xgb") # self.ddlist.addItem("topfront mlp wnd") # self.ddlist.addItem("topfront xgb wnd") # else: # self.ddlist.clear() def reset(self): todo = [self.doPose, self.doFeats, self.doActions] # if not self.todo.isVisible() or sum(todo)== 0: # QMessageBox.information(self, "Reset", "Nothing to reset") # else: self.doPose = False self.doFeats = False self.doActions = False self.doVideo = False self.doOverwrite = False self.doFront = False self.doTop = False self.doToppcf = False self.pose_chbox.setCheckState(QtCore.Qt.Unchecked) self.feat_chbox.setCheckState(QtCore.Qt.Unchecked) self.actions_chbox.setCheckState(QtCore.Qt.Unchecked) self.video_chbox.setCheckState(QtCore.Qt.Unchecked) self.overwrite_chbox.setCheckState(QtCore.Qt.Unchecked) self.front_chbox.setCheckState(QtCore.Qt.Unchecked) self.top_chbox.setCheckState(QtCore.Qt.Unchecked) # self.toppcf_chbox.setCheckState(QtCore.Qt.Unchecked) self.str_proc = '' self.progress.setText(self.str_proc) self.VideoName.setText('') self.fname = '' self.statusBar().showMessage('') self.changeEnable_wdj(True) self.clearProgress() def changeEnable_wdj(self, b=False): self.run_mars.setEnabled(b) self.reset_btn.setEnabled(b) self.pose_chbox.setEnabled(b) self.feat_chbox.setEnabled(b) self.actions_chbox.setEnabled(b) self.video_chbox.setEnabled(b) self.overwrite_chbox.setEnabled(b) # self.add2queue_btn.setEnabled(b) # self.ddlist.setEnabled(b) self.front_chbox.setEnabled(b) self.top_chbox.setEnabled(b) # self.toppcf_chbox.setEnabled(b) # def stop_event(self): # print('Stopped') # # self.genericThread.stop() # # self.genericThread.wait() # self.statusBar().showMessage('Stopped processing') # self.changeEnable_wdj(True) # # self.stop_run.setVisible(False) def update_thread(self, prog): if prog == 1: print('Thread pose done') if prog == 2: print('Thread features done') if prog == 3: print('Thread actions done') if prog == 4: print('Thread video done') def thread_done(self): print('Thread ended') # self.changeEnable_wdj(True) # self.stop_run.setVisible(False) def queue_done(self): print('Queue ended') self.changeEnable_wdj(True) def updateProgess(self, barMsg, msg): self.statusBar().showMessage(barMsg) self.str_proc += msg self.progress.setText(self.str_proc) self.scrollText() def updateProgbar(self, value, set_max): if set_max != 0: self.progbar.setMaximum(set_max) self.progbar.setValue(value) def updateBigProgbar(self, value, set_max): if set_max != 0: self.big_progbar.setMaximum(set_max) self.big_progbar.setValue(value) def clearProgress(self): self.str_proc = 'Console cleared. \n' self.progress.setText(self.str_proc) self.resize(self.screen_w / 2, self.screen_h / 2) # self.adjustSize() # self.changeEnable_wdj(True) def scrollText(self): MAX_LINES = 20 all_lines = self.str_proc.splitlines() if len(all_lines) > MAX_LINES: renewed_lines = all_lines[-MAX_LINES:] self.str_proc = '\n'.join(renewed_lines) + '\n' def run_event(self): todo = [self.doPose, self.doFeats, self.doActions, self.doVideo] if not self.todo.isVisible(): QMessageBox.information(self, "Empty selection", "Select a folder to process.") elif sum(todo) == 0: QMessageBox.information(self, "Empty selection", "Select at least one task to do.") else: self.str_proc = '' self.progress.setVisible(True) self.genericThread = GenericThread(self.doPose, self.doFeats, self.doActions, self.doVideo, self.doOverwrite, self.doFront, self.doTop, self.doToppcf, self.queue, self.fname) self.genericThread.update_th.connect(self.update_thread) self.genericThread.done_th.connect(self.thread_done) self.genericThread.done_queue.connect(self.queue_done) self.genericThread.update_progbar_sig.connect(self.updateProgbar) self.genericThread.update_big_progbar_sig.connect( self.updateBigProgbar) self.genericThread.update_progress.connect(self.updateProgess) # self.genericThread.classifier_to_use = self.ddlist.currentText() self.genericThread.clear_sig.connect(self.clearProgress) self.genericThread.start() # self.stop_run.setVisible(True) self.changeEnable_wdj(False)
def __init__(self, *args, **kwargs): super(MainWindow, self).__init__(*args, **kwargs) self.browser = QWebEngineView() self.browser.setUrl(QUrl("http://google.com")) self.browser.urlChanged.connect(self.update_urlbar) self.browser.loadFinished.connect(self.update_title) self.setCentralWidget(self.browser) self.status = QStatusBar() self.setStatusBar(self.status) navtb = QToolBar("Navigation") navtb.setIconSize(QSize(16, 16)) self.addToolBar(navtb) back_btn = QAction(QIcon(os.path.join('images', 'arrow-180.png')), "Back", self) back_btn.setStatusTip("Back to previous page") back_btn.triggered.connect(self.browser.back) navtb.addAction(back_btn) next_btn = QAction(QIcon(os.path.join('images', 'arrow-000.png')), "Forward", self) next_btn.setStatusTip("Forward to next page") next_btn.triggered.connect(self.browser.forward) navtb.addAction(next_btn) reload_btn = QAction( QIcon(os.path.join('images', 'arrow-circle-315.png')), "Reload", self) reload_btn.setStatusTip("Reload page") reload_btn.triggered.connect(self.browser.reload) navtb.addAction(reload_btn) home_btn = QAction(QIcon(os.path.join('images', 'home.png')), "Home", self) home_btn.setStatusTip("Go home") home_btn.triggered.connect(self.navigate_home) navtb.addAction(home_btn) navtb.addSeparator() self.httpsicon = QLabel() # Yes, really! self.httpsicon.setPixmap( QPixmap(os.path.join('images', 'lock-nossl.png'))) navtb.addWidget(self.httpsicon) self.urlbar = QLineEdit() self.urlbar.returnPressed.connect(self.navigate_to_url) navtb.addWidget(self.urlbar) stop_btn = QAction(QIcon(os.path.join('images', 'cross-circle.png')), "Stop", self) stop_btn.setStatusTip("Stop loading current page") stop_btn.triggered.connect(self.browser.stop) navtb.addAction(stop_btn) # Uncomment to disable native menubar on Mac # self.menuBar().setNativeMenuBar(False) file_menu = self.menuBar().addMenu("&File") open_file_action = QAction( QIcon(os.path.join('images', 'disk--arrow.png')), "Open file...", self) open_file_action.setStatusTip("Open from file") open_file_action.triggered.connect(self.open_file) file_menu.addAction(open_file_action) save_file_action = QAction( QIcon(os.path.join('images', 'disk--pencil.png')), "Save Page As...", self) save_file_action.setStatusTip("Save current page to file") save_file_action.triggered.connect(self.save_file) file_menu.addAction(save_file_action) print_action = QAction(QIcon(os.path.join('images', 'printer.png')), "Print...", self) print_action.setStatusTip("Print current page") print_action.triggered.connect(self.print_page) file_menu.addAction(print_action) help_menu = self.menuBar().addMenu("&Help") about_action = QAction(QIcon(os.path.join('images', 'question.png')), "About MooseAche", self) about_action.setStatusTip("Find out more about MooseAche") # Hungry! about_action.triggered.connect(self.about) help_menu.addAction(about_action) navigate_mozarella_action = QAction( QIcon(os.path.join('images', 'lifebuoy.png')), "MooseAche Homepage", self) navigate_mozarella_action.setStatusTip("Go to MooseAche Homepage") navigate_mozarella_action.triggered.connect(self.navigate_mozarella) help_menu.addAction(navigate_mozarella_action) self.show() self.setWindowIcon(QIcon(os.path.join('images', 'ma-icon-64.png')))
def __init__(self): super().__init__() # tag::tabWidget[] self.tabs = QTabWidget() self.tabs.setDocumentMode(True) self.tabs.tabBarDoubleClicked.connect(self.tab_open_doubleclick) self.tabs.currentChanged.connect(self.current_tab_changed) self.tabs.setTabsClosable(True) self.tabs.tabCloseRequested.connect(self.close_current_tab) self.setCentralWidget(self.tabs) # end::tabWidget[] navtb = QToolBar("Navigation") navtb.setIconSize(QSize(16, 16)) self.addToolBar(navtb) back_btn = QAction(QIcon(os.path.join("icons", "arrow-180.png")), "Back", self) back_btn.setStatusTip("Back to previous page") back_btn.triggered.connect(lambda: self.tabs.currentWidget().back()) navtb.addAction(back_btn) next_btn = QAction(QIcon(os.path.join("icons", "arrow-000.png")), "Forward", self) next_btn.setStatusTip("Forward to next page") next_btn.triggered.connect(lambda: self.tabs.currentWidget().forward()) navtb.addAction(next_btn) reload_btn = QAction( QIcon(os.path.join("icons", "arrow-circle-315.png")), "Reload", self) reload_btn.setStatusTip("Reload page") reload_btn.triggered.connect( lambda: self.tabs.currentWidget().reload()) navtb.addAction(reload_btn) home_btn = QAction(QIcon(os.path.join("icons", "home.png")), "Home", self) home_btn.setStatusTip("Go home") home_btn.triggered.connect(self.navigate_home) navtb.addAction(home_btn) navtb.addSeparator() self.httpsicon = QLabel() # Yes, really! self.httpsicon.setPixmap( QPixmap(os.path.join("icons", "lock-nossl.png"))) navtb.addWidget(self.httpsicon) self.urlbar = QLineEdit() self.urlbar.returnPressed.connect(self.navigate_to_url) navtb.addWidget(self.urlbar) stop_btn = QAction(QIcon(os.path.join("icons", "cross-circle.png")), "Stop", self) stop_btn.setStatusTip("Stop loading current page") stop_btn.triggered.connect(lambda: self.tabs.currentWidget().stop()) navtb.addAction(stop_btn) self.menuBar().setNativeMenuBar(False) self.statusBar() file_menu = self.menuBar().addMenu("&File") new_tab_action = QAction( QIcon(os.path.join("icons", "ui-tab--plus.png")), "New Tab", self) new_tab_action.setStatusTip("Open a new tab") new_tab_action.triggered.connect(lambda _: self.add_new_tab()) file_menu.addAction(new_tab_action) open_file_action = QAction( QIcon(os.path.join("icons", "disk--arrow.png")), "Open file...", self) open_file_action.setStatusTip("Open from file") open_file_action.triggered.connect(self.open_file) file_menu.addAction(open_file_action) save_file_action = QAction( QIcon(os.path.join("icons", "disk--pencil.png")), "Save Page As...", self) save_file_action.setStatusTip("Save current page to file") save_file_action.triggered.connect(self.save_file) file_menu.addAction(save_file_action) print_action = QAction(QIcon(os.path.join("icons", "printer.png")), "Print...", self) print_action.setStatusTip("Print current page") print_action.triggered.connect(self.print_page) file_menu.addAction(print_action) # Create our system printer instance. self.printer = QPrinter() help_menu = self.menuBar().addMenu("&Help") about_action = QAction( QIcon(os.path.join("icons", "question.png")), "About Mozzarella Ashbadger", self, ) about_action.setStatusTip( "Find out more about Mozzarella Ashbadger") # Hungry! about_action.triggered.connect(self.about) help_menu.addAction(about_action) navigate_mozarella_action = QAction( QIcon(os.path.join("icons", "lifebuoy.png")), "Mozzarella Ashbadger Homepage", self, ) navigate_mozarella_action.setStatusTip( "Go to Mozzarella Ashbadger Homepage") navigate_mozarella_action.triggered.connect(self.navigate_mozarella) help_menu.addAction(navigate_mozarella_action) self.add_new_tab(QUrl("http://www.google.com"), "Homepage") self.show() self.setWindowTitle("Mozzarella Ashbadger") self.setWindowIcon(QIcon(os.path.join("icons", "ma-icon-64.png")))
def __init__(self, config): assertMainThread() super().__init__(config) # state self.preventSeek = False self.beginTime = None self.timeRatio = 1.0 # gui srv = Services.getService("MainWindow") config.configLoaded.connect(self.restoreState) config.configAboutToSave.connect(self.saveState) self.config = config playbackMenu = srv.menuBar().addMenu("&Playback") style = QApplication.style() self.actStart = QAction(QIcon.fromTheme("media-playback-start", style.standardIcon(QStyle.SP_MediaPlay)), "Start Playback", self) self.actPause = QAction(QIcon.fromTheme("media-playback-pause", style.standardIcon(QStyle.SP_MediaPause)), "Pause Playback", self) self.actPause.setEnabled(False) self.actStepFwd = QAction(QIcon.fromTheme("media-seek-forward", style.standardIcon(QStyle.SP_MediaSeekForward)), "Step Forward", self) self.actStepBwd = QAction(QIcon.fromTheme("media-seek-backward", style.standardIcon(QStyle.SP_MediaSeekBackward)), "Step Backward", self) self.actSeekEnd = QAction(QIcon.fromTheme("media-skip-forward", style.standardIcon(QStyle.SP_MediaSkipForward)), "Seek End", self) self.actSeekBegin = QAction(QIcon.fromTheme("media-skip-backward", style.standardIcon(QStyle.SP_MediaSkipBackward)), "Seek Begin", self) self.actSetTimeFactor = {r : QAction("x 1/%d" % (1/r), self) if r < 1 else QAction("x %d" % r, self) for r in (1/8, 1/4, 1/2, 1, 2, 4, 8)} # pylint: disable=unnecessary-lambda # let's stay on the safe side and do not use emit as a slot... self.actStart.triggered.connect(lambda: self._startPlayback.emit()) self.actPause.triggered.connect(lambda: self._pausePlayback.emit()) self.actStepFwd.triggered.connect(lambda: self._stepForward.emit(self.selectedStream())) self.actStepBwd.triggered.connect(lambda: self._stepBackward.emit(self.selectedStream())) self.actSeekEnd.triggered.connect(lambda: self._seekEnd.emit()) self.actSeekBegin.triggered.connect(lambda: self._seekBeginning.emit()) # pylint: enable=unnecessary-lambda def setTimeFactor(newFactor): logger.debug("new time factor %f", newFactor) self._setTimeFactor.emit(newFactor) for r in self.actSetTimeFactor: logger.debug("adding action for time factor %f", r) self.actSetTimeFactor[r].triggered.connect(functools.partial(setTimeFactor, r)) self.dockWidget = srv.newDockWidget("PlaybackControl", None, Qt.LeftDockWidgetArea) self.dockWidgetContents = QWidget(self.dockWidget) self.dockWidget.setWidget(self.dockWidgetContents) toolLayout = QBoxLayout(QBoxLayout.TopToBottom, self.dockWidgetContents) toolLayout.setContentsMargins(0, 0, 0, 0) toolBar = QToolBar() toolLayout.addWidget(toolBar) toolBar.addAction(self.actSeekBegin) toolBar.addAction(self.actStepBwd) toolBar.addAction(self.actStart) toolBar.addAction(self.actPause) toolBar.addAction(self.actStepFwd) toolBar.addAction(self.actSeekEnd) playbackMenu.addAction(self.actSeekBegin) playbackMenu.addAction(self.actStepBwd) playbackMenu.addAction(self.actStart) playbackMenu.addAction(self.actPause) playbackMenu.addAction(self.actStepFwd) playbackMenu.addAction(self.actSeekEnd) playbackMenu.addSeparator() for r in self.actSetTimeFactor: playbackMenu.addAction(self.actSetTimeFactor[r]) self.timeRatioLabel = QLabel("x 1") self.timeRatioLabel.addActions(list(self.actSetTimeFactor.values())) self.timeRatioLabel.setContextMenuPolicy(Qt.ActionsContextMenu) toolBar.addSeparator() toolBar.addWidget(self.timeRatioLabel) contentsLayout = QGridLayout() toolLayout.addLayout(contentsLayout, 10) # now we add a position view self.positionSlider = QSlider(Qt.Horizontal, self.dockWidgetContents) self.beginLabel = QLabel(parent=self.dockWidgetContents) self.beginLabel.setAlignment(Qt.AlignLeft|Qt.AlignCenter) self.currentLabel = QLabel(parent=self.dockWidgetContents) self.currentLabel.setAlignment(Qt.AlignHCenter|Qt.AlignCenter) self.endLabel = QLabel(parent=self.dockWidgetContents) self.endLabel.setAlignment(Qt.AlignRight|Qt.AlignCenter) contentsLayout.addWidget(self.beginLabel, 0, 0, alignment=Qt.AlignLeft) contentsLayout.addWidget(self.currentLabel, 0, 1, alignment=Qt.AlignHCenter) contentsLayout.addWidget(self.endLabel, 0, 2, alignment=Qt.AlignRight) contentsLayout.addWidget(self.positionSlider, 1, 0, 1, 3) self.positionSlider.setTracking(False) self.positionSlider.valueChanged.connect(self.onSliderValueChanged, Qt.DirectConnection) self.positionSlider.sliderMoved.connect(self.displayPosition) # file browser self.browser = BrowserWidget(self.dockWidget) self.nameFiltersChanged.connect(self._onNameFiltersChanged, Qt.QueuedConnection) contentsLayout.addWidget(self.browser, 3, 0, 1, 3) contentsLayout.setRowStretch(3, 100) self.browser.activated.connect(self.browserActivated) self.actShowAllFiles = QAction("Show all files") self.actShowAllFiles.setCheckable(True) self.actShowAllFiles.setChecked(False) self.actShowAllFiles.toggled.connect(self._onShowAllFiles) playbackMenu.addSeparator() playbackMenu.addAction(self.actShowAllFiles) self.actGroupStream = QActionGroup(self) self.actGroupStream.setExclusionPolicy(QActionGroup.ExclusionPolicy.ExclusiveOptional) playbackMenu.addSeparator() self.actGroupStreamMenu = playbackMenu.addMenu("Step Stream") self._selectedStream = None self.recentSeqs = [QAction() for i in range(10)] playbackMenu.addSeparator() recentMenu = playbackMenu.addMenu("Recent") for a in self.recentSeqs: a.setVisible(False) a.triggered.connect(self.openRecent) recentMenu.addAction(a) self._supportedFeaturesChanged(set(), set())
class EditorFrame(QWidget): # --- Init methods --- def __init__(self, config, sig_message): """ Editor frame. Contains a toolbar and an editor widget :param config: application configuration file :param sig_message: signal to emit to display a message in the main frame's status bar """ QWidget.__init__(self) self.setMinimumSize(QSize(630, 500)) self.config = config # Widgets self.editor = CodeEditor(config) self.editor.setMinimumSize(QSize(600, 430)) self.open_file_btn = OpenFileButton(config) self.open_file_btn.set_content = self.editor.setPlainText # Reroute text set method directly to the text editor widget self.open_file_btn.set_new_file_name = self.__init_title self.save_as_btn = SaveAsFileButton(config, sig_message) self.save_as_btn.get_content_to_save = self.retrieve_text # Bind the text retrieve method in order to get the text to save self.save_as_btn.set_new_file_name = self.__init_title self.save_btn = SaveFileButton(config, sig_message) self.save_btn.get_content_to_save = self.retrieve_text self.assemble_btn = AssembleButton(config) self.search_field = QLineEdit() self.search_field.setPlaceholderText("Search (press return)") self.search_field.returnPressed.connect(self.do_search) # Editor's shortcuts binding self.editor.on_ctrl_o_activated = self.open_file_btn.on_open # Open action self.editor.on_ctrl_s_activated = self.do_save self.editor.on_ctrl_f_activated = self.do_search # Final initialization self.__init_title() self._init_tool_bar() self._set_layout() self._connect_all() self._set_stylesheet() self.editor.setFocus() # Set the default focus on the Editor def __init_title(self, file_name=""): """ Sets the currently edited file in this frame's title :param file_name: full file path """ if file_name: self.setWindowTitle("DigiQt - Editing '" + file_name.split("/")[-1] + "'") else: # In the case no file name is specified, we have an empty editor, we display default text self.setWindowTitle("DigiQt - Assemble Editor") self.save_btn.setEnabled(file_name != "") self.save_btn.set_file_path(file_name) def _init_tool_bar(self): """ Creates the main toolbar with all its content """ self.toolbar = QToolBar() self.toolbar.setFixedHeight(70) self.toolbar.addWidget(self.open_file_btn) self.toolbar.addWidget(self.save_btn) self.toolbar.addWidget(self.save_as_btn) self.toolbar.addSeparator() self.toolbar.addWidget(self.search_field) # Empty space to align the assemble button to the right spacer = QWidget() spacer.setStyleSheet("background-color: transparent;") spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.toolbar.addWidget(spacer) self.toolbar.addWidget(self.assemble_btn) def _set_layout(self): """ Creates this Widget's Layout """ box = QGridLayout() box.setContentsMargins(0, 0, 0, 0) box.addWidget(self.toolbar, 0, 0) box.addWidget(self.editor, 1, 0) self.setLayout(box) def _connect_all(self): """ Connects all the buttons to methods """ def _set_stylesheet(self): self.toolbar.setStyleSheet(style.get_stylesheet("qtoolbar")) self.editor.setStyleSheet( "background-color: " + self.config.get('colors', 'editor_bg') + "; color: " + self.config.get('colors', 'asm_text_default') + ";") self.search_field.setStyleSheet( "border: 2px solid gray; border-radius: 10px; padding: 0 8px; background: #585858; color: white" ) # Execution Frame self.setStyleSheet(style.get_stylesheet("common")) # --- Buttons callbacks methods --- def retrieve_text(self): """ Gets the content of the code editor widget :return: the code """ return self.editor.toPlainText() def do_save(self): """ Delegating method triggered upon Ctrl+S action. Performs a Save if a file is opened, or a SaveAs if not. """ if self.save_btn.file_path: self.save_btn.on_save() else: self.save_as_btn.on_save_as() def do_search(self, text=None): """ Searches the value present in the search field, or the places the specified text if there is one as search value, but does not triggers the search. :param text: Text to search (None will trigger a search on the field content) """ if text: self.search_field.setText(text) else: self.editor.selectNext(self.search_field.text()) # --- Close handler --- def closeEvent(self, event): """ Event called upon a red-cross click. """ self.on_close() def on_close(self): """ Reroot this method in the Main Frame in order to Updates the execution frame's open editor icon and tooltip :return: """ pass
class Ui_FE14MapEditor(QMainWindow): def __init__(self, parent=None): super().__init__(parent) self.toolbar = QToolBar() self.toggle_coordinate_type_action = QAction("Toggle Coordinate Type") self.refresh_action = QAction("Refresh") self.refresh_action.setShortcut(QKeySequence("Ctrl+R")) self.copy_spawn_action = QAction("Copy Spawn") self.copy_spawn_action.setShortcut(QKeySequence("Ctrl+C")) self.paste_spawn_action = QAction("Paste Spawn") self.paste_spawn_action.setShortcut(QKeySequence("Ctrl+V")) self.add_spawn_action = QAction("Add Spawn") self.delete_spawn_action = QAction("Delete Spawn") self.add_group_action = QAction("Add Group") self.delete_group_action = QAction("Delete Group") self.add_tile_action = QAction("Add Tile") self.toggle_mode_action = QAction("Toggle Mode") self.undo_action = QAction("Undo") self.undo_action.setShortcut(QKeySequence("Ctrl+Z")) self.redo_action = QAction("Redo") self.redo_action.setShortcut(QKeySequence("Ctrl+Shift+Z")) self.toolbar.addActions( [self.toggle_coordinate_type_action, self.refresh_action]) self.toolbar.addSeparator() self.toolbar.addActions([ self.copy_spawn_action, self.paste_spawn_action, self.add_spawn_action, self.delete_spawn_action, self.add_group_action, self.delete_group_action ]) self.toolbar.addSeparator() self.toolbar.addAction(self.add_tile_action) self.toolbar.addSeparator() self.toolbar.addAction(self.toggle_mode_action) self.toolbar.addSeparator() self.toolbar.addActions([self.undo_action, self.redo_action]) self.addToolBar(self.toolbar) self.model_view = QTreeView() self.model_view.setHeaderHidden(True) self.grid = FE14MapGrid() self.grid_scroll = QScrollArea() self.grid_scroll.setWidgetResizable(True) self.grid_scroll.setWidget(self.grid) self.tile_list = QListView() self.terrain_pane = FE14TerrainEditorPane() self.spawn_pane = FE14SpawnEditorPane() self.model_view.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.model_view_context_menu = QMenu() self.model_view_context_menu.addActions( [self.toggle_coordinate_type_action, self.refresh_action]) self.model_view_context_menu.addSeparator() self.model_view_context_menu.addActions([ self.copy_spawn_action, self.paste_spawn_action, self.add_spawn_action, self.delete_spawn_action, self.add_group_action, self.delete_group_action ]) self.model_view_context_menu.addSeparator() self.model_view_context_menu.addAction(self.add_tile_action) self.model_view_context_menu.addSeparator() self.model_view_context_menu.addAction(self.toggle_mode_action) self.model_view_context_menu.addSeparator() self.model_view_context_menu.addActions( [self.undo_action, self.redo_action]) self.status_bar = QStatusBar() self.coordinate_type_label = QLabel() self.status_bar.addPermanentWidget(self.coordinate_type_label) self.setStatusBar(self.status_bar) self.main_widget = QSplitter() self.main_widget.setOrientation(QtCore.Qt.Horizontal) self.main_widget.addWidget(self.model_view) self.main_widget.addWidget(self.grid_scroll) self.main_widget.addWidget(self.spawn_pane) self.main_widget.addWidget(self.terrain_pane) self.setCentralWidget(self.main_widget)
def __init__(self, path_to_rom=""): super(MainWindow, self).__init__() self.setWindowIcon(icon("foundry.ico")) file_menu = QMenu("File") open_rom_action = file_menu.addAction("&Open ROM") open_rom_action.triggered.connect(self.on_open_rom) self.open_m3l_action = file_menu.addAction("&Open M3L") self.open_m3l_action.triggered.connect(self.on_open_m3l) file_menu.addSeparator() save_rom_action = file_menu.addAction("&Save ROM") save_rom_action.triggered.connect(self.on_save_rom) save_rom_as_action = file_menu.addAction("&Save ROM as ...") save_rom_as_action.triggered.connect(self.on_save_rom_as) """ file_menu.AppendSeparator() """ self.save_m3l_action = file_menu.addAction("&Save M3L") self.save_m3l_action.triggered.connect(self.on_save_m3l) """ file_menu.Append(ID_SAVE_LEVEL_TO, "&Save Level to", "") file_menu.AppendSeparator() file_menu.Append(ID_APPLY_IPS_PATCH, "&Apply IPS Patch", "") file_menu.AppendSeparator() file_menu.Append(ID_ROM_PRESET, "&ROM Preset", "") """ file_menu.addSeparator() settings_action = file_menu.addAction("&Settings") settings_action.triggered.connect(show_settings) file_menu.addSeparator() exit_action = file_menu.addAction("&Exit") exit_action.triggered.connect(lambda _: self.close()) self.menuBar().addMenu(file_menu) """ edit_menu = wx.Menu() edit_menu.Append(ID_EDIT_LEVEL, "&Edit Level", "") edit_menu.Append(ID_EDIT_OBJ_DEFS, "&Edit Object Definitions", "") edit_menu.Append(ID_EDIT_PALETTE, "&Edit Palette", "") edit_menu.Append(ID_EDIT_GRAPHICS, "&Edit Graphics", "") edit_menu.Append(ID_EDIT_MISC, "&Edit Miscellaneous", "") edit_menu.AppendSeparator() edit_menu.Append(ID_FREE_FORM_MODE, "&Free form Mode", "") edit_menu.Append(ID_LIMIT_SIZE, "&Limit Size", "") """ level_menu = QMenu("Level") select_level_action = level_menu.addAction("&Select Level") select_level_action.triggered.connect(self.open_level_selector) """ level_menu.Append(ID_GOTO_NEXT_AREA, "&Go to next Area", "") level_menu.AppendSeparator() """ self.reload_action = level_menu.addAction("&Reload Level") self.reload_action.triggered.connect(self.reload_level) level_menu.addSeparator() self.edit_header_action = level_menu.addAction("&Edit Header") self.edit_header_action.triggered.connect(self.on_header_editor) """ level_menu.Append(ID_EDIT_POINTERS, "&Edit Pointers", "") """ self.menuBar().addMenu(level_menu) object_menu = QMenu("Objects") view_blocks_action = object_menu.addAction("&View Blocks") view_blocks_action.triggered.connect(self.on_block_viewer) view_objects_action = object_menu.addAction("&View Objects") view_objects_action.triggered.connect(self.on_object_viewer) """ object_menu.AppendSeparator() object_menu.Append(ID_CLONE_OBJECT_ENEMY, "&Clone Object/Enemy", "") object_menu.AppendSeparator() object_menu.Append(ID_ADD_3_BYTE_OBJECT, "&Add 3 Byte Object", "") object_menu.Append(ID_ADD_4_BYTE_OBJECT, "&Add 4 Byte Object", "") object_menu.Append(ID_ADD_ENEMY, "&Add Enemy", "") object_menu.AppendSeparator() object_menu.Append(ID_DELETE_OBJECT_ENEMY, "&Delete Object/Enemy", "") object_menu.Append(ID_DELETE_ALL, "&Delete All", "") """ self.menuBar().addMenu(object_menu) view_menu = QMenu("View") view_menu.triggered.connect(self.on_menu) action = view_menu.addAction("Mario") action.setProperty(ID_PROP, ID_MARIO) action.setCheckable(True) action.setChecked(SETTINGS["draw_mario"]) action = view_menu.addAction("&Jumps on objects") action.setProperty(ID_PROP, ID_JUMP_OBJECTS) action.setCheckable(True) action.setChecked(SETTINGS["draw_jump_on_objects"]) action = view_menu.addAction("Items in blocks") action.setProperty(ID_PROP, ID_ITEM_BLOCKS) action.setCheckable(True) action.setChecked(SETTINGS["draw_items_in_blocks"]) action = view_menu.addAction("Invisible items") action.setProperty(ID_PROP, ID_INVISIBLE_ITEMS) action.setCheckable(True) action.setChecked(SETTINGS["draw_invisible_items"]) view_menu.addSeparator() action = view_menu.addAction("Jump Zones") action.setProperty(ID_PROP, ID_JUMPS) action.setCheckable(True) action.setChecked(SETTINGS["draw_jumps"]) action = view_menu.addAction("&Grid lines") action.setProperty(ID_PROP, ID_GRID_LINES) action.setCheckable(True) action.setChecked(SETTINGS["draw_grid"]) action = view_menu.addAction("Resize Type") action.setProperty(ID_PROP, ID_RESIZE_TYPE) action.setCheckable(True) action.setChecked(SETTINGS["draw_expansion"]) view_menu.addSeparator() action = view_menu.addAction("&Block Transparency") action.setProperty(ID_PROP, ID_TRANSPARENCY) action.setCheckable(True) action.setChecked(SETTINGS["block_transparency"]) view_menu.addSeparator() view_menu.addAction("&Save Screenshot of Level").triggered.connect( self.on_screenshot) """ view_menu.Append(ID_BACKGROUND_FLOOR, "&Background & Floor", "") view_menu.Append(ID_TOOLBAR, "&Toolbar", "") view_menu.AppendSeparator() view_menu.Append(ID_ZOOM, "&Zoom", "") view_menu.AppendSeparator() view_menu.Append(ID_USE_ROM_GRAPHICS, "&Use ROM Graphics", "") view_menu.Append(ID_PALETTE, "&Palette", "") view_menu.AppendSeparator() view_menu.Append(ID_MORE, "&More", "") """ self.menuBar().addMenu(view_menu) help_menu = QMenu("Help") """ help_menu.Append(ID_ENEMY_COMPATIBILITY, "&Enemy Compatibility", "") help_menu.Append(ID_TROUBLESHOOTING, "&Troubleshooting", "") help_menu.AppendSeparator() help_menu.Append(ID_PROGRAM_WEBSITE, "&Program Website", "") help_menu.Append(ID_MAKE_A_DONATION, "&Make a Donation", "") help_menu.AppendSeparator() """ update_action = help_menu.addAction("Check for updates") update_action.triggered.connect(self.on_check_for_update) help_menu.addSeparator() video_action = help_menu.addAction("Feature Video on YouTube") video_action.triggered.connect(lambda: open_url(feature_video_link)) discord_action = help_menu.addAction("SMB3 Rom Hacking Discord") discord_action.triggered.connect(lambda: open_url(discord_link)) help_menu.addSeparator() about_action = help_menu.addAction("&About") about_action.triggered.connect(self.on_about) self.menuBar().addMenu(help_menu) self.level_selector = LevelSelector(parent=self) self.block_viewer = None self.object_viewer = None self.level_ref = LevelRef() self.level_ref.data_changed.connect(self._on_level_data_changed) self.context_menu = ContextMenu(self.level_ref) self.context_menu.triggered.connect(self.on_menu) self.level_view = LevelView(self, self.level_ref, self.context_menu) self.scroll_panel = QScrollArea() self.scroll_panel.setWidgetResizable(True) self.scroll_panel.setWidget(self.level_view) self.setCentralWidget(self.scroll_panel) self.spinner_panel = SpinnerPanel(self, self.level_ref) self.spinner_panel.zoom_in_triggered.connect(self.level_view.zoom_in) self.spinner_panel.zoom_out_triggered.connect(self.level_view.zoom_out) self.spinner_panel.object_change.connect(self.on_spin) self.object_list = ObjectList(self, self.level_ref, self.context_menu) self.object_dropdown = ObjectDropdown(self) self.object_dropdown.object_selected.connect( self._on_placeable_object_selected) self.level_size_bar = LevelSizeBar(self, self.level_ref) self.enemy_size_bar = EnemySizeBar(self, self.level_ref) self.jump_list = JumpList(self, self.level_ref) self.jump_list.add_jump.connect(self.on_jump_added) self.jump_list.edit_jump.connect(self.on_jump_edit) self.jump_list.remove_jump.connect(self.on_jump_removed) splitter = QSplitter(self) splitter.setOrientation(Qt.Vertical) splitter.addWidget(self.object_list) splitter.setStretchFactor(0, 1) splitter.addWidget(self.jump_list) splitter.setChildrenCollapsible(False) level_toolbar = QToolBar("Level Info Toolbar", self) level_toolbar.setContextMenuPolicy(Qt.PreventContextMenu) level_toolbar.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum) level_toolbar.setOrientation(Qt.Horizontal) level_toolbar.setFloatable(False) level_toolbar.addWidget(self.spinner_panel) level_toolbar.addWidget(self.object_dropdown) level_toolbar.addWidget(self.level_size_bar) level_toolbar.addWidget(self.enemy_size_bar) level_toolbar.addWidget(splitter) level_toolbar.setAllowedAreas(Qt.LeftToolBarArea | Qt.RightToolBarArea) self.addToolBar(Qt.RightToolBarArea, level_toolbar) self.object_toolbar = ObjectToolBar(self) self.object_toolbar.object_selected.connect( self._on_placeable_object_selected) object_toolbar = QToolBar("Object Toolbar", self) object_toolbar.setContextMenuPolicy(Qt.PreventContextMenu) object_toolbar.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum) object_toolbar.setFloatable(False) object_toolbar.addWidget(self.object_toolbar) object_toolbar.setAllowedAreas(Qt.LeftToolBarArea | Qt.RightToolBarArea) self.addToolBar(Qt.LeftToolBarArea, object_toolbar) menu_toolbar = QToolBar("Menu Toolbar", self) menu_toolbar.setOrientation(Qt.Horizontal) menu_toolbar.setIconSize(QSize(20, 20)) menu_toolbar.addAction( icon("settings.svg"), "Editor Settings").triggered.connect(show_settings) menu_toolbar.addSeparator() menu_toolbar.addAction(icon("folder.svg"), "Open ROM").triggered.connect(self.on_open_rom) menu_toolbar.addAction( icon("save.svg"), "Save Level").triggered.connect(self.on_save_rom) menu_toolbar.addSeparator() self.undo_action = menu_toolbar.addAction(icon("rotate-ccw.svg"), "Undo Action") self.undo_action.triggered.connect(self.level_ref.undo) self.undo_action.setEnabled(False) self.redo_action = menu_toolbar.addAction(icon("rotate-cw.svg"), "Redo Action") self.redo_action.triggered.connect(self.level_ref.redo) self.redo_action.setEnabled(False) menu_toolbar.addSeparator() menu_toolbar.addAction(icon("play-circle.svg"), "Play Level").triggered.connect(self.on_play) menu_toolbar.addSeparator() menu_toolbar.addAction(icon("zoom-out.svg"), "Zoom Out").triggered.connect( self.level_view.zoom_out) menu_toolbar.addAction(icon("zoom-in.svg"), "Zoom In").triggered.connect( self.level_view.zoom_in) menu_toolbar.addSeparator() menu_toolbar.addAction(icon("tool.svg"), "Edit Level Header").triggered.connect( self.on_header_editor) self.jump_destination_action = menu_toolbar.addAction( icon("arrow-right-circle.svg"), "Go to Jump Destination") self.jump_destination_action.triggered.connect( self._go_to_jump_destination) menu_toolbar.addSeparator() # menu_toolbar.addAction(icon("help-circle.svg"), "What's this?") self.addToolBar(Qt.TopToolBarArea, menu_toolbar) self.status_bar = ObjectStatusBar(self, self.level_ref) self.setStatusBar(self.status_bar) self.delete_shortcut = QShortcut(QKeySequence(Qt.Key_Delete), self, self.remove_selected_objects) QShortcut(QKeySequence(Qt.CTRL + Qt.Key_X), self, self._cut_objects) QShortcut(QKeySequence(Qt.CTRL + Qt.Key_C), self, self._copy_objects) QShortcut(QKeySequence(Qt.CTRL + Qt.Key_V), self, self._paste_objects) QShortcut(QKeySequence(Qt.CTRL + Qt.Key_Z), self, self.level_ref.undo) QShortcut(QKeySequence(Qt.CTRL + Qt.Key_Y), self, self.level_ref.redo) QShortcut(QKeySequence(Qt.CTRL + Qt.SHIFT + Qt.Key_Z), self, self.level_ref.redo) QShortcut(QKeySequence(Qt.CTRL + Qt.Key_Plus), self, self.level_view.zoom_in) QShortcut(QKeySequence(Qt.CTRL + Qt.Key_Minus), self, self.level_view.zoom_out) QShortcut(QKeySequence(Qt.CTRL + Qt.Key_A), self, self.level_view.select_all) if not self.on_open_rom(path_to_rom): self.deleteLater() self.showMaximized()
class MainWindow(QMainWindow): def __init__(self, app: QApplication): super().__init__() self.current_file = None self.console_dock: QDockWidget = None self.tools_dock: QDockWidget = None self.toolbar: QToolBar = None self.graph_widget: GraphWidget = None self.log_console_widget: LogConsoleWidget = None self.tools_widget: ToolsWidget = None self.file_menu: QMenu = None self.help_menu: QMenu = None self.view_menu: QMenu = None self.docks_menu: QMenu = None self.about_action: QAction = None self.new_action: QAction = None self.open_action: QAction = None self.save_action: QAction = None self.save_as_action: QAction = None self.exit_action: QAction = None self.toggle_tools_dock: QAction = None self.toggle_console_dock: QAction = None self.create_actions(app) self.create_widgets() self.create_docks() self.create_menus() self.create_toolbar() self.create_statusbar() self.setCentralWidget(self.graph_widget) self.addDockWidget(Qt.BottomDockWidgetArea, self.console_dock) self.addDockWidget(Qt.RightDockWidgetArea, self.tools_dock) self.addToolBar(self.toolbar) self.setWindowTitle(self.tr("Proofy")) self.read_settings() def create_statusbar(self): self.statusBar().showMessage(self.tr("Welcome to Proofy!")) def create_docks(self): self.console_dock = QDockWidget(self.tr("Console")) self.console_dock.setWidget(self.log_console_widget) self.tools_dock = QDockWidget(self.tr("Tools")) self.tools_dock.setWidget(self.tools_widget) def create_toolbar(self): self.toolbar = QToolBar(self.tr("Tools"), self) self.toolbar.setStatusTip(self.tr("Tools")) self.toolbar.addActions([ self.new_action, self.open_action, self.save_action, self.save_as_action, self.exit_action, ]) self.toolbar.addSeparator() self.toolbar.addAction(self.about_action) def create_widgets(self): self.log_console_widget = LogConsoleWidget() self.log_console_widget.add_loggers(logger) self.graph_widget = GraphWidget(self.log_console_widget) self.tools_widget = ToolsWidget(graph_widget=self.graph_widget) def create_menus(self): self.file_menu = self.menuBar().addMenu("File") self.file_menu.setStatusTip(self.tr("File operations")) self.file_menu.addActions([ self.new_action, self.open_action, self.save_action, self.save_as_action, self.exit_action, ]) self.view_menu = self.menuBar().addMenu("View") self.view_menu.setStatusTip(self.tr("View settings")) self.docks_menu = self.view_menu.addMenu("Docks") self.docks_menu.addAction(self.toggle_tools_dock) self.docks_menu.addAction(self.toggle_console_dock) self.help_menu = self.menuBar().addMenu("Help") self.help_menu.setStatusTip(self.tr("Help")) self.help_menu.addAction(self.about_action) def create_actions(self, app): self.about_action = QAction( app.style().standardIcon( QtWidgets.QStyle.SP_MessageBoxInformation), "About", self, ) self.about_action.setStatusTip("Show information about Proofy") self.about_action.triggered.connect(self.about) self.new_action = QAction( app.style().standardIcon(QtWidgets.QStyle.SP_FileIcon), "New...", self) self.new_action.setStatusTip(self.tr("Create a new file")) self.new_action.setShortcuts(QKeySequence.New) self.new_action.triggered.connect(self.new) self.open_action = QAction( app.style().standardIcon(QtWidgets.QStyle.SP_DialogOpenButton), "Open...", self, ) self.open_action.setStatusTip(self.tr("Open file")) self.open_action.setShortcuts(QKeySequence.Open) self.open_action.triggered.connect(self.open) self.save_action = QAction( app.style().standardIcon(QtWidgets.QStyle.SP_DialogSaveButton), "Save...", self, ) self.save_action.setStatusTip(self.tr("Save file")) self.save_action.setShortcuts(QKeySequence.Save) self.save_action.triggered.connect(self.save) self.save_as_action = QAction( app.style().standardIcon(QtWidgets.QStyle.SP_DriveFDIcon), "Save As...", self, ) self.save_as_action.setStatusTip(self.tr("Save to file")) self.save_as_action.setShortcuts(QKeySequence.SaveAs) self.save_as_action.triggered.connect(self.save_as) self.exit_action = QAction( app.style().standardIcon(QtWidgets.QStyle.SP_DialogCloseButton), "Exit", self, ) self.exit_action.setStatusTip(self.tr("Exit Proofy")) self.exit_action.setShortcuts(QKeySequence.Quit) self.exit_action.triggered.connect(self.exit) self.toggle_console_dock = QAction("Toggle Console Dock", self) self.toggle_console_dock.setStatusTip( "Toggle visibility of the console dock") self.toggle_console_dock.triggered.connect( lambda _: self.console_dock.setVisible(not self.console_dock. isVisible())) self.toggle_tools_dock = QAction("Toggle Tools Dock", self) self.toggle_tools_dock.setStatusTip( "Toggle visibility of the tools dock") self.toggle_tools_dock.triggered.connect( lambda _: self.tools_dock.setVisible(not self.tools_dock.isVisible( ))) @Slot() def about(self): logger.debug(locals()) QMessageBox.about( self, "About Proofy", self.tr(f""" <h1>Proofy {__version__}</h1> <p> <b>Proofy is a formal proof system GUI.</b> </p> <p> Oh, it looks like Proofy wants to talk! <blockquote>Proofy likes Sequent Calculus! And circles! And edges! And arrows! And ...</blockquote> </p> """), ) def closeEvent(self, event: QCloseEvent): logger.debug(locals()) if self.unsaved_check(): self.write_settings() event.accept() else: event.ignore() @Slot() def exit(self): logger.debug(locals()) if self.unsaved_check(): QApplication.quit() @Slot() def new(self): logger.debug(locals()) if self.unsaved_check(): self.current_file = None def set_file_status(self, *, modified: bool): if self.current_file: file = pathlib.Path(self.current_file[0]) self.setWindowTitle(f"{file.name}[*] [{file}] - Proofy") self.setWindowModified(modified) else: self.setWindowTitle(f"Proofy[*]") self.setWindowModified(modified) @Slot() def open(self): logger.debug(locals()) if self.unsaved_check(): if (path := QFileDialog.getOpenFileName( self, caption=self.tr("Open File"), filter=self.graph_widget.get_open_file_extensions(), )): try: QApplication.setOverrideCursor(Qt.WaitCursor) self.graph_widget.open_file(*path) self.statusBar().showMessage(f"Opened {path} successfully") self.current_file = path self.set_file_status(modified=False) except Exception as e: logger.error(e) finally: QApplication.restoreOverrideCursor()
else: lbl.setText('') sim.cleanup() t.stop() benc_timer.stop() action.changed.connect(_handle_sim_action) toolbar = QToolBar() lbl = QLabel() benc_timer = QTimer(w) def _on_bench(): global ticks lbl.setText(f'Frequency: {ticks} Hz') ticks = 0 benc_timer.timeout.connect(_on_bench) toolbar.addAction(action) toolbar.addSeparator() toolbar.addWidget(lbl) w.addToolBar(toolbar) w.setCentralWidget(ed) w.setWindowTitle(make_title()) w.show() app.exec_()
def createToolBar(self): toolbar = QToolBar() act = toolbar.addAction(QIcon.fromTheme("document-new"), "Create a new note", self.newNote) act.setShortcut(QKeySequence.New) toolbar.addAction(QIcon.fromTheme("folder-new"), "Create a new notebook", self.newNotebook) toolbar.addSeparator() act = toolbar.addAction(QIcon.fromTheme("document-save"), "Save changes to current note", self.saveNote) act.setShortcut(QKeySequence.Save) toolbar.addAction(QIcon.fromTheme("document-send"), "Export current note") toolbar.addSeparator() toolbar.addAction(QIcon.fromTheme("format-text-bold"), "Bold") toolbar.addAction(QIcon.fromTheme("format-text-italic"), "Italic") toolbar.addAction(QIcon.fromTheme("format-text-underline"), "Underline") self.headingsCombo = QComboBox() self.headingsCombo.addItem("H1") self.headingsCombo.addItem("H2") self.headingsCombo.addItem("H3") self.headingsCombo.addItem("H4") self.headingsCombo.addItem("H5") self.headingsCombo.addItem("H6") toolbar.addWidget(self.headingsCombo) toolbar.addSeparator() toolbar.addAction(QIcon.fromTheme("format-list-unordered"), "Insert bulleted list") toolbar.addAction(QIcon.fromTheme("format-list-ordered"), "Insert numbered list") toolbar.addAction(QIcon.fromTheme("insert-link"), "Inserts a link") toolbar.addSeparator() self.editableAction = toolbar.addAction( QIcon.fromTheme("edit"), "Toggle edit or markdown visualizer") self.editableAction.setCheckable(True) self.editableAction.setChecked(True) self.editableAction.setShortcut(QKeySequence("Ctrl+E")) QObject.connect(self.editableAction, SIGNAL('triggered(bool)'), self.editTriggered) toolbar.addAction(QIcon.fromTheme("system-search"), "Search") self.notebooksCombo = QComboBox() self.notebooksCombo.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) self.notebooksCombo.addItem(QIcon.fromTheme("folder"), "Create new notebook") self.notesCombo = QComboBox() self.notesCombo.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) QObject.connect(self.notebooksCombo, SIGNAL("activated(QString)"), self.switchNotebook) QObject.connect(self.notesCombo, SIGNAL("activated(QString)"), self.switchNote) self.spacer = QWidget() self.spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) toolbar.addWidget(self.spacer) toolbar.addWidget(self.notebooksCombo) toolbar.addWidget(self.notesCombo) return toolbar