summaryrefslogtreecommitdiffstats
path: root/src/extension/prefdialog/parameter-notebook.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/extension/prefdialog/parameter-notebook.cpp')
-rw-r--r--src/extension/prefdialog/parameter-notebook.cpp285
1 files changed, 285 insertions, 0 deletions
diff --git a/src/extension/prefdialog/parameter-notebook.cpp b/src/extension/prefdialog/parameter-notebook.cpp
new file mode 100644
index 0000000..2f431db
--- /dev/null
+++ b/src/extension/prefdialog/parameter-notebook.cpp
@@ -0,0 +1,285 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/** \file
+ * Notebook and NotebookPage parameters for extensions.
+ */
+
+/*
+ * Authors:
+ * Johan Engelen <johan@shouraizou.nl>
+ * Jon A. Cruz <jon@joncruz.org>
+ *
+ * Copyright (C) 2006 Author
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#include "parameter-notebook.h"
+
+#include <unordered_set>
+
+#include <gtkmm/box.h>
+#include <gtkmm/notebook.h>
+
+#include "preferences.h"
+
+#include "extension/extension.h"
+
+#include "xml/node.h"
+
+namespace Inkscape {
+namespace Extension {
+
+
+ParamNotebook::ParamNotebookPage::ParamNotebookPage(Inkscape::XML::Node *xml, Inkscape::Extension::Extension *ext)
+ : InxParameter(xml, ext)
+{
+ // Read XML tree of page and parse parameters
+ if (xml) {
+ Inkscape::XML::Node *child_repr = xml->firstChild();
+ while (child_repr) {
+ const char *chname = child_repr->name();
+ if (!strncmp(chname, INKSCAPE_EXTENSION_NS_NC, strlen(INKSCAPE_EXTENSION_NS_NC))) {
+ chname += strlen(INKSCAPE_EXTENSION_NS);
+ }
+ if (chname[0] == '_') { // allow leading underscore in tag names for backwards-compatibility
+ chname++;
+ }
+
+ if (InxWidget::is_valid_widget_name(chname)) {
+ InxWidget *widget = InxWidget::make(child_repr, _extension);
+ if (widget) {
+ _children.push_back(widget);
+ }
+ } else if (child_repr->type() == XML::NodeType::ELEMENT_NODE) {
+ g_warning("Invalid child element ('%s') in notebook page in extension '%s'.",
+ chname, _extension->get_id());
+ } else if (child_repr->type() != XML::NodeType::COMMENT_NODE){
+ g_warning("Invalid child element found in notebook page in extension '%s'.", _extension->get_id());
+ }
+
+ child_repr = child_repr->next();
+ }
+ }
+}
+
+
+/**
+ * Creates a notebookpage widget for a notebook.
+ *
+ * Builds a notebook page (a vbox) and puts parameters on it.
+ */
+Gtk::Widget *ParamNotebook::ParamNotebookPage::get_widget(sigc::signal<void> *changeSignal)
+{
+ if (_hidden) {
+ return nullptr;
+ }
+
+ Gtk::Box * vbox = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_VERTICAL));
+ vbox->set_border_width(GUI_BOX_MARGIN);
+ vbox->set_spacing(GUI_BOX_SPACING);
+
+ // add parameters onto page (if any)
+ for (auto child : _children) {
+ Gtk::Widget *child_widget = child->get_widget(changeSignal);
+ if (child_widget) {
+ int indent = child->get_indent();
+ child_widget->set_margin_start(indent *GUI_INDENTATION);
+ vbox->pack_start(*child_widget, false, true, 0); // fill=true does not have an effect here, but allows the
+ // child to choose to expand by setting hexpand/vexpand
+
+ const char *tooltip = child->get_tooltip();
+ if (tooltip) {
+ child_widget->set_tooltip_text(tooltip);
+ }
+ }
+ }
+
+ vbox->show();
+
+ return dynamic_cast<Gtk::Widget *>(vbox);
+}
+
+/** End ParamNotebookPage **/
+
+
+
+/** ParamNotebook **/
+
+ParamNotebook::ParamNotebook(Inkscape::XML::Node *xml, Inkscape::Extension::Extension *ext)
+ : InxParameter(xml, ext)
+{
+ // Read XML tree to add pages (allow _page for backwards compatibility)
+ if (xml) {
+ Inkscape::XML::Node *child_repr = xml->firstChild();
+ while (child_repr) {
+ const char *chname = child_repr->name();
+ if (chname && (!strcmp(chname, INKSCAPE_EXTENSION_NS "page") ||
+ !strcmp(chname, INKSCAPE_EXTENSION_NS "_page") )) {
+ ParamNotebookPage *page;
+ page = new ParamNotebookPage(child_repr, ext);
+
+ if (page) {
+ _children.push_back(page);
+ }
+ } else if (child_repr->type() == XML::NodeType::ELEMENT_NODE) {
+ g_warning("Invalid child element ('%s') for parameter '%s' in extension '%s'. Expected 'page'.",
+ chname, _name, _extension->get_id());
+ } else if (child_repr->type() != XML::NodeType::COMMENT_NODE){
+ g_warning("Invalid child element found in parameter '%s' in extension '%s'. Expected 'page'.",
+ _name, _extension->get_id());
+ }
+ child_repr = child_repr->next();
+ }
+ }
+ if (_children.empty()) {
+ g_warning("No (valid) pages for parameter '%s' in extension '%s'", _name, _extension->get_id());
+ }
+
+ // check for duplicate page names
+ std::unordered_set<std::string> names;
+ for (auto child : _children) {
+ ParamNotebookPage *page = static_cast<ParamNotebookPage *>(child);
+ auto ret = names.emplace(page->_name);
+ if (!ret.second) {
+ g_warning("Duplicate page name ('%s') for parameter '%s' in extension '%s'.",
+ page->_name, _name, _extension->get_id());
+ }
+ }
+
+ // get value (initialize with value of first page if pref is empty)
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ _value = prefs->getString(pref_name());
+
+ if (_value.empty()) {
+ if (!_children.empty()) {
+ ParamNotebookPage *first_page = dynamic_cast<ParamNotebookPage *>(_children[0]);
+ _value = first_page->_name;
+ }
+ }
+}
+
+
+/**
+ * A function to set the \c _value.
+ *
+ * This function sets the internal value, but it also sets the value
+ * in the preferences structure. To put it in the right place \c pref_name() is used.
+ *
+ * @param in The number of the page to set as new value.
+ */
+const Glib::ustring& ParamNotebook::set(const int in)
+{
+ int i = in < _children.size() ? in : _children.size()-1;
+ ParamNotebookPage *page = dynamic_cast<ParamNotebookPage *>(_children[i]);
+
+ if (page) {
+ _value = page->_name;
+
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ prefs->setString(pref_name(), _value);
+ }
+
+ return _value;
+}
+
+std::string ParamNotebook::value_to_string() const
+{
+ return _value.raw();
+}
+
+
+/** A special category of Gtk::Notebook to handle notebook parameters. */
+class NotebookWidget : public Gtk::Notebook {
+private:
+ ParamNotebook *_pref;
+public:
+ /**
+ * Build a notebookpage preference for the given parameter.
+ * @param pref Where to get the string (pagename) from, and where to put it when it changes.
+ */
+ NotebookWidget(ParamNotebook *pref)
+ : Gtk::Notebook()
+ , _pref(pref)
+ , activated(false)
+ {
+ // don't have to set the correct page: this is done in ParamNotebook::get_widget hook function
+ this->signal_switch_page().connect(sigc::mem_fun(this, &NotebookWidget::changed_page));
+ }
+
+ void changed_page(Gtk::Widget *page, guint pagenum);
+
+ bool activated;
+};
+
+/**
+ * Respond to the selected page of notebook changing.
+ * This function responds to the changing by reporting it to
+ * ParamNotebook. The change is only reported when the notebook
+ * is actually visible. This to exclude 'fake' changes when the
+ * notebookpages are added or removed.
+ */
+void NotebookWidget::changed_page(Gtk::Widget * /*page*/, guint pagenum)
+{
+ if (get_visible()) {
+ _pref->set((int)pagenum);
+ }
+}
+
+/**
+ * Creates a Notebook widget for a notebook parameter.
+ *
+ * Builds a notebook and puts pages in it.
+ */
+Gtk::Widget *ParamNotebook::get_widget(sigc::signal<void> *changeSignal)
+{
+ if (_hidden) {
+ return nullptr;
+ }
+
+ NotebookWidget *notebook = Gtk::manage(new NotebookWidget(this));
+
+ // add pages (if any) and switch to previously selected page
+ int current_page = -1;
+ int selected_page = -1;
+ for (auto child : _children) {
+ ParamNotebookPage *page = dynamic_cast<ParamNotebookPage *>(child);
+ g_assert(child); // A ParamNotebook has only children of type ParamNotebookPage.
+ // If we receive a non-page child here something is very wrong!
+ current_page++;
+
+ Gtk::Widget *page_widget = page->get_widget(changeSignal);
+
+ Glib::ustring page_text = page->_text;
+ if (page->_translatable != NO) { // translate unless explicitly marked untranslatable
+ page_text = page->get_translation(page_text.c_str());
+ }
+
+ notebook->append_page(*page_widget, page_text);
+
+ if (_value == page->_name) {
+ selected_page = current_page;
+ }
+ }
+ if (selected_page >= 0) {
+ notebook->set_current_page(selected_page);
+ }
+
+ notebook->show();
+
+ return static_cast<Gtk::Widget *>(notebook);
+}
+
+
+} // namespace Extension
+} // namespace Inkscape
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :