Code

Fixed missing palette when using file open on a new document.
[inkscape.git] / src / ui / dialog / swatches.cpp
2 /** @file
3  * @brief Color swatches dialog
4  */
5 /* Authors:
6  *   Jon A. Cruz
7  *   John Bintz
8  *
9  * Copyright (C) 2005 Jon A. Cruz
10  * Copyright (C) 2008 John Bintz
11  *
12  * Released under GNU GPL, read the file 'COPYING' for more information
13  */
15 #include <errno.h>
16 #include <map>
18 #include <gtk/gtkdialog.h> //for GTK_RESPONSE* types
19 #include <gtk/gtkdnd.h>
20 #include <gtk/gtkmenu.h>
21 #include <gtk/gtkmenuitem.h>
22 #include <gtk/gtkseparatormenuitem.h>
23 #include <glibmm/i18n.h>
24 #include <gdkmm/pixbuf.h>
26 #include "color-item.h"
27 #include "desktop.h"
28 #include "desktop-handles.h"
29 #include "desktop-style.h"
30 #include "document.h"
31 #include "document-private.h"
32 #include "extension/db.h"
33 #include "inkscape.h"
34 #include "inkscape.h"
35 #include "io/sys.h"
36 #include "io/resource.h"
37 #include "message-context.h"
38 #include "path-prefix.h"
39 #include "preferences.h"
40 #include "sp-item.h"
41 #include "sp-gradient-fns.h"
42 #include "sp-gradient.h"
43 #include "sp-gradient-vector.h"
44 #include "swatches.h"
45 #include "style.h"
46 #include "ui/previewholder.h"
47 #include "widgets/gradient-vector.h"
48 #include "widgets/eek-preview.h"
49 #include "display/nr-plain-stuff.h"
50 #include "sp-gradient-reference.h"
53 namespace Inkscape {
54 namespace UI {
55 namespace Dialogs {
57 #define VBLOCK 16
58 #define PREVIEW_PIXBUF_WIDTH 128
60 void _loadPaletteFile( gchar const *filename );
63 class DocTrack;
65 std::vector<SwatchPage*> possible;
66 static std::map<SPDocument*, SwatchPage*> docPalettes;
67 static std::vector<DocTrack*> docTrackings;
68 static std::map<SwatchesPanel*, SPDocument*> docPerPanel;
72 static void handleClick( GtkWidget* /*widget*/, gpointer callback_data ) {
73     ColorItem* item = reinterpret_cast<ColorItem*>(callback_data);
74     if ( item ) {
75         item->buttonClicked(false);
76     }
77 }
79 static void handleSecondaryClick( GtkWidget* /*widget*/, gint /*arg1*/, gpointer callback_data ) {
80     ColorItem* item = reinterpret_cast<ColorItem*>(callback_data);
81     if ( item ) {
82         item->buttonClicked(true);
83     }
84 }
86 static GtkWidget* popupMenu = 0;
87 static std::vector<GtkWidget*> popupExtras;
88 static ColorItem* bounceTarget = 0;
89 static SwatchesPanel* bouncePanel = 0;
91 static void redirClick( GtkMenuItem *menuitem, gpointer /*user_data*/ )
92 {
93     if ( bounceTarget ) {
94         handleClick( GTK_WIDGET(menuitem), bounceTarget );
95     }
96 }
98 static void redirSecondaryClick( GtkMenuItem *menuitem, gpointer /*user_data*/ )
99 {
100     if ( bounceTarget ) {
101         handleSecondaryClick( GTK_WIDGET(menuitem), 0, bounceTarget );
102     }
105 static void editGradientImpl( SPGradient* gr )
107     if ( gr ) {
108         GtkWidget *dialog = sp_gradient_vector_editor_new( gr );
109         gtk_widget_show( dialog );
110     }
113 static void editGradient( GtkMenuItem */*menuitem*/, gpointer /*user_data*/ )
115     if ( bounceTarget ) {
116         SwatchesPanel* swp = bouncePanel;
117         SPDesktop* desktop = swp ? swp->getDesktop() : 0;
118         SPDocument *doc = desktop ? desktop->doc() : 0;
119         if (doc) {
120             std::string targetName(bounceTarget->def.descr);
121             const GSList *gradients = sp_document_get_resource_list(doc, "gradient");
122             for (const GSList *item = gradients; item; item = item->next) {
123                 SPGradient* grad = SP_GRADIENT(item->data);
124                 if ( targetName == grad->getId() ) {
125                     editGradientImpl( grad );
126                     break;
127                 }
128             }
129         }
130     }
133 static void addNewGradient( GtkMenuItem */*menuitem*/, gpointer /*user_data*/ )
135     if ( bounceTarget ) {
136         SwatchesPanel* swp = bouncePanel;
137         SPDesktop* desktop = swp ? swp->getDesktop() : 0;
138         SPDocument *doc = desktop ? desktop->doc() : 0;
139         if (doc) {
140             Inkscape::XML::Document *xml_doc = sp_document_repr_doc(doc);
142             Inkscape::XML::Node *repr = xml_doc->createElement("svg:linearGradient");
143             repr->setAttribute("osb:paint", "solid");
144             Inkscape::XML::Node *stop = xml_doc->createElement("svg:stop");
145             stop->setAttribute("offset", "0");
146             stop->setAttribute("style", "stop-color:#000;stop-opacity:1;");
147             repr->appendChild(stop);
148             Inkscape::GC::release(stop);
150             SP_OBJECT_REPR( SP_DOCUMENT_DEFS(doc) )->addChild(repr, NULL);
152             SPGradient * gr = static_cast<SPGradient *>(doc->getObjectByRepr(repr));
154             Inkscape::GC::release(repr);
157             editGradientImpl( gr );
158         }
159     }
162 static SwatchesPanel* findContainingPanel( GtkWidget *widget )
164     SwatchesPanel *swp = 0;
166     std::map<GtkWidget*, SwatchesPanel*> rawObjects;
167     for (std::map<SwatchesPanel*, SPDocument*>::iterator it = docPerPanel.begin(); it != docPerPanel.end(); ++it) {
168         rawObjects[GTK_WIDGET(it->first->gobj())] = it->first;
169     }
171     for (GtkWidget* curr = widget; curr && !swp; curr = gtk_widget_get_parent(curr)) {
172         if (rawObjects.find(curr) != rawObjects.end()) {
173             swp = rawObjects[curr];
174         }
175     }
177     return swp;
180 gboolean colorItemHandleButtonPress( GtkWidget* widget, GdkEventButton* event, gpointer user_data)
182     gboolean handled = FALSE;
184     if ( (event->button == 3) && (event->type == GDK_BUTTON_PRESS) ) {
185         SwatchesPanel* swp = findContainingPanel( widget );
187         if ( !popupMenu ) {
188             popupMenu = gtk_menu_new();
189             GtkWidget* child = 0;
191             //TRANSLATORS: An item in context menu on a colour in the swatches
192             child = gtk_menu_item_new_with_label(_("Set fill"));
193             g_signal_connect( G_OBJECT(child),
194                               "activate",
195                               G_CALLBACK(redirClick),
196                               user_data);
197             gtk_menu_shell_append(GTK_MENU_SHELL(popupMenu), child);
199             //TRANSLATORS: An item in context menu on a colour in the swatches
200             child = gtk_menu_item_new_with_label(_("Set stroke"));
202             g_signal_connect( G_OBJECT(child),
203                               "activate",
204                               G_CALLBACK(redirSecondaryClick),
205                               user_data);
206             gtk_menu_shell_append(GTK_MENU_SHELL(popupMenu), child);
208             child = gtk_separator_menu_item_new();
209             gtk_menu_shell_append(GTK_MENU_SHELL(popupMenu), child);
210             popupExtras.push_back(child);
212             child = gtk_menu_item_new_with_label(_("Add"));
213             g_signal_connect( G_OBJECT(child),
214                               "activate",
215                               G_CALLBACK(addNewGradient),
216                               user_data );
217             gtk_menu_shell_append(GTK_MENU_SHELL(popupMenu), child);
218             popupExtras.push_back(child);
220             child = gtk_menu_item_new_with_label(_("Delete"));
221             gtk_menu_shell_append(GTK_MENU_SHELL(popupMenu), child);
222             //popupExtras.push_back(child);
223             gtk_widget_set_sensitive( child, FALSE );
225             child = gtk_menu_item_new_with_label(_("Edit..."));
226             g_signal_connect( G_OBJECT(child),
227                               "activate",
228                               G_CALLBACK(editGradient),
229                               user_data );
230             gtk_menu_shell_append(GTK_MENU_SHELL(popupMenu), child);
231             popupExtras.push_back(child);
233             child = gtk_separator_menu_item_new();
234             gtk_menu_shell_append(GTK_MENU_SHELL(popupMenu), child);
235             popupExtras.push_back(child);
237             child = gtk_menu_item_new_with_label(_("Convert"));
238             gtk_menu_shell_append(GTK_MENU_SHELL(popupMenu), child);
239             //popupExtras.push_back(child);
240             gtk_widget_set_sensitive( child, FALSE );
242             gtk_widget_show_all(popupMenu);
243         }
245         ColorItem* item = reinterpret_cast<ColorItem*>(user_data);
246         if ( item ) {
247             bool show = swp && (swp->getSelectedIndex() == 0);
248             for ( std::vector<GtkWidget*>::iterator it = popupExtras.begin(); it != popupExtras.end(); ++ it) {
249                 gtk_widget_set_sensitive(*it, show);
250             }
252             bounceTarget = item;
253             bouncePanel = swp;
254             if ( popupMenu ) {
255                 gtk_menu_popup(GTK_MENU(popupMenu), NULL, NULL, NULL, NULL, event->button, event->time);
256                 handled = TRUE;
257             }
258         }
259     }
261     return handled;
265 static char* trim( char* str ) {
266     char* ret = str;
267     while ( *str && (*str == ' ' || *str == '\t') ) {
268         str++;
269     }
270     ret = str;
271     while ( *str ) {
272         str++;
273     }
274     str--;
275     while ( str > ret && (( *str == ' ' || *str == '\t' ) || *str == '\r' || *str == '\n') ) {
276         *str-- = 0;
277     }
278     return ret;
281 void skipWhitespace( char*& str ) {
282     while ( *str == ' ' || *str == '\t' ) {
283         str++;
284     }
287 bool parseNum( char*& str, int& val ) {
288     val = 0;
289     while ( '0' <= *str && *str <= '9' ) {
290         val = val * 10 + (*str - '0');
291         str++;
292     }
293     bool retval = !(*str == 0 || *str == ' ' || *str == '\t' || *str == '\r' || *str == '\n');
294     return retval;
298 void _loadPaletteFile( gchar const *filename )
300     char block[1024];
301     FILE *f = Inkscape::IO::fopen_utf8name( filename, "r" );
302     if ( f ) {
303         char* result = fgets( block, sizeof(block), f );
304         if ( result ) {
305             if ( strncmp( "GIMP Palette", block, 12 ) == 0 ) {
306                 bool inHeader = true;
307                 bool hasErr = false;
309                 SwatchPage *onceMore = new SwatchPage();
311                 do {
312                     result = fgets( block, sizeof(block), f );
313                     block[sizeof(block) - 1] = 0;
314                     if ( result ) {
315                         if ( block[0] == '#' ) {
316                             // ignore comment
317                         } else {
318                             char *ptr = block;
319                             // very simple check for header versus entry
320                             while ( *ptr == ' ' || *ptr == '\t' ) {
321                                 ptr++;
322                             }
323                             if ( (*ptr == 0) || (*ptr == '\r') || (*ptr == '\n') ) {
324                                 // blank line. skip it.
325                             } else if ( '0' <= *ptr && *ptr <= '9' ) {
326                                 // should be an entry link
327                                 inHeader = false;
328                                 ptr = block;
329                                 Glib::ustring name("");
330                                 int r = 0;
331                                 int g = 0;
332                                 int b = 0;
333                                 skipWhitespace(ptr);
334                                 if ( *ptr ) {
335                                     hasErr = parseNum(ptr, r);
336                                     if ( !hasErr ) {
337                                         skipWhitespace(ptr);
338                                         hasErr = parseNum(ptr, g);
339                                     }
340                                     if ( !hasErr ) {
341                                         skipWhitespace(ptr);
342                                         hasErr = parseNum(ptr, b);
343                                     }
344                                     if ( !hasErr && *ptr ) {
345                                         char* n = trim(ptr);
346                                         if (n != NULL) {
347                                             name = n;
348                                         }
349                                     }
350                                     if ( !hasErr ) {
351                                         // Add the entry now
352                                         Glib::ustring nameStr(name);
353                                         ColorItem* item = new ColorItem( r, g, b, nameStr );
354                                         onceMore->_colors.push_back(item);
355                                     }
356                                 } else {
357                                     hasErr = true;
358                                 }
359                             } else {
360                                 if ( !inHeader ) {
361                                     // Hmmm... probably bad. Not quite the format we want?
362                                     hasErr = true;
363                                 } else {
364                                     char* sep = strchr(result, ':');
365                                     if ( sep ) {
366                                         *sep = 0;
367                                         char* val = trim(sep + 1);
368                                         char* name = trim(result);
369                                         if ( *name ) {
370                                             if ( strcmp( "Name", name ) == 0 )
371                                             {
372                                                 onceMore->_name = val;
373                                             }
374                                             else if ( strcmp( "Columns", name ) == 0 )
375                                             {
376                                                 gchar* endPtr = 0;
377                                                 guint64 numVal = g_ascii_strtoull( val, &endPtr, 10 );
378                                                 if ( (numVal == G_MAXUINT64) && (ERANGE == errno) ) {
379                                                     // overflow
380                                                 } else if ( (numVal == 0) && (endPtr == val) ) {
381                                                     // failed conversion
382                                                 } else {
383                                                     onceMore->_prefWidth = numVal;
384                                                 }
385                                             }
386                                         } else {
387                                             // error
388                                             hasErr = true;
389                                         }
390                                     } else {
391                                         // error
392                                         hasErr = true;
393                                     }
394                                 }
395                             }
396                         }
397                     }
398                 } while ( result && !hasErr );
399                 if ( !hasErr ) {
400                     possible.push_back(onceMore);
401 #if ENABLE_MAGIC_COLORS
402                     ColorItem::_wireMagicColors( onceMore );
403 #endif // ENABLE_MAGIC_COLORS
404                 } else {
405                     delete onceMore;
406                 }
407             }
408         }
410         fclose(f);
411     }
414 static void loadEmUp()
416     static bool beenHere = false;
417     if ( !beenHere ) {
418         beenHere = true;
420         std::list<gchar *> sources;
421         sources.push_back( profile_path("palettes") );
422         sources.push_back( g_strdup(INKSCAPE_PALETTESDIR) );
423         sources.push_back( g_strdup(CREATE_PALETTESDIR) );
425         // Use this loop to iterate through a list of possible document locations.
426         while (!sources.empty()) {
427             gchar *dirname = sources.front();
429             if ( Inkscape::IO::file_test( dirname, G_FILE_TEST_EXISTS )
430                 && Inkscape::IO::file_test( dirname, G_FILE_TEST_IS_DIR )) {
431                 GError *err = 0;
432                 GDir *directory = g_dir_open(dirname, 0, &err);
433                 if (!directory) {
434                     gchar *safeDir = Inkscape::IO::sanitizeString(dirname);
435                     g_warning(_("Palettes directory (%s) is unavailable."), safeDir);
436                     g_free(safeDir);
437                 } else {
438                     gchar *filename = 0;
439                     while ((filename = (gchar *)g_dir_read_name(directory)) != NULL) {
440                         gchar* lower = g_ascii_strdown( filename, -1 );
441 //                        if ( g_str_has_suffix(lower, ".gpl") ) {
442                             gchar* full = g_build_filename(dirname, filename, NULL);
443                             if ( !Inkscape::IO::file_test( full, G_FILE_TEST_IS_DIR ) ) {
444                                 _loadPaletteFile(full);
445                             }
446                             g_free(full);
447 //                      }
448                         g_free(lower);
449                     }
450                     g_dir_close(directory);
451                 }
452             }
454             // toss the dirname
455             g_free(dirname);
456             sources.pop_front();
457         }
458     }
469 SwatchesPanel& SwatchesPanel::getInstance()
471     return *new SwatchesPanel();
475 /**
476  * Constructor
477  */
478 SwatchesPanel::SwatchesPanel(gchar const* prefsPath) :
479     Inkscape::UI::Widget::Panel("", prefsPath, SP_VERB_DIALOG_SWATCHES, "", true),
480     _holder(0),
481     _clear(0),
482     _remove(0),
483     _currentIndex(0),
484     _currentDesktop(0),
485     _currentDocument(0)
487     Gtk::RadioMenuItem* hotItem = 0;
488     _holder = new PreviewHolder();
489     _clear = new ColorItem( ege::PaintDef::CLEAR );
490     _remove = new ColorItem( ege::PaintDef::NONE );
491     if (docPalettes.empty()) {
492         SwatchPage *docPalette = new SwatchPage();
494         docPalette->_name = "Auto";
495         docPalettes[0] = docPalette;
496     }
498     loadEmUp();
499     if ( !possible.empty() ) {
500         SwatchPage* first = 0;
501         int index = 0;
502         Glib::ustring targetName;
503         if ( !_prefs_path.empty() ) {
504             Inkscape::Preferences *prefs = Inkscape::Preferences::get();
505             targetName = prefs->getString(_prefs_path + "/palette");
506             if (!targetName.empty()) {
507                 if (targetName == "Auto") {
508                     first = docPalettes[0];
509                 } else {
510                     index++;
511                     for ( std::vector<SwatchPage*>::iterator iter = possible.begin(); iter != possible.end(); ++iter ) {
512                         if ( (*iter)->_name == targetName ) {
513                             first = *iter;
514                             break;
515                         }
516                         index++;
517                     }
518                 }
519             }
520         }
522         if ( !first ) {
523             first = docPalettes[0];
524             _currentIndex = 0;
525         } else {
526             _currentIndex = index;
527         }
529         _rebuild();
531         Gtk::RadioMenuItem::Group groupOne;
533         int i = 0;
534         std::vector<SwatchPage*> swatchSets = _getSwatchSets();
535         for ( std::vector<SwatchPage*>::iterator it = swatchSets.begin(); it != swatchSets.end(); it++ ) {
536             SwatchPage* curr = *it;
537             Gtk::RadioMenuItem* single = manage(new Gtk::RadioMenuItem(groupOne, curr->_name));
538             if ( curr == first ) {
539                 hotItem = single;
540             }
541             _regItem( single, 3, i );
542             i++;
543         }
544     }
547     _getContents()->pack_start(*_holder, Gtk::PACK_EXPAND_WIDGET);
548     _setTargetFillable(_holder);
550     show_all_children();
552     restorePanelPrefs();
553     if ( hotItem ) {
554         hotItem->set_active();
555     }
558 SwatchesPanel::~SwatchesPanel()
560     _trackDocument( this, 0 );
562     _documentConnection.disconnect();
563     _selChanged.disconnect();
565     if ( _clear ) {
566         delete _clear;
567     }
568     if ( _remove ) {
569         delete _remove;
570     }
571     if ( _holder ) {
572         delete _holder;
573     }
576 void SwatchesPanel::setOrientation( Gtk::AnchorType how )
578     // Must call the parent class or bad things might happen
579     Inkscape::UI::Widget::Panel::setOrientation( how );
581     if ( _holder )
582     {
583         _holder->setOrientation( Gtk::ANCHOR_SOUTH );
584     }
587 void SwatchesPanel::setDesktop( SPDesktop* desktop )
589     if ( desktop != _currentDesktop ) {
590         if ( _currentDesktop ) {
591             _documentConnection.disconnect();
592             _selChanged.disconnect();
593         }
595         _currentDesktop = desktop;
597         if ( desktop ) {
598             _currentDesktop->selection->connectChanged(
599                 sigc::hide(sigc::mem_fun(*this, &SwatchesPanel::_updateFromSelection)));
601             _currentDesktop->selection->connectModified(
602                 sigc::hide(sigc::hide(sigc::mem_fun(*this, &SwatchesPanel::_updateFromSelection))));
604             _currentDesktop->connectToolSubselectionChanged(
605                 sigc::hide(sigc::mem_fun(*this, &SwatchesPanel::_updateFromSelection)));
607             sigc::bound_mem_functor1<void, Inkscape::UI::Dialogs::SwatchesPanel, SPDocument*> first = sigc::mem_fun(*this, &SwatchesPanel::_setDocument);
608             sigc::slot<void, SPDocument*> base2 = first;
609             sigc::slot<void,SPDesktop*, SPDocument*> slot2 = sigc::hide<0>( base2 );
610             _documentConnection = desktop->connectDocumentReplaced( slot2 );
612             _setDocument( desktop->doc() );
613         } else {
614             _setDocument(0);
615         }
616     }
620 class DocTrack
622 public:
623     DocTrack(SPDocument *doc, sigc::connection &gradientRsrcChanged, sigc::connection &defsChanged, sigc::connection &defsModified) :
624         doc(doc),
625         gradientRsrcChanged(gradientRsrcChanged),
626         defsChanged(defsChanged),
627         defsModified(defsModified)
628     {
629     }
631     ~DocTrack()
632     {
633         if (doc) {
634             gradientRsrcChanged.disconnect();
635             defsChanged.disconnect();
636             defsModified.disconnect();
637         }
638     }
640     SPDocument *doc;
641     sigc::connection gradientRsrcChanged;
642     sigc::connection defsChanged;
643     sigc::connection defsModified;
645 private:
646     DocTrack(DocTrack const &); // no copy
647     DocTrack &operator=(DocTrack const &); // no assign
648 };
650 void SwatchesPanel::_trackDocument( SwatchesPanel *panel, SPDocument *document )
652     SPDocument *oldDoc = 0;
653     if (docPerPanel.find(panel) != docPerPanel.end()) {
654         oldDoc = docPerPanel[panel];
655         if (!oldDoc) {
656             docPerPanel.erase(panel); // Should not be needed, but clean up just in case.
657         }
658     }
659     if (oldDoc != document) {
660         if (oldDoc) {
661             docPerPanel[panel] = 0;
662             bool found = false;
663             for (std::map<SwatchesPanel*, SPDocument*>::iterator it = docPerPanel.begin(); (it != docPerPanel.end()) && !found; ++it) {
664                 found = (it->second == document);
665             }
666             if (!found) {
667                 for (std::vector<DocTrack*>::iterator it = docTrackings.begin(); it != docTrackings.end(); ++it){
668                     if ((*it)->doc == oldDoc) {
669                         delete *it;
670                         docTrackings.erase(it);
671                         break;
672                     }
673                 }
674             }
675         }
677         if (document) {
678             bool found = false;
679             for (std::map<SwatchesPanel*, SPDocument*>::iterator it = docPerPanel.begin(); (it != docPerPanel.end()) && !found; ++it) {
680                 found = (it->second == document);
681             }
682             docPerPanel[panel] = document;
683             if (!found) {
684                 sigc::connection conn1 = sp_document_resources_changed_connect( document, "gradient", sigc::bind(sigc::ptr_fun(&SwatchesPanel::handleGradientsChange), document) );
685                 sigc::connection conn2 = SP_DOCUMENT_DEFS(document)->connectRelease( sigc::hide(sigc::bind(sigc::ptr_fun(&SwatchesPanel::handleDefsModified), document)) );
686                 sigc::connection conn3 = SP_DOCUMENT_DEFS(document)->connectModified( sigc::hide(sigc::hide(sigc::bind(sigc::ptr_fun(&SwatchesPanel::handleDefsModified), document))) );
688                 DocTrack *dt = new DocTrack(document, conn1, conn2, conn3);
689                 docTrackings.push_back(dt);
691                 if (docPalettes.find(document) == docPalettes.end()) {
692                     SwatchPage *docPalette = new SwatchPage();
693                     docPalette->_name = "Auto";
694                     docPalettes[document] = docPalette;
695                 }
696             }
697         }
698     }
700     std::set<SPDocument*> docs;
701     for (std::map<SwatchesPanel*, SPDocument*>::iterator it = docPerPanel.begin(); it != docPerPanel.end(); ++it) {
702         docs.insert(it->second);
703     }
706 void SwatchesPanel::_setDocument( SPDocument *document )
708     if ( document != _currentDocument ) {
709         _trackDocument(this, document);
710         _currentDocument = document;
711         handleGradientsChange( document );
712     }
715 static void recalcSwatchContents(SPDocument* doc,
716                 std::vector<ColorItem*> &tmpColors,
717                 std::map<ColorItem*, guchar*> &previewMappings,
718                 std::map<ColorItem*, SPGradient*> &gradMappings)
720     std::vector<SPGradient*> newList;
722     const GSList *gradients = sp_document_get_resource_list(doc, "gradient");
723     for (const GSList *item = gradients; item; item = item->next) {
724         SPGradient* grad = SP_GRADIENT(item->data);
725         if ( grad->isSwatch() ) {
726             newList.push_back(SP_GRADIENT(item->data));
727         }
728     }
730     if ( !newList.empty() ) {
731         for ( std::vector<SPGradient*>::iterator it = newList.begin(); it != newList.end(); ++it )
732         {
733             SPGradient* grad = *it;
734             sp_gradient_ensure_vector( grad );
735             SPGradientStop first = grad->vector.stops[0];
736             SPColor color = first.color;
737             guint32 together = color.toRGBA32(first.opacity);
739             SPGradientStop second = (*it)->vector.stops[1];
740             SPColor color2 = second.color;
742             Glib::ustring name( grad->getId() );
743             unsigned int r = SP_RGBA32_R_U(together);
744             unsigned int g = SP_RGBA32_G_U(together);
745             unsigned int b = SP_RGBA32_B_U(together);
746             ColorItem* item = new ColorItem( r, g, b, name );
748             gint width = PREVIEW_PIXBUF_WIDTH;
749             gint height = VBLOCK;
750             guchar* px = g_new( guchar, 3 * height * width );
751             nr_render_checkerboard_rgb( px, width, height, 3 * width, 0, 0 );
753             sp_gradient_render_vector_block_rgb( grad,
754                                                  px, width, height, 3 * width,
755                                                  0, width, TRUE );
757             previewMappings[item] = px;
759             tmpColors.push_back(item);
760             gradMappings[item] = grad;
761         }
762     }
765 void SwatchesPanel::handleGradientsChange(SPDocument *document)
767     SwatchPage *docPalette = (docPalettes.find(document) != docPalettes.end()) ? docPalettes[document] : 0;
768     if (docPalette) {
769         std::vector<ColorItem*> tmpColors;
770         std::map<ColorItem*, guchar*> tmpPrevs;
771         std::map<ColorItem*, SPGradient*> tmpGrads;
772         recalcSwatchContents(document, tmpColors, tmpPrevs, tmpGrads);
774         for (std::map<ColorItem*, guchar*>::iterator it = tmpPrevs.begin(); it != tmpPrevs.end(); ++it) {
775             it->first->setPixData(it->second, PREVIEW_PIXBUF_WIDTH, VBLOCK);
776         }
778         for (std::map<ColorItem*, SPGradient*>::iterator it = tmpGrads.begin(); it != tmpGrads.end(); ++it) {
779             it->first->setGradient(it->second);
780         }
782         docPalette->_colors.swap(tmpColors);
783         for (std::vector<ColorItem*>::iterator it = tmpColors.begin(); it != tmpColors.end(); ++it) {
784             delete *it;
785         }
788         // Figure out which SwatchesPanel instances are affected and update them.
790         for (std::map<SwatchesPanel*, SPDocument*>::iterator it = docPerPanel.begin(); it != docPerPanel.end(); ++it) {
791             if (it->second == document) {
792                 SwatchesPanel* swp = it->first;
793                 std::vector<SwatchPage*> pages = swp->_getSwatchSets();
794                 SwatchPage* curr = pages[swp->_currentIndex];
795                 if (curr == docPalette) {
796                     swp->_rebuild();
797                 }
798             }
799         }
800     }
803 void SwatchesPanel::handleDefsModified(SPDocument *document)
805     SwatchPage *docPalette = (docPalettes.find(document) != docPalettes.end()) ? docPalettes[document] : 0;
806     if (docPalette) {
807         std::vector<ColorItem*> tmpColors;
808         std::map<ColorItem*, guchar*> tmpPrevs;
809         std::map<ColorItem*, SPGradient*> tmpGrads;
810         recalcSwatchContents(document, tmpColors, tmpPrevs, tmpGrads);
812         int cap = std::min(docPalette->_colors.size(), tmpColors.size());
813         for (int i = 0; i < cap; i++) {
814             ColorItem* newColor = tmpColors[i];
815             ColorItem* oldColor = docPalette->_colors[i];
816             if ( (newColor->def.getType() != oldColor->def.getType()) ||
817                  (newColor->def.getR() != oldColor->def.getR()) ||
818                  (newColor->def.getG() != oldColor->def.getG()) ||
819                  (newColor->def.getB() != oldColor->def.getB()) ) {
820                 oldColor->def.setRGB(newColor->def.getR(), newColor->def.getG(), newColor->def.getB());
821             }
822             if (tmpGrads.find(newColor) != tmpGrads.end()) {
823                 oldColor->setGradient(tmpGrads[newColor]);
824             }
825             if ( tmpPrevs.find(newColor) != tmpPrevs.end() ) {
826                 oldColor->setPixData(tmpPrevs[newColor], PREVIEW_PIXBUF_WIDTH, VBLOCK);
827             }
828         }
829     }
832 std::vector<SwatchPage*> SwatchesPanel::_getSwatchSets() const
834     std::vector<SwatchPage*> tmp;
835     if (docPalettes.find(_currentDocument) != docPalettes.end()) {
836         tmp.push_back(docPalettes[_currentDocument]);
837     }
839     tmp.insert(tmp.end(), possible.begin(), possible.end());
841     return tmp;
844 void SwatchesPanel::_updateFromSelection()
846     SwatchPage *docPalette = (docPalettes.find(_currentDocument) != docPalettes.end()) ? docPalettes[_currentDocument] : 0;
847     if ( docPalette ) {
848         Glib::ustring fillId;
849         Glib::ustring strokeId;
851         SPStyle *tmpStyle = sp_style_new( sp_desktop_document(_currentDesktop) );
852         int result = sp_desktop_query_style( _currentDesktop, tmpStyle, QUERY_STYLE_PROPERTY_FILL );
853         switch (result) {
854             case QUERY_STYLE_SINGLE:
855             case QUERY_STYLE_MULTIPLE_AVERAGED:
856             case QUERY_STYLE_MULTIPLE_SAME:
857             {
858                 if (tmpStyle->fill.set && tmpStyle->fill.isPaintserver()) {
859                     SPPaintServer* server = tmpStyle->getFillPaintServer();
860                     if ( SP_IS_GRADIENT(server) ) {
861                         SPGradient* target = 0;
862                         SPGradient* grad = SP_GRADIENT(server);
863                         if (grad->repr->attribute("osb:paint")) {
864                             target = grad;
865                         } else if ( grad->ref ) {
866                             SPGradient *tmp = grad->ref->getObject();
867                             if ( tmp && tmp->repr->attribute("osb:paint") ) {
868                                 target = tmp;
869                             }
870                         }
871                         if ( target ) {
872                             gchar const* id = target->repr->attribute("id");
873                             if ( id ) {
874                                 fillId = id;
875                             }
876                         }
877                     }
878                 }
879                 break;
880             }
881         }
883         result = sp_desktop_query_style( _currentDesktop, tmpStyle, QUERY_STYLE_PROPERTY_STROKE );
884         switch (result) {
885             case QUERY_STYLE_SINGLE:
886             case QUERY_STYLE_MULTIPLE_AVERAGED:
887             case QUERY_STYLE_MULTIPLE_SAME:
888             {
889                 if (tmpStyle->stroke.set && tmpStyle->stroke.isPaintserver()) {
890                     SPPaintServer* server = tmpStyle->getStrokePaintServer();
891                     if ( SP_IS_GRADIENT(server) ) {
892                         SPGradient* target = 0;
893                         SPGradient* grad = SP_GRADIENT(server);
894                         if (grad->repr->attribute("osb:paint")) {
895                             target = grad;
896                         } else if ( grad->ref ) {
897                             SPGradient *tmp = grad->ref->getObject();
898                             if ( tmp && tmp->repr->attribute("osb:paint") ) {
899                                 target = tmp;
900                             }
901                         }
902                         if ( target ) {
903                             gchar const* id = target->repr->attribute("id");
904                             if ( id ) {
905                                 strokeId = id;
906                             }
907                         }
908                     }
909                 }
910                 break;
911             }
912         }
913         sp_style_unref(tmpStyle);
915         for ( std::vector<ColorItem*>::iterator it = docPalette->_colors.begin(); it != docPalette->_colors.end(); ++it ) {
916             ColorItem* item = *it;
917             bool isFill = (fillId == item->def.descr);
918             bool isStroke = (strokeId == item->def.descr);
919             item->setState( isFill, isStroke );
920         }
921     }
924 void SwatchesPanel::_handleAction( int setId, int itemId )
926     switch( setId ) {
927         case 3:
928         {
929             std::vector<SwatchPage*> pages = _getSwatchSets();
930             if ( itemId >= 0 && itemId < static_cast<int>(pages.size()) ) {
931                 _currentIndex = itemId;
933                 if ( !_prefs_path.empty() ) {
934                     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
935                     prefs->setString(_prefs_path + "/palette", pages[_currentIndex]->_name);
936                 }
938                 _rebuild();
939             }
940         }
941         break;
942     }
945 void SwatchesPanel::_rebuild()
947     std::vector<SwatchPage*> pages = _getSwatchSets();
948     SwatchPage* curr = pages[_currentIndex];
949     _holder->clear();
951     if ( curr->_prefWidth > 0 ) {
952         _holder->setColumnPref( curr->_prefWidth );
953     }
954     _holder->freezeUpdates();
955     // TODO restore once 'clear' works _holder->addPreview(_clear);
956     _holder->addPreview(_remove);
957     for ( std::vector<ColorItem*>::iterator it = curr->_colors.begin(); it != curr->_colors.end(); it++ ) {
958         _holder->addPreview(*it);
959     }
960     _holder->thawUpdates();
966 } //namespace Dialogs
967 } //namespace UI
968 } //namespace Inkscape
971 /*
972   Local Variables:
973   mode:c++
974   c-file-style:"stroustrup"
975   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
976   indent-tabs-mode:nil
977   fill-column:99
978   End:
979 */
980 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :