コード例 #1
0
    def __init__(self, optparse):
        """Constructor"""
        QMainWindow.__init__(self, None)
        self.setupUi(self)
        self.opts, self.args = optparse

        logview.setParent(self)
        logview.setWindowFlags(Qt.Dialog)

        self.statusbar_label = QLabel()
        self.statusbar_label.setIndent(2)
        self.statusbar_label.setSizePolicy(QSizePolicy.Ignored,
                                           QSizePolicy.Fixed)
        self.statusbar.addPermanentWidget(self.statusbar_label, 1)
        self.update_status(
            self.tr("Welcome to M64Py version %s." % FRONTEND_VERSION))

        self.sizes = {
            SIZE_1X: self.action1X,
            SIZE_2X: self.action2X,
            SIZE_3X: self.action3X
        }

        self.slots = {}
        self.view = None
        self.stack = None
        self.glwidget = None
        self.cheats = None
        self.maximized = False
        self.widgets_height = None

        self.settings = Settings(self)
        self.worker = Worker(self)

        self.vidext = bool(self.settings.get_int_safe("enable_vidext", 1))

        self.create_state_slots()
        self.create_widgets()
        self.recent_files = RecentFiles(self)
        self.connect_signals()
        self.worker.init()
コード例 #2
0
    def __init__(self, optparse):
        """Constructor"""
        QMainWindow.__init__(self, None)
        self.setupUi(self)
        self.opts, self.args = optparse

        logview.setParent(self)
        logview.setWindowFlags(Qt.Dialog)

        self.statusbar_label = QLabel()
        self.statusbar_label.setIndent(2)
        self.statusbar.addPermanentWidget(self.statusbar_label, 1)
        self.update_status(self.tr(
            "Welcome to M64Py version %s." % FRONTEND_VERSION))

        self.sizes = {
            SIZE_1X: self.action1X,
            SIZE_2X: self.action2X,
            SIZE_3X: self.action3X}

        self.slots = {}
        self.view = None
        self.stack = None
        self.glwidget = None
        self.cheats = None
        self.maximized = False
        self.widgets_height = None

        self.settings = Settings(self)
        self.worker = Worker(self)

        self.vidext = bool(
            int(self.settings.qset.value("enable_vidext", 1)))

        self.create_state_slots()
        self.create_widgets()
        self.recent_files = RecentFiles(self)
        self.connect_signals()
        self.worker.init()
コード例 #3
0
class MainWindow(QMainWindow, Ui_MainWindow):
    """Frontend main window"""

    rom_opened = pyqtSignal()
    rom_closed = pyqtSignal()
    file_open = pyqtSignal(str, str)
    file_opening = pyqtSignal(str)
    set_caption = pyqtSignal(str)
    state_changed = pyqtSignal(tuple)
    save_image = pyqtSignal(bool)
    info_dialog = pyqtSignal(str)
    archive_dialog = pyqtSignal(list)

    def __init__(self, optparse):
        """Constructor"""
        QMainWindow.__init__(self, None)
        self.setupUi(self)
        self.opts, self.args = optparse

        logview.setParent(self)
        logview.setWindowFlags(Qt.Dialog)

        self.statusbar_label = QLabel()
        self.statusbar_label.setIndent(2)
        self.statusbar_label.setSizePolicy(QSizePolicy.Ignored,
                                           QSizePolicy.Fixed)
        self.statusbar.addPermanentWidget(self.statusbar_label, 1)
        self.update_status(
            self.tr("Welcome to M64Py version %s." % FRONTEND_VERSION))

        self.sizes = {
            SIZE_1X: self.action1X,
            SIZE_2X: self.action2X,
            SIZE_3X: self.action3X
        }

        self.slots = {}
        self.view = None
        self.stack = None
        self.glwidget = None
        self.cheats = None
        self.maximized = False
        self.widgets_height = None

        self.settings = Settings(self)
        self.worker = Worker(self)

        self.vidext = bool(self.settings.get_int_safe("enable_vidext", 1))

        self.create_state_slots()
        self.create_widgets()
        self.recent_files = RecentFiles(self)
        self.connect_signals()
        self.worker.init()

    def closeEvent(self, event):
        self.worker.quit()

    def changeEvent(self, event):
        if event.type() == QEvent.WindowStateChange:
            if event.oldState() == Qt.WindowMaximized:
                self.maximized = False
            elif event.oldState() == Qt.WindowNoState and \
                    self.windowState() == Qt.WindowMaximized:
                self.maximized = True

    def resizeEvent(self, event):
        event.ignore()
        size = event.size()
        width, height = size.width(), size.height()
        if self.widgets_height:
            width, height = size.width(), size.height() - self.widgets_height
            self.window_size_triggered((width, height))
        else:
            width, height = size.width(), size.height()
            self.resize(width, height)

    def showEvent(self, event):
        if not self.widgets_height:
            width, height = self.settings.get_size_safe()
            menubar_height = self.menubar.size().height()
            statusbar_height = self.statusbar.size().height()
            self.widgets_height = menubar_height + statusbar_height
            self.resize(width, height + self.widgets_height)
            self.create_size_actions()
            self.center_widget()

    def window_size_triggered(self, size):
        width, height = size
        if self.vidext and self.worker.core.get_handle():
            fullscreen = self.window().isFullScreen()
            # event.ignore() doesn't work on windows
            if not sys.platform == "win32":
                if not fullscreen and \
                        bool(self.settings.get_int_safe("keep_aspect", 1)):
                    width, height = self.keep_aspect(size)

            self.worker.core.config.open_section("Video-General")
            self.worker.core.config.set_parameter("ScreenWidth", width)
            self.worker.core.config.set_parameter("ScreenHeight", height)

            if not fullscreen:
                video_size = (width << 16) + height
            else:
                video_size = (width << 16) + (height + self.widgets_height)
            if self.worker.state in (M64EMU_RUNNING, M64EMU_PAUSED):
                self.worker.core_state_set(M64CORE_VIDEO_SIZE, video_size)

        self.set_sizes((width, height))
        self.settings.qset.setValue("size", (width, height))
        self.resize(width, height + self.widgets_height)

    def set_sizes(self, size):
        """Sets 'Window Size' radio buttons on resize event."""
        width, height = size
        if size in self.sizes.keys():
            self.sizes[(width, height)].setChecked(True)
        else:
            for action in self.sizes.values():
                action.setChecked(False)

    def keep_aspect(self, size):
        """Keeps 4:3 aspect ratio."""
        width, height = size
        if self.maximized:
            return width, height
        fixed_ratio = 1.3333333333333333
        current_ratio = float(width) / float(height)
        if fixed_ratio > current_ratio:
            w = int(width)
            h = int(width / fixed_ratio)
        else:
            h = int(height)
            w = int(height * fixed_ratio)
        return w, h

    def center_widget(self):
        """Centers widget on desktop."""
        size = self.size()
        desktop = QApplication.desktop()
        width, height = size.width(), size.height()
        dwidth, dheight = desktop.width(), desktop.height()
        cw, ch = (dwidth / 2) - (width / 2), (dheight / 2) - (height / 2)
        self.move(cw, ch)

    def connect_signals(self):
        """Connects signals."""
        self.rom_opened.connect(self.on_rom_opened)
        self.rom_closed.connect(self.on_rom_closed)
        self.file_open.connect(self.on_file_open)
        self.file_opening.connect(self.on_file_opening)
        self.set_caption.connect(self.on_set_caption)
        self.state_changed.connect(self.on_state_changed)
        self.save_image.connect(self.on_save_image)
        self.info_dialog.connect(self.on_info_dialog)
        self.archive_dialog.connect(self.on_archive_dialog)

    def create_widgets(self):
        """Creates central widgets."""
        self.stack = QStackedWidget(self)
        self.setCentralWidget(self.stack)
        self.view = View(self)
        self.stack.addWidget(self.view)
        self.glwidget = GLWidget(self)
        self.worker.video.set_widget(self)
        self.stack.addWidget(self.glwidget)
        self.stack.setCurrentWidget(self.view)

    def create_state_slots(self):
        """Creates state slot actions."""
        group = QActionGroup(self)
        group.setExclusive(True)
        for slot in range(10):
            self.slots[slot] = QAction(self)
            self.slots[slot].setCheckable(True)
            self.slots[slot].setText("Slot %d" % slot)
            self.slots[slot].setShortcut(QKeySequence(str(slot)))
            self.slots[slot].setActionGroup(group)
            self.menuStateSlot.addAction(self.slots[slot])
        self.slots[0].setChecked(True)
        for slot, action in self.slots.items():
            action.triggered.connect(
                lambda t, s=slot: self.worker.state_set_slot(s))

    def create_size_actions(self):
        """Creates window size actions."""
        group = QActionGroup(self)
        group.setExclusive(True)
        for num, size in enumerate(sorted(self.sizes.keys()), 1):
            width, height = size
            action = self.sizes[size]
            action.setActionGroup(group)
            w, h = width, height + self.widgets_height
            action.setText("%dX" % num)
            action.setToolTip("%sx%s" % (width, height))
            action.triggered.connect(lambda t, wi=w, he=h: self.resize(wi, he))

    def on_file_open(self, filepath=None, filename=None):
        """Opens ROM file."""
        if not filepath:
            action = self.sender()
            filepath = action.data()
        self.worker.core_state_query(M64CORE_EMU_STATE)
        if self.worker.state in [M64EMU_RUNNING, M64EMU_PAUSED]:
            self.worker.stop()
        self.worker.set_filepath(filepath, filename)
        self.worker.start()
        self.raise_()

    def update_status(self, status):
        """Updates label in status bar."""
        self.statusbar_label.setText(status)

    def on_set_caption(self, title):
        """Sets window title."""
        self.setWindowTitle(title)

    def on_file_opening(self, filepath):
        """Updates status on file opening."""
        self.update_status("Loading %s..." % (os.path.basename(filepath)))

    def on_save_image(self, title):
        """Saves snapshot or title image."""
        self.worker.save_image(title)

    def on_info_dialog(self, info):
        """Shows info dialog."""
        self.settings.show_page(0)
        self.settings.raise_()
        InfoDialog(self.settings, info)

    def on_archive_dialog(self, files):
        """Shows archive dialog."""
        archive = ArchiveDialog(self, files)
        rval = archive.exec_()
        if rval == QDialog.Accepted:
            curr_item = archive.listWidget.currentItem()
            fname = curr_item.data(Qt.UserRole)
            self.worker.filename = fname

    def on_state_changed(self, states):
        """Toggles actions state."""
        load, pause, action, cheats = states
        self.menuLoad.setEnabled(load)
        self.menuRecent.setEnabled(load)
        self.menuStateSlot.setEnabled(load)
        self.actionLoadState.setEnabled(action)
        self.actionSaveState.setEnabled(action)
        self.actionLoadFrom.setEnabled(action)
        self.actionSaveAs.setEnabled(action)
        self.actionSaveScreenshot.setEnabled(action)
        self.actionShowROMInfo.setEnabled(action)
        self.actionMute.setEnabled(action)
        self.actionStop.setEnabled(action)
        self.actionReset.setEnabled(action)
        self.actionSoftReset.setEnabled(action)
        self.actionLimitFPS.setEnabled(action)
        self.actionSlowDown.setEnabled(action)
        self.actionSpeedUp.setEnabled(action)
        self.actionFullscreen.setEnabled(action)
        self.actionCheats.setEnabled(cheats)
        self.actionPause.setEnabled(pause)
        self.actionPaths.setEnabled(not action)
        self.actionEmulator.setEnabled(not action)
        self.actionGraphics.setEnabled(not action)
        self.actionPlugins.setEnabled(not action)

    def on_rom_opened(self):
        if self.vidext:
            self.stack.setCurrentWidget(self.glwidget)
            self.glwidget.setFocus(True)
        if not self.cheats:
            self.cheats = Cheat(self)
        self.update_status(self.worker.core.rom_settings.goodname.decode())
        QTimer.singleShot(2000, self.worker.toggle_actions)

    def on_rom_closed(self):
        if self.vidext and self.isFullScreen():
            self.glwidget.toggle_fs.emit()
        self.stack.setCurrentWidget(self.view)
        self.actionMute.setChecked(False)
        self.actionPause.setChecked(False)
        self.actionLimitFPS.setChecked(True)
        self.on_set_caption("M64Py")
        self.update_status("ROM closed.")
        del self.cheats
        self.cheats = None

    @pyqtSlot()
    def on_actionManually_triggered(self):
        """Shows ROM file dialog."""
        dialog = QFileDialog()
        dialog.setFileMode(QFileDialog.ExistingFile)
        last_dir = self.settings.qset.value("last_dir")
        file_path, _ = dialog.getOpenFileName(
            self, self.tr("Load ROM Image"), last_dir,
            "Nintendo64 ROM (%s);;All files (*)" % EXT_FILTER)
        if file_path:
            self.file_open.emit(file_path, None)
            last_dir = QFileInfo(file_path).path()
            self.settings.qset.setValue("last_dir", last_dir)

    @pyqtSlot()
    def on_actionFromList_triggered(self):
        """Shows ROM list."""
        ROMList(self)

    @pyqtSlot()
    def on_actionShowROMInfo_triggered(self):
        """Shows ROM information."""
        RomInfo(self)

    @pyqtSlot()
    def on_actionLoadState_triggered(self):
        """Loads state."""
        self.worker.state_load()

    @pyqtSlot()
    def on_actionSaveState_triggered(self):
        """Saves state."""
        self.worker.state_save()

    @pyqtSlot()
    def on_actionLoadFrom_triggered(self):
        """Loads state from file."""
        dialog = QFileDialog()
        dialog.setFileMode(QFileDialog.ExistingFile)
        file_path, _ = dialog.getOpenFileName(
            self, self.tr("Load State From File"),
            os.path.join(self.worker.core.config.get_path("UserData"), "save"),
            "M64P/PJ64 Saves (*.st* *.m64p *.zip *.pj);;All files (*)")
        if file_path:
            self.worker.state_load(file_path)

    @pyqtSlot()
    def on_actionSaveAs_triggered(self):
        """Saves state to file."""
        dialog = QFileDialog()
        file_path, file_filter = dialog.getSaveFileName(
            self, self.tr("Save State To File"),
            os.path.join(self.worker.core.config.get_path("UserData"), "save"),
            ";;".join([
                save_filter for save_filter, save_ext in M64P_SAVES.values()
            ]), M64P_SAVES[M64SAV_M64P][0])
        if file_path:
            for save_type, filters in M64P_SAVES.items():
                save_filter, save_ext = filters
                if file_filter == save_filter:
                    if not file_path.endswith(save_ext):
                        file_path = "%s.%s" % (file_path, save_ext)
                    self.worker.state_save(file_path, save_type)

    @pyqtSlot()
    def on_actionSaveScreenshot_triggered(self):
        """Saves screenshot."""
        self.worker.save_screenshot()

    @pyqtSlot()
    def on_actionPause_triggered(self):
        """Toggles pause."""
        self.worker.toggle_pause()

    @pyqtSlot()
    def on_actionMute_triggered(self):
        """Toggles mute."""
        self.worker.toggle_mute()

    @pyqtSlot()
    def on_actionStop_triggered(self):
        """Stops emulator."""
        self.worker.stop()

    @pyqtSlot()
    def on_actionReset_triggered(self):
        """Resets emulator."""
        self.worker.reset()

    @pyqtSlot()
    def on_actionSoftReset_triggered(self):
        """Resets emulator."""
        self.worker.reset(True)

    @pyqtSlot()
    def on_actionLimitFPS_triggered(self):
        """Toggles speed limit."""
        self.worker.toggle_speed_limit()

    @pyqtSlot()
    def on_actionSlowDown_triggered(self):
        """Speeds down emulator."""
        self.worker.speed_down()

    @pyqtSlot()
    def on_actionSpeedUp_triggered(self):
        """Speeds up emulator."""
        self.worker.speed_up()

    @pyqtSlot()
    def on_actionCheats_triggered(self):
        """Shows cheat dialog."""
        if self.cheats:
            self.cheats.show()

    @pyqtSlot()
    def on_actionFullscreen_triggered(self):
        """Toggles fullscreen."""
        self.worker.toggle_fs()

    @pyqtSlot()
    def on_actionPythonConsole_triggered(self):
        """Shows python console."""
        pythonconsoleforeground(self)

    @pyqtSlot()
    def on_actionPaths_triggered(self):
        """Shows paths settings."""
        self.settings.show_page(0)

    @pyqtSlot()
    def on_actionEmulator_triggered(self):
        """Shows emulator settings."""
        self.settings.show_page(1)

    @pyqtSlot()
    def on_actionGraphics_triggered(self):
        """Shows emulator settings."""
        self.settings.show_page(2)

    @pyqtSlot()
    def on_actionPlugins_triggered(self):
        """Shows plugins settings."""
        self.settings.show_page(3)

    @pyqtSlot()
    def on_actionAbout_triggered(self):
        """Shows about dialog."""
        AboutDialog(self)

    @pyqtSlot()
    def on_actionLicense_triggered(self):
        """Shows license dialog."""
        LicenseDialog(self)

    @pyqtSlot()
    def on_actionLog_triggered(self):
        """Shows log dialog."""
        logview.show()
コード例 #4
0
class MainWindow(QMainWindow, Ui_MainWindow):
    """Frontend main window"""

    rom_opened = pyqtSignal()
    rom_closed = pyqtSignal()
    file_open = pyqtSignal(str, str)
    file_opening = pyqtSignal(str)
    set_caption = pyqtSignal(str)
    state_changed = pyqtSignal(tuple)
    save_image = pyqtSignal(bool)
    info_dialog = pyqtSignal(str)
    archive_dialog = pyqtSignal(list)

    def __init__(self, optparse):
        """Constructor"""
        QMainWindow.__init__(self, None)
        self.setupUi(self)
        self.opts, self.args = optparse

        logview.setParent(self)
        logview.setWindowFlags(Qt.Dialog)

        self.statusbar_label = QLabel()
        self.statusbar_label.setIndent(2)
        self.statusbar.addPermanentWidget(self.statusbar_label, 1)
        self.update_status(self.tr(
            "Welcome to M64Py version %s." % FRONTEND_VERSION))

        self.sizes = {
            SIZE_1X: self.action1X,
            SIZE_2X: self.action2X,
            SIZE_3X: self.action3X}

        self.slots = {}
        self.view = None
        self.stack = None
        self.glwidget = None
        self.cheats = None
        self.maximized = False
        self.widgets_height = None

        self.settings = Settings(self)
        self.worker = Worker(self)

        self.vidext = bool(
            int(self.settings.qset.value("enable_vidext", 1)))

        self.create_state_slots()
        self.create_widgets()
        self.recent_files = RecentFiles(self)
        self.connect_signals()
        self.worker.init()

    def closeEvent(self, event):
        self.worker.quit()

    def changeEvent(self, event):
        if event.type() == QEvent.WindowStateChange:
            if event.oldState() == Qt.WindowMaximized:
                self.maximized = False
            elif event.oldState() == Qt.WindowNoState and \
                    self.windowState() == Qt.WindowMaximized:
                self.maximized = True

    def resizeEvent(self, event):
        event.ignore()
        size = event.size()
        width, height = size.width(), size.height()
        if self.widgets_height:
            width, height = size.width(), size.height() - self.widgets_height
            self.window_size_triggered((width, height))
        else:
            width, height = size.width(), size.height()
            self.resize(width, height)

    def showEvent(self, event):
        if not self.widgets_height:
            width, height = self.settings.qset.value("size", SIZE_1X)
            menubar_height = self.menubar.size().height()
            statusbar_height = self.statusbar.size().height()
            self.widgets_height = menubar_height + statusbar_height
            self.resize(width, height + self.widgets_height)
            self.create_size_actions()
            self.center_widget()

    def window_size_triggered(self, size):
        width, height = size
        if self.vidext and self.worker.core.get_handle():
            fullscreen = self.window().isFullScreen()
            # event.ignore() doesn't work on windows
            if not sys.platform == "win32":
                if not fullscreen and \
                        bool(int(self.settings.qset.value("keep_aspect", 1))):
                    width, height = self.keep_aspect(size)

            self.worker.core.config.open_section("Video-General")
            self.worker.core.config.set_parameter("ScreenWidth", width)
            self.worker.core.config.set_parameter("ScreenHeight", height)

            if not fullscreen:
                video_size = (width << 16) + height
            else:
                video_size = (width << 16) + (height + self.widgets_height)
            if self.worker.state in (M64EMU_RUNNING, M64EMU_PAUSED):
                self.worker.core_state_set(M64CORE_VIDEO_SIZE, video_size)

        self.set_sizes((width, height))
        self.settings.qset.setValue("size", (width, height))
        self.resize(width, height + self.widgets_height)

    def set_sizes(self, size):
        """Sets 'Window Size' radio buttons on resize event."""
        width, height = size
        if size in self.sizes.keys():
            self.sizes[(width, height)].setChecked(True)
        else:
            for action in self.sizes.values():
                action.setChecked(False)

    def keep_aspect(self, size):
        """Keeps 4:3 aspect ratio."""
        width, height = size
        if self.maximized:
            return width, height
        fixed_ratio = 1.3333333333333333
        current_ratio = float(width)/float(height)
        if fixed_ratio > current_ratio:
            w = int(width)
            h = int(width/fixed_ratio)
        else:
            h = int(height)
            w = int(height*fixed_ratio)
        return w, h

    def center_widget(self):
        """Centers widget on desktop."""
        size = self.size()
        desktop = QApplication.desktop()
        width, height = size.width(), size.height()
        dwidth, dheight = desktop.width(), desktop.height()
        cw, ch = (dwidth/2)-(width/2), (dheight/2)-(height/2)
        self.move(cw, ch)

    def connect_signals(self):
        """Connects signals."""
        self.connect(self, SIGNAL("rom_opened()"), self.on_rom_opened)
        self.connect(self, SIGNAL("rom_closed()"), self.on_rom_closed)
        self.connect(self, SIGNAL("file_open(PyQt_PyObject, PyQt_PyObject)"), self.file_open)
        self.connect(self, SIGNAL("file_opening(PyQt_PyObject)"), self.on_file_opening)
        self.connect(self, SIGNAL("set_caption(PyQt_PyObject)"), self.on_set_caption)
        self.connect(self, SIGNAL("state_changed(PyQt_PyObject)"), self.on_state_changed)
        self.connect(self, SIGNAL("save_image(PyQt_PyObject)"), self.on_save_image)
        self.connect(self, SIGNAL("info_dialog(PyQt_PyObject)"), self.on_info_dialog)
        self.connect(self, SIGNAL("archive_dialog(PyQt_PyObject)"), self.on_archive_dialog)

    def create_widgets(self):
        """Creates central widgets."""
        self.stack = QStackedWidget(self)
        self.setCentralWidget(self.stack)
        self.view = View(self)
        self.stack.addWidget(self.view)
        if self.vidext:
            self.glwidget = GLWidget(self)
            self.worker.video.set_widget(self)
            self.stack.addWidget(self.glwidget)
        self.stack.setCurrentWidget(self.view)

    def create_state_slots(self):
        """Creates state slot actions."""
        group = QActionGroup(self)
        group.setExclusive(True)
        for slot in range(10):
            self.slots[slot] = QAction(self)
            self.slots[slot].setCheckable(True)
            self.slots[slot].setText("Slot %d" % slot)
            self.slots[slot].setShortcut(QKeySequence(str(slot)))
            self.slots[slot].setActionGroup(group)
            self.menuStateSlot.addAction(self.slots[slot])
        self.slots[0].setChecked(True)
        for slot, action in self.slots.items():
            self.connect(action, SIGNAL("triggered()"),
                         lambda s=slot: self.worker.state_set_slot(s))

    def create_size_actions(self):
        """Creates window size actions."""
        group = QActionGroup(self)
        group.setExclusive(True)
        for num, size in enumerate(
                sorted(self.sizes.keys()), 1):
            width, height = size
            action = self.sizes[size]
            action.setActionGroup(group)
            w, h = width, height+self.widgets_height
            action.setText("%dX" % num)
            action.setToolTip("%sx%s" % (width, height))
            self.connect(action, SIGNAL("triggered()"),
                         lambda wi=w, he=h: self.resize(wi, he))

    def file_open(self, filepath=None, filename=None):
        """Opens ROM file."""
        if not filepath:
            action = self.sender()
            filepath = action.data()
        self.worker.core_state_query(M64CORE_EMU_STATE)
        if self.worker.state in [M64EMU_RUNNING, M64EMU_PAUSED]:
            self.worker.stop()
        self.worker.set_filepath(filepath, filename)
        self.worker.start()
        self.raise_()

    def update_status(self, status):
        """Updates label in status bar."""
        self.statusbar_label.setText(status)

    def on_set_caption(self, title):
        """Sets window title."""
        self.setWindowTitle(title)

    def on_file_opening(self, filepath):
        """Updates status on file opening."""
        self.update_status("Loading %s..." % (
            os.path.basename(filepath)))

    def on_save_image(self, title):
        """Saves snapshot or title image."""
        self.worker.save_image(title)

    def on_info_dialog(self, info):
        """Shows info dialog."""
        self.settings.show_page(0)
        self.settings.raise_()
        InfoDialog(self.settings, info)

    def on_archive_dialog(self, files):
        """Shows archive dialog."""
        archive = ArchiveDialog(self, files)
        rval = archive.exec_()
        if rval == QDialog.Accepted:
            curr_item = archive.listWidget.currentItem()
            fname = curr_item.data(Qt.UserRole)
            self.worker.filename = fname

    def on_state_changed(self, states):
        """Toggles actions state."""
        load, pause, action, cheats = states
        self.menuLoad.setEnabled(load)
        self.menuRecent.setEnabled(load)
        self.menuStateSlot.setEnabled(load)
        self.actionLoadState.setEnabled(action)
        self.actionSaveState.setEnabled(action)
        self.actionLoadFrom.setEnabled(action)
        self.actionSaveAs.setEnabled(action)
        self.actionSaveScreenshot.setEnabled(action)
        self.actionShowROMInfo.setEnabled(action)
        self.actionMute.setEnabled(action)
        self.actionStop.setEnabled(action)
        self.actionReset.setEnabled(action)
        self.actionSoftReset.setEnabled(action)
        self.actionLimitFPS.setEnabled(action)
        self.actionSlowDown.setEnabled(action)
        self.actionSpeedUp.setEnabled(action)
        self.actionFullscreen.setEnabled(action)
        self.actionCheats.setEnabled(cheats)
        self.actionPause.setEnabled(pause)
        self.actionPaths.setEnabled(not action)
        self.actionEmulator.setEnabled(not action)
        self.actionGraphics.setEnabled(not action)
        self.actionPlugins.setEnabled(not action)

    def on_rom_opened(self):
        if self.vidext:
            self.stack.setCurrentWidget(self.glwidget)
            self.glwidget.setFocus(True)
        if not self.cheats:
            self.cheats = Cheat(self)
        self.update_status(self.worker.core.rom_settings.goodname)
        QTimer.singleShot(2000, self.worker.toggle_actions)

    def on_rom_closed(self):
        if self.vidext and self.isFullScreen():
            self.glwidget.emit(SIGNAL("toggle_fs()"))
        self.stack.setCurrentWidget(self.view)
        self.actionMute.setChecked(False)
        self.actionPause.setChecked(False)
        self.actionLimitFPS.setChecked(True)
        self.on_set_caption("M64Py")
        self.update_status("ROM closed.")
        del self.cheats
        self.cheats = None

    @pyqtSignature("")
    def on_actionManually_triggered(self):
        """Shows ROM file dialog."""
        dialog = QFileDialog()
        dialog.setFileMode(QFileDialog.ExistingFile)
        last_dir = self.settings.qset.value("last_dir")
        filepath = dialog.getOpenFileName(
                self, self.tr("Load ROM Image"), last_dir,
                "Nintendo64 ROM (%s);;All files (*)" % EXT_FILTER)
        if filepath:
            self.emit(SIGNAL("file_open(PyQt_PyObject, PyQt_PyObject)"), filepath, None)
            last_dir = QFileInfo(filepath).path()
            self.settings.qset.setValue("last_dir", last_dir)

    @pyqtSignature("")
    def on_actionFromList_triggered(self):
        """Shows ROM list."""
        ROMList(self)

    @pyqtSignature("")
    def on_actionShowROMInfo_triggered(self):
        """Shows ROM information."""
        RomInfo(self)

    @pyqtSignature("")
    def on_actionLoadState_triggered(self):
        """Loads state."""
        self.worker.state_load()

    @pyqtSignature("")
    def on_actionSaveState_triggered(self):
        """Saves state."""
        self.worker.state_save()

    @pyqtSignature("")
    def on_actionLoadFrom_triggered(self):
        """Loads state from file."""
        dialog = QFileDialog()
        dialog.setFileMode(QFileDialog.ExistingFile)
        file_path = dialog.getOpenFileName(
            self, self.tr("Load State From File"),
            os.path.join(self.worker.core.config.get_path("UserData"), "save"),
            "M64P/PJ64 Saves (*.st* *.m64p *.zip *.pj);;All files (*)")
        if file_path:
            self.worker.state_load(file_path)

    @pyqtSignature("")
    def on_actionSaveAs_triggered(self):
        """Saves state to file."""
        dialog = QFileDialog()
        file_path, file_filter = dialog.getSaveFileNameAndFilter(
            self, self.tr("Save State To File"),
            os.path.join(self.worker.core.config.get_path("UserData"), "save"),
            ";;".join([save_filter for save_filter, save_ext in M64P_SAVES.values()]),
            M64P_SAVES[M64SAV_M64P][0])
        if file_path:
            for save_type, filters in M64P_SAVES.items():
                save_filter, save_ext = filters
                if file_filter == save_filter:
                    if not file_path.endswith(save_ext):
                        file_path = "%s.%s" % (file_path, save_ext)
                    self.worker.state_save(file_path, save_type)


    @pyqtSignature("")
    def on_actionSaveScreenshot_triggered(self):
        """Saves screenshot."""
        self.worker.save_screenshot()

    @pyqtSignature("")
    def on_actionPause_triggered(self):
        """Toggles pause."""
        self.worker.toggle_pause()

    @pyqtSignature("")
    def on_actionMute_triggered(self):
        """Toggles mute."""
        self.worker.toggle_mute()

    @pyqtSignature("")
    def on_actionStop_triggered(self):
        """Stops emulator."""
        self.worker.stop()

    @pyqtSignature("")
    def on_actionReset_triggered(self):
        """Resets emulator."""
        self.worker.reset()

    @pyqtSignature("")
    def on_actionSoftReset_triggered(self):
        """Resets emulator."""
        self.worker.reset(True)

    @pyqtSignature("")
    def on_actionLimitFPS_triggered(self):
        """Toggles speed limit."""
        self.worker.toggle_speed_limit()

    @pyqtSignature("")
    def on_actionSlowDown_triggered(self):
        """Speeds down emulator."""
        self.worker.speed_down()

    @pyqtSignature("")
    def on_actionSpeedUp_triggered(self):
        """Speeds up emulator."""
        self.worker.speed_up()

    @pyqtSignature("")
    def on_actionCheats_triggered(self):
        """Shows cheat dialog."""
        if self.cheats:
            self.cheats.show()

    @pyqtSignature("")
    def on_actionFullscreen_triggered(self):
        """Toggles fullscreen."""
        self.worker.toggle_fs()

    @pyqtSignature("")
    def on_actionPaths_triggered(self):
        """Shows paths settings."""
        self.settings.show_page(0)

    @pyqtSignature("")
    def on_actionEmulator_triggered(self):
        """Shows emulator settings."""
        self.settings.show_page(1)

    @pyqtSignature("")
    def on_actionGraphics_triggered(self):
        """Shows emulator settings."""
        self.settings.show_page(2)

    @pyqtSignature("")
    def on_actionPlugins_triggered(self):
        """Shows plugins settings."""
        self.settings.show_page(3)

    @pyqtSignature("")
    def on_actionAbout_triggered(self):
        """Shows about dialog."""
        AboutDialog(self)

    @pyqtSignature("")
    def on_actionLicense_triggered(self):
        """Shows license dialog."""
        LicenseDialog(self)

    @pyqtSignature("")
    def on_actionLog_triggered(self):
        """Shows log dialog."""
        logview.show()