Exemple #1
0
    def __init__(self, module_pkgname, hooks_scripts):
        super().__init__(QtCore.Qt.Horizontal)
        self._win_title_base = "Node.gl controller"
        self.setWindowTitle(self._win_title_base)

        self._module_pkgname = module_pkgname
        self._scripts_mgr = ScriptsManager(module_pkgname)
        self._hooks_caller = HooksCaller(hooks_scripts)
        self._hooks_ctl = HooksController(self._get_scene, self._hooks_caller)

        get_scene_func = self._get_scene

        self._config = Config(module_pkgname)

        # Apply previous geometry (position + dimensions)
        rect = self._config.get("geometry")
        if rect:
            geometry = QtCore.QRect(*rect)
            self.setGeometry(geometry)

        graph_view = GraphView(get_scene_func, self._config)
        export_view = ExportView(get_scene_func, self._config)
        hooks_view = HooksView(self._hooks_ctl, self._config)
        self._medias_view = MediasView(self._config)
        serial_view = SerialView(get_scene_func)

        self._tabs = [
            ("Hooks", hooks_view),
            ("Graph view", graph_view),
            ("Export", export_view),
            ("Medias", self._medias_view),
            ("Serialization", serial_view),
        ]
        self._last_tab_index = -1

        self._tab_widget = QtWidgets.QTabWidget()
        for tab_name, tab_view in self._tabs:
            self._tab_widget.addTab(tab_view, tab_name)
        self._tab_widget.currentChanged.connect(self._currentTabChanged)

        self._scene_toolbar = Toolbar(self._config)
        self._scene_toolbar.sceneChanged.connect(self._scene_changed)
        self._scene_toolbar.sceneChanged.connect(self._scene_changed_hook)
        self._scene_toolbar.sceneChanged.connect(self._config.scene_changed)
        self._scene_toolbar.aspectRatioChanged.connect(
            self._config.set_aspect_ratio)
        self._scene_toolbar.samplesChanged.connect(self._config.set_samples)
        self._scene_toolbar.frameRateChanged.connect(
            self._config.set_frame_rate)
        self._scene_toolbar.logLevelChanged.connect(self._config.set_log_level)
        self._scene_toolbar.clearColorChanged.connect(
            self._config.set_clear_color)
        self._scene_toolbar.backendChanged.connect(self._config.set_backend)

        self._errbuf = QtWidgets.QPlainTextEdit()
        self._errbuf.setFont(
            QtGui.QFontDatabase.systemFont(QtGui.QFontDatabase.FixedFont))
        self._errbuf.setReadOnly(True)
        self._errbuf.hide()

        tabs_and_errbuf = QtWidgets.QVBoxLayout()
        tabs_and_errbuf.addWidget(self._tab_widget)
        tabs_and_errbuf.addWidget(self._errbuf)
        tabs_and_errbuf_widget = QtWidgets.QWidget()
        tabs_and_errbuf_widget.setLayout(tabs_and_errbuf)

        self.addWidget(self._scene_toolbar)
        self.addWidget(tabs_and_errbuf_widget)
        self.setStretchFactor(1, 1)

        self._scene_toolbar.reload_btn.clicked.connect(
            self._scripts_mgr.reload)  # TODO: drop
        self._scripts_mgr.error.connect(self._all_scripts_err)
        self._scripts_mgr.scriptsChanged.connect(
            self._scene_toolbar.on_scripts_changed)
        self._scripts_mgr.start()

        self.error.connect(self._scene_err)
        self.sceneLoaded.connect(self._scene_loaded)

        # Load the previous scene if the current and previously loaded
        # module packages match
        prev_pkgname = self._config.get("pkg")
        prev_module = self._config.get("module")
        prev_scene = self._config.get("scene")
        if prev_pkgname == module_pkgname:
            self._scene_toolbar.load_scene_from_name(prev_module, prev_scene)
