diff options
| author | Liam P. White <inkscapebronyat-signgmaildotcom> | 2014-03-04 23:05:52 +0000 |
|---|---|---|
| committer | Liam P. White <inkscapebronyat-signgmaildotcom> | 2014-03-04 23:05:52 +0000 |
| commit | 12971e975dae83c23e89cdbff99e990d3916b6ff (patch) | |
| tree | f16e505e187693567e75503dc8095ffecf2bad12 /src | |
| parent | Remove tag dialog temporarily (diff) | |
| download | inkscape-12971e975dae83c23e89cdbff99e990d3916b6ff.tar.gz inkscape-12971e975dae83c23e89cdbff99e990d3916b6ff.zip | |
Added some basic swatch stuff (does not compile)
(bzr r13090.1.14)
Diffstat (limited to 'src')
| -rw-r--r-- | src/ui/dialog/swatches.cpp | 2938 | ||||
| -rw-r--r-- | src/ui/dialog/swatches.h | 155 |
2 files changed, 2156 insertions, 937 deletions
diff --git a/src/ui/dialog/swatches.cpp b/src/ui/dialog/swatches.cpp index 711bcfe2d..a0c79b8ac 100644 --- a/src/ui/dialog/swatches.cpp +++ b/src/ui/dialog/swatches.cpp @@ -43,10 +43,10 @@ #include "path-prefix.h" #include "preferences.h" #include "sp-item.h" +#include "sp-gradient-fns.h" #include "sp-gradient.h" #include "sp-gradient-vector.h" #include "style.h" -#include "ui/previewholder.h" #include "widgets/desktop-widget.h" #include "widgets/gradient-vector.h" #include "widgets/eek-preview.h" @@ -57,7 +57,6 @@ #include "verbs.h" #include "gradient-chemistry.h" #include "helper/action.h" -#include "helper/action-context.h" #include "xml/node-observer.h" #include "xml/repr.h" #include "sp-pattern.h" @@ -68,1172 +67,2255 @@ #include "svg/svg-color.h" #include "sp-radial-gradient.h" #include "color-rgba.h" -#include "event-context.h" +#include "svg/css-ostringstream.h" +//#include "event-context.h" //no longer exists #include <queue> -//sorry! #ifdef WIN32 #include <windows.h> #endif +guint get_group0_keyval(GdkEventKey *event); +void sp_desktop_set_gradient(SPDesktop *desktop, SPGradient* gradient, bool fill); + namespace Inkscape { namespace UI { namespace Dialogs { -#define VBLOCK 16 -#define PREVIEW_PIXBUF_WIDTH 128 #define SWATCHES_FILE_NAME "swatches.svg" -void _loadPaletteFile( gchar const *filename, gboolean user=FALSE ); - -std::list<SwatchPage*> userSwatchPages; -std::list<SwatchPage*> systemSwatchPages; -static std::map<SPDocument*, SwatchPage*> docPalettes; -static std::vector<DocTrack*> docTrackings; -static std::map<SwatchesPanel*, SPDocument*> docPerPanel; - - -class SwatchesPanelHook : public SwatchesPanel -{ -public: - static void convertGradient( GtkMenuItem *menuitem, gpointer userData ); - static void deleteGradient( GtkMenuItem *menuitem, gpointer userData ); -}; +static char* trim( char* str ) { + char* ret = str; + while ( *str && (*str == ' ' || *str == '\t') ) { + str++; + } + ret = str; + while ( *str ) { + str++; + } + str--; + while ( str > ret && (( *str == ' ' || *str == '\t' ) || *str == '\r' || *str == '\n') ) { + *str-- = 0; + } + return ret; +} -static void handleClick( GtkWidget* /*widget*/, gpointer callback_data ) { - ColorItem* item = reinterpret_cast<ColorItem*>(callback_data); - if ( item ) { - item->buttonClicked(false); +static void skipWhitespace( char*& str ) { + while ( *str == ' ' || *str == '\t' ) { + str++; } } -static void handleSecondaryClick( GtkWidget* /*widget*/, gint /*arg1*/, gpointer callback_data ) { - ColorItem* item = reinterpret_cast<ColorItem*>(callback_data); - if ( item ) { - item->buttonClicked(true); +static bool parseNum( char*& str, int& val ) { + val = 0; + while ( '0' <= *str && *str <= '9' ) { + val = val * 10 + (*str - '0'); + str++; } + bool retval = !(*str == 0 || *str == ' ' || *str == '\t' || *str == '\r' || *str == '\n'); + return retval; } -static GtkWidget* popupMenu = 0; -static GtkWidget *popupSubHolder = 0; -static GtkWidget *popupSub = 0; -static std::vector<Glib::ustring> popupItems; -static std::vector<GtkWidget*> popupExtras; -static ColorItem* bounceTarget = 0; -static SwatchesPanel* bouncePanel = 0; +static char * SwatchFile; +static SPDocument * SwatchDocument; +static unsigned int page_suffix; -static void redirClick( GtkMenuItem *menuitem, gpointer /*user_data*/ ) +static void loadPalletFile() { - if ( bounceTarget ) { - handleClick( GTK_WIDGET(menuitem), bounceTarget ); + if (!SwatchDocument) { + SwatchFile=g_build_filename(INKSCAPE_PALETTESDIR, _("swatches.svg"), NULL); + SwatchDocument=SPDocument::createNewDoc (SwatchFile, TRUE); + if (!SwatchDocument) { + SwatchDocument = SPDocument::createNewDoc(NULL, TRUE, true); + sp_repr_save_file(SwatchDocument->getReprDoc(), SwatchFile, SP_SVG_NS_URI); + } } } -static void redirSecondaryClick( GtkMenuItem *menuitem, gpointer /*user_data*/ ) +static void addStop( Inkscape::XML::Node *parent, Glib::ustring const &color, gfloat opacity, gchar const *offset ) { - if ( bounceTarget ) { - handleSecondaryClick( GTK_WIDGET(menuitem), 0, bounceTarget ); +#ifdef SP_GR_VERBOSE + g_message("addStop(%p, %s, %d, %s)", parent, color.c_str(), opacity, offset); +#endif + Inkscape::XML::Node *stop = parent->document()->createElement("svg:stop"); + { + gchar *tmp = g_strdup_printf( "stop-color:%s;stop-opacity:%f;", color.c_str(), opacity < 0.0 ? 0.0 : (opacity > 1.0 ? 1.0 : opacity) ); + stop->setAttribute( "style", tmp ); + g_free(tmp); } + + stop->setAttribute( "offset", offset ); + + parent->appendChild(stop); + Inkscape::GC::release(stop); } -static void editGradientImpl( SPDesktop* desktop, SPGradient* gr ) +static SPGroup* importGPL(SPDocument* doc, const gchar* full) { - if ( gr ) { - bool shown = false; - if ( desktop && desktop->doc() ) { - Inkscape::Selection *selection = sp_desktop_selection( desktop ); - GSList const *items = selection->itemList(); - if (items) { - SPStyle *query = sp_style_new( desktop->doc() ); - int result = objects_query_fillstroke(const_cast<GSList *>(items), query, true); - if ( (result == QUERY_STYLE_MULTIPLE_SAME) || (result == QUERY_STYLE_SINGLE) ) { - // could be pertinent - if (query->fill.isPaintserver()) { - SPPaintServer* server = query->getFillPaintServer(); - if ( SP_IS_GRADIENT(server) ) { - SPGradient* grad = SP_GRADIENT(server); - if ( grad->isSwatch() && grad->getId() == gr->getId()) { - desktop->_dlg_mgr->showDialog("FillAndStroke"); - shown = true; + SPGroup* ret = NULL; + if ( !Inkscape::IO::file_test( full, G_FILE_TEST_IS_DIR ) ) { + + /*Load the pallet file here*/ + char block[1024]; + FILE *f = Inkscape::IO::fopen_utf8name( full, "r" ); + if ( f ) { + char* result = fgets( block, sizeof(block), f ); + if ( result ) { + if ( strncmp( "GIMP Palette", block, 12 ) == 0 ) { + bool inHeader = true; + bool hasErr = false; + + Inkscape::XML::Node * page = doc->getReprDoc()->createElement("svg:g"); + gchar *id=NULL; + do { + g_free(id); + id = g_strdup_printf("page%d", page_suffix++); + } while (doc->getObjectById(id)); + + page->setAttribute("id", id); + + do { + result = fgets( block, sizeof(block), f ); + block[sizeof(block) - 1] = 0; + if ( result ) { + if ( block[0] == '#' ) { + // ignore comment + } else { + char *ptr = block; + // very simple check for header versus entry + while ( *ptr == ' ' || *ptr == '\t' ) { + ptr++; + } + if ( (*ptr == 0) || (*ptr == '\r') || (*ptr == '\n') ) { + // blank line. skip it. + } else if ( '0' <= *ptr && *ptr <= '9' ) { + // should be an entry link + inHeader = false; + ptr = block; + Glib::ustring name(""); + skipWhitespace(ptr); + if ( *ptr ) { + int r = 0; + int g = 0; + int b = 0; + hasErr = parseNum(ptr, r); + if ( !hasErr ) { + skipWhitespace(ptr); + hasErr = parseNum(ptr, g); + } + if ( !hasErr ) { + skipWhitespace(ptr); + hasErr = parseNum(ptr, b); + } + if ( !hasErr && *ptr ) { + char* n = trim(ptr); + if (n != NULL) { + name = g_dpgettext2(NULL, "Palette", n); + } + } + if ( !hasErr ) { + // Add the entry now + + Inkscape::XML::Node *grad = doc->getReprDoc()->createElement("svg:linearGradient"); + grad->setAttribute("inkscape:label", name.c_str()); + grad->setAttribute( "osb:paint", "solid", 0 ); + SPColor color((float)r / 255, (float)g / 255, (float)b / 255); + addStop(grad, color.toString(), 1, "0"); + page->appendChild(grad); + Inkscape::GC::release(grad); + } + } else { + hasErr = true; + } + } else { + if ( !inHeader ) { + // Hmmm... probably bad. Not quite the format we want? + hasErr = true; + } else { + char* sep = strchr(result, ':'); + if ( sep ) { + *sep = 0; + char* val = trim(sep + 1); + char* name = trim(result); + if ( *name ) { + if ( strcmp( "Name", name ) == 0 ) + { + page->setAttribute("inkscape:label", val); + } + } else { + // error + hasErr = true; + } + } else { + // error + hasErr = true; + } + } + } } } + } while ( result && !hasErr ); + if ( !hasErr ) { + doc->getDefs()->appendChild(page); + Inkscape::GC::release(page); + SPObject* obj = doc->getObjectByRepr(page); + if (SP_IS_GROUP(obj)) { + ret = SP_GROUP(obj); + } + #if ENABLE_MAGIC_COLORS + ColorItem::_wireMagicColors( onceMore ); + #endif // ENABLE_MAGIC_COLORS + } else { + delete page; } } - sp_style_unref(query); } - } - if (!shown) { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - if (prefs->getBool("/dialogs/gradienteditor/showlegacy", false)) { - // Legacy gradient dialog - GtkWidget *dialog = sp_gradient_vector_editor_new( gr ); - gtk_widget_show( dialog ); - } else { - // Invoke the gradient tool - Inkscape::Verb *verb = Inkscape::Verb::get( SP_VERB_CONTEXT_GRADIENT ); - if ( verb ) { - SPAction *action = verb->get_action( Inkscape::ActionContext( ( Inkscape::UI::View::View * ) SP_ACTIVE_DESKTOP ) ); - if ( action ) { - sp_action_perform( action, NULL ); - } - } - } + fclose(f); } + /* end loading the pallet file*/ } + return ret; } -static void editGradient( GtkMenuItem */*menuitem*/, gpointer /*user_data*/ ) +SwatchesPanel& SwatchesPanel::getInstance() { - if ( bounceTarget ) { - SwatchesPanel* swp = bouncePanel; - SPDesktop* desktop = swp ? swp->getDesktop() : 0; - SPDocument *doc = desktop ? desktop->doc() : 0; - if (doc) { - std::string targetName(bounceTarget->def.descr); - const GSList *gradients = doc->getResourceList("gradient"); - for (const GSList *item = gradients; item; item = item->next) { - SPGradient* grad = SP_GRADIENT(item->data); - if ( targetName == grad->getId() ) { - editGradientImpl( desktop, grad ); - break; + return *new SwatchesPanel(); +} + +class SwatchesPanel::StopWatcher : public Inkscape::XML::NodeObserver { +public: + StopWatcher(SwatchesPanel* pnl, SPStop* obj) : + _pnl(pnl), + _obj(obj), + _repr(obj->getRepr()) + { + _repr->addObserver(*this); + } + + ~StopWatcher() { + _repr->removeObserver(*this); + } + + virtual void notifyChildAdded( Inkscape::XML::Node &/*node*/, Inkscape::XML::Node &/*child*/, Inkscape::XML::Node */*prev*/ ){} + virtual void notifyChildRemoved( Inkscape::XML::Node &/*node*/, Inkscape::XML::Node &/*child*/, Inkscape::XML::Node */*prev*/ ){} + virtual void notifyChildOrderChanged( Inkscape::XML::Node &/*node*/, Inkscape::XML::Node &/*child*/, Inkscape::XML::Node */*old_prev*/, Inkscape::XML::Node */*new_prev*/ ){} + virtual void notifyContentChanged( Inkscape::XML::Node &/*node*/, Util::ptr_shared<char> /*old_content*/, Util::ptr_shared<char> /*new_content*/ ) {} + + virtual void notifyAttributeChanged( Inkscape::XML::Node &/*node*/, GQuark name, Util::ptr_shared<char> /*old_value*/, Util::ptr_shared<char> /*new_value*/ ) { + if (_pnl && _obj) { + _pnl->_defsChanged( ); + } + } + + SwatchesPanel* _pnl; + SPStop* _obj; + Inkscape::XML::Node* _repr; +}; + +class SwatchesPanel::GradientWatcher : public Inkscape::XML::NodeObserver { +public: + GradientWatcher(SwatchesPanel* pnl, SPGradient* obj) : + _pnl(pnl), + _obj(obj), + _repr(obj->getRepr()), + _labelAttr(g_quark_from_string("inkscape:label")), + _swatchAttr(g_quark_from_string("osb:paint")) + { + _repr->addObserver(*this); + } + + ~GradientWatcher() { + _repr->removeObserver(*this); + } + + virtual void notifyChildAdded( Inkscape::XML::Node &/*node*/, Inkscape::XML::Node &/*child*/, Inkscape::XML::Node */*prev*/ ) + { + if ( _pnl && _obj && _obj->isSwatch()) { + _pnl->_defsChanged( ); + } + } + virtual void notifyChildRemoved( Inkscape::XML::Node &/*node*/, Inkscape::XML::Node &/*child*/, Inkscape::XML::Node */*prev*/ ) + { + if ( _pnl && _obj && _obj->isSwatch() ) { + _pnl->_defsChanged( ); + } + } + virtual void notifyChildOrderChanged( Inkscape::XML::Node &/*node*/, Inkscape::XML::Node &/*child*/, Inkscape::XML::Node */*old_prev*/, Inkscape::XML::Node */*new_prev*/ ) + { + if ( _pnl && _obj && _obj->isSwatch() ) { + _pnl->_defsChanged( ); + } + } + virtual void notifyContentChanged( Inkscape::XML::Node &/*node*/, Util::ptr_shared<char> /*old_content*/, Util::ptr_shared<char> /*new_content*/ ) {} + virtual void notifyAttributeChanged( Inkscape::XML::Node &/*node*/, GQuark name, Util::ptr_shared<char> /*old_value*/, Util::ptr_shared<char> /*new_value*/ ) { + if (_pnl && _obj && ((_obj->isSwatch() && name == _labelAttr) || name == _swatchAttr)) { + _pnl->_defsChanged( ); + } + } + + SwatchesPanel* _pnl; + SPGradient* _obj; + Inkscape::XML::Node* _repr; + GQuark _labelAttr; + GQuark _swatchAttr; +}; + +class SwatchesPanel::SwatchWatcher : public Inkscape::XML::NodeObserver { +public: + SwatchWatcher(SwatchesPanel* pnl, SPObject* obj, bool builtIn) : + _pnl(pnl), + _obj(obj), + _builtIn(builtIn), + _repr(obj->getRepr()), + _labelAttr(g_quark_from_string("inkscape:label")), + _swatchAttr(g_quark_from_string("osb:paint")) + { + _repr->addObserver(*this); + } + + ~SwatchWatcher() { + _repr->removeObserver(*this); + } + + virtual void notifyChildAdded( Inkscape::XML::Node &/*node*/, Inkscape::XML::Node &child, Inkscape::XML::Node */*prev*/ ) + { + if ( _pnl && _obj) { + SPObject *childobj = _builtIn ? SwatchDocument->getObjectByRepr(&child) : (_pnl->_currentDocument ? _pnl->_currentDocument->getObjectByRepr(&child) : 0); + if (childobj && ((SP_IS_GRADIENT(childobj) && SP_GRADIENT(childobj)->hasStops()) || SP_IS_GROUP(childobj))) { + if (_builtIn) { + _pnl->_swatchesChanged( ); + } else { + _pnl->_defsChanged( ); } } } } -} - -void SwatchesPanelHook::convertGradient( GtkMenuItem * /*menuitem*/, gpointer userData ) -{ - if ( bounceTarget ) { - SwatchesPanel* swp = bouncePanel; - SPDesktop* desktop = swp ? swp->getDesktop() : 0; - SPDocument *doc = desktop ? desktop->doc() : 0; - gint index = GPOINTER_TO_INT(userData); - if ( doc && (index >= 0) && (static_cast<guint>(index) < popupItems.size()) ) { - Glib::ustring targetName = popupItems[index]; - - const GSList *gradients = doc->getResourceList("gradient"); - for (const GSList *item = gradients; item; item = item->next) { - SPGradient* grad = SP_GRADIENT(item->data); - if ( targetName == grad->getId() ) { - grad->setSwatch(); - DocumentUndo::done(doc, SP_VERB_CONTEXT_GRADIENT, - _("Add gradient stop")); - break; + virtual void notifyChildRemoved( Inkscape::XML::Node &/*node*/, Inkscape::XML::Node &child, Inkscape::XML::Node */*prev*/ ) + { + if ( _pnl && _obj) { + if (_builtIn) { + _pnl->_swatchesChanged( ); + } else { + _pnl->_defsChanged( ); + } + } + } + virtual void notifyChildOrderChanged( Inkscape::XML::Node &/*node*/, Inkscape::XML::Node &child, Inkscape::XML::Node */*old_prev*/, Inkscape::XML::Node */*new_prev*/ ) + { + if ( _pnl && _obj) { + SPObject *childobj = _builtIn ? SwatchDocument->getObjectByRepr(&child) : (_pnl->_currentDocument ? _pnl->_currentDocument->getObjectByRepr(&child) : 0); + if (childobj && ((SP_IS_GRADIENT(childobj) && SP_GRADIENT(childobj)->hasStops()) || SP_IS_GROUP(childobj))) { + if (_builtIn) { + _pnl->_swatchesChanged( ); + } else { + _pnl->_defsChanged( ); } } } } -} + virtual void notifyContentChanged( Inkscape::XML::Node &/*node*/, Util::ptr_shared<char> /*old_content*/, Util::ptr_shared<char> /*new_content*/ ) {} + virtual void notifyAttributeChanged( Inkscape::XML::Node &/*node*/, GQuark name, Util::ptr_shared<char> /*old_value*/, Util::ptr_shared<char> /*new_value*/ ) { + if (_pnl && _obj && name == _labelAttr) { + if (_builtIn) { + _pnl->_swatchesChanged( ); + } else { + _pnl->_defsChanged( ); + } + } + } -void SwatchesPanelHook::deleteGradient( GtkMenuItem */*menuitem*/, gpointer /*userData*/ ) + SwatchesPanel* _pnl; + SPObject* _obj; + bool _builtIn; + Inkscape::XML::Node* _repr; + GQuark _labelAttr; + GQuark _swatchAttr; +}; + +class SwatchesPanel::ModelColumns : public Gtk::TreeModel::ColumnRecord { - if ( bounceTarget ) { - SwatchesPanel* swp = bouncePanel; - SPDesktop* desktop = swp ? swp->getDesktop() : 0; - sp_gradient_unset_swatch(desktop, bounceTarget->def.descr); +public: + + ModelColumns() + { + add(_colObject); + add(_colLabel); } -} + virtual ~ModelColumns() {} + + Gtk::TreeModelColumn<SPObject*> _colObject; + Gtk::TreeModelColumn<Glib::ustring> _colLabel; +}; -static SwatchesPanel* findContainingPanel( GtkWidget *widget ) +class SwatchesPanel::ModelColumnsDoc : public Gtk::TreeModel::ColumnRecord { - SwatchesPanel *swp = 0; +public: - std::map<GtkWidget*, SwatchesPanel*> rawObjects; - for (std::map<SwatchesPanel*, SPDocument*>::iterator it = docPerPanel.begin(); it != docPerPanel.end(); ++it) { - rawObjects[GTK_WIDGET(it->first->gobj())] = it->first; + ModelColumnsDoc() + { + add(_colObject); + add(_colLabel); + add(_colPixbuf); } + virtual ~ModelColumnsDoc() {} + + Gtk::TreeModelColumn<SPObject*> _colObject; + Gtk::TreeModelColumn<Glib::ustring> _colLabel; + Gtk::TreeModelColumn<Glib::RefPtr<Gdk::Pixbuf> > _colPixbuf; +}; - for (GtkWidget* curr = widget; curr && !swp; curr = gtk_widget_get_parent(curr)) { - if (rawObjects.find(curr) != rawObjects.end()) { - swp = rawObjects[curr]; +static void StripChildGroups(Inkscape::XML::Node * node, SPObject* addTo) +{ + for (Inkscape::XML::Node * it = node->firstChild(); it != NULL;) { + if (!strcmp(it->name(), "svg:g")) { + Inkscape::XML::Node * todel = it; + it = it->next(); + node->removeChild(todel); + } else { + it = it->next(); } } - - return swp; + addTo->appendChildRepr(node); } -static void removeit( GtkWidget *widget, gpointer data ) +static void BubbleChildGroups(Inkscape::XML::Node * node, SPObject* addTo) { - gtk_container_remove( GTK_CONTAINER(data), widget ); + std::queue<Inkscape::XML::Node *> groups; + for (Inkscape::XML::Node * it = node->firstChild(); it != NULL; ) { + if (!strcmp(it->name(), "svg:g")) { + groups.push(it->duplicate(addTo->document->getReprDoc())); + Inkscape::XML::Node * todel = it; + it = it->next(); + node->removeChild(todel); + } else { + it = it->next(); + } + } + addTo->appendChildRepr(node); + while (!groups.empty()) { + Inkscape::XML::Node * it = groups.front(); + groups.pop(); + BubbleChildGroups(it, addTo); + Inkscape::GC::release(it); + } } -/* extern'ed from colot-item.cpp */ -gboolean colorItemHandleButtonPress( GtkWidget* widget, GdkEventButton* event, gpointer user_data ); +void SwatchesPanel::_addSwatchButtonClicked(SPGroup* swatch, bool recurse) +{ + if (_currentDocument) { + if (swatch && SP_IS_GROUP(swatch) ) { + Inkscape::XML::Node * copy = swatch->getRepr()->duplicate(_currentDocument->getReprDoc()); + if (recurse) { + BubbleChildGroups(copy, _currentDocument->getDefs()); + } else { + StripChildGroups(copy, _currentDocument->getDefs()); + } + Inkscape::GC::release(copy); + DocumentUndo::done(_currentDocument, SP_VERB_DIALOG_SWATCHES, _("Add swatches to document")); + } + } +} -gboolean colorItemHandleButtonPress( GtkWidget* widget, GdkEventButton* event, gpointer user_data ) +void SwatchesPanel::_importButtonClicked(bool addToDoc, bool addToBI) { - gboolean handled = FALSE; - - if ( event && (event->button == 3) && (event->type == GDK_BUTTON_PRESS) ) { - SwatchesPanel* swp = findContainingPanel( widget ); - - if ( !popupMenu ) { - popupMenu = gtk_menu_new(); - GtkWidget* child = 0; - - //TRANSLATORS: An item in context menu on a colour in the swatches - child = gtk_menu_item_new_with_label(_("Set fill")); - g_signal_connect( G_OBJECT(child), - "activate", - G_CALLBACK(redirClick), - user_data); - gtk_menu_shell_append(GTK_MENU_SHELL(popupMenu), child); - - //TRANSLATORS: An item in context menu on a colour in the swatches - child = gtk_menu_item_new_with_label(_("Set stroke")); - - g_signal_connect( G_OBJECT(child), - "activate", - G_CALLBACK(redirSecondaryClick), - user_data); - gtk_menu_shell_append(GTK_MENU_SHELL(popupMenu), child); - - child = gtk_separator_menu_item_new(); - gtk_menu_shell_append(GTK_MENU_SHELL(popupMenu), child); - popupExtras.push_back(child); - - child = gtk_menu_item_new_with_label(_("Delete")); - g_signal_connect( G_OBJECT(child), - "activate", - G_CALLBACK(SwatchesPanelHook::deleteGradient), - user_data ); - gtk_menu_shell_append(GTK_MENU_SHELL(popupMenu), child); - popupExtras.push_back(child); - gtk_widget_set_sensitive( child, FALSE ); - - child = gtk_menu_item_new_with_label(_("Edit...")); - g_signal_connect( G_OBJECT(child), - "activate", - G_CALLBACK(editGradient), - user_data ); - gtk_menu_shell_append(GTK_MENU_SHELL(popupMenu), child); - popupExtras.push_back(child); - - child = gtk_separator_menu_item_new(); - gtk_menu_shell_append(GTK_MENU_SHELL(popupMenu), child); - popupExtras.push_back(child); - - child = gtk_menu_item_new_with_label(_("Convert")); - gtk_menu_shell_append(GTK_MENU_SHELL(popupMenu), child); - //popupExtras.push_back(child); - //gtk_widget_set_sensitive( child, FALSE ); + if (addToDoc || addToBI) { + //# Get the current directory for finding files + static Glib::ustring open_path; + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + + if(open_path.empty()) + { + Glib::ustring attr = prefs->getString("/dialogs/open/path"); + if (!attr.empty()) open_path = attr; + } + + //# Test if the open_path directory exists + if (!Inkscape::IO::file_test(open_path.c_str(), + (GFileTest)(G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) + open_path = ""; + + #ifdef WIN32 + //# If no open path, default to our win32 documents folder + if (open_path.empty()) + { + // The path to the My Documents folder is read from the + // value "HKEY_CURRENT_USER\Software\Windows\CurrentVersion\Explorer\Shell Folders\Personal" + HKEY key = NULL; + if(RegOpenKeyExA(HKEY_CURRENT_USER, + "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", + 0, KEY_QUERY_VALUE, &key) == ERROR_SUCCESS) { - popupSubHolder = child; - popupSub = gtk_menu_new(); - gtk_menu_item_set_submenu( GTK_MENU_ITEM(child), popupSub ); + WCHAR utf16path[_MAX_PATH]; + DWORD value_type; + DWORD data_size = sizeof(utf16path); + if(RegQueryValueExW(key, L"Personal", NULL, &value_type, + (BYTE*)utf16path, &data_size) == ERROR_SUCCESS) + { + g_assert(value_type == REG_SZ); + gchar *utf8path = g_utf16_to_utf8( + (const gunichar2*)utf16path, -1, NULL, NULL, NULL); + if(utf8path) + { + open_path = Glib::ustring(utf8path); + g_free(utf8path); + } + } } + } + #endif - gtk_widget_show_all(popupMenu); + //# If no open path, default to our home directory + if (open_path.empty()) + { + open_path = g_get_home_dir(); + open_path.append(G_DIR_SEPARATOR_S); } - if ( user_data ) { - ColorItem* item = reinterpret_cast<ColorItem*>(user_data); - bool show = swp && (swp->getSelectedIndex() == 0); - for ( std::vector<GtkWidget*>::iterator it = popupExtras.begin(); it != popupExtras.end(); ++ it) { - gtk_widget_set_sensitive(*it, show); - } + Gtk::Window * parent = SP_ACTIVE_DESKTOP->getToplevel(); + //# Create a dialog + Inkscape::UI::Dialog::FileOpenDialog *openDialogInstance = + Inkscape::UI::Dialog::FileOpenDialog::create( + *parent, open_path, + Inkscape::UI::Dialog::SWATCH_TYPES, + _("Select file to open")); - bounceTarget = item; - bouncePanel = swp; - popupItems.clear(); - if ( popupMenu ) { - gtk_container_foreach(GTK_CONTAINER(popupSub), removeit, popupSub); - bool processed = false; - GtkWidget *wdgt = gtk_widget_get_ancestor(widget, SP_TYPE_DESKTOP_WIDGET); - if ( wdgt ) { - SPDesktopWidget *dtw = SP_DESKTOP_WIDGET(wdgt); - if ( dtw && dtw->desktop ) { - // Pick up all gradients with vectors - const GSList *gradients = (dtw->desktop->doc())->getResourceList("gradient"); - gint index = 0; - for (const GSList *curr = gradients; curr; curr = curr->next) { - SPGradient* grad = SP_GRADIENT(curr->data); - if ( grad->hasStops() && !grad->isSwatch() ) { - //gl = g_slist_prepend(gl, curr->data); - processed = true; - GtkWidget *child = gtk_menu_item_new_with_label(grad->getId()); - gtk_menu_shell_append(GTK_MENU_SHELL(popupSub), child); - - popupItems.push_back(grad->getId()); - g_signal_connect( G_OBJECT(child), - "activate", - G_CALLBACK(SwatchesPanelHook::convertGradient), - GINT_TO_POINTER(index) ); - index++; - } - } + //# Show the dialog + bool const success = openDialogInstance->show(); - gtk_widget_show_all(popupSub); - } - } - gtk_widget_set_sensitive( popupSubHolder, processed ); + //# Save the folder the user selected for later + open_path = openDialogInstance->getCurrentDirectory(); - gtk_menu_popup(GTK_MENU(popupMenu), NULL, NULL, NULL, NULL, event->button, event->time); - handled = TRUE; - } + if (!success) + { + delete openDialogInstance; + return; } - } - return handled; -} + //# User selected something. Get name and type + Glib::ustring fileName = openDialogInstance->getFilename(); + //# We no longer need the file dialog object - delete it + delete openDialogInstance; + openDialogInstance = NULL; -static char* trim( char* str ) { - char* ret = str; - while ( *str && (*str == ' ' || *str == '\t') ) { - str++; - } - ret = str; - while ( *str ) { - str++; - } - str--; - while ( str > ret && (( *str == ' ' || *str == '\t' ) || *str == '\r' || *str == '\n') ) { - *str-- = 0; - } - return ret; -} -static void skipWhitespace( char*& str ) { - while ( *str == ' ' || *str == '\t' ) { - str++; - } -} + if (!fileName.empty()) + { + Glib::ustring newFileName = Glib::filename_to_utf8(fileName); + + if ( newFileName.size() > 0) + fileName = newFileName; + else + g_warning( "ERROR CONVERTING OPEN FILENAME TO UTF-8" ); + + open_path = Glib::path_get_dirname (fileName); + open_path.append(G_DIR_SEPARATOR_S); + prefs->setString("/dialogs/open/path", open_path); + + SPDocument* importdoc = SPDocument::createNewDoc(fileName.c_str(), true); + Inkscape::XML::Node * page = NULL; + if (importdoc && importdoc->getDefs()) { + if (addToBI) { + page = SwatchDocument->getReprDoc()->createElement("svg:g"); + gchar *id=NULL; + do { + g_free(id); + id = g_strdup_printf("page%d", page_suffix++); + } while (SwatchDocument->getObjectById(id)); + + page->setAttribute("id", id); + gchar* name = g_path_get_basename(importdoc->getName()); + page->setAttribute("inkscape:label", name); + g_free(name); + } -static bool parseNum( char*& str, int& val ) { - val = 0; - while ( '0' <= *str && *str <= '9' ) { - val = val * 10 + (*str - '0'); - str++; + for (SPObject* it = importdoc->getDefs()->firstChild(); it != NULL; it = it->next) { + if (SP_IS_GROUP(it)) { + if (page) { + Inkscape::XML::Node * copy = it->getRepr()->duplicate(SwatchDocument->getReprDoc()); + page->appendChild(copy); + } + if (addToDoc) { + _addSwatchButtonClicked(SP_GROUP(it), false); + } + } + } + if (page) { + SwatchDocument->getDefs()->appendChildRepr(page); + sp_repr_save_file(SwatchDocument->getReprDoc(), SwatchFile, SP_SVG_NS_URI); + } + + importdoc->doUnref(); + } else { + SPGroup* g = importGPL(addToBI ? SwatchDocument : _currentDocument, fileName.c_str()); + if (addToBI) { + if (addToDoc) { + _addSwatchButtonClicked(g, false); + } + sp_repr_save_file(SwatchDocument->getReprDoc(), SwatchFile, SP_SVG_NS_URI); + } else { + DocumentUndo::done(_currentDocument, SP_VERB_DIALOG_SWATCHES, _("Add swatches to document")); + } + } + } } - bool retval = !(*str == 0 || *str == ' ' || *str == '\t' || *str == '\r' || *str == '\n'); - return retval; } - -void _loadPaletteFile( gchar const *filename, gboolean user/*=FALSE*/ ) +void SwatchesPanel::SetSelectedFill(SPGradient* swatch) { - char block[1024]; - FILE *f = Inkscape::IO::fopen_utf8name( filename, "r" ); - if ( f ) { - char* result = fgets( block, sizeof(block), f ); - if ( result ) { - if ( strncmp( "GIMP Palette", block, 12 ) == 0 ) { - bool inHeader = true; - bool hasErr = false; - - SwatchPage *onceMore = new SwatchPage(); - - do { - result = fgets( block, sizeof(block), f ); - block[sizeof(block) - 1] = 0; - if ( result ) { - if ( block[0] == '#' ) { - // ignore comment - } else { - char *ptr = block; - // very simple check for header versus entry - while ( *ptr == ' ' || *ptr == '\t' ) { - ptr++; + if (_currentDesktop && _currentDocument) { + SPItem* it = _currentDesktop->selection->singleItem(); + if (it) { + if (it->style->fill.isSet()) { + if (it->style->fill.isPaintserver()) { + SPPaintServer * server = it->style->getFillPaintServer(); + if (SP_IS_GRADIENT(server)) { + SPGradient *grad = SP_GRADIENT(server)->getVector(); + Inkscape::XML::Node * repr = grad->getRepr(); + Inkscape::XML::Node * drepr = swatch->getRepr(); + if (repr != drepr && grad != swatch) { + while (SPStop* olds = swatch->getFirstStop()) { + olds->deleteObject(); } - if ( (*ptr == 0) || (*ptr == '\r') || (*ptr == '\n') ) { - // blank line. skip it. - } else if ( '0' <= *ptr && *ptr <= '9' ) { - // should be an entry link - inHeader = false; - ptr = block; - Glib::ustring name(""); - skipWhitespace(ptr); - if ( *ptr ) { - int r = 0; - int g = 0; - int b = 0; - hasErr = parseNum(ptr, r); - if ( !hasErr ) { - skipWhitespace(ptr); - hasErr = parseNum(ptr, g); - } - if ( !hasErr ) { - skipWhitespace(ptr); - hasErr = parseNum(ptr, b); - } - if ( !hasErr && *ptr ) { - char* n = trim(ptr); - if (n != NULL) { - name = g_dpgettext2(NULL, "Palette", n); - } - } - if ( !hasErr ) { - // Add the entry now - Glib::ustring nameStr(name); - ColorItem* item = new ColorItem( r, g, b, nameStr ); - onceMore->_colors.push_back(item); - } - } else { - hasErr = true; - } - } else { - if ( !inHeader ) { - // Hmmm... probably bad. Not quite the format we want? - hasErr = true; - } else { - char* sep = strchr(result, ':'); - if ( sep ) { - *sep = 0; - char* val = trim(sep + 1); - char* name = trim(result); - if ( *name ) { - if ( strcmp( "Name", name ) == 0 ) - { - onceMore->_name = val; - } - else if ( strcmp( "Columns", name ) == 0 ) - { - gchar* endPtr = 0; - guint64 numVal = g_ascii_strtoull( val, &endPtr, 10 ); - if ( (numVal == G_MAXUINT64) && (ERANGE == errno) ) { - // overflow - } else if ( (numVal == 0) && (endPtr == val) ) { - // failed conversion - } else { - onceMore->_prefWidth = numVal; - } - } - } else { - // error - hasErr = true; - } - } else { - // error - hasErr = true; - } - } + for (SPStop* news = grad->getVector()->getFirstStop(); news != NULL; news = news->getNextStop()) { + Inkscape::XML::Node* clone = news->getRepr()->duplicate(_currentDocument->getReprDoc()); + swatch->appendChildRepr(clone); + Inkscape::GC::release(clone); + } + swatch->setSwatch(); + if (!_noLink.get_active()) { + sp_item_set_gradient(it, sp_gradient_ensure_vector_normalized(swatch), SP_IS_RADIALGRADIENT(swatch) ? SP_GRADIENT_TYPE_RADIAL : SP_GRADIENT_TYPE_LINEAR, Inkscape::FOR_FILL); } + DocumentUndo::done(_currentDocument, SP_VERB_DIALOG_SWATCHES, _("Set Gradient Swatch")); } } - } while ( result && !hasErr ); - if ( !hasErr ) { - if (user) - userSwatchPages.push_back(onceMore); - else - systemSwatchPages.push_back(onceMore); -#if ENABLE_MAGIC_COLORS - ColorItem::_wireMagicColors( onceMore ); -#endif // ENABLE_MAGIC_COLORS - } else { - delete onceMore; + } else if (it->style->fill.isColor()) { + while (SPStop* olds = swatch->getFirstStop()) { + olds->deleteObject(); + } + addStop(swatch->getRepr(), it->style->fill.value.color.toString(), SP_SCALE24_TO_FLOAT(it->style->fill_opacity.value), "0"); + swatch->setSwatch(); + if (!_noLink.get_active()) { + SPGradient* normalized = sp_gradient_ensure_vector_normalized(swatch); + sp_item_set_gradient(it, normalized, SP_GRADIENT_TYPE_LINEAR, Inkscape::FOR_FILL); + } + DocumentUndo::done(_currentDocument, SP_VERB_DIALOG_SWATCHES, _("Set Color Swatch")); } } } - - fclose(f); } } -static bool -compare_swatch_names(SwatchPage const *a, SwatchPage const *b) { - - return g_utf8_collate(a->_name.c_str(), b->_name.c_str()) < 0; -} - -static void loadEmUp() +void SwatchesPanel::SetSelectedStroke(SPGradient* swatch) { - static bool beenHere = false; - gboolean userPalete = true; - if ( !beenHere ) { - beenHere = true; - - std::list<gchar *> sources; - sources.push_back( profile_path("palettes") ); - sources.push_back( g_strdup(INKSCAPE_PALETTESDIR) ); - sources.push_back( g_strdup(CREATE_PALETTESDIR) ); - - // Use this loop to iterate through a list of possible document locations. - while (!sources.empty()) { - gchar *dirname = sources.front(); - if ( Inkscape::IO::file_test( dirname, G_FILE_TEST_EXISTS ) - && Inkscape::IO::file_test( dirname, G_FILE_TEST_IS_DIR )) { - GError *err = 0; - GDir *directory = g_dir_open(dirname, 0, &err); - if (!directory) { - gchar *safeDir = Inkscape::IO::sanitizeString(dirname); - g_warning(_("Palettes directory (%s) is unavailable."), safeDir); - g_free(safeDir); - } else { - gchar *filename = 0; - while ((filename = (gchar *)g_dir_read_name(directory)) != NULL) { - gchar* lower = g_ascii_strdown( filename, -1 ); -// if ( g_str_has_suffix(lower, ".gpl") ) { - if ( !g_str_has_suffix(lower, "~") ) { - gchar* full = g_build_filename(dirname, filename, NULL); - if ( !Inkscape::IO::file_test( full, G_FILE_TEST_IS_DIR ) ) { - _loadPaletteFile(full, userPalete); + if (_currentDesktop && _currentDocument) { + SPItem* it = _currentDesktop->selection->singleItem(); + if (it) { + if (it->style->stroke.isSet()) { + if (it->style->stroke.isPaintserver()) { + SPPaintServer * server = it->style->getStrokePaintServer(); + if (SP_IS_GRADIENT(server)) { + SPGradient *grad = SP_GRADIENT(server)->getVector(); + Inkscape::XML::Node * repr = grad->getRepr(); + Inkscape::XML::Node * drepr = swatch->getRepr(); + if (repr != drepr && grad != swatch) { + while (SPStop* olds = swatch->getFirstStop()) { + olds->deleteObject(); + } + for (SPStop* news = grad->getVector()->getFirstStop(); news != NULL; news = news->getNextStop()) { + Inkscape::XML::Node* clone = news->getRepr()->duplicate(_currentDocument->getReprDoc()); + swatch->appendChildRepr(clone); + Inkscape::GC::release(clone); + } + swatch->setSwatch(); + if (!_noLink.get_active()) { + sp_item_set_gradient(it, sp_gradient_ensure_vector_normalized(swatch), SP_IS_RADIALGRADIENT(swatch) ? SP_GRADIENT_TYPE_RADIAL : SP_GRADIENT_TYPE_LINEAR, Inkscape::FOR_STROKE); } - g_free(full); - } -// } - g_free(lower); + DocumentUndo::done(_currentDocument, SP_VERB_DIALOG_SWATCHES, _("Set Gradient Swatch")); + } + } + } else if (it->style->stroke.isColor()) { + while (SPStop* olds = swatch->getFirstStop()) { + olds->deleteObject(); } - g_dir_close(directory); + addStop(swatch->getRepr(), it->style->stroke.value.color.toString(), SP_SCALE24_TO_FLOAT(it->style->stroke_opacity.value), "0"); + swatch->setSwatch(); + if (!_noLink.get_active()) { + SPGradient* normalized = sp_gradient_ensure_vector_normalized(swatch); + sp_item_set_gradient(it, normalized, SP_GRADIENT_TYPE_LINEAR, Inkscape::FOR_STROKE); + } + DocumentUndo::done(_currentDocument, SP_VERB_DIALOG_SWATCHES, _("Set Color Swatch")); } } - - // toss the dirname - g_free(dirname); - sources.pop_front(); - userPalete = false; } } - - // Sort the list of swatches by name, grouped by user/system - userSwatchPages.sort(compare_swatch_names); - systemSwatchPages.sort(compare_swatch_names); - } +void SwatchesPanel::MoveSwatchDown(SPGradient* swatch) +{ + if (_currentDocument && swatch) { + SPObject* next = swatch->next; + while (next && (!SP_IS_GRADIENT(next) || !(SP_GRADIENT(next)->isSwatch()))) { + next = next->next; + } + if (next) { + Inkscape::XML::Node* repr = swatch->getRepr(); + repr->parent()->changeOrder(repr, next->getRepr()); + DocumentUndo::done(_currentDocument, SP_VERB_DIALOG_SWATCHES, _("Move Swatch Right")); + } + } +} - -SwatchesPanel& SwatchesPanel::getInstance() +void SwatchesPanel::MoveSwatchUp(SPGradient* swatch) { - return *new SwatchesPanel(); + if (_currentDocument && swatch) { + SPObject* g = NULL; + SPObject* next = swatch->parent->firstChild(); + while (next && next != swatch) { + if (SP_IS_GRADIENT(next) && SP_GRADIENT(next)->isSwatch()) { + g = next; + } + next = next->next; + } + if (g) { + g = g->getPrev(); + Inkscape::XML::Node* repr = swatch->getRepr(); + repr->parent()->changeOrder(repr, g ? g->getRepr() : NULL); + DocumentUndo::done(_currentDocument, SP_VERB_DIALOG_SWATCHES, _("Move Swatch Left")); + } + } } +void SwatchesPanel::RemoveSwatch(SPGradient* swatch) +{ + if (_currentDocument) { + if (swatch->isReferenced()) { + Inkscape::XML::Node * repr = swatch->getRepr(); + repr->parent()->removeChild(repr); + _currentDocument->getDefs()->getRepr()->appendChild(repr); + SP_GRADIENT(_currentDocument->getObjectByRepr(repr))->setSwatch(false); + } else { + swatch->deleteObject(false); + } + } +} -/** - * Constructor - */ -SwatchesPanel::SwatchesPanel(gchar const* prefsPath) : - Inkscape::UI::Widget::Panel("", prefsPath, SP_VERB_DIALOG_SWATCHES, "", true), - _holder(0), - _clear(0), - _remove(0), - _currentIndex(0), - _currentDesktop(0), - _currentDocument(0) +void SwatchesPanel::_setSelectionSwatch(SPGradient* swatch, bool isStroke) { - Gtk::RadioMenuItem* hotItem = 0; - _holder = new PreviewHolder(); - _clear = new ColorItem( ege::PaintDef::CLEAR ); - _remove = new ColorItem( ege::PaintDef::NONE ); - if (docPalettes.empty()) { - SwatchPage *docPalette = new SwatchPage(); - - docPalette->_name = "Auto"; - docPalettes[0] = docPalette; - } - - loadEmUp(); - if ( !systemSwatchPages.empty() ) { - SwatchPage* first = 0; - int index = 0; - Glib::ustring targetName; - if ( !_prefs_path.empty() ) { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - targetName = prefs->getString(_prefs_path + "/palette"); - if (!targetName.empty()) { - if (targetName == "Auto") { - first = docPalettes[0]; + if (_currentDocument) { + if (swatch) { + if (_noLink.get_active()) { + if (swatch->isSolid()) { + ColorRGBA rgba(swatch->getFirstStop()->getEffectiveColor().toRGBA32(swatch->getFirstStop()->opacity)); + sp_desktop_set_color(_currentDesktop, rgba, false, !isStroke); } else { - //index++; - std::vector<SwatchPage*> pages = _getSwatchSets(); - for ( std::vector<SwatchPage*>::iterator iter = pages.begin(); iter != pages.end(); ++iter ) { - if ( (*iter)->_name == targetName ) { - first = *iter; - break; - } - index++; - } + SPCSSAttr *css = sp_repr_css_attr_new(); + sp_repr_css_set_property(css, isStroke ? "stroke-opacity" : "fill-opacity", "1.0"); + + Inkscape::XML::Node * clone = swatch->getRepr()->duplicate(_currentDocument->getReprDoc()); + _currentDocument->getDefs()->appendChildRepr(clone); + SPGradient* grad = SP_GRADIENT(_currentDocument->getObjectByRepr(clone)); + Inkscape::GC::release(clone); + grad->setSwatch(false); + SPGradient* normalized = sp_gradient_ensure_vector_normalized(grad); +// for (GSList const * it = _currentDesktop->selection->itemList(); it != NULL; it = it->next) { +// sp_desktop_apply_css_recursive(SP_ITEM(it->data), css, true); +// sp_item_set_gradient(SP_ITEM(it->data), normalized, SP_IS_RADIALGRADIENT(normalized) ? SP_GRADIENT_TYPE_RADIAL : SP_GRADIENT_TYPE_LINEAR, isStroke ? Inkscape::FOR_STROKE : Inkscape::FOR_FILL); +// } + sp_desktop_set_style(_currentDesktop, css); + sp_desktop_set_gradient(_currentDesktop, normalized, !isStroke); + sp_repr_css_attr_unref (css); } + } else { + SPCSSAttr *css = sp_repr_css_attr_new(); + sp_repr_css_set_property(css, isStroke ? "stroke-opacity" : "fill-opacity", "1.0"); + + SPGradient* normalized = sp_gradient_ensure_vector_normalized(swatch); +// for (GSList const * it = _currentDesktop->selection->itemList(); it != NULL; it = it->next) { +// sp_desktop_apply_css_recursive(SP_ITEM(it->data), css, true); +// sp_item_set_gradient(SP_ITEM(it->data), normalized, SP_IS_RADIALGRADIENT(normalized) ? SP_GRADIENT_TYPE_RADIAL : SP_GRADIENT_TYPE_LINEAR, isStroke ? Inkscape::FOR_STROKE : Inkscape::FOR_FILL); +// } + sp_desktop_set_style(_currentDesktop, css); + sp_desktop_set_gradient(_currentDesktop, normalized, !isStroke); + sp_repr_css_attr_unref (css); } + } else { + SPCSSAttr *css = sp_repr_css_attr_new (); + sp_repr_css_set_property (css, isStroke ? "stroke" : "fill", "none"); + sp_desktop_set_style(_currentDesktop, css); } - - if ( !first ) { - first = docPalettes[0]; - _currentIndex = 0; + if (isStroke) { + DocumentUndo::done(_currentDocument, SP_VERB_DIALOG_SWATCHES, _("Set item stroke swatch")); } else { - _currentIndex = index; + DocumentUndo::done(_currentDocument, SP_VERB_DIALOG_SWATCHES, _("Set item fill swatch")); } + } +} - _rebuild(); - - Gtk::RadioMenuItem::Group groupOne; - - int i = 0; - std::vector<SwatchPage*> swatchSets = _getSwatchSets(); - for ( std::vector<SwatchPage*>::iterator it = swatchSets.begin(); it != swatchSets.end(); ++it) { - SwatchPage* curr = *it; - Gtk::RadioMenuItem* single = manage(new Gtk::RadioMenuItem(groupOne, curr->_name)); - if ( curr == first ) { - hotItem = single; +void SwatchesPanel::_swatchClicked(GdkEventButton* event, SPGradient* swatch) +{ + if (_currentDesktop) { + if (event->button == 3) { + Gtk::Menu * menu = Gtk::manage(new Gtk::Menu()); + + Gtk::MenuItem* mi; + + Glib::ustring us = Glib::ustring::compose("<b>%1</b>", swatch ? (swatch->label() ? swatch->label() : swatch->getId()) : _("[None]")); + mi = Gtk::manage(new Gtk::MenuItem(swatch ? (swatch->label() ? swatch->label() : swatch->getId()) : _("[None]"))); + Gtk::Label* namelbl = dynamic_cast<Gtk::Label*>(mi->get_child()); + if (namelbl) { + namelbl->set_markup(us); + } + mi->show(); + mi->set_sensitive(false); + menu->append(*mi); + + Gtk::SeparatorMenuItem* sep; + sep = manage(new Gtk::SeparatorMenuItem()); + sep->show(); + menu->append(*sep); + + mi = Gtk::manage(new Gtk::MenuItem(_("Set Fill"))); + mi->signal_activate().connect_notify(sigc::bind<SPGradient*, bool>(sigc::mem_fun(*this, &SwatchesPanel::_setSelectionSwatch), swatch, false)); + mi->show(); + mi->set_sensitive(_currentDesktop && !_currentDesktop->selection->isEmpty()); + menu->append(*mi); + + mi = Gtk::manage(new Gtk::MenuItem(_("Set Stroke"))); + mi->signal_activate().connect_notify(sigc::bind<SPGradient*, bool>(sigc::mem_fun(*this, &SwatchesPanel::_setSelectionSwatch), swatch, true)); + mi->show(); + mi->set_sensitive(_currentDesktop && !_currentDesktop->selection->isEmpty()); + menu->append(*mi); + + if (swatch) { + sep = manage(new Gtk::SeparatorMenuItem()); + sep->show(); + menu->append(*sep); + + mi = Gtk::manage(new Gtk::MenuItem(_("Set to Selected Fill"))); + mi->signal_activate().connect_notify(sigc::bind<SPGradient*>(sigc::mem_fun(*this, &SwatchesPanel::SetSelectedFill), swatch)); + mi->show(); + mi->set_sensitive(_currentDesktop && _currentDesktop->selection->singleItem()); + menu->append(*mi); + + mi = Gtk::manage(new Gtk::MenuItem(_("Set to Selected Stroke"))); + mi->signal_activate().connect_notify(sigc::bind<SPGradient*>(sigc::mem_fun(*this, &SwatchesPanel::SetSelectedStroke), swatch)); + mi->show(); + mi->set_sensitive(_currentDesktop && _currentDesktop->selection->singleItem()); + menu->append(*mi); + + + sep = manage(new Gtk::SeparatorMenuItem()); + sep->show(); + menu->append(*sep); + + mi = Gtk::manage(new Gtk::MenuItem(_("Move Left"))); + mi->signal_activate().connect_notify(sigc::bind<SPGradient*>(sigc::mem_fun(*this, &SwatchesPanel::MoveSwatchUp), swatch)); + mi->show(); + menu->append(*mi); + + mi = Gtk::manage(new Gtk::MenuItem(_("Move Right"))); + mi->signal_activate().connect_notify(sigc::bind<SPGradient*>(sigc::mem_fun(*this, &SwatchesPanel::MoveSwatchDown), swatch)); + mi->show(); + menu->append(*mi); + + sep = manage(new Gtk::SeparatorMenuItem()); + sep->show(); + menu->append(*sep); + + mi = Gtk::manage(new Gtk::MenuItem(_("Remove"))); + mi->signal_activate().connect_notify(sigc::bind<SPGradient*>(sigc::mem_fun(*this, &SwatchesPanel::RemoveSwatch), swatch)); + mi->show(); + menu->append(*mi); } - _regItem( single, 3, i ); - i++; + menu->popup(event->button, event->time); + } else if (!_currentDesktop->selection->isEmpty()) { + _setSelectionSwatch(swatch, event->state & GDK_SHIFT_MASK); } } +} - if (Glib::ustring(prefsPath) == "/dialogs/swatches") { - Gtk::Requisition sreq; -#if WITH_GTKMM_3_0 - Gtk::Requisition sreq_natural; - get_preferred_size(sreq_natural, sreq); -#else - sreq = size_request(); -#endif - int minHeight = 60; - if (sreq.height < minHeight) { - set_size_request(70, minHeight); +void SwatchesPanel::MoveDown(SPGroup* page) +{ + if (_currentDocument && page) { + SPObject* next = page->next; + while (next && !SP_IS_GROUP(next)) { + next = next->next; + } + if (next) { + Inkscape::XML::Node* repr = page->getRepr(); + repr->parent()->changeOrder(repr, next->getRepr()); + DocumentUndo::done(_currentDocument, SP_VERB_DIALOG_SWATCHES, _("Move Swatch Down")); } } +} - _getContents()->pack_start(*_holder, Gtk::PACK_EXPAND_WIDGET); - _setTargetFillable(_holder); - - show_all_children(); - - restorePanelPrefs(); - if ( hotItem ) { - hotItem->set_active(); +void SwatchesPanel::MoveUp(SPGroup* page) +{ + if (_currentDocument && page) { + SPObject* g = NULL; + SPObject* next = page->parent->firstChild(); + while (next && next != page) { + if (SP_IS_GROUP(next)) { + g = next; + } + next = next->next; + } + if (g) { + g = g->getPrev(); + Inkscape::XML::Node* repr = page->getRepr(); + repr->parent()->changeOrder(repr, g ? g->getRepr() : NULL); + DocumentUndo::done(_currentDocument, SP_VERB_DIALOG_SWATCHES, _("Move Swatch Up")); + } } } -SwatchesPanel::~SwatchesPanel() +void SwatchesPanel::Remove(SPGroup* page) { - _trackDocument( this, 0 ); + if (_currentDocument && page) { + std::vector<Inkscape::XML::Node*> toMove; + for(SPObject* obj = page->firstChild(); obj != NULL; obj = obj->next) { + if (SP_IS_GRADIENT(obj)) { + SPGradient* grad = SP_GRADIENT(obj); + if (grad->isReferenced()) { + toMove.push_back(grad->getRepr()); + } + } + } + while (!toMove.empty()) { + Inkscape::XML::Node * repr = toMove.back(); + toMove.pop_back(); + repr->parent()->removeChild(repr); + _currentDocument->getDefs()->getRepr()->appendChild(repr); + SP_GRADIENT(_currentDocument->getObjectByRepr(repr))->setSwatch(false); + } + page->deleteObject(false); + DocumentUndo::done(_currentDocument, SP_VERB_DIALOG_SWATCHES, _("Remove Swatch Group")); + } +} - _documentConnection.disconnect(); - _selChanged.disconnect(); +void SwatchesPanel::AddSelectedFill(SPGroup* page) +{ + if (_currentDesktop && _currentDocument) { + SPItem* it = _currentDesktop->selection->singleItem(); + if (it) { + if (it->style->fill.isSet()) { + if (it->style->fill.isPaintserver()) { + SPPaintServer * server = it->style->getFillPaintServer(); + if (SP_IS_GRADIENT(server)) { + SPGradient *grad = SP_GRADIENT(server)->getVector(); + if (_noLink.get_active()) { + Inkscape::XML::Node * clone = grad->getRepr()->duplicate(_currentDocument->getReprDoc()); + clone->setAttribute( "osb:paint", "gradient", 0 ); + if (page) { + page->appendChildRepr(clone); + } else { + _currentDocument->getDefs()->appendChildRepr(clone); + } + Inkscape::GC::release(clone); + DocumentUndo::done(_currentDocument, SP_VERB_DIALOG_SWATCHES, _("Add Gradient Swatch")); + } else if (grad->isSwatch()) { + Inkscape::XML::Node * repr = grad->getRepr(); + Inkscape::XML::Node * clone = repr->duplicate(_currentDocument->getReprDoc()); + if (page) { + page->appendChildRepr(clone); + } else { + _currentDocument->getDefs()->appendChildRepr(clone); + } + SPGradient *newgrad = SP_GRADIENT(_currentDocument->getObjectByRepr(clone)); + + sp_item_set_gradient(it, sp_gradient_ensure_vector_normalized(newgrad), SP_IS_RADIALGRADIENT(newgrad) ? SP_GRADIENT_TYPE_RADIAL : SP_GRADIENT_TYPE_LINEAR, Inkscape::FOR_FILL); + Inkscape::GC::release(clone); + DocumentUndo::done(_currentDocument, SP_VERB_DIALOG_SWATCHES, _("Add Gradient Swatch")); + } else { + Inkscape::XML::Node * repr = grad->getRepr(); + Inkscape::XML::Node * drepr = page ? page->getRepr() : _currentDocument->getDefs()->getRepr(); + if (repr->parent() != drepr) { + repr->parent()->removeChild(repr); + drepr->appendChild(repr); + } + SP_GRADIENT(_currentDocument->getObjectByRepr(repr))->setSwatch(); + DocumentUndo::done(_currentDocument, SP_VERB_DIALOG_SWATCHES, _("Add Gradient Swatch")); + } + } + } else if (it->style->fill.isColor()) { + Inkscape::XML::Node *grad = _currentDocument->getReprDoc()->createElement("svg:linearGradient"); + grad->setAttribute( "osb:paint", "solid", 0 ); + addStop(grad, it->style->fill.value.color.toString(), SP_SCALE24_TO_FLOAT(it->style->fill_opacity.value), "0"); + if (page) { + page->appendChild(grad); + } else { + _currentDocument->getDefs()->appendChild(grad); + } + SPGradient* normalized = sp_gradient_ensure_vector_normalized(SP_GRADIENT(_currentDocument->getObjectByRepr(grad))); + Inkscape::GC::release(grad); + if (!_noLink.get_active()) { + sp_item_set_gradient(it, normalized, SP_GRADIENT_TYPE_LINEAR, Inkscape::FOR_FILL); + } + DocumentUndo::done(_currentDocument, SP_VERB_DIALOG_SWATCHES, _("Add Color Swatch")); + } + } + } + } +} - if ( _clear ) { - delete _clear; +void SwatchesPanel::AddSelectedStroke(SPGroup* page) +{ + if (_currentDesktop && _currentDocument) { + SPItem* it = _currentDesktop->selection->singleItem(); + if (it) { + if (it->style->stroke.isSet()) { + if (it->style->stroke.isPaintserver()) { + SPPaintServer * server = it->style->getStrokePaintServer(); + if (SP_IS_GRADIENT(server)) { + SPGradient *grad = SP_GRADIENT(server)->getVector(); + if (_noLink.get_active()) { + Inkscape::XML::Node * clone = grad->getRepr()->duplicate(_currentDocument->getReprDoc()); + clone->setAttribute( "osb:paint", "gradient", 0 ); + if (page) { + page->appendChildRepr(clone); + } else { + _currentDocument->getDefs()->appendChildRepr(clone); + } + Inkscape::GC::release(clone); + DocumentUndo::done(_currentDocument, SP_VERB_DIALOG_SWATCHES, _("Add Gradient Swatch")); + } else if (grad->isSwatch()) { + Inkscape::XML::Node * repr = grad->getRepr(); + Inkscape::XML::Node * clone = repr->duplicate(_currentDocument->getReprDoc()); + if (page) { + page->appendChildRepr(clone); + } else { + _currentDocument->getDefs()->appendChildRepr(clone); + } + SPGradient *newgrad = SP_GRADIENT(_currentDocument->getObjectByRepr(clone)); + + sp_item_set_gradient(it, sp_gradient_ensure_vector_normalized(newgrad), SP_IS_RADIALGRADIENT(newgrad) ? SP_GRADIENT_TYPE_RADIAL : SP_GRADIENT_TYPE_LINEAR, Inkscape::FOR_STROKE); + Inkscape::GC::release(clone); + DocumentUndo::done(_currentDocument, SP_VERB_DIALOG_SWATCHES, _("Add Gradient Swatch")); + } else { + Inkscape::XML::Node * repr = grad->getRepr(); + Inkscape::XML::Node * drepr = page ? page->getRepr() : _currentDocument->getDefs()->getRepr(); + if (repr->parent() != drepr) { + repr->parent()->removeChild(repr); + drepr->appendChild(repr); + } + SP_GRADIENT(_currentDocument->getObjectByRepr(repr))->setSwatch(); + DocumentUndo::done(_currentDocument, SP_VERB_DIALOG_SWATCHES, _("Add Gradient Swatch")); + } + } + } else if (it->style->stroke.isColor()) { + Inkscape::XML::Node *grad = _currentDocument->getReprDoc()->createElement("svg:linearGradient"); + grad->setAttribute( "osb:paint", "solid", 0 ); + addStop(grad, it->style->stroke.value.color.toString(), SP_SCALE24_TO_FLOAT(it->style->stroke_opacity.value), "0"); + if (page) { + page->appendChild(grad); + } else { + _currentDocument->getDefs()->appendChild(grad); + } + SPGradient* normalized = sp_gradient_ensure_vector_normalized(SP_GRADIENT(_currentDocument->getObjectByRepr(grad))); + Inkscape::GC::release(grad); + if (!_noLink.get_active()) { + sp_item_set_gradient(it, normalized, SP_GRADIENT_TYPE_LINEAR, Inkscape::FOR_STROKE); + } + DocumentUndo::done(_currentDocument, SP_VERB_DIALOG_SWATCHES, _("Add Color Swatch")); + } + } + } } - if ( _remove ) { - delete _remove; +} + +void SwatchesPanel::_addBIButtonClicked(GdkEventButton* event) +{ + if (popUpImportMenu) { + popUpImportMenu->popup(event->button, event->time); } - if ( _holder ) { - delete _holder; +} + +void SwatchesPanel::NewGroupBI() +{ + if (_currentDocument) { + Inkscape::XML::Node * page = SwatchDocument->getReprDoc()->createElement("svg:g"); + gchar *id=NULL; + do { + g_free(id); + id = g_strdup_printf("page%d", page_suffix++); + } while (SwatchDocument->getObjectById(id)); + + page->setAttribute("id", id); + + SwatchDocument->getDefs()->appendChild(page); + sp_repr_save_file(SwatchDocument->getReprDoc(), SwatchFile, SP_SVG_NS_URI); } } -void SwatchesPanel::setOrientation(SPAnchorType how) +void SwatchesPanel::NewGroup() { - // Must call the parent class or bad things might happen - Inkscape::UI::Widget::Panel::setOrientation( how ); + if (_currentDocument) { + Inkscape::XML::Node * page = _currentDocument->getReprDoc()->createElement("svg:g"); + gchar *id=NULL; + do { + g_free(id); + id = g_strdup_printf("page%d", page_suffix++); + } while (_currentDocument->getObjectById(id)); + + page->setAttribute("id", id); + + _currentDocument->getDefs()->appendChild(page); + DocumentUndo::done(_currentDocument, SP_VERB_DIALOG_SWATCHES, _("New Swatch Group")); + } +} - if ( _holder ) - { - _holder->setOrientation(SP_ANCHOR_SOUTH); +void SwatchesPanel::SaveAs() +{ + if (_currentDocument) { + Inkscape::XML::Node * page = _currentDocument->getReprDoc()->createElement("svg:g"); + gchar *id=NULL; + do { + g_free(id); + id = g_strdup_printf("page%d", page_suffix++); + } while (_currentDocument->getObjectById(id)); + + page->setAttribute("id", id); + + std::vector<Inkscape::XML::Node*> toMove; + for (SPObject *it = _currentDocument->getDefs()->firstChild(); it != NULL; it = it->next) { + if (SP_IS_GRADIENT(it)) { + SPGradient* grad = SP_GRADIENT(it); + if (grad->isSwatch()) { + toMove.push_back(grad->getRepr()); + } + } + } + while (!toMove.empty()) { + Inkscape::XML::Node* repr = toMove.back(); + toMove.pop_back(); + repr->parent()->removeChild(repr); + page->appendChild(repr); + } + _currentDocument->getDefs()->appendChild(page); + DocumentUndo::done(_currentDocument, SP_VERB_DIALOG_SWATCHES, _("Save Swatch Group")); } } -void SwatchesPanel::setDesktop( SPDesktop* desktop ) +void SwatchesPanel::Duplicate(SPGroup* oldpage) { - if ( desktop != _currentDesktop ) { - if ( _currentDesktop ) { - _documentConnection.disconnect(); - _selChanged.disconnect(); + if (_currentDocument) { + Inkscape::XML::Node * page = _currentDocument->getReprDoc()->createElement("svg:g"); + gchar *id=NULL; + do { + g_free(id); + id = g_strdup_printf("page%d", page_suffix++); + } while (_currentDocument->getObjectById(id)); + + page->setAttribute("id", id); + if (oldpage->label()) page->setAttribute("inkscape:label", oldpage->label()); + + for (SPObject *it = oldpage->firstChild(); it != NULL; it = it->next) { + if (SP_IS_GRADIENT(it)) { + SPGradient* grad = SP_GRADIENT(it); + if (grad->isSwatch()) { + Inkscape::XML::Node * copy = grad->getRepr()->duplicate(_currentDocument->getReprDoc()); + page->appendChild(copy); + Inkscape::GC::release(copy); + } + } } + _currentDocument->getDefs()->appendChild(page); + DocumentUndo::done(_currentDocument, SP_VERB_DIALOG_SWATCHES, _("Duplicate Swatch Group")); + } +} - _currentDesktop = desktop; +void SwatchesPanel::_lblClick(GdkEventButton* event, SPGroup* page) +{ + Gtk::Menu * menu = Gtk::manage(new Gtk::Menu()); + + Gtk::MenuItem* mi; + Glib::ustring us = Glib::ustring::compose("<b>%1</b>", page ? (page->label() ? page->label() : page->getId()) : _("[Base]")); + mi = Gtk::manage(new Gtk::MenuItem(page ? (page->label() ? page->label() : page->getId()) : _("[Base]"))); + Gtk::Label* namelbl = dynamic_cast<Gtk::Label*>(mi->get_child()); + if (namelbl) { + namelbl->set_markup(us); + } + mi->show(); + mi->set_sensitive(false); + menu->append(*mi); + + Gtk::SeparatorMenuItem* sep; + sep = manage(new Gtk::SeparatorMenuItem()); + sep->show(); + menu->append(*sep); + + mi = Gtk::manage(new Gtk::MenuItem(_("Add Selected Fill"))); + mi->signal_activate().connect_notify(sigc::bind<SPGroup*>(sigc::mem_fun(*this, &SwatchesPanel::AddSelectedFill), page)); + mi->show(); + mi->set_sensitive(_currentDesktop && _currentDesktop->selection->singleItem()); + menu->append(*mi); + + mi = Gtk::manage(new Gtk::MenuItem(_("Add Selected Stroke"))); + mi->signal_activate().connect_notify(sigc::bind<SPGroup*>(sigc::mem_fun(*this, &SwatchesPanel::AddSelectedStroke), page)); + mi->show(); + mi->set_sensitive(_currentDesktop && _currentDesktop->selection->singleItem()); + menu->append(*mi); + + sep = manage(new Gtk::SeparatorMenuItem()); + sep->show(); + menu->append(*sep); + + if (page) { + + mi = Gtk::manage(new Gtk::MenuItem(_("Move Up"))); + mi->signal_activate().connect_notify(sigc::bind<SPGroup*>(sigc::mem_fun(*this, &SwatchesPanel::MoveUp), page)); + mi->show(); + menu->append(*mi); + + mi = Gtk::manage(new Gtk::MenuItem(_("Move Down"))); + mi->signal_activate().connect_notify(sigc::bind<SPGroup*>(sigc::mem_fun(*this, &SwatchesPanel::MoveDown), page)); + mi->show(); + menu->append(*mi); + + sep = manage(new Gtk::SeparatorMenuItem()); + sep->show(); + menu->append(*sep); + + mi = Gtk::manage(new Gtk::MenuItem(_("Duplicate"))); + mi->signal_activate().connect_notify(sigc::bind<SPGroup*>(sigc::mem_fun(*this, &SwatchesPanel::Duplicate), page)); + mi->show(); + menu->append(*mi); + + sep = manage(new Gtk::SeparatorMenuItem()); + sep->show(); + menu->append(*sep); + + mi = Gtk::manage(new Gtk::MenuItem(_("Remove"))); + mi->signal_activate().connect_notify(sigc::bind<SPGroup*>(sigc::mem_fun(*this, &SwatchesPanel::Remove), page)); + mi->show(); + menu->append(*mi); + } else { + mi = Gtk::manage(new Gtk::MenuItem(_("Create New Group"))); + mi->signal_activate().connect_notify(sigc::mem_fun(*this, &SwatchesPanel::NewGroup)); + mi->show(); + menu->append(*mi); + + mi = Gtk::manage(new Gtk::MenuItem(_("Save As New Group"))); + mi->signal_activate().connect_notify(sigc::mem_fun(*this, &SwatchesPanel::SaveAs)); + mi->show(); + menu->append(*mi); + } + + menu->popup(event->button, event->time); +} - if ( desktop ) { - _currentDesktop->selection->connectChanged( - sigc::hide(sigc::mem_fun(*this, &SwatchesPanel::_updateFromSelection))); +void SwatchesPanel::_defsChanged() +{ + if (_storeDoc) { + _storeDoc->clear(); + } + + while (!docWatchers.empty()) { + Inkscape::XML::NodeObserver* w = docWatchers.back(); + docWatchers.pop_back(); + delete w; + } + + std::vector<Gtk::Widget *> tableChildren = _insideTable.get_children(); + for (std::vector<Gtk::Widget *>::iterator c = tableChildren.begin(); c != tableChildren.end(); ++c) { + _insideTable.remove(**c); + } + + if (_currentDocument) { + Gtk::EventBox* eb; + Gtk::Label* lbl; + if (_showlabels) { + eb = Gtk::manage(new Gtk::EventBox()); + eb->add_events(Gdk::BUTTON_PRESS_MASK); + eb->signal_button_press_event().connect_notify(sigc::bind<SPGroup*>(sigc::mem_fun(*this, &SwatchesPanel::_lblClick), NULL)); + + lbl = Gtk::manage(new Gtk::Label(_("[Base]"))); + eb->add(*lbl); + _insideTable.attach( *eb, 0, 1, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND , 5, 0); + } + Glib::ustring str1 = Glib::ustring(_("[None]")); + ColorItem* item = Gtk::manage(new ColorItem(NULL, NULL, NULL, str1)); + //item->signal_button_press_event().connect_notify(sigc::bind<SPGradient *>(sigc::mem_fun(*this, &SwatchesPanel::_swatchClicked), NULL)); + item->setName(_("[None]")); + _insideTable.attach( *item, _showlabels ? 1 : 0, _showlabels ? 2 : 1, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND ); + + unsigned int i = 1; + for (SPObject *it = _currentDocument->getDefs()->firstChild(); it != NULL; it = it->next) { + if (SP_IS_GRADIENT(it)) { + SPGradient* grad = SP_GRADIENT(it); + if (grad->hasStops()) { + + GradientWatcher* w = new GradientWatcher(this, grad); + docWatchers.push_back(w); + + if (grad->isSwatch()) { + + for (SPStop* s = grad->getFirstStop(); s != NULL; s = s->getNextStop()) { + StopWatcher* sw = new StopWatcher(this, s); + docWatchers.push_back(sw); + } - _currentDesktop->selection->connectModified( - sigc::hide(sigc::hide(sigc::mem_fun(*this, &SwatchesPanel::_updateFromSelection)))); + if (_storeDoc) { + Gtk::TreeModel::iterator iter = _storeDoc->append(); + Gtk::TreeModel::Row row = *iter; + row[_modelDoc->_colObject] = grad; + row[_modelDoc->_colLabel] = grad->label() ? grad->label() : grad->getId(); + GdkPixbuf* pixb = sp_gradient_to_pixbuf (grad, 64, 18); + row[_modelDoc->_colPixbuf] = Glib::wrap(pixb); + } + Glib::ustring str2 = Glib::ustring(it->label() ? it->label() : it->getId()); + item = Gtk::manage(new ColorItem(NULL, NULL, NULL, str2)); + item->setGradient(grad); + //item->colorItemHandleButtonPress().connect_notify(sigc::bind<SPGradient *>(sigc::mem_fun(*this, &SwatchesPanel::_swatchClicked), grad)); + item->setName(it->label() ? it->label() : it->getId()); + if (_showlabels) { + _insideTable.attach( *item, 1 + (i % 20), 2 + (i % 20), i / 20, i / 20 + 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND ); + } else { + _insideTable.attach( *item, i, i + 1, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND ); + } - _currentDesktop->connectToolSubselectionChanged( - sigc::hide(sigc::mem_fun(*this, &SwatchesPanel::_updateFromSelection))); + i++; + } + } + } + } + + for (SPObject *it = _currentDocument->getDefs()->firstChild(); it != NULL; it = it->next) { + if (SP_IS_GROUP(it)) { + SwatchWatcher* w = new SwatchWatcher(this, it, false); + docWatchers.push_back(w); + + if (_showlabels) { + i += 20 - (i % 20); + eb = Gtk::manage(new Gtk::EventBox()); + eb->add_events(Gdk::BUTTON_PRESS_MASK); + eb->signal_button_press_event().connect_notify(sigc::bind<SPGroup*>(sigc::mem_fun(*this, &SwatchesPanel::_lblClick), SP_GROUP(it))); + lbl = Gtk::manage(new Gtk::Label(it->label() ? it->label() : it->getId())); + eb->add(*lbl); + _insideTable.attach( *eb, 0, 1, i / 20, i / 20 + 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND , 5, 0); + } + + Gtk::TreeModel::iterator rowiter; + + if (_storeDoc) { + rowiter = _storeDoc->append(); + Gtk::TreeModel::Row row = *rowiter; + row[_modelDoc->_colObject] = it; + row[_modelDoc->_colLabel] = it->label() ? it->label() : it->getId(); + } + + for (SPObject *cit = it->firstChild(); cit != NULL; cit = cit->next) { + if (SP_IS_GRADIENT(cit)) { + SPGradient* grad = SP_GRADIENT(cit); + + if (grad->hasStops()) { + + GradientWatcher* w = new GradientWatcher(this, grad); + docWatchers.push_back(w); + + if (grad->isSwatch()) { + + for (SPStop* s = grad->getFirstStop(); s != NULL; s = s->getNextStop()) { + StopWatcher* sw = new StopWatcher(this, s); + docWatchers.push_back(sw); + } - sigc::bound_mem_functor1<void, Inkscape::UI::Dialogs::SwatchesPanel, SPDocument*> first = sigc::mem_fun(*this, &SwatchesPanel::_setDocument); - sigc::slot<void, SPDocument*> base2 = first; - sigc::slot<void,SPDesktop*, SPDocument*> slot2 = sigc::hide<0>( base2 ); - _documentConnection = desktop->connectDocumentReplaced( slot2 ); + if (_storeDoc && rowiter) { + Gtk::TreeModel::iterator iter = _storeDoc->append(rowiter->children()); + Gtk::TreeModel::Row row = *iter; + row[_modelDoc->_colObject] = grad; + row[_modelDoc->_colLabel] = grad->label() ? grad->label() : grad->getId(); + GdkPixbuf* pixb = sp_gradient_to_pixbuf (grad, 64, 18); + row[_modelDoc->_colPixbuf] = Glib::wrap(pixb); - _setDocument( desktop->doc() ); - } else { - _setDocument(0); + _editDoc.expand_to_path(_storeDoc->get_path(iter)); + } + Glib::ustring str3= Glib::ustring(cit->label() ? cit->label() : cit->getId()); + item = Gtk::manage(new ColorItem(NULL, NULL, NULL, str3)); + item->setGradient(grad); + //item->signal_button_press_event().connect_notify(sigc::bind<SPGradient *>(sigc::mem_fun(*this, &SwatchesPanel::_swatchClicked), grad)); + item->setName(cit->label() ? cit->label() : cit->getId()); + if (_showlabels) { + _insideTable.attach( *item, 1 + (i % 20), 2 + (i % 20), i / 20, i / 20 + 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND ); + } else { + _insideTable.attach( *item, i, i + 1, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND ); + } + i++; + } + } + } + } + } } } + + _scroller.show_all_children(); + _scroller.queue_draw(); } - -class DocTrack +Gtk::MenuItem* SwatchesPanel::_addSwatchGroup(SPGroup* group, Gtk::TreeModel::Row* parentRow) { -public: - DocTrack(SPDocument *doc, sigc::connection &docDestroy, sigc::connection &gradientRsrcChanged, sigc::connection &defsChanged, sigc::connection &defsModified) : - doc(doc), - updatePending(false), - lastGradientUpdate(0.0), - docDestroy(docDestroy), - gradientRsrcChanged(gradientRsrcChanged), - defsChanged(defsChanged), - defsModified(defsModified) - { - if ( !timer ) { - timer = new Glib::Timer(); - refreshTimer = Glib::signal_timeout().connect( sigc::ptr_fun(handleTimerCB), 33 ); + Gtk::MenuItem* mi = manage(new Gtk::MenuItem(group->label() ? group->label() : group->getId(),1)); + Gtk::Menu* m = NULL; + + Gtk::TreeModel::Row* r; + if (_store) { + Gtk::TreeModel::iterator iter = parentRow ? _store->append(parentRow->children()) : _store->append(); + Gtk::TreeModel::Row row = *iter; + row[_model->_colObject] = group; + row[_model->_colLabel] = group->label() ? group->label() : group->getId(); + + if (SP_IS_GROUP(group->parent) && SP_GROUP(group->parent)->expanded()) { + _editBI.expand_to_path(_store->get_path(iter)); } - timerRefCount++; + r = &row; + } else { + r = NULL; } - - ~DocTrack() + + bool hasswatches = false; + for (SPObject * obj = group->firstChild(); obj != NULL; obj = obj->next) { - timerRefCount--; - if ( timerRefCount <= 0 ) { - refreshTimer.disconnect(); - timerRefCount = 0; - if ( timer ) { - timer->stop(); - delete timer; - timer = 0; + if (SP_IS_GROUP(obj)) { + if (!m) { + m = manage(new Gtk::Menu()); + m->show_all(); + mi->set_submenu(*m); + + Gtk::MenuItem* basemi = manage(new Gtk::MenuItem(_("[All]"))); + basemi->show(); + Gtk::Label* namelbl = dynamic_cast<Gtk::Label*>(basemi->get_child()); + if (namelbl) { + namelbl->set_markup(_("<b>[All]</b>")); + } + basemi->signal_activate().connect(sigc::bind<SPGroup*, bool>(sigc::mem_fun(*this, &SwatchesPanel::_addSwatchButtonClicked), group, true)); + m->append(*basemi); + + Gtk::SeparatorMenuItem* sep = manage(new Gtk::SeparatorMenuItem()); + sep->show(); + m->append(*sep); } + SwatchWatcher* w = new SwatchWatcher(this, obj, true); + rootWatchers.push_back(w); + m->append(*_addSwatchGroup(SP_GROUP(obj), r)); + } else if (SP_IS_GRADIENT(obj)) { + hasswatches = true; } - if (doc) { - docDestroy.disconnect(); - gradientRsrcChanged.disconnect(); - defsChanged.disconnect(); - defsModified.disconnect(); - doc = NULL; + } + if (!m) { + mi->signal_activate().connect(sigc::bind<SPGroup*, bool>(sigc::mem_fun(*this, &SwatchesPanel::_addSwatchButtonClicked), group, false)); + } else if (hasswatches) { + Glib::ustring us = Glib::ustring::compose("<b>%1</b>", group->label() ? group->label() : group->getId()); + Gtk::MenuItem* basemi = manage(new Gtk::MenuItem(group->label() ? group->label() : group->getId())); + basemi->show(); + Gtk::Label* namelbl = dynamic_cast<Gtk::Label*>(basemi->get_child()); + if (namelbl) { + namelbl->set_markup(us); } + basemi->signal_activate().connect(sigc::bind<SPGroup*, bool>(sigc::mem_fun(*this, &SwatchesPanel::_addSwatchButtonClicked), group, false)); + m->prepend(*basemi); } + mi->show(); + return mi; +} - static bool handleTimerCB(); - - /** - * Checks if update should be queued or executed immediately. - * - * @return true if the update was queued and should not be immediately executed. - */ - static bool queueUpdateIfNeeded(SPDocument *doc); - - static Glib::Timer *timer; - static int timerRefCount; - static sigc::connection refreshTimer; - - SPDocument *doc; - bool updatePending; - double lastGradientUpdate; - sigc::connection docDestroy; - sigc::connection gradientRsrcChanged; - sigc::connection defsChanged; - sigc::connection defsModified; - -private: - DocTrack(DocTrack const &); // no copy - DocTrack &operator=(DocTrack const &); // no assign -}; - -Glib::Timer *DocTrack::timer = 0; -int DocTrack::timerRefCount = 0; -sigc::connection DocTrack::refreshTimer; +void SwatchesPanel::_swatchesChanged() +{ + while (!rootWatchers.empty()) { + Inkscape::XML::NodeObserver* w = rootWatchers.back(); + rootWatchers.pop_back(); + delete w; + } -static const double DOC_UPDATE_THREASHOLD = 0.090; + std::vector<Gtk::Widget *> menuChildren = popUpMenu->get_children(); + for (std::vector<Gtk::Widget *>::iterator c = menuChildren.begin(); c != menuChildren.end(); ++c) { + popUpMenu->remove(**c); + } + + if (_store) { + _store->clear(); + } + + Gtk::MenuItem* mi; + + for (SPObject * obj = SwatchDocument->getDefs()->firstChild(); obj != NULL; obj = obj->next) + { + if (SP_IS_GROUP(obj)) { + SwatchWatcher* w = new SwatchWatcher(this, obj, true); + rootWatchers.push_back(w); + popUpMenu->append(*_addSwatchGroup(SP_GROUP(obj), NULL)); + + } + } + Gtk::SeparatorMenuItem* sep = manage(new Gtk::SeparatorMenuItem()); + sep->show(); + popUpMenu->append(*sep); + + mi = manage(new Gtk::MenuItem(_("New Swatch Group..."),1)); + mi->signal_activate().connect(sigc::mem_fun(*this, &SwatchesPanel::NewGroup)); + mi->show(); + popUpMenu->append(*mi); + + mi = manage(new Gtk::MenuItem(_("Add Swatch File..."),1)); + mi->signal_activate().connect(sigc::bind<bool, bool>(sigc::mem_fun(*this, &SwatchesPanel::_importButtonClicked), true, false)); + mi->show(); + popUpMenu->append(*mi); + + mi = manage(new Gtk::MenuItem(_("Import Swatch File..."),1)); + mi->signal_activate().connect(sigc::bind<bool, bool>(sigc::mem_fun(*this, &SwatchesPanel::_importButtonClicked), true, true)); + mi->show(); + popUpMenu->append(*mi); +} -bool DocTrack::handleTimerCB() +void SwatchesPanel::_styleButton( Gtk::Button& btn, SPDesktop *desktop, unsigned int code, char const* iconName, char const* fallback ) { - double now = timer->elapsed(); + bool set = false; + + if ( iconName ) { + GtkWidget *child = sp_icon_new( Inkscape::ICON_SIZE_SMALL_TOOLBAR, iconName ); + gtk_widget_show( child ); + btn.add( *manage(Glib::wrap(child)) ); + btn.set_relief(Gtk::RELIEF_NONE); + set = true; + } - std::vector<DocTrack *> needCallback; - for (std::vector<DocTrack *>::iterator it = docTrackings.begin(); it != docTrackings.end(); ++it) { - DocTrack *track = *it; - if ( track->updatePending && ( (now - track->lastGradientUpdate) >= DOC_UPDATE_THREASHOLD) ) { - needCallback.push_back(track); + if ( desktop ) { + Verb *verb = Verb::get( code ); + if ( verb ) { + SPAction *action = verb->get_action(desktop); + if ( !set && action && action->image ) { + GtkWidget *child = sp_icon_new( Inkscape::ICON_SIZE_SMALL_TOOLBAR, action->image ); + gtk_widget_show( child ); + btn.add( *manage(Glib::wrap(child)) ); + set = true; + } } } + + btn.set_tooltip_text (fallback); + + if ( !set ) { + btn.set_label( fallback ); + } +} - for (std::vector<DocTrack *>::iterator it = needCallback.begin(); it != needCallback.end(); ++it) { - DocTrack *track = *it; - if ( std::find(docTrackings.begin(), docTrackings.end(), track) != docTrackings.end() ) { // Just in case one gets deleted while we are looping - // Note: calling handleDefsModified will call queueUpdateIfNeeded and thus update the time and flag. - SwatchesPanel::handleDefsModified(track->doc); +void SwatchesPanel::_addButtonClicked(GdkEventButton* event) { + if ( (event->type == GDK_BUTTON_PRESS) && (event->button == 3 || event->button == 1) ) { + if (popUpMenu) { + popUpMenu->popup(event->button, event->time); } } +} - return true; +void SwatchesPanel::NoLinkToggled() { + static Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + Glib::ustring nolink = Glib::ustring::compose("%1/nolink", _prefs_path); + prefs->setBool(nolink, _noLink.get_active()); } -bool DocTrack::queueUpdateIfNeeded( SPDocument *doc ) +bool SwatchesPanel::_handleButtonEvent(GdkEventButton *event) { - bool deferProcessing = false; - for (std::vector<DocTrack*>::iterator it = docTrackings.begin(); it != docTrackings.end(); ++it) { - DocTrack *track = *it; - if ( track->doc == doc ) { - double now = timer->elapsed(); - double elapsed = now - track->lastGradientUpdate; - - if ( elapsed < DOC_UPDATE_THREASHOLD ) { - deferProcessing = true; - track->updatePending = true; - } else { - track->lastGradientUpdate = now; - track->updatePending = false; - } + static unsigned doubleclick = 0; + if ( (event->type == GDK_2BUTTON_PRESS) && (event->button == 1) ) { + doubleclick = 1; + } - break; + if ( event->type == GDK_BUTTON_RELEASE && doubleclick) { + doubleclick = 0; + Gtk::TreeModel::Path path; + Gtk::TreeViewColumn* col = 0; + int x = static_cast<int>(event->x); + int y = static_cast<int>(event->y); + int x2 = 0; + int y2 = 0; + if ( _editBI.get_path_at_pos( x, y, path, col, x2, y2 ) && col == _name_columnBI) { + // Double click on the Layer name, enable editing + _text_rendererBI->property_editable() = true; + _editBI.set_cursor (path, *_name_columnBI, true); + grab_focus(); } } - return deferProcessing; + + return false; } -void SwatchesPanel::_trackDocument( SwatchesPanel *panel, SPDocument *document ) +bool SwatchesPanel::_handleKeyEvent(GdkEventKey *event) { - SPDocument *oldDoc = NULL; - if (docPerPanel.find(panel) != docPerPanel.end()) { - oldDoc = docPerPanel[panel]; - if (!oldDoc) { - docPerPanel.erase(panel); // Should not be needed, but clean up just in case. - } - } - if (oldDoc != document) { - if (oldDoc) { - docPerPanel[panel] = NULL; - bool found = false; - for (std::map<SwatchesPanel*, SPDocument*>::iterator it = docPerPanel.begin(); (it != docPerPanel.end()) && !found; ++it) { - found = (it->second == document); - } - if (!found) { - for (std::vector<DocTrack*>::iterator it = docTrackings.begin(); it != docTrackings.end(); ++it){ - if ((*it)->doc == oldDoc) { - delete *it; - docTrackings.erase(it); - break; - } + switch (get_group0_keyval(event)) { + case GDK_KEY_Return: + case GDK_KEY_KP_Enter: + case GDK_KEY_F2: { + Gtk::TreeModel::iterator iter = _editBI.get_selection()->get_selected(); + if (iter && !_text_rendererBI->property_editable()) { + Gtk::TreeRow row = *iter; + SPObject * obj = row[_model->_colObject]; + if (obj) { + Gtk::TreeModel::Path *path = new Gtk::TreeModel::Path(iter); + // Edit the layer label + _text_rendererBI->property_editable() = true; + _editBI.set_cursor(*path, *_name_columnBI, true); + grab_focus(); + return true; } } } - - if (document) { - bool found = false; - for (std::map<SwatchesPanel*, SPDocument*>::iterator it = docPerPanel.begin(); (it != docPerPanel.end()) && !found; ++it) { - found = (it->second == document); - } - docPerPanel[panel] = document; - if (!found) { - sigc::connection conn0 = document->connectDestroy(sigc::bind(sigc::ptr_fun(&SwatchesPanel::handleDocumentDestroy), document)); - sigc::connection conn1 = document->connectResourcesChanged( "gradient", sigc::bind(sigc::ptr_fun(&SwatchesPanel::handleGradientsChange), document) ); - sigc::connection conn2 = document->getDefs()->connectRelease( sigc::hide(sigc::bind(sigc::ptr_fun(&SwatchesPanel::handleDefsModified), document)) ); - sigc::connection conn3 = document->getDefs()->connectModified( sigc::hide(sigc::hide(sigc::bind(sigc::ptr_fun(&SwatchesPanel::handleDefsModified), document))) ); - - DocTrack *dt = new DocTrack(document, conn0, conn1, conn2, conn3); - docTrackings.push_back(dt); - - if (docPalettes.find(document) == docPalettes.end()) { - SwatchPage *docPalette = new SwatchPage(); - docPalette->_name = "Auto"; - docPalettes[document] = docPalette; + case GDK_KEY_Delete: { + + Gtk::TreeModel::iterator iter = _editBI.get_selection()->get_selected(); + if (iter) { + Gtk::TreeRow row = *iter; + SPObject * obj = row[_model->_colObject]; + if (obj) { + obj->deleteObject(false); + sp_repr_save_file(SwatchDocument->getReprDoc(), SwatchFile, SP_SVG_NS_URI); } } + return true; } + break; } + return false; } -void SwatchesPanel::_setDocument( SPDocument *document ) +void SwatchesPanel::_handleEdited(const Glib::ustring& path, const Glib::ustring& new_text) { - if ( document != _currentDocument ) { - _trackDocument(this, document); - _currentDocument = document; - handleGradientsChange( document ); - } + Gtk::TreeModel::iterator iter = _editBI.get_model()->get_iter(path); + Gtk::TreeModel::Row row = *iter; + + _renameObject(row, new_text); + _text_rendererBI->property_editable() = false; } -static void recalcSwatchContents(SPDocument* doc, - boost::ptr_vector<ColorItem> &tmpColors, - std::map<ColorItem*, cairo_pattern_t*> &previewMappings, - std::map<ColorItem*, SPGradient*> &gradMappings) +void SwatchesPanel::_handleEditingCancelled() { - std::vector<SPGradient*> newList; - - if (doc) { - const GSList *gradients = doc->getResourceList("gradient"); - for (const GSList *item = gradients; item; item = item->next) { - SPGradient* grad = SP_GRADIENT(item->data); - if ( grad->isSwatch() ) { - newList.push_back(SP_GRADIENT(item->data)); + _text_rendererBI->property_editable() = false; +} + +void SwatchesPanel::_renameObject(Gtk::TreeModel::Row row, const Glib::ustring& name) +{ + if ( row && SwatchDocument) { + SPObject* obj = row[_model->_colObject]; + if ( obj ) { + gchar const* oldLabel = obj->label(); + if ( !name.empty() && (!oldLabel || name != oldLabel) ) { + obj->setLabel(name.c_str()); + sp_repr_save_file(SwatchDocument->getReprDoc(), SwatchFile, SP_SVG_NS_URI); } } } +} - if ( !newList.empty() ) { - std::reverse(newList.begin(), newList.end()); - for ( std::vector<SPGradient*>::iterator it = newList.begin(); it != newList.end(); ++it ) - { - SPGradient* grad = *it; - - cairo_surface_t *preview = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, - PREVIEW_PIXBUF_WIDTH, VBLOCK); - cairo_t *ct = cairo_create(preview); - - Glib::ustring name( grad->getId() ); - ColorItem* item = new ColorItem( 0, 0, 0, name ); - - cairo_pattern_t *check = ink_cairo_pattern_create_checkerboard(); - cairo_pattern_t *gradient = sp_gradient_create_preview_pattern(grad, PREVIEW_PIXBUF_WIDTH); - cairo_set_source(ct, check); - cairo_paint(ct); - cairo_set_source(ct, gradient); - cairo_paint(ct); - - cairo_destroy(ct); - cairo_pattern_destroy(gradient); - cairo_pattern_destroy(check); - - cairo_pattern_t *prevpat = cairo_pattern_create_for_surface(preview); - cairo_surface_destroy(preview); +void SwatchesPanel::_setCollapsed(SPGroup * group) +{ + group->setExpanded(false); + group->updateRepr(SP_OBJECT_WRITE_NO_CHILDREN | SP_OBJECT_WRITE_EXT); + for (SPObject *iter = group->children; iter != NULL; iter = iter->next) + { + if (SP_IS_GROUP(iter)) _setCollapsed(SP_GROUP(iter)); + } +} - previewMappings[item] = prevpat; +void SwatchesPanel::_setExpanded(const Gtk::TreeModel::iterator& iter, const Gtk::TreeModel::Path& /*path*/, bool isexpanded) +{ + Gtk::TreeModel::Row row = *iter; - tmpColors.push_back(item); - gradMappings[item] = grad; + SPObject* obj = row[_model->_colObject]; + if (obj && SP_IS_GROUP(obj)) + { + if (isexpanded) + { + SP_GROUP(obj)->setExpanded(isexpanded); + obj->updateRepr(SP_OBJECT_WRITE_NO_CHILDREN | SP_OBJECT_WRITE_EXT); + } + else + { + _setCollapsed(SP_GROUP(obj)); } } + sp_repr_save_file(SwatchDocument->getReprDoc(), SwatchFile, SP_SVG_NS_URI); } -void SwatchesPanel::handleDocumentDestroy(SPDocument *document) +void SwatchesPanel::_deleteButtonClicked() { - if (document) { - for (std::vector<DocTrack*>::iterator it = docTrackings.begin(); it != docTrackings.end(); ++it){ - if ((*it)->doc == document) { - delete *it; - docTrackings.erase(it); - break; - } + Gtk::TreeModel::iterator iter = _editBI.get_selection()->get_selected(); + if (iter) { + Gtk::TreeModel::Row row = *iter; + SPObject* obj = row[_model->_colObject]; + if (obj) { + obj->deleteObject(false); + sp_repr_save_file(SwatchDocument->getReprDoc(), SwatchFile, SP_SVG_NS_URI); } + } +} - if (docPalettes.find(document) != docPalettes.end()) { - docPalettes.erase(document); +bool SwatchesPanel::_handleButtonEventDoc(GdkEventButton* event) +{ + static unsigned doubleclick = 0; + + if ( (event->type == GDK_BUTTON_PRESS) && (event->button == 3) ) { + // TODO - fix to a better is-popup function + Gtk::TreeModel::Path path; + int x = static_cast<int>(event->x); + int y = static_cast<int>(event->y); + if ( _editDoc.get_path_at_pos( x, y, path ) ) { + Gtk::TreeModel::Children::iterator iter = _editDoc.get_model()->get_iter(path); + Gtk::TreeModel::Row row = *iter; + + SPObject* obj = row[_modelDoc->_colObject]; + if (SP_IS_GRADIENT(obj)) { + _swatchClicked(event, SP_GRADIENT(obj)); + } else if (SP_IS_GROUP(obj)) { + _lblClick(event, SP_GROUP(obj)); + } else { + _lblClick(event, NULL); + } + } else { + _lblClick(event, NULL); } + } + + if ( (event->type == GDK_2BUTTON_PRESS) && (event->button == 1) ) { + doubleclick = 1; + } - for (std::map<SwatchesPanel*, SPDocument*>::iterator it = docPerPanel.begin(); it != docPerPanel.end(); ++it) { - if (it->second == document) { - SwatchesPanel* swp = it->first; - std::vector<SwatchPage*> pages = swp->_getSwatchSets(); - if ((swp->_currentIndex >= static_cast<int>(pages.size())) && (pages.size() > 0)) - { - swp->_setSelectedIndex(swp->_getSwatchSets().size() - 1); - } - swp->_rebuild(); - docPerPanel.erase(it); - break; - } + if ( event->type == GDK_BUTTON_RELEASE && doubleclick) { + doubleclick = 0; + Gtk::TreeModel::Path path; + Gtk::TreeViewColumn* col = 0; + int x = static_cast<int>(event->x); + int y = static_cast<int>(event->y); + int x2 = 0; + int y2 = 0; + if ( _editDoc.get_path_at_pos( x, y, path, col, x2, y2 ) && col == _name_columnDoc) { + // Double click on the Layer name, enable editing + _text_rendererDoc->property_editable() = true; + _editDoc.set_cursor (path, *_name_columnDoc, true); + grab_focus(); } } + + return false; } -void SwatchesPanel::handleGradientsChange(SPDocument *document) +void SwatchesPanel::_deleteButtonClickedDoc() { - SwatchPage *docPalette = (docPalettes.find(document) != docPalettes.end()) ? docPalettes[document] : 0; - if (docPalette) { - boost::ptr_vector<ColorItem> tmpColors; - std::map<ColorItem*, cairo_pattern_t*> tmpPrevs; - std::map<ColorItem*, SPGradient*> tmpGrads; - recalcSwatchContents(document, tmpColors, tmpPrevs, tmpGrads); - - for (std::map<ColorItem*, cairo_pattern_t*>::iterator it = tmpPrevs.begin(); it != tmpPrevs.end(); ++it) { - it->first->setPattern(it->second); - cairo_pattern_destroy(it->second); + Gtk::TreeModel::iterator iter = _editDoc.get_selection()->get_selected(); + if (iter) { + Gtk::TreeRow row = *iter; + SPObject * obj = row[_modelDoc->_colObject]; + if (SP_IS_GRADIENT(obj)) { + RemoveSwatch(SP_GRADIENT(obj)); + } else if (SP_IS_GROUP(obj)) { + Remove(SP_GROUP(obj)); } + } +} - for (std::map<ColorItem*, SPGradient*>::iterator it = tmpGrads.begin(); it != tmpGrads.end(); ++it) { - it->first->setGradient(it->second); - } - - docPalette->_colors.swap(tmpColors); - - // Figure out which SwatchesPanel instances are affected and update them. - - for (std::map<SwatchesPanel*, SPDocument*>::iterator it = docPerPanel.begin(); it != docPerPanel.end(); ++it) { - if (it->second == document) { - SwatchesPanel* swp = it->first; - std::vector<SwatchPage*> pages = swp->_getSwatchSets(); - SwatchPage* curr = pages[swp->_currentIndex]; - if (curr == docPalette) { - swp->_rebuild(); +bool SwatchesPanel::_handleKeyEventDoc(GdkEventKey *event) +{ + switch (get_group0_keyval(event)) { + case GDK_KEY_Return: + case GDK_KEY_KP_Enter: + case GDK_KEY_F2: { + Gtk::TreeModel::iterator iter = _editDoc.get_selection()->get_selected(); + if (iter && !_text_rendererDoc->property_editable()) { + Gtk::TreeRow row = *iter; + SPObject * obj = row[_modelDoc->_colObject]; + if (obj) { + Gtk::TreeModel::Path *path = new Gtk::TreeModel::Path(iter); + // Edit the layer label + _text_rendererDoc->property_editable() = true; + _editDoc.set_cursor(*path, *_name_columnDoc, true); + grab_focus(); + return true; } } } + case GDK_KEY_Delete: { + + _deleteButtonClickedDoc(); + return true; + } + break; } + return false; } -void SwatchesPanel::handleDefsModified(SPDocument *document) +void SwatchesPanel::_renameObjectDoc(Gtk::TreeModel::Row row, const Glib::ustring& name) { - SwatchPage *docPalette = (docPalettes.find(document) != docPalettes.end()) ? docPalettes[document] : 0; - if (docPalette && !DocTrack::queueUpdateIfNeeded(document) ) { - boost::ptr_vector<ColorItem> tmpColors; - std::map<ColorItem*, cairo_pattern_t*> tmpPrevs; - std::map<ColorItem*, SPGradient*> tmpGrads; - recalcSwatchContents(document, tmpColors, tmpPrevs, tmpGrads); - - if ( tmpColors.size() != docPalette->_colors.size() ) { - handleGradientsChange(document); - } else { - int cap = std::min(docPalette->_colors.size(), tmpColors.size()); - for (int i = 0; i < cap; i++) { - ColorItem *newColor = &tmpColors[i]; - ColorItem *oldColor = &docPalette->_colors[i]; - if ( (newColor->def.getType() != oldColor->def.getType()) || - (newColor->def.getR() != oldColor->def.getR()) || - (newColor->def.getG() != oldColor->def.getG()) || - (newColor->def.getB() != oldColor->def.getB()) ) { - oldColor->def.setRGB(newColor->def.getR(), newColor->def.getG(), newColor->def.getB()); - } - if (tmpGrads.find(newColor) != tmpGrads.end()) { - oldColor->setGradient(tmpGrads[newColor]); - } - if ( tmpPrevs.find(newColor) != tmpPrevs.end() ) { - oldColor->setPattern(tmpPrevs[newColor]); - } + if ( row && SwatchDocument) { + SPObject* obj = row[_modelDoc->_colObject]; + if ( obj ) { + gchar const* oldLabel = obj->label(); + if ( !name.empty() && (!oldLabel || name != oldLabel) ) { + obj->setLabel(name.c_str()); } } - - for (std::map<ColorItem*, cairo_pattern_t*>::iterator it = tmpPrevs.begin(); it != tmpPrevs.end(); ++it) { - cairo_pattern_destroy(it->second); - } } } +void SwatchesPanel::_handleEditedDoc(const Glib::ustring& path, const Glib::ustring& new_text) +{ + Gtk::TreeModel::iterator iter = _editDoc.get_model()->get_iter(path); + Gtk::TreeModel::Row row = *iter; -std::vector<SwatchPage*> SwatchesPanel::_getSwatchSets() const + _renameObjectDoc(row, new_text); + _text_rendererDoc->property_editable() = false; +} + +void SwatchesPanel::_handleEditingCancelledDoc() +{ + _text_rendererDoc->property_editable() = false; +} + +/* + * Drap and drop within the tree + * Save the drag source and drop target SPObjects and if its a drag between layers or into (sublayer) a layer + */ +bool SwatchesPanel::_handleDragDrop(const Glib::RefPtr<Gdk::DragContext>& context, int x, int y, guint time) { - std::vector<SwatchPage*> tmp; - if (docPalettes.find(_currentDocument) != docPalettes.end()) { - tmp.push_back(docPalettes[_currentDocument]); + int cell_x = 0, cell_y = 0; + Gtk::TreeModel::Path target_path; + Gtk::TreeView::Column *target_column; + + bool _dnd_top = false; + _dnd_into = false; + _dnd_target = SwatchDocument->getDefs()->lastChild(); + Gtk::TreeModel::iterator itersel = _editBI.get_selection()->get_selected(); + if (!itersel) { + return true; } + Gtk::TreeModel::Row rowsel = *itersel; + _dnd_source = rowsel[_model->_colObject]; - tmp.insert(tmp.end(), userSwatchPages.begin(), userSwatchPages.end()); - tmp.insert(tmp.end(), systemSwatchPages.begin(), systemSwatchPages.end()); + if (!_dnd_source) { + return true; + } + + if (_editBI.get_path_at_pos (x, y, target_path, target_column, cell_x, cell_y)) { + // Are we before, inside or after the drop layer + Gdk::Rectangle rect; + _editBI.get_background_area (target_path, *target_column, rect); + int cell_height = rect.get_height(); + _dnd_into = (cell_y > (int)(cell_height * 1/3) && cell_y <= (int)(cell_height * 2/3)); + if (cell_y < (int)(cell_height * 1/3)) { + Gtk::TreeModel::Path next_path = target_path; + if (next_path.prev()) { + target_path = next_path; + } else { + // Dragging to the "end" + Gtk::TreeModel::Path up_path = target_path; + up_path.up(); + if (_store->iter_is_valid(_store->get_iter(up_path))) { + // Drop into parent + target_path = up_path; + _dnd_into = true; + } else { + _dnd_top = true; + // Drop into the top level + _dnd_target = NULL; + } + } + } + if (!_dnd_top) { + Gtk::TreeModel::iterator iter = _store->get_iter(target_path); + if (_store->iter_is_valid(iter)) { + Gtk::TreeModel::Row row = *iter; + SPObject *obj = row[_model->_colObject]; + if (obj) { + _dnd_target = obj; + } + } + } + } + + if (_dnd_source != _dnd_target) { + + Inkscape::XML::Node *target_ref = _dnd_target ? _dnd_target->getRepr() : NULL; + Inkscape::XML::Node *our_ref = _dnd_source->getRepr(); + + if (target_ref != our_ref) { + if (!target_ref) { + target_ref = SwatchDocument->getDefs()->getRepr(); + if (target_ref != our_ref->parent()) { + our_ref->parent()->removeChild(our_ref); + target_ref->addChild(our_ref, NULL); + } else { + our_ref->parent()->changeOrder(our_ref, NULL); + } + } else if (_dnd_into) { + // Move this inside of the target at the end + our_ref->parent()->removeChild(our_ref); + target_ref->addChild(our_ref, NULL); + } else if (target_ref->parent() != our_ref->parent()) { + // Change in parent, need to remove and add + our_ref->parent()->removeChild(our_ref); + target_ref->parent()->addChild(our_ref, target_ref); + } else { + // Same parent, just move + our_ref->parent()->changeOrder(our_ref, target_ref); + } + } + sp_repr_save_file(SwatchDocument->getReprDoc(), SwatchFile, SP_SVG_NS_URI); + } - return tmp; + return true; } -void SwatchesPanel::_updateFromSelection() +/* + * Drap and drop within the tree + * Save the drag source and drop target SPObjects and if its a drag between layers or into (sublayer) a layer + */ +bool SwatchesPanel::_handleDragDropDoc(const Glib::RefPtr<Gdk::DragContext>& context, int x, int y, guint time) { - SwatchPage *docPalette = (docPalettes.find(_currentDocument) != docPalettes.end()) ? docPalettes[_currentDocument] : 0; - if ( docPalette ) { - Glib::ustring fillId; - Glib::ustring strokeId; - - SPStyle *tmpStyle = sp_style_new( sp_desktop_document(_currentDesktop) ); - int result = sp_desktop_query_style( _currentDesktop, tmpStyle, QUERY_STYLE_PROPERTY_FILL ); - switch (result) { - case QUERY_STYLE_SINGLE: - case QUERY_STYLE_MULTIPLE_AVERAGED: - case QUERY_STYLE_MULTIPLE_SAME: - { - if (tmpStyle->fill.set && tmpStyle->fill.isPaintserver()) { - SPPaintServer* server = tmpStyle->getFillPaintServer(); - if ( SP_IS_GRADIENT(server) ) { - SPGradient* target = 0; - SPGradient* grad = SP_GRADIENT(server); - - if ( grad->isSwatch() ) { - target = grad; - } else if ( grad->ref ) { - SPGradient *tmp = grad->ref->getObject(); - if ( tmp && tmp->isSwatch() ) { - target = tmp; - } - } - if ( target ) { - //XML Tree being used directly here while it shouldn't be - gchar const* id = target->getRepr()->attribute("id"); - if ( id ) { - fillId = id; - } - } - } + int cell_x = 0, cell_y = 0; + Gtk::TreeModel::Path target_path; + Gtk::TreeView::Column *target_column; + + bool _dnd_top = false; + _dnd_into = false; + _dnd_target = _currentDocument->getDefs()->lastChild(); + Gtk::TreeModel::iterator itersel = _editDoc.get_selection()->get_selected(); + if (!itersel) { + return true; + } + Gtk::TreeModel::Row rowsel = *itersel; + _dnd_source = rowsel[_modelDoc->_colObject]; + + if (!_dnd_source) { + return true; + } + + if (_editDoc.get_path_at_pos (x, y, target_path, target_column, cell_x, cell_y)) { + // Are we before, inside or after the drop layer + Gdk::Rectangle rect; + _editDoc.get_background_area (target_path, *target_column, rect); + int cell_height = rect.get_height(); + _dnd_into = (cell_y > (int)(cell_height * 1/3) && cell_y <= (int)(cell_height * 2/3)); + if (cell_y < (int)(cell_height * 1/3)) { + Gtk::TreeModel::Path next_path = target_path; + if (next_path.prev()) { + target_path = next_path; + } else { + // Dragging to the "end" + Gtk::TreeModel::Path up_path = target_path; + up_path.up(); + if (_storeDoc->iter_is_valid(_storeDoc->get_iter(up_path))) { + // Drop into parent + target_path = up_path; + _dnd_into = true; + } else { + _dnd_top = true; + // Drop into the top level + _dnd_target = NULL; } - break; } } - - result = sp_desktop_query_style( _currentDesktop, tmpStyle, QUERY_STYLE_PROPERTY_STROKE ); - switch (result) { - case QUERY_STYLE_SINGLE: - case QUERY_STYLE_MULTIPLE_AVERAGED: - case QUERY_STYLE_MULTIPLE_SAME: - { - if (tmpStyle->stroke.set && tmpStyle->stroke.isPaintserver()) { - SPPaintServer* server = tmpStyle->getStrokePaintServer(); - if ( SP_IS_GRADIENT(server) ) { - SPGradient* target = 0; - SPGradient* grad = SP_GRADIENT(server); - if ( grad->isSwatch() ) { - target = grad; - } else if ( grad->ref ) { - SPGradient *tmp = grad->ref->getObject(); - if ( tmp && tmp->isSwatch() ) { - target = tmp; - } - } - if ( target ) { - //XML Tree being used directly here while it shouldn't be - gchar const* id = target->getRepr()->attribute("id"); - if ( id ) { - strokeId = id; - } + if (!_dnd_top) { + Gtk::TreeModel::iterator iter = _storeDoc->get_iter(target_path); + if (_storeDoc->iter_is_valid(iter)) { + Gtk::TreeModel::Row row = *iter; + SPObject *obj = row[_modelDoc->_colObject]; + if (obj) { + _dnd_target = obj; + if (SP_IS_GRADIENT(obj)) { + _dnd_into = false; + if (SP_IS_GROUP(_dnd_source)) { + _dnd_target = obj->parent; } + } else if (SP_IS_GROUP(_dnd_source)) { + _dnd_into = false; } } - break; } } - sp_style_unref(tmpStyle); - - for ( boost::ptr_vector<ColorItem>::iterator it = docPalette->_colors.begin(); it != docPalette->_colors.end(); ++it ) { - ColorItem* item = &*it; - bool isFill = (fillId == item->def.descr); - bool isStroke = (strokeId == item->def.descr); - item->setState( isFill, isStroke ); + } + + if (_dnd_source != _dnd_target) { + + Inkscape::XML::Node *target_ref = _dnd_target ? _dnd_target->getRepr() : NULL; + Inkscape::XML::Node *our_ref = _dnd_source->getRepr(); + + if (target_ref != our_ref) { + if (!target_ref) { + target_ref = _currentDocument->getDefs()->getRepr(); + if (target_ref != our_ref->parent()) { + our_ref->parent()->removeChild(our_ref); + target_ref->addChild(our_ref, NULL); + } else { + our_ref->parent()->changeOrder(our_ref, NULL); + } + } else if (_dnd_into) { + // Move this inside of the target at the end + our_ref->parent()->removeChild(our_ref); + target_ref->addChild(our_ref, NULL); + } else if (target_ref->parent() != our_ref->parent()) { + // Change in parent, need to remove and add + our_ref->parent()->removeChild(our_ref); + target_ref->parent()->addChild(our_ref, target_ref); + } else { + // Same parent, just move + our_ref->parent()->changeOrder(our_ref, target_ref); + } } + DocumentUndo::done( _currentDocument , SP_VERB_DIALOG_SWATCHES, + _("Moved Swatches")); } + + return true; } -void SwatchesPanel::_handleAction( int setId, int itemId ) + +/** + * Constructor + */ +SwatchesPanel::SwatchesPanel(gchar const* prefsPath, bool showLabels) : + Inkscape::UI::Widget::Panel("", prefsPath, SP_VERB_DIALOG_SWATCHES, ""), + _scroller(), + _insideTable(1, 2), + _insideV(), + _insideH(), + _buttonsRow(), + _outsideV(), + _noLink(_("Don't Link")), + _showlabels(showLabels), + _store(0), + _scrollerBI(), + _editBI(), + _buttonsRowBI(), + _editBIV(), + _storeDoc(0), + _scrollerDoc(), + _editDoc(), + _buttonsRowDoc(), + _editDocV(), + _notebook(), + rootWatcher(0), + docWatcher(0), + _currentDesktop(0), + _currentDocument(0) { - switch( setId ) { - case 3: + _insideH.pack_start(_insideTable, Gtk::PACK_SHRINK); + if (_showlabels) { + _insideV.pack_start(_insideH, Gtk::PACK_SHRINK); + _scroller.add(_insideV); + } else { + _scroller.property_height_request() = 45; + _scroller.add(_insideH); + } + + popUpMenu = manage( new Gtk::Menu() ); + popUpMenu->show_all_children(); + + Gtk::Button* btn = manage( new Gtk::Button() ); + _styleButton( *btn, SP_ACTIVE_DESKTOP, SP_VERB_LAYER_NEW, GTK_STOCK_ADD, _("Add Swatch") ); + btn->signal_button_press_event().connect_notify( sigc::mem_fun(*this, &SwatchesPanel::_addButtonClicked) ); + _buttonsRow.pack_start(*btn, Gtk::PACK_SHRINK); + +// btn = manage( new Gtk::Button() ); +// _styleButton( *btn, SP_ACTIVE_DESKTOP, SP_VERB_LAYER_NEW, GTK_STOCK_DISCONNECT, C_("Unlink", "New") ); +// _buttonsRow.pack_end(*btn, Gtk::PACK_SHRINK); + + static Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + Glib::ustring nolink = Glib::ustring::compose("%1/nolink", prefsPath); + _noLink.set_tooltip_text(_("Don't link swatches")); + _noLink.set_active(prefs->getBool(nolink, false)); + _noLink.signal_toggled().connect_notify(sigc::mem_fun(*this, &SwatchesPanel::NoLinkToggled)); + _buttonsRow.pack_end(_noLink, Gtk::PACK_SHRINK); + + _scroller.set_policy( Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC ); + _scroller.set_shadow_type(Gtk::SHADOW_NONE); + + if (_showlabels) { + _outsideV.pack_end(_buttonsRow, Gtk::PACK_SHRINK); + _outsideV.pack_end(_scroller, Gtk::PACK_EXPAND_WIDGET); + + _notebook.append_page(_outsideV, "Use"); + { - _setSelectedIndex(itemId); + ModelColumnsDoc *zoop = new ModelColumnsDoc(); + _modelDoc = zoop; + + _storeDoc = Gtk::TreeStore::create( *zoop ); + + _editDoc.set_model( _storeDoc ); + _editDoc.set_headers_visible(false); + _editDoc.set_reorderable(true); + _editDoc.enable_model_drag_dest (Gdk::ACTION_MOVE); + + Gtk::Button* btn = manage( new Gtk::Button() ); + _styleButton( *btn, SP_ACTIVE_DESKTOP, SP_VERB_LAYER_NEW, GTK_STOCK_ADD, _("Import Swatch") ); + btn->signal_button_press_event().connect_notify( sigc::mem_fun(*this, &SwatchesPanel::_addButtonClicked)); + _buttonsRowDoc.pack_start(*btn, Gtk::PACK_SHRINK); + + btn = manage( new Gtk::Button() ); + _styleButton( *btn, SP_ACTIVE_DESKTOP, SP_VERB_LAYER_DELETE, GTK_STOCK_DELETE, _("Delete Swatch") ); + btn->signal_button_press_event().connect_notify( sigc::hide(sigc::mem_fun(*this, &SwatchesPanel::_deleteButtonClickedDoc))); + _buttonsRowDoc.pack_start(*btn, Gtk::PACK_SHRINK); + + _pixbuf_rendererDoc = manage(new Gtk::CellRendererPixbuf()); + int pixbufColNum = _editDoc.append_column("Pixbuf", *_pixbuf_rendererDoc) - 1; + _pixbuf_columnDoc = _editDoc.get_column(pixbufColNum); + _pixbuf_columnDoc->add_attribute(_pixbuf_rendererDoc->property_pixbuf(), _modelDoc->_colPixbuf); + + _text_rendererDoc = manage(new Gtk::CellRendererText()); + int nameColNum = _editDoc.append_column("Name", *_text_rendererDoc) - 1; + _name_columnDoc = _editDoc.get_column(nameColNum); + _name_columnDoc->add_attribute(_text_rendererDoc->property_text(), _modelDoc->_colLabel); + + _text_rendererDoc->signal_edited().connect( sigc::mem_fun(*this, &SwatchesPanel::_handleEditedDoc) ); + _text_rendererDoc->signal_editing_canceled().connect( sigc::mem_fun(*this, &SwatchesPanel::_handleEditingCancelledDoc) ); + + _editDoc.set_expander_column( *_editDoc.get_column(nameColNum) ); + + _editDoc.signal_button_press_event().connect( sigc::mem_fun(*this, &SwatchesPanel::_handleButtonEventDoc), false ); + _editDoc.signal_button_release_event().connect( sigc::mem_fun(*this, &SwatchesPanel::_handleButtonEventDoc), false ); + _editDoc.signal_key_press_event().connect( sigc::mem_fun(*this, &SwatchesPanel::_handleKeyEventDoc), false ); + + _editDoc.signal_drag_drop().connect( sigc::mem_fun(*this, &SwatchesPanel::_handleDragDropDoc), false); + + _scrollerDoc.set_policy( Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC ); + _scrollerDoc.set_shadow_type(Gtk::SHADOW_IN); + _scrollerDoc.add(_editDoc); + + _editDocV.pack_start(_scrollerDoc, Gtk::PACK_EXPAND_WIDGET); + _editDocV.pack_end(_buttonsRowDoc, Gtk::PACK_SHRINK); + + _notebook.append_page(_editDocV, "Edit"); } - break; + + { + popUpImportMenu = Gtk::manage(new Gtk::Menu()); + + Gtk::MenuItem* mi = Gtk::manage(new Gtk::MenuItem(_("New Swatch Group..."))); + mi->signal_activate().connect_notify(sigc::mem_fun(*this, &SwatchesPanel::NewGroupBI)); + mi->show(); + popUpImportMenu->append(*mi); + + mi = Gtk::manage(new Gtk::MenuItem(_("Import Swatch File..."))); + mi->signal_activate().connect_notify(sigc::bind<bool, bool>(sigc::mem_fun(*this, &SwatchesPanel::_importButtonClicked), false, true)); + mi->show(); + popUpImportMenu->append(*mi); + + ModelColumns *zoop = new ModelColumns(); + _model = zoop; + + _store = Gtk::TreeStore::create( *zoop ); + + _editBI.set_model( _store ); + _editBI.set_headers_visible(false); + _editBI.set_reorderable(true); + _editBI.enable_model_drag_dest (Gdk::ACTION_MOVE); + + Gtk::Button* btn = manage( new Gtk::Button() ); + _styleButton( *btn, SP_ACTIVE_DESKTOP, SP_VERB_LAYER_NEW, GTK_STOCK_ADD, _("Import Swatch") ); + btn->signal_button_press_event().connect_notify(sigc::mem_fun(*this, &SwatchesPanel::_addBIButtonClicked)); + _buttonsRowBI.pack_start(*btn, Gtk::PACK_SHRINK); + + btn = manage( new Gtk::Button() ); + _styleButton( *btn, SP_ACTIVE_DESKTOP, SP_VERB_LAYER_DELETE, GTK_STOCK_DELETE, _("Delete Swatch") ); + btn->signal_button_press_event().connect_notify( sigc::hide(sigc::mem_fun(*this, &SwatchesPanel::_deleteButtonClicked))); + _buttonsRowBI.pack_start(*btn, Gtk::PACK_SHRINK); + + _text_rendererBI = manage(new Gtk::CellRendererText()); + int nameColNum = _editBI.append_column("Name", *_text_rendererBI) - 1; + _name_columnBI = _editBI.get_column(nameColNum); + _name_columnBI->add_attribute(_text_rendererBI->property_text(), _model->_colLabel); + + _text_rendererBI->signal_edited().connect( sigc::mem_fun(*this, &SwatchesPanel::_handleEdited) ); + _text_rendererBI->signal_editing_canceled().connect( sigc::mem_fun(*this, &SwatchesPanel::_handleEditingCancelled) ); + + _editBI.set_expander_column( *_editBI.get_column(nameColNum) ); + + _editBI.signal_button_press_event().connect( sigc::mem_fun(*this, &SwatchesPanel::_handleButtonEvent), false ); + _editBI.signal_button_release_event().connect( sigc::mem_fun(*this, &SwatchesPanel::_handleButtonEvent), false ); + _editBI.signal_key_press_event().connect( sigc::mem_fun(*this, &SwatchesPanel::_handleKeyEvent), false ); + + _editBI.signal_drag_drop().connect( sigc::mem_fun(*this, &SwatchesPanel::_handleDragDrop), false); + _editBI.signal_row_collapsed().connect( sigc::bind<bool>(sigc::mem_fun(*this, &SwatchesPanel::_setExpanded), false)); + _editBI.signal_row_expanded().connect( sigc::bind<bool>(sigc::mem_fun(*this, &SwatchesPanel::_setExpanded), true)); + + _scrollerBI.set_policy( Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC ); + _scrollerBI.set_shadow_type(Gtk::SHADOW_IN); + _scrollerBI.add(_editBI); + + _editBIV.pack_start(_scrollerBI, Gtk::PACK_EXPAND_WIDGET); + _editBIV.pack_end(_buttonsRowBI, Gtk::PACK_SHRINK); + + _notebook.append_page(_editBIV, "Edit Built-In"); + } + + _getContents()->pack_end(_notebook, Gtk::PACK_EXPAND_WIDGET); + } else { + //_outsideV.pack_end(_scroller, Gtk::PACK_SHRINK); + _buttonsRow.pack_end(_scroller, Gtk::PACK_EXPAND_WIDGET); + //_getContents()->pack_end(_outsideV, Gtk::PACK_SHRINK); + _getContents()->pack_end(_buttonsRow, Gtk::PACK_SHRINK); } + + loadPalletFile(); + + rootWatcher = new SwatchWatcher(this, SwatchDocument->getDefs(), true); + SwatchDocument->getDefs()->getRepr()->addObserver(*rootWatcher); + _swatchesChanged(); } -void SwatchesPanel::_setSelectedIndex( int index ) +SwatchesPanel::~SwatchesPanel() { - std::vector<SwatchPage*> pages = _getSwatchSets(); - if ( index >= 0 && index < static_cast<int>(pages.size()) ) { - _currentIndex = index; + if (rootWatcher) { + rootWatcher->_repr->removeObserver(*rootWatcher); + delete rootWatcher; + } + + if (docWatcher) { + docWatcher->_repr->removeObserver(*docWatcher); + delete docWatcher; + } + + _documentConnection.disconnect(); + _selChanged.disconnect(); +} - if ( !_prefs_path.empty() ) { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setString(_prefs_path + "/palette", pages[_currentIndex]->_name); +void SwatchesPanel::setDesktop( SPDesktop* desktop ) +{ + Inkscape::UI::Widget::Panel::setDesktop(desktop); + if ( desktop != _currentDesktop ) { + if ( _currentDesktop ) { + _documentConnection.disconnect(); + _selChanged.disconnect(); } - _rebuild(); + _currentDesktop = desktop; + + if ( desktop ) { + //_currentDesktop->selection->connectChanged(sigc::hide(sigc::mem_fun(*this, &SwatchesPanel::_updateFromSelection))); + + _documentConnection = desktop->connectDocumentReplaced(sigc::mem_fun(*this, &SwatchesPanel::_setDocument)); + + _setDocument( desktop, desktop->doc() ); + } else { + _setDocument(0, 0); + } } } -void SwatchesPanel::_rebuild() +void SwatchesPanel::_setDocument( SPDesktop* desktop, SPDocument *document ) { - std::vector<SwatchPage*> pages = _getSwatchSets(); - if (_currentIndex < static_cast<int>(pages.size())) { - SwatchPage* curr = pages[_currentIndex]; - _holder->clear(); - - if ( curr->_prefWidth > 0 ) { - _holder->setColumnPref( curr->_prefWidth ); + if ( document != _currentDocument ) { + if (docWatcher) { + docWatcher->_repr->removeObserver(*docWatcher); + delete docWatcher; + docWatcher = NULL; } - _holder->freezeUpdates(); - // TODO restore once 'clear' works _holder->addPreview(_clear); - _holder->addPreview(_remove); - for ( boost::ptr_vector<ColorItem>::iterator it = curr->_colors.begin(); it != curr->_colors.end(); ++it) { - _holder->addPreview(&*it); + _currentDocument = document; + + if (_currentDocument) { + docWatcher = new SwatchWatcher(this, _currentDocument->getDefs(), false); + _currentDocument->getDefs()->getRepr()->addObserver(*docWatcher); } - _holder->thawUpdates(); + _defsChanged(); } } @@ -1241,6 +2323,48 @@ void SwatchesPanel::_rebuild() } //namespace UI } //namespace Inkscape +//should be okay to add this here +guint get_group0_keyval(GdkEventKey *event) { + guint keyval = 0; + gdk_keymap_translate_keyboard_state(gdk_keymap_get_for_display( + gdk_display_get_default()), event->hardware_keycode, + (GdkModifierType) event->state, 0 /*event->key.group*/, &keyval, + NULL, NULL, NULL); + return keyval; +} + +void +sp_desktop_set_gradient(SPDesktop *desktop, SPGradient* gradient, bool fill) +{ + + bool intercepted = false; + + if (gradient->isSolid()) { + ColorRGBA color(gradient->getFirstStop()->getEffectiveColor().toRGBA32(gradient->getFirstStop()->opacity)); + guint32 rgba = SP_RGBA32_F_COMPOSE(color[0], color[1], color[2], color[3]); + gchar b[64]; + sp_svg_write_color(b, sizeof(b), rgba); + SPCSSAttr *css = sp_repr_css_attr_new(); + if (fill) { + sp_repr_css_set_property(css, "fill", b); + Inkscape::CSSOStringStream osalpha; + osalpha << color[3]; + sp_repr_css_set_property(css, "fill-opacity", osalpha.str().c_str()); + } else { + sp_repr_css_set_property(css, "stroke", b); + Inkscape::CSSOStringStream osalpha; + osalpha << color[3]; + sp_repr_css_set_property(css, "stroke-opacity", osalpha.str().c_str()); + } + intercepted = desktop->_set_style_signal.emit(css); + } + + if (!intercepted) { + for (const GSList *it = desktop->selection->itemList(); it != NULL; it = it->next) { + sp_item_set_gradient(SP_ITEM(it->data), gradient, SP_IS_RADIALGRADIENT(gradient) ? SP_GRADIENT_TYPE_RADIAL : SP_GRADIENT_TYPE_LINEAR, !fill ? Inkscape::FOR_STROKE : Inkscape::FOR_FILL); + } + } +} /* Local Variables: diff --git a/src/ui/dialog/swatches.h b/src/ui/dialog/swatches.h index 3abb81d98..cb8f87962 100644 --- a/src/ui/dialog/swatches.h +++ b/src/ui/dialog/swatches.h @@ -12,66 +12,161 @@ #include "ui/widget/panel.h" #include "enums.h" +#include "sp-object.h" +#include "sp-item-group.h" +#include <gtk/gtk.h> +#include <gtkmm/radiomenuitem.h> +#include <gtkmm/menuitem.h> +#include <gtkmm/scrolledwindow.h> +#include <gtkmm/table.h> +#include <gtkmm/box.h> +#include <gtkmm/menu.h> +#include <gtkmm/notebook.h> +#include <gtkmm/treeview.h> +#include <gtkmm/treestore.h> +#include <gtkmm/treemodel.h> +#include "sp-gradient.h" +#include "xml/node-observer.h" namespace Inkscape { namespace UI { -class PreviewHolder; - namespace Dialogs { -class ColorItem; -class SwatchPage; -class DocTrack; - /** * A panel that displays paint swatches. */ class SwatchesPanel : public Inkscape::UI::Widget::Panel { public: - SwatchesPanel(gchar const* prefsPath = "/dialogs/swatches"); + SwatchesPanel(gchar const* prefsPath = "/dialogs/swatches", bool showLabels = true); virtual ~SwatchesPanel(); - + static SwatchesPanel& getInstance(); - virtual void setOrientation(SPAnchorType how); - virtual void setDesktop( SPDesktop* desktop ); virtual SPDesktop* getDesktop() {return _currentDesktop;} - virtual int getSelectedIndex() {return _currentIndex;} // temporary - protected: - static void handleDocumentDestroy(SPDocument *document); - static void handleGradientsChange(SPDocument *document); - - virtual void _updateFromSelection(); - virtual void _handleAction( int setId, int itemId ); - virtual void _setDocument( SPDocument *document ); - virtual void _setSelectedIndex( int index ); - virtual void _rebuild(); - virtual std::vector<SwatchPage*> _getSwatchSets() const; + virtual void _setDocument( SPDesktop* desktop, SPDocument *document ); private: + class ModelColumns; + class ModelColumnsDoc; + + class StopWatcher; + class GradientWatcher; + class SwatchWatcher; + SwatchesPanel(SwatchesPanel const &); // no copy SwatchesPanel &operator=(SwatchesPanel const &); // no assign + + void _styleButton( Gtk::Button& btn, SPDesktop *desktop, unsigned int code, char const* iconName, char const* fallback ); + + void _setSelectionSwatch(SPGradient* swatchItem, bool isStroke); + + void NoLinkToggled(); + void NewGroup(); + void NewGroupBI(); + void _addBIButtonClicked(GdkEventButton* event); + void Duplicate(SPGroup* page); + void SaveAs(); + void AddSelectedFill(SPGroup* page); + void AddSelectedStroke(SPGroup* page); + void MoveUp(SPGroup* page); + void MoveDown(SPGroup* page); + void Remove(SPGroup* page); + + void SetSelectedFill(SPGradient* swatch); + void SetSelectedStroke(SPGradient* swatch); + void MoveSwatchUp(SPGradient* swatch); + void MoveSwatchDown(SPGradient* swatch); + void RemoveSwatch(SPGradient* swatch); + + void _lblClick(GdkEventButton* event, SPGroup* page); + void _addSwatchButtonClicked(SPGroup* swatch, bool recurse); + void _defsChanged(); + void _importButtonClicked(bool addToDoc, bool addToBI); + void _deleteButtonClicked(); + void _addButtonClicked(GdkEventButton* event); + void _swatchClicked(GdkEventButton* event, SPGradient* swatchItem); + + Gtk::MenuItem* _addSwatchGroup(SPGroup* group, Gtk::TreeModel::Row* parentRow); + void _swatchesChanged(); + + bool _handleButtonEvent(GdkEventButton *event); + bool _handleKeyEvent(GdkEventKey *event); + + void _handleEdited(const Glib::ustring& path, const Glib::ustring& new_text); + void _handleEditingCancelled(); + void _renameObject(Gtk::TreeModel::Row row, const Glib::ustring& name); + + void _setCollapsed(SPGroup * group); + void _setExpanded(const Gtk::TreeModel::iterator& iter, const Gtk::TreeModel::Path& /*path*/, bool isexpanded); + + void _deleteButtonClickedDoc(); + bool _handleButtonEventDoc(GdkEventButton* event); + bool _handleKeyEventDoc(GdkEventKey *event); + + void _handleEditedDoc(const Glib::ustring& path, const Glib::ustring& new_text); + void _handleEditingCancelledDoc(); + void _renameObjectDoc(Gtk::TreeModel::Row row, const Glib::ustring& name); + + bool _handleDragDropDoc(const Glib::RefPtr<Gdk::DragContext>& context, int x, int y, guint time); + bool _handleDragDrop(const Glib::RefPtr<Gdk::DragContext>& context, int x, int y, guint time); + + Gtk::Menu *popUpMenu; + Gtk::Menu *popUpImportMenu; + + Gtk::ScrolledWindow _scroller; + Gtk::Table _insideTable; + Gtk::VBox _insideV; + Gtk::HBox _insideH; + Gtk::HBox _buttonsRow; + Gtk::VBox _outsideV; + Gtk::CheckButton _noLink; + bool _showlabels; + + SwatchesPanel::ModelColumns* _model; + Glib::RefPtr<Gtk::TreeStore> _store; + + Gtk::CellRendererText *_text_rendererBI; + Gtk::TreeView::Column *_name_columnBI; + Gtk::ScrolledWindow _scrollerBI; + Gtk::TreeView _editBI; + Gtk::HBox _buttonsRowBI; + Gtk::VBox _editBIV; + + SwatchesPanel::ModelColumnsDoc* _modelDoc; + Glib::RefPtr<Gtk::TreeStore> _storeDoc; + + Gtk::CellRendererText *_text_rendererDoc; + Gtk::CellRendererPixbuf *_pixbuf_rendererDoc; + Gtk::TreeView::Column *_name_columnDoc; + Gtk::TreeView::Column *_pixbuf_columnDoc; + Gtk::ScrolledWindow _scrollerDoc; + Gtk::TreeView _editDoc; + Gtk::HBox _buttonsRowDoc; + Gtk::VBox _editDocV; + + Gtk::Notebook _notebook; + + SwatchWatcher* rootWatcher; + std::vector<Inkscape::XML::NodeObserver*> rootWatchers; + + std::vector<Inkscape::XML::NodeObserver*> docWatchers; + SwatchWatcher* docWatcher; - static void _trackDocument( SwatchesPanel *panel, SPDocument *document ); - static void handleDefsModified(SPDocument *document); - - PreviewHolder* _holder; - ColorItem* _clear; - ColorItem* _remove; - int _currentIndex; SPDesktop* _currentDesktop; SPDocument* _currentDocument; + + bool _dnd_into; + SPObject* _dnd_source; + SPObject* _dnd_target; sigc::connection _documentConnection; sigc::connection _selChanged; - - friend class DocTrack; }; } //namespace Dialogs |
