Ejemplo n.º 1
0
class DayTimeEditor(QtGui.QMainWindow, Ui_MainWindow):

    """ This is the main editor class which handles the user interface """

    def __init__(self):

        # Init mounts
        self._mount_mgr = MountManager(None)
        self._mount_mgr.mount()

        self._plugin_mgr = PluginManager(None)
        self._plugin_mgr.load()

        QtGui.QMainWindow.__init__(self)
        self.setupUi()
        self._tree_widgets = []
        self._cmd_queue = set()

        self._update_settings_list()

        self._selected_setting_handle = None
        self._selected_setting = None
        self._selected_plugin = None
        self._current_time = 0.5
        self._on_time_changed(self.time_slider.value())
        self.set_settings_visible(False)

        self._bg_thread = Thread(target=self.updateThread)
        self._bg_thread.start()

    def set_settings_visible(self, visibility):
        if not visibility:
            self.frame_current_setting.hide()
            self.lbl_select_setting.show()
        else:
            self.frame_current_setting.show()
            self.lbl_select_setting.hide()

    def closeEvent(self, event):  # noqa
        event.accept()
        import os
        os._exit(1)

    def updateThread(self):  # noqa
        """ Seperate update thread """

        while True:
            if self._cmd_queue:
                cmd = self._cmd_queue.pop()
                if cmd == "settime":
                    NetworkCommunication.send_async(
                        NetworkCommunication.DAYTIME_PORT, "settime " + str(self._current_time))
                    continue
                elif cmd == "write_settings":
                    self._plugin_mgr.save_daytime_overrides("/$$rpconfig/daytime.yaml")
                    NetworkCommunication.send_async(
                        NetworkCommunication.DAYTIME_PORT, "loadconf")
                else:
                    print("Unkown cmd:", cmd)

            time.sleep(0.1)

    def setupUi(self):  # noqa
        """ Setups the UI Components """
        Ui_MainWindow.setupUi(self, self)
        self.settings_tree.setColumnWidth(0, 160)
        self.settings_tree.expandAll()

        self.edit_widget = CurveWidget(self)
        self.edit_widget.set_change_handler(self._on_curve_edited)
        self.prefab_edit_widget.addWidget(self.edit_widget)

        connect(self.time_slider, QtCore.SIGNAL("valueChanged(int)"), self._on_time_changed)
        connect(self.settings_tree,
                QtCore.SIGNAL("itemSelectionChanged()"), self._on_setting_selected)
        connect(self.btn_insert_point, QtCore.SIGNAL("clicked()"), self._insert_point)
        connect(self.btn_reset, QtCore.SIGNAL("clicked()"), self._reset_settings)

    def _reset_settings(self):
        """ Resets the current plugins settings """
        # QtGui.QMessageBox.warning(self, "Houston, we have a problem!",
        #     "This functionality is not yet implemented! Blame tobspr if you need it.\n\n"
        #     "On a more serious note, you can still hand-edit config/daytime.yaml.",
        #     QtGui.QMessageBox.Ok, QtGui.QMessageBox.Ok)

        # Ask the user if he's really sure about it
        msg = "Are you sure you want to reset the control points of '" +\
              self._selected_setting_handle.label + "'?\n"
        msg += "!! This cannot be undone !! They will be lost forever (a long time!)."
        reply = QtGui.QMessageBox.question(
            self, "Warning", msg, QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
        if reply == QtGui.QMessageBox.Yes:

            QtGui.QMessageBox.information(self, "Success", "Control points have been reset!")
            default = self._selected_setting_handle.default
            self._selected_setting_handle.curves[0].set_single_value(default)
            self._update_settings_list()
            self._cmd_queue.add("write_settings")

    def _insert_point(self):
        """ Asks the user to insert a new point """
        dialog = PointDialog(self)
        if dialog.exec_():
            time, val = dialog.get_value()
            minutes = (time.hour() * 60 + time.minute()) / (24 * 60)

            if (val < self._selected_setting_handle.minvalue or
               val > self._selected_setting_handle.maxvalue):
                QtGui.QMessageBox.information(
                    self, "Invalid Value", "Value is out of setting range!", QtGui.QMessageBox.Ok)
                return

            val_linear = self._selected_setting_handle.get_linear_value(val)
            self._selected_setting_handle.curves[0].append_cv(minutes, val_linear)
            self._cmd_queue.add("write_settings")

    def _update_tree_widgets(self):
        """ Updates the tree widgets """
        for setting_handle, widget in self._tree_widgets:
            value = setting_handle.get_scaled_value_at(self._current_time)
            formatted = setting_handle.format(value)
            widget.setText(1, formatted)

            if setting_handle.type == "color":
                widget.setBackground(1, QtGui.QBrush(QtGui.QColor(*value)))

    def _on_curve_edited(self):
        """ Called when the curve got edited in the curve widget """
        self._cmd_queue.add("write_settings")
        self._update_tree_widgets()

    def _on_setting_selected(self):
        """ Called when a setting got selected in the settings tree """
        selected = self.settings_tree.selectedItems()
        if len(selected) != 1:
            self._selected_setting = None
            self._selected_plugin = None
            self._selected_setting_handle = None
            self.edit_widget.set_curves([])
            self.set_settings_visible(False)
        else:
            selected = selected[0]

            self._selected_plugin = selected._plugin_id
            self._selected_setting = selected._setting_id
            self._selected_setting_handle = selected._setting_handle

            self.lbl_current_setting.setText(self._selected_setting_handle.label)
            self.lbl_setting_desc.setText(self._selected_setting_handle.description)

            self.edit_widget.set_curves(self._selected_setting_handle.curves)

            if self._selected_setting_handle.type == "color":
                self.edit_widget.set_unit_processor(lambda x: str(int(x * 255)))
                self.btn_insert_point.hide()
            else:
                self.edit_widget.set_unit_processor(
                    lambda x: self._selected_setting_handle.format(
                        self._selected_setting_handle.get_scaled_value(x)))
                self.btn_insert_point.show()

            self.set_settings_visible(True)
            self._update_tree_widgets()

    def _on_time_changed(self, val):
        """ Handler when the time slider got moved """
        hour = val // (60 * 60 * 60)
        minute = (val // (60 * 60)) % 60
        ftime = float(val) / (24 * 60 * 60 * 60)

        self.time_label.setText(str(hour).zfill(2) + ":" + str(minute).zfill(2))
        self.time_float_label.setText("{:1.4f}".format(ftime))
        self.edit_widget.set_current_time(ftime)
        self._current_time = ftime
        self._update_tree_widgets()
        self._cmd_queue.add("settime")

    def _update_settings_list(self):
        """ Updates the list of visible settings """

        self.settings_tree.clear()
        self._tree_widgets = []

        for plugin_id, plugin in iteritems(self._plugin_mgr.instances):

            daytime_settings = self._plugin_mgr.day_settings[plugin_id]

            if not daytime_settings:
                # Skip plugins with empty settings
                continue

            plugin_head = QtGui.QTreeWidgetItem(self.settings_tree)
            plugin_head.setText(0, plugin.name)
            plugin_head.setFlags(QtCore.Qt.ItemIsEnabled)
            font = QtGui.QFont()
            font.setBold(True)
            if not self._plugin_mgr.is_plugin_enabled(plugin_id):
                plugin_head.setText(0, plugin.name)
            plugin_head.setFont(0, font)

            # Display all settings
            for setting, setting_handle in iteritems(daytime_settings):
                setting_item = QtGui.QTreeWidgetItem(plugin_head)
                setting_item.setText(0, setting_handle.label)
                setting_item.setTextColor(0, QtGui.QColor(150, 150, 150))
                setting_item.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable)
                setting_item._setting_id = setting
                setting_item._setting_handle = setting_handle
                setting_item._plugin_id = plugin_id
                setting_item.setToolTip(0, setting_handle.description)
                setting_item.setToolTip(1, setting_handle.description)
                self._tree_widgets.append((setting_handle, setting_item))

        self.settings_tree.expandAll()
Ejemplo n.º 2
0
class PluginConfigurator(QtGui.QMainWindow, Ui_MainWindow):

    """ Interface to change the plugin settings """

    def __init__(self):
        # Init mounts
        self._mount_mgr = MountManager(None)
        self._mount_mgr.mount()

        self._plugin_mgr = PluginManager(None)
        self._plugin_mgr.requires_daytime_settings = False

        QtGui.QMainWindow.__init__(self)
        Ui_MainWindow.__init__(self)
        self.setupUi(self)

        self._current_plugin = None
        self._current_plugin_instance = None
        self.lbl_restart_pipeline.hide()
        self._set_settings_visible(False)
        self._update_queue = list()

        connect(self.lst_plugins, QtCore.SIGNAL("itemSelectionChanged()"),
                self.on_plugin_selected)
        connect(self.lst_plugins, QtCore.SIGNAL("itemChanged(QListWidgetItem*)"),
                self.on_plugin_state_changed)
        connect(self.btn_reset_plugin_settings, QtCore.SIGNAL("clicked()"),
                self.on_reset_plugin_settings)

        self._load_plugin_list()

        # Adjust column widths
        self.table_plugin_settings.setColumnWidth(0, 110)
        self.table_plugin_settings.setColumnWidth(1, 80)
        self.table_plugin_settings.setColumnWidth(2, 120)

        update_thread = Thread(target=self.update_thread, args=())
        update_thread.start()

    def closeEvent(self, event):  # noqa
        event.accept()
        import os
        os._exit(1)

    def on_reset_plugin_settings(self):
        """ Gets called when the user wants to reset settings of a plugin """

        # Ask the user if he's really sure about it
        msg = "Are you sure you want to reset the settings of '"
        msg += self._current_plugin_instance.name + "'?\n"
        msg += "This does not reset the Time of Day settings of this plugin.\n\n"
        msg += "!! This cannot be undone !! They will be lost forever (a long time!)."
        reply = QtGui.QMessageBox.question(
            self, "Warning", msg, QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
        if reply == QtGui.QMessageBox.Yes:

            QtGui.QMessageBox.information(
                self, "Success",
                "Settings have been reset! You may have to restart the pipeline.")
            self._plugin_mgr.reset_plugin_settings(self._current_plugin)

            # Save config
            self._plugin_mgr.save_overrides("/$$rpconfig/plugins.yaml")

            # Always show the restart hint, even if its not always required
            self._show_restart_hint()

            # Re-render everything
            self._load_plugin_list()

    def on_plugin_state_changed(self, item):
        """ Handler when a plugin got activated/deactivated """
        plugin_id = item._plugin_id
        state = item.checkState() == QtCore.Qt.Checked
        self._plugin_mgr.set_plugin_enabled(plugin_id, state)
        self._rewrite_plugin_config()
        self._show_restart_hint()

    def on_plugin_selected(self):
        """ Gets called when a plugin got selected in the plugin list """
        selected_item = self.lst_plugins.selectedItems()
        if not selected_item:
            self._current_plugin = None
            self._current_plugin_instance = None
            self._set_settings_visible(False)
            return
        assert len(selected_item) == 1
        selected_item = selected_item[0]
        self._current_plugin = selected_item._plugin_id
        self._current_plugin_instance = self._plugin_mgr.instances[self._current_plugin]
        assert(self._current_plugin_instance is not None)
        self._render_current_plugin()
        self._set_settings_visible(True)

    def update_thread(self):
        """ Internal update thread """
        while True:
            if len(self._update_queue) > 0:
                item = self._update_queue.pop(-1)
                NetworkCommunication.send_async(NetworkCommunication.CONFIG_PORT, item)

                if item.startswith("setval "):
                    setting_id = item.split()[1]
                    for entry in list(self._update_queue):
                        if entry.split()[1] == setting_id:
                            self._update_queue.remove(entry)
            time.sleep(0.2)

    def _rewrite_plugin_config(self):
        """ Rewrites the plugin configuration """
        self._plugin_mgr.save_overrides("/$$rpconfig/plugins.yaml")

    def _render_current_plugin(self):
        """ Displays the currently selected plugin """
        self.lbl_plugin_name.setText(self._current_plugin_instance.name)

        version_str = "Version " + self._current_plugin_instance.version
        version_str += " by " + self._current_plugin_instance.author

        self.lbl_plugin_version.setText(version_str)
        self.lbl_plugin_desc.setText(self._current_plugin_instance.description)

        if "(!)" in version_str:
            self.lbl_plugin_version.setStyleSheet(
                "background: rgb(200, 50, 50); padding: 5px; color: #eee;"
                "padding-left: 3px; border-radius: 3px;")
        else:
            self.lbl_plugin_version.setStyleSheet("color: #4f8027;")

        self._render_current_settings()

    def _show_restart_hint(self):
        """ Shows a hint to restart the pipeline """
        self.lbl_restart_pipeline.show()

    def _render_current_settings(self):
        """ Renders the current plugin settings """
        settings = self._plugin_mgr.settings[self._current_plugin]

        # remove all rows
        while self.table_plugin_settings.rowCount() > 0:
            self.table_plugin_settings.removeRow(0)

        label_font = QtGui.QFont()
        label_font.setPointSize(10)
        label_font.setFamily("Segoe UI")

        desc_font = QtGui.QFont()
        desc_font.setPointSize(8)
        desc_font.setFamily("Segoe UI")

        for index, (name, handle) in enumerate(iteritems(settings)):
            if not handle.should_be_visible(settings):
                continue

            row_index = self.table_plugin_settings.rowCount()

            # Increase row count
            self.table_plugin_settings.insertRow(self.table_plugin_settings.rowCount())

            label = QtGui.QLabel()
            label.setText(handle.label)
            label.setWordWrap(True)
            label.setFont(label_font)

            if handle.shader_runtime or handle.runtime:
                # label.setBackground(QtGui.QColor(200, 255, 200, 255))
                label.setStyleSheet("background: rgba(162, 204, 128, 255);")
            else:
                label.setStyleSheet("background: rgba(230, 230, 230, 255);")

            label.setMargin(10)

            self.table_plugin_settings.setCellWidget(row_index, 0, label)

            item_default = QtGui.QTableWidgetItem()
            item_default.setText(str(handle.default))
            item_default.setTextAlignment(QtCore.Qt.AlignCenter)
            self.table_plugin_settings.setItem(row_index, 1, item_default)

            setting_widget = self._get_widget_for_setting(name, handle)
            self.table_plugin_settings.setCellWidget(row_index, 2, setting_widget)

            label_desc = QtGui.QLabel()
            label_desc.setText(handle.description)
            label_desc.setWordWrap(True)
            label_desc.setFont(desc_font)
            label_desc.setStyleSheet("color: #555;padding: 5px;")

            self.table_plugin_settings.setCellWidget(row_index, 3, label_desc)

    def _do_update_setting(self, setting_id, value):
        """ Updates a setting of the current plugin """

        # Check whether the setting is a runtime setting
        setting_handle = self._plugin_mgr.get_setting_handle(
            self._current_plugin, setting_id)

        # Skip the setting in case the value is equal
        if setting_handle.value == value:
            return

        # Otherwise set the new value
        setting_handle.set_value(value)
        self._rewrite_plugin_config()

        if not setting_handle.runtime and not setting_handle.shader_runtime:
            self._show_restart_hint()
        else:
            # In case the setting is dynamic, notice the pipeline about it:
            # print("Sending reload packet ...")
            self._update_queue.append("setval {}.{} {}".format(
                self._current_plugin, setting_id, value))

        # Update GUI, but only in case of enum and bool values, since they can trigger
        # display conditions:
        if setting_handle.type == "enum" or setting_handle.type == "bool":
            self._render_current_settings()

    def _on_setting_bool_changed(self, setting_id, value):
        self._do_update_setting(setting_id, value == QtCore.Qt.Checked)

    def _on_setting_scalar_changed(self, setting_id, value):
        self._do_update_setting(setting_id, value)

    def _on_setting_enum_changed(self, setting_id, value):
        self._do_update_setting(setting_id, value)

    def _on_setting_slider_changed(self, setting_id, setting_type, bound_objs, value):
        if setting_type == "float":
            value /= 100000.0
        self._do_update_setting(setting_id, value)

        for obj in bound_objs:
            obj.setValue(value)

    def _on_setting_spinbox_changed(self, setting_id, setting_type, bound_objs, value):
        self._do_update_setting(setting_id, value)
        # Assume objects are sliders, so we need to rescale the value
        for obj in bound_objs:
            obj.setValue(value * 100000.0 if setting_type == "float" else value)

    def _choose_path(self, setting_id, setting_handle, bound_objs):
        """ Shows a file chooser to show an path from """

        this_dir = os.path.dirname(os.path.realpath(__file__))
        plugin_dir = os.path.join(this_dir, "../../rpplugins/" + self._current_plugin, "resources")
        plugin_dir = os.path.abspath(plugin_dir)
        search_dir = os.path.join(plugin_dir, setting_handle.base_path)

        print("Plugin dir =", plugin_dir)
        print("Search dir =", search_dir)

        current_file = setting_handle.value.replace("\\", "/").split("/")[-1]
        print("Current file =", current_file)
        file_dlg = QtGui.QFileDialog(self, "Choose File ..", search_dir, setting_handle.file_type)
        file_dlg.selectFile(current_file)
        # file_dlg.setViewMode(QtGui.QFileDialog.Detail)

        if file_dlg.exec_():
            filename = file_dlg.selectedFiles()
            filename = filename[-1]
            print("QT selected files returned:", filename)

            filename = os.path.relpath(str(filename), plugin_dir)
            filename = filename.replace("\\", "/")
            print("Relative path is", filename)
            self._do_update_setting(setting_id, filename)

            display_file = filename.split("/")[-1]
            for obj in bound_objs:
                obj.setText(display_file)

    def _get_widget_for_setting(self, setting_id, setting):
        """ Returns an appropriate widget to control the given setting """

        widget = QtGui.QWidget()
        layout = QtGui.QVBoxLayout()
        layout.setAlignment(QtCore.Qt.AlignCenter)
        widget.setLayout(layout)

        if setting.type == "bool":
            box = QtGui.QCheckBox()
            box.setChecked(QtCore.Qt.Checked if setting.value else QtCore.Qt.Unchecked)
            connect(box, QtCore.SIGNAL("stateChanged(int)"),
                    partial(self._on_setting_bool_changed, setting_id))
            layout.addWidget(box)

        elif setting.type == "float" or setting.type == "int":

            if setting.type == "float":
                box = QtGui.QDoubleSpinBox()

                if setting.maxval - setting.minval <= 2.0:
                    box.setDecimals(4)
            else:
                box = QtGui.QSpinBox()
            box.setMinimum(setting.minval)
            box.setMaximum(setting.maxval)
            box.setValue(setting.value)

            box.setAlignment(QtCore.Qt.AlignCenter)

            slider = QtGui.QSlider()
            slider.setOrientation(QtCore.Qt.Horizontal)

            if setting.type == "float":
                box.setSingleStep(abs(setting.maxval - setting.minval) / 100.0)
                slider.setMinimum(setting.minval * 100000.0)
                slider.setMaximum(setting.maxval * 100000.0)
                slider.setValue(setting.value * 100000.0)
            elif setting.type == "int":
                box.setSingleStep(max(1, (setting.maxval - setting.minval) / 32))
                slider.setMinimum(setting.minval)
                slider.setMaximum(setting.maxval)
                slider.setValue(setting.value)

            layout.addWidget(box)
            layout.addWidget(slider)

            connect(slider, QtCore.SIGNAL("valueChanged(int)"),
                    partial(self._on_setting_slider_changed, setting_id, setting.type, [box]))

            value_type = "int" if setting.type == "int" else "double"

            connect(box, QtCore.SIGNAL("valueChanged(" + value_type + ")"),
                    partial(self._on_setting_spinbox_changed, setting_id, setting.type, [slider]))

        elif setting.type == "enum":
            box = QtGui.QComboBox()
            for value in setting.values:
                box.addItem(value)
            connect(box, QtCore.SIGNAL("currentIndexChanged(QString)"),
                    partial(self._on_setting_enum_changed, setting_id))
            box.setCurrentIndex(setting.values.index(setting.value))

            layout.addWidget(box)

        elif setting.type == "path":

            label = QtGui.QLabel()
            display_file = setting.value.replace("\\", "/").split("/")[-1]

            desc_font = QtGui.QFont()
            desc_font.setPointSize(7)
            desc_font.setFamily("Segoe UI")

            label.setText(display_file)
            label.setFont(desc_font)

            button = QtGui.QPushButton()
            button.setText("Choose File ...")
            connect(button, QtCore.SIGNAL("clicked()"), partial(
                self._choose_path, setting_id, setting, (label,)))

            layout.addWidget(label)
            layout.addWidget(button)

        else:
            print("ERROR: Unkown setting type:", setting.type)

        return widget

    def _set_settings_visible(self, flag):
        """ Sets whether the settings panel is visible or not """
        if flag:
            self.lbl_select_plugin.hide()
            self.frame_details.show()
        else:
            self.lbl_select_plugin.show()
            self.frame_details.hide()

    def _load_plugin_list(self):
        """ Reloads the whole plugin list """
        print("Loading plugin list")

        # Reset selection
        self._current_plugin = None
        self._current_plugin_instance = None
        self._set_settings_visible(False)

        # Plugins are all plugins in the plugins directory
        self._plugin_mgr.unload()
        self._plugin_mgr.load()

        self.lst_plugins.clear()
        plugins = sorted(iteritems(self._plugin_mgr.instances), key=lambda plg: plg[1].name)

        for plugin_id, instance in plugins:

            item = QtGui.QListWidgetItem()
            item.setText(" " + instance.name)

            if self._plugin_mgr.is_plugin_enabled(plugin_id):
                item.setCheckState(QtCore.Qt.Checked)
            else:
                item.setCheckState(QtCore.Qt.Unchecked)

            item._plugin_id = plugin_id
            self.lst_plugins.addItem(item)
Ejemplo n.º 3
0
    # Extract data
    print("Extracting data ..")
    lines = data.replace("\r", "").split("\n")[1:]

    # Load render pipeline api
    print("Loading plugin api ..")
    sys.path.insert(0, "../../")
    from rpcore.pluginbase.manager import PluginManager
    from rpcore.mount_manager import MountManager


    mount_mgr = MountManager(None)
    mount_mgr.mount()

    plugin_mgr = PluginManager(None)
    plugin_mgr.load()

    convert_to_linear = plugin_mgr.day_settings["scattering"]["sun_intensity"].get_linear_value

    hour, minutes = 0, 0

    data_points_azimuth = []
    data_points_altitude = []
    data_points_intensity = []

    for line in lines:
        if not line:
            break
        date, time, azim_angle, declination, ascension, elevation = line.split(",")

        float_azim = (float(azim_angle) + 180) / 360
Ejemplo n.º 4
0
class PluginConfigurator(QMainWindow, Ui_MainWindow):
    """ Interface to change the plugin settings """
    def __init__(self):

        # Init mounts
        self._mount_mgr = MountManager(None)
        self._mount_mgr.mount()

        self._plugin_mgr = PluginManager(None)
        self._plugin_mgr.requires_daytime_settings = False

        QMainWindow.__init__(self)
        Ui_MainWindow.__init__(self)
        self.setupUi(self)

        self._current_plugin = None
        self._current_plugin_instance = None
        self.lbl_restart_pipeline.hide()
        self._set_settings_visible(False)
        self._update_queue = list()

        qt_connect(self.lst_plugins, "itemSelectionChanged()",
                   self.on_plugin_selected)
        qt_connect(self.lst_plugins, "itemChanged(QListWidgetItem*)",
                   self.on_plugin_state_changed)
        qt_connect(self.btn_reset_plugin_settings, "clicked()",
                   self.on_reset_plugin_settings)

        self._load_plugin_list()

        # Adjust column widths
        self.table_plugin_settings.setColumnWidth(0, 140)
        self.table_plugin_settings.setColumnWidth(1, 105)
        self.table_plugin_settings.setColumnWidth(2, 160)

        update_thread = Thread(target=self.update_thread, args=())
        update_thread.start()

    def closeEvent(self, event):  # noqa
        event.accept()
        import os
        os._exit(1)

    def on_reset_plugin_settings(self):
        """ Gets called when the user wants to reset settings of a plugin """

        # Ask the user if he's really sure about it
        msg = "Are you sure you want to reset the settings of '"
        msg += self._current_plugin_instance.name + "'?\n"
        msg += "This does not reset the Time of Day settings of this plugin.\n\n"
        msg += "!! This cannot be undone !! They will be lost forever (a long time!)."
        reply = QMessageBox.question(self, "Warning", msg, QMessageBox.Yes,
                                     QMessageBox.No)
        if reply == QMessageBox.Yes:

            QMessageBox.information(
                self, "Success",
                "Settings have been reset! You may have to restart the pipeline."
            )
            self._plugin_mgr.reset_plugin_settings(self._current_plugin)

            # Save config
            self._plugin_mgr.save_overrides("/$$rp/config/plugins.yaml")

            # Always show the restart hint, even if its not always required
            self._show_restart_hint()

            # Re-render everything
            self._load_plugin_list()

    def on_plugin_state_changed(self, item):
        """ Handler when a plugin got activated/deactivated """
        plugin_id = item._plugin_id
        state = item.checkState() == Qt.Checked
        self._plugin_mgr.set_plugin_enabled(plugin_id, state)
        self._rewrite_plugin_config()
        self._show_restart_hint()

    def on_plugin_selected(self):
        """ Gets called when a plugin got selected in the plugin list """
        selected_item = self.lst_plugins.selectedItems()
        if not selected_item:
            self._current_plugin = None
            self._current_plugin_instance = None
            self._set_settings_visible(False)
            return
        assert len(selected_item) == 1
        selected_item = selected_item[0]
        self._current_plugin = selected_item._plugin_id
        self._current_plugin_instance = self._plugin_mgr.instances[
            self._current_plugin]
        assert (self._current_plugin_instance is not None)
        self._render_current_plugin()
        self._set_settings_visible(True)

    def update_thread(self):
        """ Internal update thread """
        while True:
            if len(self._update_queue) > 0:
                item = self._update_queue.pop(-1)
                NetworkCommunication.send_async(
                    NetworkCommunication.CONFIG_PORT, item)

                if item.startswith("setval "):
                    setting_id = item.split()[1]
                    for entry in list(self._update_queue):
                        if entry.split()[1] == setting_id:
                            self._update_queue.remove(entry)
            time.sleep(0.2)

    def _rewrite_plugin_config(self):
        """ Rewrites the plugin configuration """
        self._plugin_mgr.save_overrides("/$$rp/config/plugins.yaml")

    def _render_current_plugin(self):
        """ Displays the currently selected plugin """
        self.lbl_plugin_name.setText(
            self._current_plugin_instance.name.upper() +
            " <span style='color: #999; margin-left: 5px;'>[" +
            self._current_plugin_instance.plugin_id + "]</span>")

        version_str = "Version " + self._current_plugin_instance.version
        version_str += " by " + self._current_plugin_instance.author

        self.lbl_plugin_version.setText(version_str)
        self.lbl_plugin_desc.setText(self._current_plugin_instance.description)

        self._render_current_settings()

    def _show_restart_hint(self):
        """ Shows a hint to restart the pipeline """
        self.lbl_restart_pipeline.show()

    def _render_current_settings(self):
        """ Renders the current plugin settings """
        settings = self._plugin_mgr.settings[self._current_plugin]

        # remove all rows
        while self.table_plugin_settings.rowCount() > 0:
            self.table_plugin_settings.removeRow(0)

        label_font = QFont()
        label_font.setPointSize(10)
        label_font.setFamily("Roboto")

        desc_font = QFont()
        desc_font.setPointSize(8)
        desc_font.setFamily("Roboto")

        for index, (name, handle) in enumerate(iteritems(settings)):
            if not handle.should_be_visible(settings):
                continue

            row_index = self.table_plugin_settings.rowCount()

            # Increase row count
            self.table_plugin_settings.insertRow(
                self.table_plugin_settings.rowCount())

            label = QLabel()
            label.setText(handle.label)
            label.setWordWrap(True)
            label.setFont(label_font)

            if not (handle.shader_runtime or handle.runtime):
                label.setStyleSheet("color: #999;")

            if handle.display_conditions:
                label.setStyleSheet(label.styleSheet() + "padding-left: 10px;")

            label.setMargin(10)

            self.table_plugin_settings.setCellWidget(row_index, 0, label)

            item_default = QTableWidgetItem()
            item_default.setText(str(handle.default))
            item_default.setTextAlignment(Qt.AlignCenter)
            self.table_plugin_settings.setItem(row_index, 1, item_default)

            setting_widget = self._get_widget_for_setting(name, handle)
            self.table_plugin_settings.setCellWidget(row_index, 2,
                                                     setting_widget)

            label_desc = QLabel()
            label_desc.setText(handle.description)
            label_desc.setWordWrap(True)
            label_desc.setFont(desc_font)
            label_desc.setStyleSheet("color: #555;padding: 5px;")

            self.table_plugin_settings.setCellWidget(row_index, 3, label_desc)

    def _do_update_setting(self, setting_id, value):
        """ Updates a setting of the current plugin """

        # Check whether the setting is a runtime setting
        setting_handle = self._plugin_mgr.get_setting_handle(
            self._current_plugin, setting_id)

        # Skip the setting in case the value is equal
        if setting_handle.value == value:
            return

        # Otherwise set the new value
        setting_handle.set_value(value)
        self._rewrite_plugin_config()

        if not setting_handle.runtime and not setting_handle.shader_runtime:
            self._show_restart_hint()
        else:
            # In case the setting is dynamic, notice the pipeline about it:
            # print("Sending reload packet ...")
            self._update_queue.append("setval {}.{} {}".format(
                self._current_plugin, setting_id, value))

        # Update GUI, but only in case of enum and bool values, since they can trigger
        # display conditions:
        if setting_handle.type == "enum" or setting_handle.type == "bool":
            self._render_current_settings()

    def _on_setting_bool_changed(self, setting_id, value):
        self._do_update_setting(setting_id, value == Qt.Checked)

    def _on_setting_scalar_changed(self, setting_id, value):
        self._do_update_setting(setting_id, value)

    def _on_setting_enum_changed(self, setting_id, value):
        self._do_update_setting(setting_id, value)

    def _on_setting_power_of_two_changed(self, setting_id, value):
        self._do_update_setting(setting_id, value)

    def _on_setting_slider_changed(self, setting_id, setting_type, bound_objs,
                                   value):
        if setting_type == "float":
            value /= 100000.0
        self._do_update_setting(setting_id, value)

        for obj in bound_objs:
            obj.setValue(value)

    def _on_setting_spinbox_changed(self, setting_id, setting_type, bound_objs,
                                    value):
        self._do_update_setting(setting_id, value)
        # Assume objects are sliders, so we need to rescale the value
        for obj in bound_objs:
            obj.setValue(value *
                         100000.0 if setting_type == "float" else value)

    def _choose_path(self, setting_id, setting_handle, bound_objs):
        """ Shows a file chooser to show an path from """

        this_dir = os.path.dirname(os.path.realpath(__file__))
        plugin_dir = os.path.join(this_dir,
                                  "../../rpplugins/" + self._current_plugin,
                                  "resources")
        plugin_dir = os.path.abspath(plugin_dir)
        search_dir = os.path.join(plugin_dir, setting_handle.base_path)

        print("Plugin dir =", plugin_dir)
        print("Search dir =", search_dir)

        current_file = setting_handle.value.replace("\\", "/").split("/")[-1]
        print("Current file =", current_file)
        file_dlg = QFileDialog(self, "Choose File ..", search_dir,
                               setting_handle.file_type)
        file_dlg.selectFile(current_file)
        # file_dlg.setViewMode(QFileDialog.Detail)

        if file_dlg.exec_():
            filename = file_dlg.selectedFiles()
            filename = filename[-1]
            print("QT selected files returned:", filename)

            filename = os.path.relpath(str(filename), plugin_dir)
            filename = filename.replace("\\", "/")
            print("Relative path is", filename)
            self._do_update_setting(setting_id, filename)

            display_file = filename.split("/")[-1]
            for obj in bound_objs:
                obj.setText(display_file)

    def _get_widget_for_setting(self, setting_id, setting):
        """ Returns an appropriate widget to control the given setting """

        widget = QWidget()
        layout = QHBoxLayout()
        layout.setAlignment(Qt.AlignCenter)
        widget.setLayout(layout)

        if setting.type == "bool":
            box = QCheckBox()
            box.setChecked(Qt.Checked if setting.value else Qt.Unchecked)
            qt_connect(box, "stateChanged(int)",
                       partial(self._on_setting_bool_changed, setting_id))
            layout.addWidget(box)

        elif setting.type == "float" or setting.type == "int":

            if setting.type == "float":
                box = QDoubleSpinBox()

                if setting.maxval - setting.minval <= 2.0:
                    box.setDecimals(4)
            else:
                box = QSpinBox()
            box.setMinimum(setting.minval)
            box.setMaximum(setting.maxval)
            box.setValue(setting.value)

            box.setAlignment(Qt.AlignCenter)

            slider = QSlider()
            slider.setOrientation(Qt.Horizontal)

            if setting.type == "float":
                box.setSingleStep(abs(setting.maxval - setting.minval) / 100.0)
                slider.setMinimum(setting.minval * 100000.0)
                slider.setMaximum(setting.maxval * 100000.0)
                slider.setValue(setting.value * 100000.0)
            elif setting.type == "int":
                box.setSingleStep(
                    max(1, (setting.maxval - setting.minval) / 32))
                slider.setMinimum(setting.minval)
                slider.setMaximum(setting.maxval)
                slider.setValue(setting.value)

            layout.addWidget(box)
            layout.addWidget(slider)

            qt_connect(
                slider, "valueChanged(int)",
                partial(self._on_setting_slider_changed, setting_id,
                        setting.type, [box]))

            value_type = "int" if setting.type == "int" else "double"

            qt_connect(
                box, "valueChanged(" + value_type + ")",
                partial(self._on_setting_spinbox_changed, setting_id,
                        setting.type, [slider]))

        elif setting.type == "enum":
            box = QComboBox()
            for value in setting.values:
                box.addItem(value)
            qt_connect(box, "currentIndexChanged(QString)",
                       partial(self._on_setting_enum_changed, setting_id))
            box.setCurrentIndex(setting.values.index(setting.value))
            box.setMinimumWidth(145)

            layout.addWidget(box)

        elif setting.type == "power_of_two":

            box = QComboBox()
            resolutions = [
                str(2**i) for i in range(1, 32)
                if 2**i >= setting.minval and 2**i <= setting.maxval
            ]
            for value in resolutions:
                box.addItem(value)
            qt_connect(
                box, "currentIndexChanged(QString)",
                partial(self._on_setting_power_of_two_changed, setting_id))
            box.setCurrentIndex(resolutions.index(str(setting.value)))
            box.setMinimumWidth(145)
            layout.addWidget(box)

        elif setting.type == "sample_sequence":

            box = QComboBox()
            for value in setting.sequences:
                box.addItem(value)
            qt_connect(box, "currentIndexChanged(QString)",
                       partial(self._on_setting_enum_changed, setting_id))
            box.setCurrentIndex(setting.sequences.index(str(setting.value)))
            box.setMinimumWidth(145)
            layout.addWidget(box)

        elif setting.type == "path":

            label = QLabel()
            display_file = setting.value.replace("\\", "/").split("/")[-1]

            desc_font = QFont()
            desc_font.setPointSize(7)
            desc_font.setFamily("Roboto")

            label.setText(display_file)
            label.setFont(desc_font)

            button = QPushButton()
            button.setText("Choose File ...")
            qt_connect(
                button, "clicked()",
                partial(self._choose_path, setting_id, setting, (label, )))

            layout.addWidget(label)
            layout.addWidget(button)

        else:
            print("ERROR: Unkown setting type:", setting.type)

        return widget

    def _set_settings_visible(self, flag):
        """ Sets whether the settings panel is visible or not """
        if flag:
            self.frame_details.show()
        else:
            self.frame_details.hide()

    def _load_plugin_list(self):
        """ Reloads the whole plugin list """
        print("Loading plugin list")

        # Reset selection
        self._current_plugin = None
        self._current_plugin_instance = None
        self._set_settings_visible(False)

        # Plugins are all plugins in the plugins directory
        self._plugin_mgr.unload()
        self._plugin_mgr.load()

        self.lst_plugins.clear()
        plugins = sorted(iteritems(self._plugin_mgr.instances),
                         key=lambda plg: plg[1].name)

        item_font = QFont()
        item_font.setBold(False)
        item_font.setPointSize(10)

        for plugin_id, instance in plugins:

            item = QListWidgetItem()
            item.setText(" " + instance.name)
            item.setFont(item_font)

            if self._plugin_mgr.is_plugin_enabled(plugin_id):
                item.setCheckState(Qt.Checked)
            else:
                item.setCheckState(Qt.Unchecked)

            item._plugin_id = plugin_id
            self.lst_plugins.addItem(item)

        self.lst_plugins.setCurrentRow(0)
Ejemplo n.º 5
0
class DayTimeEditor(QMainWindow, Ui_MainWindow):

    """ This is the main editor class which handles the user interface """

    def __init__(self):

        # Init mounts
        self._mount_mgr = MountManager(None)
        self._mount_mgr.mount()

        self._plugin_mgr = PluginManager(None)
        self._plugin_mgr.load()

        QMainWindow.__init__(self)
        self.setupUi()
        self._tree_widgets = []
        self._cmd_queue = set()

        self._selected_setting_handle = None
        self._selected_setting = None
        self._selected_plugin = None
        self._current_time = 0.5

        self._update_settings_list()
        self._on_time_changed(self.time_slider.value())

        self._bg_thread = Thread(target=self.updateThread)
        self._bg_thread.start()

    def set_settings_visible(self, visibility):
        if not visibility:
            self.frame_current_setting.hide()
        else:
            self.frame_current_setting.show()

    def closeEvent(self, event):  # noqa
        event.accept()
        import os
        os._exit(1)

    def updateThread(self):  # noqa
        """ Seperate update thread """

        while True:
            if self._cmd_queue:
                cmd = self._cmd_queue.pop()
                if cmd == "settime":
                    NetworkCommunication.send_async(
                        NetworkCommunication.DAYTIME_PORT, "settime " + str(self._current_time))
                    continue
                elif cmd == "write_settings":
                    self._plugin_mgr.save_daytime_overrides("/$$rp/config/daytime.yaml")
                    NetworkCommunication.send_async(
                        NetworkCommunication.DAYTIME_PORT, "loadconf")
                else:
                    print("Unkown cmd:", cmd)

            time.sleep(0.1)

    def setupUi(self):  # noqa
        """ Setups the UI Components """
        Ui_MainWindow.setupUi(self, self)
        self.settings_tree.setColumnWidth(0, 160)
        self.settings_tree.expandAll()

        self.edit_widget = CurveWidget(self)
        self.edit_widget.set_change_handler(self._on_curve_edited)
        self.prefab_edit_widget.addWidget(self.edit_widget)

        qt_connect(self.time_slider, "valueChanged(int)", self._on_time_changed)
        qt_connect(self.settings_tree, "itemSelectionChanged()", self._on_setting_selected)
        qt_connect(self.btn_insert_point, "clicked()", self._insert_point)
        qt_connect(self.btn_reset, "clicked()", self._reset_settings)

    def _reset_settings(self):
        """ Resets the current plugins settings """
        # QMessageBox.warning(self, "Houston, we have a problem!",
        #     "This functionality is not yet implemented! Blame tobspr if you need it.\n\n"
        #     "On a more serious note, you can still hand-edit config/daytime.yaml.",
        #     QMessageBox.Ok, QMessageBox.Ok)

        # Ask the user if he's really sure about it
        msg = "Are you sure you want to reset the control points of '" +\
              self._selected_setting_handle.label + "'?\n"
        msg += "!! This cannot be undone !! They will be lost forever (a long time!)."
        reply = QMessageBox.question(
            self, "Warning", msg, QMessageBox.Yes, QMessageBox.No)
        if reply == QMessageBox.Yes:

            QMessageBox.information(self, "Success", "Control points have been reset!")
            default = self._selected_setting_handle.default
            if type(default) not in (tuple, list):
                default = [default]
            for i, val, in enumerate(default):
                self._selected_setting_handle.curves[i].set_single_value(val)
            self._update_settings_list()
            self._cmd_queue.add("write_settings")

    def _insert_point(self):
        """ Asks the user to insert a new point """
        dialog = PointDialog(self)
        if dialog.exec_():
            time, val = dialog.get_value()
            minutes = (time.hour() * 60 + time.minute()) / (24 * 60)

            if (val < self._selected_setting_handle.minvalue or
               val > self._selected_setting_handle.maxvalue):
                QMessageBox.information(
                    self, "Invalid Value", "Value is out of setting range!", QMessageBox.Ok)
                return

            val_linear = self._selected_setting_handle.get_linear_value(val)
            self._selected_setting_handle.curves[0].append_cv(minutes, val_linear)
            self._cmd_queue.add("write_settings")

    def _update_tree_widgets(self):
        """ Updates the tree widgets """
        for setting_handle, widget in self._tree_widgets:
            value = setting_handle.get_scaled_value_at(self._current_time)
            formatted = setting_handle.format(value)
            widget.setText(1, formatted)

            if setting_handle.type == "color":
                widget.setBackground(1, QBrush(QColor(*value)))

    def _on_curve_edited(self):
        """ Called when the curve got edited in the curve widget """
        self._cmd_queue.add("write_settings")
        self._update_tree_widgets()

    def _on_setting_selected(self):
        """ Called when a setting got selected in the settings tree """
        selected = self.settings_tree.selectedItems()
        if len(selected) != 1:
            self._selected_setting = None
            self._selected_plugin = None
            self._selected_setting_handle = None
            self.edit_widget.set_curves([])
            self.set_settings_visible(False)
        else:
            selected = selected[0]

            self._selected_plugin = selected._plugin_id
            self._selected_setting = selected._setting_id
            self._selected_setting_handle = selected._setting_handle

            self.lbl_current_setting.setText(self._selected_setting_handle.label)
            self.lbl_setting_desc.setText(self._selected_setting_handle.description)

            self.edit_widget.set_curves(self._selected_setting_handle.curves)

            if self._selected_setting_handle.type == "color":
                self.edit_widget.set_unit_processor(lambda x: str(int(x * 255)))
                self.btn_insert_point.hide()
            else:
                self.edit_widget.set_unit_processor(
                    lambda x: self._selected_setting_handle.format(
                        self._selected_setting_handle.get_scaled_value(x)))
                self.btn_insert_point.show()

            self.set_settings_visible(True)
            self._update_tree_widgets()

    def _on_time_changed(self, val):
        """ Handler when the time slider got moved """
        hour = val // (60 * 60 * 60)
        minute = (val // (60 * 60)) % 60
        ftime = float(val) / (24 * 60 * 60 * 60)

        self.time_label.setText(str(hour).zfill(2) + ":" + str(minute).zfill(2))
        self.time_float_label.setText("{:1.4f}".format(ftime))
        self.edit_widget.set_current_time(ftime)
        self._current_time = ftime
        self._update_tree_widgets()
        self._cmd_queue.add("settime")

    def _update_settings_list(self):
        """ Updates the list of visible settings """

        self.settings_tree.clear()
        self._tree_widgets = []

        first_item = None

        for plugin_id, plugin in iteritems(self._plugin_mgr.instances):

            daytime_settings = self._plugin_mgr.day_settings[plugin_id]

            if not daytime_settings:
                # Skip plugins with empty settings
                continue

            plugin_head = QTreeWidgetItem(self.settings_tree)
            plugin_head.setText(0, plugin.name)
            plugin_head.setFlags(Qt.ItemIsEnabled)
            font = QFont()
            font.setBold(True)
            if not self._plugin_mgr.is_plugin_enabled(plugin_id):
                plugin_head.setText(0, plugin.name)
            plugin_head.setFont(0, font)

            # Display all settings
            for setting, setting_handle in iteritems(daytime_settings):
                setting_item = QTreeWidgetItem(plugin_head)
                setting_item.setText(0, setting_handle.label)
                if PYQT_VERSION == 4:
                    setting_item.setTextColor(0, QColor(150, 150, 150))
                else:
                    setting_item.setForeground(0, QColor(150, 150, 150))
                setting_item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable)
                setting_item._setting_id = setting
                setting_item._setting_handle = setting_handle
                setting_item._plugin_id = plugin_id
                setting_item.setToolTip(0, setting_handle.description)
                setting_item.setToolTip(1, setting_handle.description)
                self._tree_widgets.append((setting_handle, setting_item))
                if not first_item:
                    first_item = setting_item

        self.settings_tree.expandAll()
        if first_item:
            self.settings_tree.setCurrentItem(first_item)
Ejemplo n.º 6
0
    # Extract data
    print("Extracting data ..")
    lines = data.replace("\r", "").split("\n")[1:]

    # Load render pipeline api
    print("Loading plugin api ..")
    sys.path.insert(0, "../../")
    from rpcore.pluginbase.manager import PluginManager
    from rpcore.mount_manager import MountManager

    mount_mgr = MountManager(None)
    mount_mgr.mount()

    plugin_mgr = PluginManager(None)
    plugin_mgr.load()

    convert_to_linear = plugin_mgr.day_settings["scattering"][
        "sun_intensity"].get_linear_value

    hour, minutes = 0, 0

    data_points_azimuth = []
    data_points_altitude = []
    data_points_intensity = []

    for line in lines:
        if not line:
            break
        date, time, azim_angle, declination, ascension, elevation = line.split(
            ",")