Exemple #2
0
class MainWindow(QtWidgets.QSplitter):

    sceneLoaded = QtCore.Signal(dict)
    error = QtCore.Signal(str)

    def __init__(self, module_pkgname, hooks_scripts):
        super().__init__(QtCore.Qt.Horizontal)
        self._win_title_base = "Node.gl controller"
        self.setWindowTitle(self._win_title_base)

        self._module_pkgname = module_pkgname
        self._scripts_mgr = ScriptsManager(module_pkgname)
        self._hooks_caller = HooksCaller(hooks_scripts)
        self._hooks_ctl = HooksController(self._get_scene, self._hooks_caller)

        get_scene_func = self._get_scene

        self._config = Config(module_pkgname)

        # Apply previous geometry (position + dimensions)
        rect = self._config.get("geometry")
        if rect:
            geometry = QtCore.QRect(*rect)
            self.setGeometry(geometry)

        graph_view = GraphView(get_scene_func, self._config)
        export_view = ExportView(get_scene_func, self._config)
        hooks_view = HooksView(self._hooks_ctl, self._config)
        self._medias_view = MediasView(self._config)
        serial_view = SerialView(get_scene_func)

        self._tabs = [
            ("Hooks", hooks_view),
            ("Graph view", graph_view),
            ("Export", export_view),
            ("Medias", self._medias_view),
            ("Serialization", serial_view),
        ]
        self._last_tab_index = -1

        self._tab_widget = QtWidgets.QTabWidget()
        for tab_name, tab_view in self._tabs:
            self._tab_widget.addTab(tab_view, tab_name)
        self._tab_widget.currentChanged.connect(self._currentTabChanged)

        self._scene_toolbar = Toolbar(self._config)
        self._scene_toolbar.sceneChanged.connect(self._scene_changed)
        self._scene_toolbar.sceneChanged.connect(self._scene_changed_hook)
        self._scene_toolbar.sceneChanged.connect(self._config.scene_changed)
        self._scene_toolbar.aspectRatioChanged.connect(
            self._config.set_aspect_ratio)
        self._scene_toolbar.samplesChanged.connect(self._config.set_samples)
        self._scene_toolbar.frameRateChanged.connect(
            self._config.set_frame_rate)
        self._scene_toolbar.logLevelChanged.connect(self._config.set_log_level)
        self._scene_toolbar.clearColorChanged.connect(
            self._config.set_clear_color)
        self._scene_toolbar.backendChanged.connect(self._config.set_backend)

        self._errbuf = QtWidgets.QPlainTextEdit()
        self._errbuf.setFont(
            QtGui.QFontDatabase.systemFont(QtGui.QFontDatabase.FixedFont))
        self._errbuf.setReadOnly(True)
        self._errbuf.hide()

        tabs_and_errbuf = QtWidgets.QVBoxLayout()
        tabs_and_errbuf.addWidget(self._tab_widget)
        tabs_and_errbuf.addWidget(self._errbuf)
        tabs_and_errbuf_widget = QtWidgets.QWidget()
        tabs_and_errbuf_widget.setLayout(tabs_and_errbuf)

        self.addWidget(self._scene_toolbar)
        self.addWidget(tabs_and_errbuf_widget)
        self.setStretchFactor(1, 1)

        self._scene_toolbar.reload_btn.clicked.connect(
            self._scripts_mgr.reload)  # TODO: drop
        self._scripts_mgr.error.connect(self._all_scripts_err)
        self._scripts_mgr.scriptsChanged.connect(
            self._scene_toolbar.on_scripts_changed)
        self._scripts_mgr.start()

        self.error.connect(self._scene_err)
        self.sceneLoaded.connect(self._scene_loaded)

        # Load the previous scene if the current and previously loaded
        # module packages match
        prev_pkgname = self._config.get("pkg")
        prev_module = self._config.get("module")
        prev_scene = self._config.get("scene")
        if prev_pkgname == module_pkgname:
            self._scene_toolbar.load_scene_from_name(prev_module, prev_scene)

    @QtCore.Slot(str)
    def _scene_err(self, err_str):
        if err_str:
            self._errbuf.setPlainText(err_str)
            self._errbuf.show()
            sys.stderr.write(err_str)
        else:
            self._errbuf.hide()

    @QtCore.Slot(str)
    def _all_scripts_err(self, err_str):
        self._scene_toolbar.clear_scripts()
        self._scene_err(err_str)

    def _get_scene(self, **cfg_overrides):
        cfg = self._scene_toolbar.get_cfg()
        if cfg["scene"] is None:
            return None
        medias = self._medias_view.get_medias()
        cfg["medias"] = medias if medias else None
        cfg["files"] = []
        cfg.update(cfg_overrides)

        self._scripts_mgr.inc_query_count()
        self._scripts_mgr.pause()
        ret = query_scene(self._module_pkgname, **cfg)
        self._scripts_mgr.update_filelist(ret["filelist"])
        self._scripts_mgr.update_modulelist(ret["modulelist"])
        self._scripts_mgr.resume()
        self._scripts_mgr.dec_query_count()

        if "error" in ret:
            self.error.emit(ret["error"])
            return None

        self.error.emit(None)
        self.sceneLoaded.emit(ret)

        return ret

    @QtCore.Slot(str, str)
    def _scene_changed(self, module_name, scene_name):
        self.setWindowTitle(
            f"{self._win_title_base} - {module_name}.{scene_name}")
        self._currentTabChanged(self._tab_widget.currentIndex())

    @QtCore.Slot(str, str)
    def _scene_changed_hook(self, module_name, scene_name):
        self._hooks_ctl.process(module_name, scene_name)

    @QtCore.Slot(dict)
    def _scene_loaded(self, cfg):
        self._scene_toolbar.set_cfg(cfg)

    def _emit_geometry(self):
        geometry = (self.x(), self.y(), self.width(), self.height())
        self._config.geometry_changed(geometry)

    @QtCore.Slot(QtGui.QResizeEvent)
    def resizeEvent(self, resize_event):
        super().resizeEvent(resize_event)
        self._emit_geometry()

    @QtCore.Slot(QtGui.QMoveEvent)
    def moveEvent(self, move_event):
        super().moveEvent(move_event)
        self._emit_geometry()

    @QtCore.Slot(QtGui.QCloseEvent)
    def closeEvent(self, close_event):
        self._hooks_ctl.stop_threads()
        for name, widget in self._tabs:
            widget.close()
        super().closeEvent(close_event)

    @QtCore.Slot(int)
    def _currentTabChanged(self, index):
        next_view = self._tabs[index][1]
        prev_view = self._tabs[self._last_tab_index][1]
        if index != self._last_tab_index and hasattr(prev_view, "leave"):
            prev_view.leave()
        if hasattr(next_view, "enter"):
            next_view.enter()
        self._last_tab_index = index
