From 91ba2c8438d995a31b48f685a6c17bf1bf4e2ab5 Mon Sep 17 00:00:00 2001 From: johanengelen Date: Thu, 14 Sep 2006 22:14:19 +0000 Subject: [PATCH] Added notebook (tabs) support for Effects. Now you can specify a notebook parameter in the .inx file, and create pages. Will commit a new effect that uses this, so there will be an example. --- src/extension/parameter.cpp | 9 +- src/extension/paramnotebook.cpp | 431 ++++++++++++++++++++++++++++++++ src/extension/paramnotebook.h | 68 +++++ 3 files changed, 506 insertions(+), 2 deletions(-) create mode 100644 src/extension/paramnotebook.cpp create mode 100644 src/extension/paramnotebook.h diff --git a/src/extension/parameter.cpp b/src/extension/parameter.cpp index a034022d9..a821a626d 100644 --- a/src/extension/parameter.cpp +++ b/src/extension/parameter.cpp @@ -3,10 +3,11 @@ */ /* - * Authors: + * Author: * Ted Gould * - * Copyright (C) 2005-2006 Authors + * Copyright (C) 2006 Johan Engelen + * Copyright (C) 2005-2006 Author * * Released under GNU GPL, read the file 'COPYING' for more information */ @@ -30,6 +31,7 @@ #include "sp-object.h" #include "parameter.h" +#include "paramnotebook.h" /** \brief The root directory in the preferences database for extension related parameters. */ @@ -239,6 +241,7 @@ public: Glib::ustring * string (void); }; /* class ParamEnum */ + /** \return None \brief This function creates a parameter that can be used later. This @@ -310,6 +313,8 @@ Parameter::make (Inkscape::XML::Node * in_repr, Inkscape::Extension::Extension * param = new ParamDescription(name, guitext, desc, scope, in_ext, in_repr); } else if (!strcmp(type, "enum")) { param = new ParamEnum(name, guitext, desc, scope, in_ext, in_repr); + } else if (!strcmp(type, "notebook")) { + param = new ParamNotebook(name, guitext, desc, scope, in_ext, in_repr); } /* Note: param could equal NULL */ diff --git a/src/extension/paramnotebook.cpp b/src/extension/paramnotebook.cpp new file mode 100644 index 000000000..a44f83692 --- /dev/null +++ b/src/extension/paramnotebook.cpp @@ -0,0 +1,431 @@ +/** \file + * Notebook and NotebookPage parameters for extensions. + */ + +/* + * Author: + * Johan Engelen + * + * Copyright (C) 2006 Author + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + + +#include +#include +#include +#include +#include + +#include + +#include + +#include "extension.h" +#include "prefs-utils.h" +#include "document-private.h" +#include "sp-object.h" + +#include "paramnotebook.h" + +/** \brief The root directory in the preferences database for extension + related parameters. */ +#define PREF_DIR "extensions" + +namespace Inkscape { +namespace Extension { + + +// \brief A class to represent the pages of a notebookparameter of an extension +class ParamNotebookPage : public Parameter { +private: + GSList * parameters; /**< A table to store the parameters for this page. + This only gets created if there are parameters on this + page */ + Gtk::Tooltips _tooltips; + +public: + static ParamNotebookPage * makepage (Inkscape::XML::Node * in_repr, Inkscape::Extension::Extension * in_ext); + + ParamNotebookPage(const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml); + ~ParamNotebookPage(void); + Gtk::Widget * get_widget(SPDocument * doc, Inkscape::XML::Node * node); + Glib::ustring * paramString (void); + gchar * get_guitext (void) {return _text;}; + +}; /* class ParamNotebookPage */ + + +ParamNotebookPage::ParamNotebookPage (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml) : + Parameter(name, guitext, desc, scope, ext) +{ + parameters = NULL; + + // Read XML to build page + if (xml != NULL) { + Inkscape::XML::Node *child_repr = sp_repr_children(xml); + while (child_repr != NULL) { + char const * chname = child_repr->name(); + if (chname[0] == '_') /* Allow _ for translation of tags */ + chname++; + if (!strcmp(chname, "param") || !strcmp(chname, "_param")) { + Parameter * param; + param = Parameter::make(child_repr, ext); + if (param != NULL) + parameters = g_slist_append(parameters, param); + } + child_repr = sp_repr_next(child_repr); + } + } + + return; +} + +ParamNotebookPage::~ParamNotebookPage (void) +{ + //destroy parameters + for (GSList * list = parameters; list != NULL; list = g_slist_next(list)) { + Parameter * param = reinterpret_cast(list->data); + delete param; + } + g_slist_free(parameters); +} + +/** \brief Return the value as a string */ +Glib::ustring * +ParamNotebookPage::paramString (void) +{ + Glib::ustring * param_string = new Glib::ustring(""); + + for (GSList * list = parameters; list != NULL; list = g_slist_next(list)) { + Parameter * param = reinterpret_cast(list->data); + + *param_string += " --"; + *param_string += param->name(); + *param_string += "="; + Glib::ustring * paramstr = param->string(); + *param_string += *paramstr; + delete paramstr; + } + + return param_string; +} + + +/** + \return None + \brief This function creates a page that can be used later. This + is typically done in the creation of the notebook and defined + in the XML file describing the extension (it's private so people + have to use the system) :) + \param in_repr The XML describing the page + + This function first grabs all of the data out of the Repr and puts + it into local variables. Actually, these are just pointers, and the + data is not duplicated so we need to be careful with it. If there + isn't a name in the XML, then no page is created as + the function just returns. + + From this point on, we're pretty committed as we've allocated an + object and we're starting to fill it. The name is set first, and + is created with a strdup to actually allocate memory for it. Then + there is a case statement (roughly because strcmp requires 'ifs') + based on what type of parameter this is. Depending which type it + is, the value is interpreted differently, but they are relatively + straight forward. In all cases the value is set to the default + value from the XML and the type is set to the interpreted type. +*/ +ParamNotebookPage * +ParamNotebookPage::makepage (Inkscape::XML::Node * in_repr, Inkscape::Extension::Extension * in_ext) +{ + const char * name; + const char * guitext; + const char * desc; + const char * scope_str; + Parameter::_scope_t scope = Parameter::SCOPE_USER; + + name = in_repr->attribute("name"); + guitext = in_repr->attribute("gui-text"); + if (guitext == NULL) + guitext = in_repr->attribute("_gui-text"); + desc = in_repr->attribute("gui-description"); + if (desc == NULL) + desc = in_repr->attribute("_gui-description"); + scope_str = in_repr->attribute("scope"); + + /* In this case we just don't have enough information */ + if (name == NULL) { + return NULL; + } + + if (scope_str != NULL) { + if (!strcmp(scope_str, "user")) { + scope = Parameter::SCOPE_USER; + } else if (!strcmp(scope_str, "document")) { + scope = Parameter::SCOPE_DOCUMENT; + } else if (!strcmp(scope_str, "node")) { + scope = Parameter::SCOPE_NODE; + } + } + + ParamNotebookPage * page = new ParamNotebookPage(name, guitext, desc, scope, in_ext, in_repr); + + /* Note: page could equal NULL */ + return page; +} + + + +/** + \brief Creates a notebookpage widget for a notebook + + Builds a notebook page (a vbox) and puts parameters on it. +*/ +Gtk::Widget * +ParamNotebookPage::get_widget (SPDocument * doc, Inkscape::XML::Node * node) +{ + Gtk::VBox * vbox = Gtk::manage(new Gtk::VBox); + vbox->set_border_width(5); + + // add parameters onto page (if any) + for (GSList * list = parameters; list != NULL; list = g_slist_next(list)) { + Parameter * param = reinterpret_cast(list->data); + Gtk::Widget * widg = param->get_widget(doc, node); + gchar const * tip = param->get_tooltip(); + + vbox->pack_start(*widg, true, true, 2); + if (tip != NULL) { + _tooltips.set_tip(*widg, Glib::ustring(tip)); + // printf("Setting tooltip: %s\n", tooltip); + } + } + + vbox->show(); + + return dynamic_cast(vbox); +} + + + + + + + + + +ParamNotebook::ParamNotebook (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml) : + Parameter(name, guitext, desc, scope, ext) +{ + pages = NULL; + + // Read XML tree to add pages: + // printf("Extension Constructor: "); + if (xml != NULL) { + Inkscape::XML::Node *child_repr = sp_repr_children(xml); + while (child_repr != NULL) { + char const * chname = child_repr->name(); + if (chname[0] == '_') /* Allow _ for translation of tags */ + chname++; + if (!strcmp(chname, "page")) { + ParamNotebookPage * page; + page = ParamNotebookPage::makepage(child_repr, ext); + if (page != NULL) pages = g_slist_append(pages, page); + } + child_repr = sp_repr_next(child_repr); + } + } + + // Initialize _value with the current page + const char * defaultval = NULL; + // set first page as default + if (pages != NULL) { + ParamNotebookPage * defpage = reinterpret_cast(pages->data); + defaultval = defpage->name(); + } + + gchar * pref_name = this->pref_name(); + const gchar * paramval = prefs_get_string_attribute(PREF_DIR, pref_name); + g_free(pref_name); + + if (paramval != NULL) + defaultval = paramval; + if (defaultval != NULL) + _value = g_strdup(defaultval); // allocate space for _value + + return; +} + +ParamNotebook::~ParamNotebook (void) +{ + //destroy pages + for (GSList * list = pages; list != NULL; list = g_slist_next(list)) { + ParamNotebookPage * page = reinterpret_cast(list->data); + delete page; + } + g_slist_free(pages); + + g_free(_value); +} + + +/** \brief A function to set the \c _value + \param in The number of the page which value must be set + \param doc A document that should be used to set the value. + \param node The node where the value may be placed + + 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_DIR + and \c pref_name() are used. + + To copy the data into _value the old memory must be free'd first. + It is important to note that \c g_free handles \c NULL just fine. Then + the passed in value is duplicated using \c g_strdup(). +*/ +const gchar * +ParamNotebook::set (const int in, SPDocument * doc, Inkscape::XML::Node * node) +{ + ParamNotebookPage * page = NULL; + int i = 0; + for (GSList * list = pages; (list != NULL) && (i <= in); list = g_slist_next(list)) { + page = reinterpret_cast(list->data); + i++; + } + + if (page == NULL) return _value; + + if (_value != NULL) g_free(_value); + _value = g_strdup(page->name()); + + gchar * prefname = this->pref_name(); + prefs_set_string_attribute(PREF_DIR, prefname, _value); + g_free(prefname); + + return _value; +} + + +/** + \brief A function to get the currentpage and the parameters in a string form + \return A string with the 'value' and all the parameters on all pages as command line arguments + + This is really a hack. The function is called by Extension::paramString() to build + the commandline string like: '--param1name=\"param1value\" --param2name=\"param2value\" ...' + Extension::paramString expects this function to return '\"param1value\"'; but instead, + this function returns: '\"param1value\" --page1param1name=\"page1param1value\" ...' + + \TODO Do this better. For example, make Parameter::paramString() that returns '--name=\"value\"' + instead of just returning '\"value\"'. +*/ +Glib::ustring * +ParamNotebook::string (void) +{ + Glib::ustring * param_string = new Glib::ustring(""); + + *param_string += "\""; + *param_string += _value; // the name of the current page + *param_string += "\""; + + for (GSList * list = pages; list != NULL; list = g_slist_next(list)) { + ParamNotebookPage * page = reinterpret_cast(list->data); + + Glib::ustring * pageparamstr = page->paramString(); + *param_string += *pageparamstr; + delete pageparamstr; + } + + // this function is called when the user pressed OK. This means the dialog will close + // very soon, and we should deactivate the 'switch-page' hook, so the last page is remembered. + + + return param_string; +} + +/** \brief A special category of Gtk::Notebook to handle notebook parameters */ +class ParamNotebookWdg : public Gtk::Notebook { +private: + ParamNotebook * _pref; + SPDocument * _doc; + Inkscape::XML::Node * _node; +public: + /** \brief 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. + */ + ParamNotebookWdg (ParamNotebook * pref, SPDocument * doc, Inkscape::XML::Node * node) : + Gtk::Notebook(), _pref(pref), _doc(doc), _node(node), 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, &ParamNotebookWdg::changed_page)); + return; + }; + void changed_page(GtkNotebookPage *page, guint pagenum); + bool activated; +}; + +/** \brief 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 +ParamNotebookWdg::changed_page(GtkNotebookPage *page, + guint pagenum) +{ + if (is_visible()) { + _pref->set((int)pagenum, _doc, _node); + } + return; +} + + + +/** + \brief Creates a Notebook widget for a notebook parameter + + Builds a notebook and puts pages in it. +*/ +Gtk::Widget * +ParamNotebook::get_widget (SPDocument * doc, Inkscape::XML::Node * node) +{ + ParamNotebookWdg * nb = Gtk::manage(new ParamNotebookWdg(this, doc, node)); + + // add pages (if any) + int i = -1; + int pagenr = i; + for (GSList * list = pages; list != NULL; list = g_slist_next(list)) { + i++; + ParamNotebookPage * page = reinterpret_cast(list->data); + Gtk::Widget * widg = page->get_widget(doc, node); + nb->append_page(*widg, _(page->get_guitext())); + if (!strcmp(_value, page->name())) { + pagenr = i; // this is the page to be displayed? + } + } + + nb->show(); + + if (pagenr >= 0) nb->set_current_page(pagenr); + + return dynamic_cast(nb); +} + + +} /* 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 : diff --git a/src/extension/paramnotebook.h b/src/extension/paramnotebook.h new file mode 100644 index 000000000..a7811576e --- /dev/null +++ b/src/extension/paramnotebook.h @@ -0,0 +1,68 @@ +#ifndef __INK_EXTENSION_PARAMNOTEBOOK_H__ +#define __INK_EXTENSION_PARAMNOTEBOOK_H__ + +/** \file + * Notebook parameter for extensions. + */ + +/* + * Author: + * Johan Engelen + * + * Copyright (C) 2006 Author + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include + +#include "xml/document.h" +#include "extension-forward.h" + +#include "parameter.h" + +namespace Inkscape { +namespace Extension { + + + +// \brief A class to represent a notebookparameter of an extension +class ParamNotebook : public Parameter { +private: + /** \brief Internal value. This should point to a string that has + been allocated in memory. And should be free'd. + It is the name of the current page. */ + gchar * _value; + + GSList * pages; /**< A table to store the pages with parameters for this notebook. + This only gets created if there are pages in this + notebook */ +public: + ParamNotebook(const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml); + ~ParamNotebook(void); + Gtk::Widget * get_widget(SPDocument * doc, Inkscape::XML::Node * node); + Glib::ustring * string (void); + + const gchar * get (const SPDocument * doc, const Inkscape::XML::Node * node) { return _value; } + const gchar * set (const int in, SPDocument * doc, Inkscape::XML::Node * node); +}; /* class ParamNotebook */ + + + + + +} /* namespace Extension */ +} /* namespace Inkscape */ + +#endif /* __INK_EXTENSION_PARAMNOTEBOOK_H__ */ + +/* + 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 : -- 2.30.2