class MainWindow(QtWidgets.QSplitter):

    error = QtCore.pyqtSignal(str)

    def __init__(self, module_pkgname, assets_dir, hooksdir):
        super(MainWindow, self).__init__(QtCore.Qt.Horizontal)
        self._win_title_base = 'Node.gl viewer'
        self.setWindowTitle(self._win_title_base)

        self._module_pkgname = module_pkgname
        self._scripts_mgr = ScriptsManager(module_pkgname)
        self._hooksdir = hooksdir

        medias = None
        if assets_dir:
            medias = []
            for f in sorted(os.listdir(assets_dir)):
                ext = f.rsplit('.', 1)[-1].lower()
                path = op.join(assets_dir, f)
                if op.isfile(path) and ext in ('mp4', 'mkv', 'avi', 'webm', 'mov', 'lrv'):
                    try:
                        media = Media(path)
                    except:
                        pass
                    else:
                        medias.append(media)

        self._medias = medias

        get_scene_func = self._get_scene

        self._hooks = None
        self._config = Config(module_pkgname)

        # Apply previous geometry (position + dimensions)
        rect = self._config.get('geometry')
        if rect:
            geometry = QtCore.QRect(*rect)
            self.setGeometry(geometry)

        gl_view = GLView(get_scene_func, self._config)
        graph_view = GraphView(get_scene_func, self._config)
        export_view = ExportView(get_scene_func, self._config)
        serial_view = SerialView(get_scene_func)

        self._tabs = [
            ('Player view', gl_view),
            ('Graph view', graph_view),
            ('Export', export_view),
            ('Serialization', serial_view),
        ]
        self._last_tab_index = -1

        self._tab_widget = QtWidgets.QTabWidget()
        for tab_name, tab_view in self._tabs:
            self._tab_widget.addTab(tab_view, tab_name)
        self._tab_widget.currentChanged.connect(self._currentTabChanged)

        self._scene_toolbar = Toolbar(self._config)
        self._scene_toolbar.sceneChanged.connect(self._scene_changed)
        self._scene_toolbar.sceneChanged.connect(self._scene_changed_hook)
        self._scene_toolbar.sceneChanged.connect(self._config.scene_changed)
        self._scene_toolbar.aspectRatioChanged.connect(gl_view.set_aspect_ratio)
        self._scene_toolbar.aspectRatioChanged.connect(export_view.set_aspect_ratio)
        self._scene_toolbar.aspectRatioChanged.connect(self._config.set_aspect_ratio)
        self._scene_toolbar.samplesChanged.connect(gl_view.set_samples)
        self._scene_toolbar.samplesChanged.connect(self._config.set_samples)
        self._scene_toolbar.frameRateChanged.connect(gl_view.set_frame_rate)
        self._scene_toolbar.frameRateChanged.connect(graph_view.set_frame_rate)
        self._scene_toolbar.frameRateChanged.connect(export_view.set_frame_rate)
        self._scene_toolbar.frameRateChanged.connect(self._config.set_frame_rate)
        self._scene_toolbar.logLevelChanged.connect(self._config.set_log_level)
        self._scene_toolbar.clearColorChanged.connect(gl_view.set_clear_color)
        self._scene_toolbar.clearColorChanged.connect(self._config.set_clear_color)
        self._scene_toolbar.backendChanged.connect(gl_view.set_backend)
        self._scene_toolbar.backendChanged.connect(self._config.set_backend)

        self._scene_toolbar.hudChanged.connect(self._config.set_hud)

        self._errbuf = QtWidgets.QPlainTextEdit()
        self._errbuf.setFont(QtGui.QFontDatabase.systemFont(QtGui.QFontDatabase.FixedFont))
        self._errbuf.setReadOnly(True)
        self._errbuf.hide()

        self._hooks_lbl = QtWidgets.QLabel()
        self._hooks_layout = QtWidgets.QHBoxLayout()
        self._hooks_layout.addWidget(self._hooks_lbl)
        self._hooks_widget = QtWidgets.QWidget()
        self._hooks_widget.setLayout(self._hooks_layout)
        self._hooks_widget.hide()

        tabs_and_errbuf = QtWidgets.QVBoxLayout()
        tabs_and_errbuf.addWidget(self._tab_widget)
        tabs_and_errbuf.addWidget(self._errbuf)
        tabs_and_errbuf.addWidget(self._hooks_widget)
        tabs_and_errbuf_widget = QtWidgets.QWidget()
        tabs_and_errbuf_widget.setLayout(tabs_and_errbuf)

        self.addWidget(self._scene_toolbar)
        self.addWidget(tabs_and_errbuf_widget)
        self.setStretchFactor(1, 1)

        self._scene_toolbar.reload_btn.clicked.connect(self._scripts_mgr.reload)  # TODO: drop
        self._scripts_mgr.error.connect(self._all_scripts_err)
        self._scripts_mgr.scriptsChanged.connect(self._scene_toolbar.on_scripts_changed)
        self._scripts_mgr.start()

        self.error.connect(self._scene_err)

        # Load the previous scene if the current and previously loaded
        # module packages match
        prev_pkgname = self._config.get('pkg')
        prev_module = self._config.get('module')
        prev_scene = self._config.get('scene')
        if prev_pkgname == module_pkgname:
            self._scene_toolbar.load_scene_from_name(prev_module, prev_scene)

    @QtCore.pyqtSlot(int, int, str)
    def _hooks_uploading(self, i, n, filename):
        self._hooks_widget.show()
        self._hooks_lbl.setText('Uploading [%d/%d]: %s...' % (i, n, filename))

    @QtCore.pyqtSlot(str, str)
    def _hooks_building_scene(self, backend, system):
        self._hooks_widget.show()
        self._hooks_lbl.setText('Building %s scene in %s...' % (system, backend))

    @QtCore.pyqtSlot()
    def _hooks_sending_scene(self):
        self._hooks_widget.show()
        self._hooks_lbl.setText('Sending scene...')

    @QtCore.pyqtSlot()
    def _hooks_done(self):
        self._hooks_widget.hide()

    @QtCore.pyqtSlot(str)
    def _scene_err(self, err_str):
        if err_str:
            self._errbuf.setPlainText(err_str)
            self._errbuf.show()
            sys.stderr.write(err_str)
        else:
            self._errbuf.hide()

    @QtCore.pyqtSlot(str)
    def _all_scripts_err(self, err_str):
        self._scene_toolbar.clear_scripts()
        self._scene_err(err_str)

    def _get_scene(self, **cfg_overrides):
        cfg = self._scene_toolbar.get_cfg()
        if cfg['scene'] is None:
            return None
        cfg['pkg'] = self._module_pkgname
        cfg['medias'] = self._medias
        cfg.update(cfg_overrides)

        self._scripts_mgr.pause()
        ret = query_subproc(query='scene', **cfg)
        if 'error' in ret:
            self._scripts_mgr.resume()
            self.error.emit(ret['error'])
            return None

        self.error.emit(None)
        self._scripts_mgr.set_filelist(ret['filelist'])
        self._scripts_mgr.resume()
        self._scene_toolbar.set_cfg(ret)

        return ret

    @QtCore.pyqtSlot(str, str)
    def _scene_changed(self, module_name, scene_name):
        self.setWindowTitle('%s - %s.%s' % (self._win_title_base, module_name, scene_name))
        self._currentTabChanged(self._tab_widget.currentIndex())

    @QtCore.pyqtSlot(str, str)
    def _scene_changed_hook(self, module_name, scene_name):
        if self._hooks:
            self._hooks.wait()
        self._hooks = Hooks(self._get_scene, self._hooksdir)
        self._hooks.uploadingFileNotif.connect(self._hooks_uploading)
        self._hooks.buildingSceneNotif.connect(self._hooks_building_scene)
        self._hooks.sendingSceneNotif.connect(self._hooks_sending_scene)
        self._hooks.finished.connect(self._hooks_done)
        self._hooks.error.connect(self._hooks_error)
        self._hooks.start()

    @QtCore.pyqtSlot(str)
    def _hooks_error(self, err):
        QtWidgets.QMessageBox.critical(self, 'Hook error', err, QtWidgets.QMessageBox.Ok)

    def _emit_geometry(self):
        geometry = (self.x(), self.y(), self.width(), self.height())
        self._config.geometry_changed(geometry)

    @QtCore.pyqtSlot(QtGui.QResizeEvent)
    def resizeEvent(self, resize_event):
        super(MainWindow, self).resizeEvent(resize_event)
        self._emit_geometry()

    @QtCore.pyqtSlot(QtGui.QMoveEvent)
    def moveEvent(self, move_event):
        super(MainWindow, self).moveEvent(move_event)
        self._emit_geometry()

    @QtCore.pyqtSlot(QtGui.QCloseEvent)
    def closeEvent(self, close_event):
        for name, widget in self._tabs:
            widget.close()
        super(MainWindow, self).closeEvent(close_event)

    @QtCore.pyqtSlot(int)
    def _currentTabChanged(self, index):
        next_view = self._tabs[index][1]
        prev_view = self._tabs[self._last_tab_index][1]
        if index != self._last_tab_index and hasattr(prev_view, 'leave'):
            prev_view.leave()
        if hasattr(next_view, 'enter'):
            next_view.enter()
        self._last_tab_index = index
    def __init__(self, module_pkgname, assets_dir, hooksdir):
        super(MainWindow, self).__init__(QtCore.Qt.Horizontal)
        self._win_title_base = 'Node.gl viewer'
        self.setWindowTitle(self._win_title_base)

        self._module_pkgname = module_pkgname
        self._scripts_mgr = ScriptsManager(module_pkgname)
        self._hooksdir = hooksdir

        medias = None
        if assets_dir:
            medias = []
            for f in sorted(os.listdir(assets_dir)):
                ext = f.rsplit('.', 1)[-1].lower()
                path = op.join(assets_dir, f)
                if op.isfile(path) and ext in ('mp4', 'mkv', 'avi', 'webm', 'mov', 'lrv'):
                    try:
                        media = Media(path)
                    except:
                        pass
                    else:
                        medias.append(media)

        self._medias = medias

        get_scene_func = self._get_scene

        self._hooks = None
        self._config = Config(module_pkgname)

        # Apply previous geometry (position + dimensions)
        rect = self._config.get('geometry')
        if rect:
            geometry = QtCore.QRect(*rect)
            self.setGeometry(geometry)

        gl_view = GLView(get_scene_func, self._config)
        graph_view = GraphView(get_scene_func, self._config)
        export_view = ExportView(get_scene_func, self._config)
        serial_view = SerialView(get_scene_func)

        self._tabs = [
            ('Player view', gl_view),
            ('Graph view', graph_view),
            ('Export', export_view),
            ('Serialization', serial_view),
        ]
        self._last_tab_index = -1

        self._tab_widget = QtWidgets.QTabWidget()
        for tab_name, tab_view in self._tabs:
            self._tab_widget.addTab(tab_view, tab_name)
        self._tab_widget.currentChanged.connect(self._currentTabChanged)

        self._scene_toolbar = Toolbar(self._config)
        self._scene_toolbar.sceneChanged.connect(self._scene_changed)
        self._scene_toolbar.sceneChanged.connect(self._scene_changed_hook)
        self._scene_toolbar.sceneChanged.connect(self._config.scene_changed)
        self._scene_toolbar.aspectRatioChanged.connect(gl_view.set_aspect_ratio)
        self._scene_toolbar.aspectRatioChanged.connect(export_view.set_aspect_ratio)
        self._scene_toolbar.aspectRatioChanged.connect(self._config.set_aspect_ratio)
        self._scene_toolbar.samplesChanged.connect(gl_view.set_samples)
        self._scene_toolbar.samplesChanged.connect(self._config.set_samples)
        self._scene_toolbar.frameRateChanged.connect(gl_view.set_frame_rate)
        self._scene_toolbar.frameRateChanged.connect(graph_view.set_frame_rate)
        self._scene_toolbar.frameRateChanged.connect(export_view.set_frame_rate)
        self._scene_toolbar.frameRateChanged.connect(self._config.set_frame_rate)
        self._scene_toolbar.logLevelChanged.connect(self._config.set_log_level)
        self._scene_toolbar.clearColorChanged.connect(gl_view.set_clear_color)
        self._scene_toolbar.clearColorChanged.connect(self._config.set_clear_color)
        self._scene_toolbar.backendChanged.connect(gl_view.set_backend)
        self._scene_toolbar.backendChanged.connect(self._config.set_backend)

        self._scene_toolbar.hudChanged.connect(self._config.set_hud)

        self._errbuf = QtWidgets.QPlainTextEdit()
        self._errbuf.setFont(QtGui.QFontDatabase.systemFont(QtGui.QFontDatabase.FixedFont))
        self._errbuf.setReadOnly(True)
        self._errbuf.hide()

        self._hooks_lbl = QtWidgets.QLabel()
        self._hooks_layout = QtWidgets.QHBoxLayout()
        self._hooks_layout.addWidget(self._hooks_lbl)
        self._hooks_widget = QtWidgets.QWidget()
        self._hooks_widget.setLayout(self._hooks_layout)
        self._hooks_widget.hide()

        tabs_and_errbuf = QtWidgets.QVBoxLayout()
        tabs_and_errbuf.addWidget(self._tab_widget)
        tabs_and_errbuf.addWidget(self._errbuf)
        tabs_and_errbuf.addWidget(self._hooks_widget)
        tabs_and_errbuf_widget = QtWidgets.QWidget()
        tabs_and_errbuf_widget.setLayout(tabs_and_errbuf)

        self.addWidget(self._scene_toolbar)
        self.addWidget(tabs_and_errbuf_widget)
        self.setStretchFactor(1, 1)

        self._scene_toolbar.reload_btn.clicked.connect(self._scripts_mgr.reload)  # TODO: drop
        self._scripts_mgr.error.connect(self._all_scripts_err)
        self._scripts_mgr.scriptsChanged.connect(self._scene_toolbar.on_scripts_changed)
        self._scripts_mgr.start()

        self.error.connect(self._scene_err)

        # Load the previous scene if the current and previously loaded
        # module packages match
        prev_pkgname = self._config.get('pkg')
        prev_module = self._config.get('module')
        prev_scene = self._config.get('scene')
        if prev_pkgname == module_pkgname:
            self._scene_toolbar.load_scene_from_name(prev_module, prev_scene)
class MainWindow(QtWidgets.QSplitter):

    error = QtCore.Signal(str)

    def __init__(self, module_pkgname, hooksdir):
        super(MainWindow, self).__init__(QtCore.Qt.Horizontal)
        self._win_title_base = 'Node.gl viewer'
        self.setWindowTitle(self._win_title_base)

        self._module_pkgname = module_pkgname
        self._scripts_mgr = ScriptsManager(module_pkgname)
        self._hooks_caller = HooksCaller(hooksdir)

        get_scene_func = self._get_scene

        self._config = Config(module_pkgname)

        # Apply previous geometry (position + dimensions)
        rect = self._config.get('geometry')
        if rect:
            geometry = QtCore.QRect(*rect)
            self.setGeometry(geometry)

        player_view = PlayerView(get_scene_func, self._config)
        graph_view = GraphView(get_scene_func, self._config)
        export_view = ExportView(get_scene_func, self._config)
        hooks_view = HooksView(self._hooks_caller)
        self._medias_view = MediasView(self._config)
        serial_view = SerialView(get_scene_func)

        self._tabs = [
            ('Player view', player_view),
            ('Graph view', graph_view),
            ('Export', export_view),
            ('Hooks', hooks_view),
            ('Medias', self._medias_view),
            ('Serialization', serial_view),
        ]
        self._last_tab_index = -1

        self._tab_widget = QtWidgets.QTabWidget()
        for tab_name, tab_view in self._tabs:
            self._tab_widget.addTab(tab_view, tab_name)
        self._tab_widget.currentChanged.connect(self._currentTabChanged)

        self._hooks_ctl = HooksController(self._get_scene, hooks_view,
                                          self._hooks_caller)

        self._scene_toolbar = Toolbar(self._config)
        self._scene_toolbar.sceneChanged.connect(self._scene_changed)
        self._scene_toolbar.sceneChanged.connect(self._scene_changed_hook)
        self._scene_toolbar.sceneChanged.connect(self._config.scene_changed)
        self._scene_toolbar.aspectRatioChanged.connect(
            self._config.set_aspect_ratio)
        self._scene_toolbar.samplesChanged.connect(self._config.set_samples)
        self._scene_toolbar.frameRateChanged.connect(
            self._config.set_frame_rate)
        self._scene_toolbar.logLevelChanged.connect(self._config.set_log_level)
        self._scene_toolbar.clearColorChanged.connect(
            self._config.set_clear_color)
        self._scene_toolbar.backendChanged.connect(self._config.set_backend)
        self._scene_toolbar.hudChanged.connect(self._config.set_hud)

        self._errbuf = QtWidgets.QPlainTextEdit()
        self._errbuf.setFont(
            QtGui.QFontDatabase.systemFont(QtGui.QFontDatabase.FixedFont))
        self._errbuf.setReadOnly(True)
        self._errbuf.hide()

        tabs_and_errbuf = QtWidgets.QVBoxLayout()
        tabs_and_errbuf.addWidget(self._tab_widget)
        tabs_and_errbuf.addWidget(self._errbuf)
        tabs_and_errbuf_widget = QtWidgets.QWidget()
        tabs_and_errbuf_widget.setLayout(tabs_and_errbuf)

        self.addWidget(self._scene_toolbar)
        self.addWidget(tabs_and_errbuf_widget)
        self.setStretchFactor(1, 1)

        self._scene_toolbar.reload_btn.clicked.connect(
            self._scripts_mgr.reload)  # TODO: drop
        self._scripts_mgr.error.connect(self._all_scripts_err)
        self._scripts_mgr.scriptsChanged.connect(
            self._scene_toolbar.on_scripts_changed)
        self._scripts_mgr.start()

        self.error.connect(self._scene_err)

        # Load the previous scene if the current and previously loaded
        # module packages match
        prev_pkgname = self._config.get('pkg')
        prev_module = self._config.get('module')
        prev_scene = self._config.get('scene')
        if prev_pkgname == module_pkgname:
            self._scene_toolbar.load_scene_from_name(prev_module, prev_scene)

    @QtCore.Slot(str)
    def _scene_err(self, err_str):
        if err_str:
            self._errbuf.setPlainText(err_str)
            self._errbuf.show()
            sys.stderr.write(err_str)
        else:
            self._errbuf.hide()

    @QtCore.Slot(str)
    def _all_scripts_err(self, err_str):
        self._scene_toolbar.clear_scripts()
        self._scene_err(err_str)

    def _get_scene(self, **cfg_overrides):
        cfg = self._scene_toolbar.get_cfg()
        if cfg['scene'] is None:
            return None
        cfg['pkg'] = self._module_pkgname
        medias = self._medias_view.get_medias()
        cfg['medias'] = medias if medias else None
        cfg.update(cfg_overrides)

        self._scripts_mgr.pause()
        ret = query_subproc(query='scene', **cfg)
        if 'error' in ret:
            self._scripts_mgr.update_filelist(ret['filelist'])
            self._scripts_mgr.resume()
            self.error.emit(ret['error'])
            return None

        self.error.emit(None)
        self._scripts_mgr.set_filelist(ret['filelist'])
        self._scripts_mgr.resume()
        self._scene_toolbar.set_cfg(ret)

        return ret

    @QtCore.Slot(str, str)
    def _scene_changed(self, module_name, scene_name):
        self.setWindowTitle('%s - %s.%s' %
                            (self._win_title_base, module_name, scene_name))
        self._currentTabChanged(self._tab_widget.currentIndex())

    @QtCore.Slot(str, str)
    def _scene_changed_hook(self, module_name, scene_name):
        self._hooks_ctl.process(module_name, scene_name)

    def _emit_geometry(self):
        geometry = (self.x(), self.y(), self.width(), self.height())
        self._config.geometry_changed(geometry)

    @QtCore.Slot(QtGui.QResizeEvent)
    def resizeEvent(self, resize_event):
        super(MainWindow, self).resizeEvent(resize_event)
        self._emit_geometry()

    @QtCore.Slot(QtGui.QMoveEvent)
    def moveEvent(self, move_event):
        super(MainWindow, self).moveEvent(move_event)
        self._emit_geometry()

    @QtCore.Slot(QtGui.QCloseEvent)
    def closeEvent(self, close_event):
        for name, widget in self._tabs:
            widget.close()
        super(MainWindow, self).closeEvent(close_event)

    @QtCore.Slot(int)
    def _currentTabChanged(self, index):
        next_view = self._tabs[index][1]
        prev_view = self._tabs[self._last_tab_index][1]
        if index != self._last_tab_index and hasattr(prev_view, 'leave'):
            prev_view.leave()
        if hasattr(next_view, 'enter'):
            next_view.enter()
        self._last_tab_index = index