Code

Implement keyboard shortcuts for single handle adjustments.
[inkscape.git] / src / ui / dialog / swatches.cpp
1 /** @file
2  * @brief Color swatches dialog
3  */
4 /* Authors:
5  *   Jon A. Cruz
6  *   John Bintz
7  *
8  * Copyright (C) 2005 Jon A. Cruz
9  * Copyright (C) 2008 John Bintz
10  *
11  * Released under GNU GPL, read the file 'COPYING' for more information
12  */
14 #include <errno.h>
15 #include <map>
17 #include <gtk/gtkdialog.h> //for GTK_RESPONSE* types
18 #include <gtk/gtkdnd.h>
19 #include <gtk/gtkmenu.h>
20 #include <gtk/gtkmenuitem.h>
21 #include <gtk/gtkseparatormenuitem.h>
22 #include <glibmm/i18n.h>
23 #include <gdkmm/pixbuf.h>
25 #include "color-item.h"
26 #include "desktop.h"
27 #include "desktop-handles.h"
28 #include "desktop-style.h"
29 #include "document.h"
30 #include "document-private.h"
31 #include "extension/db.h"
32 #include "inkscape.h"
33 #include "inkscape.h"
34 #include "io/sys.h"
35 #include "io/resource.h"
36 #include "message-context.h"
37 #include "path-prefix.h"
38 #include "preferences.h"
39 #include "sp-item.h"
40 #include "sp-gradient-fns.h"
41 #include "sp-gradient.h"
42 #include "sp-gradient-vector.h"
43 #include "swatches.h"
44 #include "style.h"
45 #include "ui/previewholder.h"
46 #include "widgets/gradient-vector.h"
47 #include "widgets/eek-preview.h"
48 #include "display/nr-plain-stuff.h"
49 #include "sp-gradient-reference.h"
51 #define USE_DOCUMENT_PALETTE 1
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 );
64 std::vector<JustForNow*> possible;
67 static void handleClick( GtkWidget* /*widget*/, gpointer callback_data ) {
68     ColorItem* item = reinterpret_cast<ColorItem*>(callback_data);
69     if ( item ) {
70         item->buttonClicked(false);
71     }
72 }
74 static void handleSecondaryClick( GtkWidget* /*widget*/, gint /*arg1*/, gpointer callback_data ) {
75     ColorItem* item = reinterpret_cast<ColorItem*>(callback_data);
76     if ( item ) {
77         item->buttonClicked(true);
78     }
79 }
81 static GtkWidget* popupMenu = 0;
82 static std::vector<GtkWidget*> popupExtras;
83 static ColorItem* bounceTarget = 0;
85 static void redirClick( GtkMenuItem *menuitem, gpointer /*user_data*/ )
86 {
87     if ( bounceTarget ) {
88         handleClick( GTK_WIDGET(menuitem), bounceTarget );
89     }
90 }
92 static void redirSecondaryClick( GtkMenuItem *menuitem, gpointer /*user_data*/ )
93 {
94     if ( bounceTarget ) {
95         handleSecondaryClick( GTK_WIDGET(menuitem), 0, bounceTarget );
96     }
97 }
99 #if USE_DOCUMENT_PALETTE
100 static void editGradientImpl( SPGradient* gr )
102     if ( gr ) {
103         GtkWidget *dialog = sp_gradient_vector_editor_new( gr );
104         gtk_widget_show( dialog );
105     }
108 static void editGradient( GtkMenuItem */*menuitem*/, gpointer /*user_data*/ )
110     if ( bounceTarget ) {
111         SwatchesPanel* swp = bounceTarget->ptr ? reinterpret_cast<SwatchesPanel*>(bounceTarget->ptr) : 0;
112         SPDesktop* desktop = swp ? swp->getDesktop() : 0;
113         SPDocument *doc = desktop ? desktop->doc() : 0;
114         if (doc) {
115             std::string targetName(bounceTarget->def.descr);
116             const GSList *gradients = sp_document_get_resource_list(doc, "gradient");
117             for (const GSList *item = gradients; item; item = item->next) {
118                 SPGradient* grad = SP_GRADIENT(item->data);
119                 if ( targetName == grad->getId() ) {
120                     editGradientImpl( grad );
121                     break;
122                 }
123             }
124         }
125     }
128 static void addNewGradient( GtkMenuItem */*menuitem*/, gpointer /*user_data*/ )
130     if ( bounceTarget ) {
131         SwatchesPanel* swp = bounceTarget->ptr ? reinterpret_cast<SwatchesPanel*>(bounceTarget->ptr) : 0;
132         SPDesktop* desktop = swp ? swp->getDesktop() : 0;
133         SPDocument *doc = desktop ? desktop->doc() : 0;
134         if (doc) {
135             Inkscape::XML::Document *xml_doc = sp_document_repr_doc(doc);
137             Inkscape::XML::Node *repr = xml_doc->createElement("svg:linearGradient");
138             repr->setAttribute("osb:paint", "solid");
139             Inkscape::XML::Node *stop = xml_doc->createElement("svg:stop");
140             stop->setAttribute("offset", "0");
141             stop->setAttribute("style", "stop-color:#000;stop-opacity:1;");
142             repr->appendChild(stop);
143             Inkscape::GC::release(stop);
145             SP_OBJECT_REPR( SP_DOCUMENT_DEFS(doc) )->addChild(repr, NULL);
147             SPGradient * gr = static_cast<SPGradient *>(doc->getObjectByRepr(repr));
149             Inkscape::GC::release(repr);
152             editGradientImpl( gr );
153             // Work-around for timing of gradient addition change. Must follow edit.
154             if ( swp ) {
155                 swp->handleGradientsChange();
156             }
157         }
158     }
160 #endif // USE_DOCUMENT_PALETTE
162 gboolean colorItemHandleButtonPress( GtkWidget* /*widget*/, GdkEventButton* event, gpointer user_data)
164     gboolean handled = FALSE;
166     if ( (event->button == 3) && (event->type == GDK_BUTTON_PRESS) ) {
167         if ( !popupMenu ) {
168             popupMenu = gtk_menu_new();
169             GtkWidget* child = 0;
171             //TRANSLATORS: An item in context menu on a colour in the swatches
172             child = gtk_menu_item_new_with_label(_("Set fill"));
173             g_signal_connect( G_OBJECT(child),
174                               "activate",
175                               G_CALLBACK(redirClick),
176                               user_data);
177             gtk_menu_shell_append(GTK_MENU_SHELL(popupMenu), child);
179             //TRANSLATORS: An item in context menu on a colour in the swatches
180             child = gtk_menu_item_new_with_label(_("Set stroke"));
182             g_signal_connect( G_OBJECT(child),
183                               "activate",
184                               G_CALLBACK(redirSecondaryClick),
185                               user_data);
186             gtk_menu_shell_append(GTK_MENU_SHELL(popupMenu), child);
188 #if USE_DOCUMENT_PALETTE
189             child = gtk_separator_menu_item_new();
190             gtk_menu_shell_append(GTK_MENU_SHELL(popupMenu), child);
191             popupExtras.push_back(child);
193             child = gtk_menu_item_new_with_label(_("Add"));
194             g_signal_connect( G_OBJECT(child),
195                               "activate",
196                               G_CALLBACK(addNewGradient),
197                               user_data );
198             gtk_menu_shell_append(GTK_MENU_SHELL(popupMenu), child);
199             popupExtras.push_back(child);
201             child = gtk_menu_item_new_with_label(_("Delete"));
202             gtk_menu_shell_append(GTK_MENU_SHELL(popupMenu), child);
203             //popupExtras.push_back(child);
204             gtk_widget_set_sensitive( child, FALSE );
206             child = gtk_menu_item_new_with_label(_("Edit..."));
207             g_signal_connect( G_OBJECT(child),
208                               "activate",
209                               G_CALLBACK(editGradient),
210                               user_data );
211             gtk_menu_shell_append(GTK_MENU_SHELL(popupMenu), child);
212             popupExtras.push_back(child);
214             child = gtk_separator_menu_item_new();
215             gtk_menu_shell_append(GTK_MENU_SHELL(popupMenu), child);
216             popupExtras.push_back(child);
218             child = gtk_menu_item_new_with_label(_("Convert"));
219             gtk_menu_shell_append(GTK_MENU_SHELL(popupMenu), child);
220             //popupExtras.push_back(child);
221             gtk_widget_set_sensitive( child, FALSE );
222 #endif // USE_DOCUMENT_PALETTE
224             gtk_widget_show_all(popupMenu);
225         }
227         ColorItem* item = reinterpret_cast<ColorItem*>(user_data);
228         if ( item ) {
229             SwatchesPanel* swp = item->ptr ? reinterpret_cast<SwatchesPanel*>(item->ptr) : 0;
230             bool show = swp && (swp->getSelectedIndex() == 0);
231             for ( std::vector<GtkWidget*>::iterator it = popupExtras.begin(); it != popupExtras.end(); ++ it) {
232                 gtk_widget_set_sensitive(*it, show);
233             }
235             bounceTarget = item;
236             if ( popupMenu ) {
237                 gtk_menu_popup(GTK_MENU(popupMenu), NULL, NULL, NULL, NULL, event->button, event->time);
238                 handled = TRUE;
239             }
240         }
241     }
243     return handled;
247 static char* trim( char* str ) {
248     char* ret = str;
249     while ( *str && (*str == ' ' || *str == '\t') ) {
250         str++;
251     }
252     ret = str;
253     while ( *str ) {
254         str++;
255     }
256     str--;
257     while ( str > ret && (( *str == ' ' || *str == '\t' ) || *str == '\r' || *str == '\n') ) {
258         *str-- = 0;
259     }
260     return ret;
263 void skipWhitespace( char*& str ) {
264     while ( *str == ' ' || *str == '\t' ) {
265         str++;
266     }
269 bool parseNum( char*& str, int& val ) {
270     val = 0;
271     while ( '0' <= *str && *str <= '9' ) {
272         val = val * 10 + (*str - '0');
273         str++;
274     }
275     bool retval = !(*str == 0 || *str == ' ' || *str == '\t' || *str == '\r' || *str == '\n');
276     return retval;
280 void _loadPaletteFile( gchar const *filename )
282     char block[1024];
283     FILE *f = Inkscape::IO::fopen_utf8name( filename, "r" );
284     if ( f ) {
285         char* result = fgets( block, sizeof(block), f );
286         if ( result ) {
287             if ( strncmp( "GIMP Palette", block, 12 ) == 0 ) {
288                 bool inHeader = true;
289                 bool hasErr = false;
291                 JustForNow *onceMore = new JustForNow();
293                 do {
294                     result = fgets( block, sizeof(block), f );
295                     block[sizeof(block) - 1] = 0;
296                     if ( result ) {
297                         if ( block[0] == '#' ) {
298                             // ignore comment
299                         } else {
300                             char *ptr = block;
301                             // very simple check for header versus entry
302                             while ( *ptr == ' ' || *ptr == '\t' ) {
303                                 ptr++;
304                             }
305                             if ( (*ptr == 0) || (*ptr == '\r') || (*ptr == '\n') ) {
306                                 // blank line. skip it.
307                             } else if ( '0' <= *ptr && *ptr <= '9' ) {
308                                 // should be an entry link
309                                 inHeader = false;
310                                 ptr = block;
311                                 Glib::ustring name("");
312                                 int r = 0;
313                                 int g = 0;
314                                 int b = 0;
315                                 skipWhitespace(ptr);
316                                 if ( *ptr ) {
317                                     hasErr = parseNum(ptr, r);
318                                     if ( !hasErr ) {
319                                         skipWhitespace(ptr);
320                                         hasErr = parseNum(ptr, g);
321                                     }
322                                     if ( !hasErr ) {
323                                         skipWhitespace(ptr);
324                                         hasErr = parseNum(ptr, b);
325                                     }
326                                     if ( !hasErr && *ptr ) {
327                                         char* n = trim(ptr);
328                                         if (n != NULL) {
329                                             name = n;
330                                         }
331                                     }
332                                     if ( !hasErr ) {
333                                         // Add the entry now
334                                         Glib::ustring nameStr(name);
335                                         ColorItem* item = new ColorItem( r, g, b, nameStr );
336                                         onceMore->_colors.push_back(item);
337                                     }
338                                 } else {
339                                     hasErr = true;
340                                 }
341                             } else {
342                                 if ( !inHeader ) {
343                                     // Hmmm... probably bad. Not quite the format we want?
344                                     hasErr = true;
345                                 } else {
346                                     char* sep = strchr(result, ':');
347                                     if ( sep ) {
348                                         *sep = 0;
349                                         char* val = trim(sep + 1);
350                                         char* name = trim(result);
351                                         if ( *name ) {
352                                             if ( strcmp( "Name", name ) == 0 )
353                                             {
354                                                 onceMore->_name = val;
355                                             }
356                                             else if ( strcmp( "Columns", name ) == 0 )
357                                             {
358                                                 gchar* endPtr = 0;
359                                                 guint64 numVal = g_ascii_strtoull( val, &endPtr, 10 );
360                                                 if ( (numVal == G_MAXUINT64) && (ERANGE == errno) ) {
361                                                     // overflow
362                                                 } else if ( (numVal == 0) && (endPtr == val) ) {
363                                                     // failed conversion
364                                                 } else {
365                                                     onceMore->_prefWidth = numVal;
366                                                 }
367                                             }
368                                         } else {
369                                             // error
370                                             hasErr = true;
371                                         }
372                                     } else {
373                                         // error
374                                         hasErr = true;
375                                     }
376                                 }
377                             }
378                         }
379                     }
380                 } while ( result && !hasErr );
381                 if ( !hasErr ) {
382                     possible.push_back(onceMore);
383 #if ENABLE_MAGIC_COLORS
384                     ColorItem::_wireMagicColors( onceMore );
385 #endif // ENABLE_MAGIC_COLORS
386                 } else {
387                     delete onceMore;
388                 }
389             }
390         }
392         fclose(f);
393     }
396 static void loadEmUp()
398     static bool beenHere = false;
399     if ( !beenHere ) {
400         beenHere = true;
402         std::list<gchar *> sources;
403         sources.push_back( profile_path("palettes") );
404         sources.push_back( g_strdup(INKSCAPE_PALETTESDIR) );
405         sources.push_back( g_strdup(CREATE_PALETTESDIR) );
407         // Use this loop to iterate through a list of possible document locations.
408         while (!sources.empty()) {
409             gchar *dirname = sources.front();
411             if ( Inkscape::IO::file_test( dirname, G_FILE_TEST_EXISTS )
412                 && Inkscape::IO::file_test( dirname, G_FILE_TEST_IS_DIR )) {
413                 GError *err = 0;
414                 GDir *directory = g_dir_open(dirname, 0, &err);
415                 if (!directory) {
416                     gchar *safeDir = Inkscape::IO::sanitizeString(dirname);
417                     g_warning(_("Palettes directory (%s) is unavailable."), safeDir);
418                     g_free(safeDir);
419                 } else {
420                     gchar *filename = 0;
421                     while ((filename = (gchar *)g_dir_read_name(directory)) != NULL) {
422                         gchar* lower = g_ascii_strdown( filename, -1 );
423 //                        if ( g_str_has_suffix(lower, ".gpl") ) {
424                             gchar* full = g_build_filename(dirname, filename, NULL);
425                             if ( !Inkscape::IO::file_test( full, G_FILE_TEST_IS_DIR ) ) {
426                                 _loadPaletteFile(full);
427                             }
428                             g_free(full);
429 //                      }
430                         g_free(lower);
431                     }
432                     g_dir_close(directory);
433                 }
434             }
436             // toss the dirname
437             g_free(dirname);
438             sources.pop_front();
439         }
440     }
451 SwatchesPanel& SwatchesPanel::getInstance()
453     return *new SwatchesPanel();
457 /**
458  * Constructor
459  */
460 SwatchesPanel::SwatchesPanel(gchar const* prefsPath) :
461     Inkscape::UI::Widget::Panel("", prefsPath, SP_VERB_DIALOG_SWATCHES, "", true),
462     _holder(0),
463     _clear(0),
464     _remove(0),
465     _currentIndex(0),
466     _currentDesktop(0),
467     _currentDocument(0),
468     _ptr(0)
470     Gtk::RadioMenuItem* hotItem = 0;
471     _holder = new PreviewHolder();
472     _clear = new ColorItem( ege::PaintDef::CLEAR );
473     _clear->ptr = this;
474     _remove = new ColorItem( ege::PaintDef::NONE );
475     _remove->ptr = this;
476 #if USE_DOCUMENT_PALETTE
477     {
478         JustForNow *docPalette = new JustForNow();
480         docPalette->_name = "Auto";
481         possible.push_back(docPalette);
483         _ptr = docPalette;
484     }
485 #endif // USE_DOCUMENT_PALETTE
486     loadEmUp();
487     if ( !possible.empty() ) {
488         JustForNow* first = 0;
489         int index = 0;
490         Glib::ustring targetName;
491         if ( !_prefs_path.empty() ) {
492             Inkscape::Preferences *prefs = Inkscape::Preferences::get();
493             targetName = prefs->getString(_prefs_path + "/palette");
494             if (!targetName.empty()) {
495                 for ( std::vector<JustForNow*>::iterator iter = possible.begin(); iter != possible.end(); ++iter ) {
496                     if ( (*iter)->_name == targetName ) {
497                         first = *iter;
498                         break;
499                     }
500                     index++;
501                 }
502             }
503         }
505         if ( !first ) {
506             first = possible.front();
507             _currentIndex = 0;
508         } else {
509             _currentIndex = index;
510         }
512         _rebuild();
514         Gtk::RadioMenuItem::Group groupOne;
516         int i = 0;
517         for ( std::vector<JustForNow*>::iterator it = possible.begin(); it != possible.end(); it++ ) {
518             JustForNow* curr = *it;
519             Gtk::RadioMenuItem* single = manage(new Gtk::RadioMenuItem(groupOne, curr->_name));
520             if ( curr == first ) {
521                 hotItem = single;
522             }
523             _regItem( single, 3, i );
524             i++;
525         }
526     }
529     _getContents()->pack_start(*_holder, Gtk::PACK_EXPAND_WIDGET);
530     _setTargetFillable(_holder);
532     show_all_children();
534     restorePanelPrefs();
535     if ( hotItem ) {
536         hotItem->set_active();
537     }
540 SwatchesPanel::~SwatchesPanel()
542     _documentConnection.disconnect();
543     _resourceConnection.disconnect();
544     _selChanged.disconnect();
545     _setModified.disconnect();
546     _subselChanged.disconnect();
547     _defsChanged.disconnect();
548     _defsModified.disconnect();
550     if ( _clear ) {
551         delete _clear;
552     }
553     if ( _remove ) {
554         delete _remove;
555     }
556     if ( _holder ) {
557         delete _holder;
558     }
561 void SwatchesPanel::setOrientation( Gtk::AnchorType how )
563     // Must call the parent class or bad things might happen
564     Inkscape::UI::Widget::Panel::setOrientation( how );
566     if ( _holder )
567     {
568         _holder->setOrientation( Gtk::ANCHOR_SOUTH );
569     }
572 void SwatchesPanel::setDesktop( SPDesktop* desktop )
574     if ( desktop != _currentDesktop ) {
575         if ( _currentDesktop ) {
576             _documentConnection.disconnect();
577             _selChanged.disconnect();
578             _setModified.disconnect();
579             _subselChanged.disconnect();
580         }
582         _currentDesktop = desktop;
584         if ( desktop ) {
585             _currentDesktop->selection->connectChanged(
586                 sigc::hide(sigc::mem_fun(*this, &SwatchesPanel::_updateFromSelection)));
588             _currentDesktop->selection->connectModified(
589                 sigc::hide(sigc::hide(sigc::mem_fun(*this, &SwatchesPanel::_updateFromSelection))));
591             _currentDesktop->connectToolSubselectionChanged(
592                 sigc::hide(sigc::mem_fun(*this, &SwatchesPanel::_updateFromSelection)));
594             sigc::bound_mem_functor1<void, Inkscape::UI::Dialogs::SwatchesPanel, SPDocument*> first = sigc::mem_fun(*this, &SwatchesPanel::_setDocument);
595             sigc::slot<void, SPDocument*> base2 = first;
596             sigc::slot<void,SPDesktop*, SPDocument*> slot2 = sigc::hide<0>( base2 );
597             _documentConnection = desktop->connectDocumentReplaced( slot2 );
599             _setDocument( desktop->doc() );
600         } else {
601             _setDocument(0);
602         }
603     }
606 void SwatchesPanel::_setDocument( SPDocument *document )
608     if ( document != _currentDocument ) {
609         if ( _currentDocument ) {
610             _resourceConnection.disconnect();
611             _defsChanged.disconnect();
612             _defsModified.disconnect();
613         }
614         _currentDocument = document;
615         if ( _currentDocument ) {
616             _resourceConnection = sp_document_resources_changed_connect(document,
617                                                                         "gradient",
618                                                                         sigc::mem_fun(*this, &SwatchesPanel::handleGradientsChange));
620             // connect to release and modified signals of the defs (i.e. when someone changes gradient)
621             _defsChanged = SP_DOCUMENT_DEFS(document)->connectRelease(sigc::hide(sigc::mem_fun(*this, &SwatchesPanel::handleDefsModified)));
622             _defsModified = SP_DOCUMENT_DEFS(document)->connectModified(sigc::hide(sigc::hide(sigc::mem_fun(*this, &SwatchesPanel::handleDefsModified))));
623         }
625         handleGradientsChange();
626     }
629 #if USE_DOCUMENT_PALETTE
630 static void recalcSwatchContents(SPDocument* doc,
631                 std::vector<ColorItem*> &tmpColors,
632                 std::map<ColorItem*, guchar*> &previewMappings,
633                 std::map<ColorItem*, SPGradient*> &gradMappings,
634                 void* ptr)
636     std::vector<SPGradient*> newList;
638     const GSList *gradients = sp_document_get_resource_list(doc, "gradient");
639     for (const GSList *item = gradients; item; item = item->next) {
640         SPGradient* grad = SP_GRADIENT(item->data);
641         if ( grad->isSwatch() ) {
642             newList.push_back(SP_GRADIENT(item->data));
643         }
644     }
646     if ( !newList.empty() ) {
647         for ( std::vector<SPGradient*>::iterator it = newList.begin(); it != newList.end(); ++it )
648         {
649             SPGradient* grad = *it;
650             sp_gradient_ensure_vector( grad );
651             SPGradientStop first = grad->vector.stops[0];
652             SPColor color = first.color;
653             guint32 together = color.toRGBA32(first.opacity);
655             SPGradientStop second = (*it)->vector.stops[1];
656             SPColor color2 = second.color;
658             Glib::ustring name( grad->getId() );
659             unsigned int r = SP_RGBA32_R_U(together);
660             unsigned int g = SP_RGBA32_G_U(together);
661             unsigned int b = SP_RGBA32_B_U(together);
662             ColorItem* item = new ColorItem( r, g, b, name );
663             item->ptr = ptr;
665             gint width = PREVIEW_PIXBUF_WIDTH;
666             gint height = VBLOCK;
667             guchar* px = g_new( guchar, 3 * height * width );
668             nr_render_checkerboard_rgb( px, width, height, 3 * width, 0, 0 );
670             sp_gradient_render_vector_block_rgb( grad,
671                                                  px, width, height, 3 * width,
672                                                  0, width, TRUE );
674             previewMappings[item] = px;
676             tmpColors.push_back(item);
677             gradMappings[item] = grad;
678         }
679     }
681 #endif // USE_DOCUMENT_PALETTE
683 void SwatchesPanel::handleGradientsChange()
685 // Invoked when the list of gradients itself changes due to additions, removals, etc.
686 #if USE_DOCUMENT_PALETTE
687     if ( _ptr ) {
688         JustForNow *docPalette = reinterpret_cast<JustForNow *>(_ptr);
689         if (docPalette) {
690             std::vector<ColorItem*> tmpColors;
691             std::map<ColorItem*, guchar*> tmpPrevs;
692             std::map<ColorItem*, SPGradient*> tmpGrads;
693             recalcSwatchContents(_currentDocument, tmpColors, tmpPrevs, tmpGrads, this);
695             for (std::map<ColorItem*, guchar*>::iterator it = tmpPrevs.begin(); it != tmpPrevs.end(); ++it) {
696                 it->first->setPixData(it->second, PREVIEW_PIXBUF_WIDTH, VBLOCK);
697             }
699             for (std::map<ColorItem*, SPGradient*>::iterator it = tmpGrads.begin(); it != tmpGrads.end(); ++it) {
700                 it->first->setGradient(it->second);
701             }
703             docPalette->_colors.swap(tmpColors);
704             for (std::vector<ColorItem*>::iterator it = tmpColors.begin(); it != tmpColors.end(); ++it) {
705                 delete *it;
706             }
708             JustForNow* curr = possible[_currentIndex];
709             if (curr == docPalette) {
710                 _rebuild();
711             }
712         }
713     }
714 #endif // USE_DOCUMENT_PALETTE
717 void SwatchesPanel::handleDefsModified()
719 #if USE_DOCUMENT_PALETTE
720     if ( _ptr ) {
721         JustForNow *docPalette = reinterpret_cast<JustForNow *>(_ptr);
722         if (docPalette) {
723             std::vector<ColorItem*> tmpColors;
724             std::map<ColorItem*, guchar*> tmpPrevs;
725             std::map<ColorItem*, SPGradient*> tmpGrads;
726             recalcSwatchContents(_currentDocument, tmpColors, tmpPrevs, tmpGrads, this);
728             int cap = std::min(docPalette->_colors.size(), tmpColors.size());
729             for (int i = 0; i < cap; i++) {
730                 ColorItem* newColor = tmpColors[i];
731                 ColorItem* oldColor = docPalette->_colors[i];
732                 if ( (newColor->def.getType() != oldColor->def.getType()) ||
733                      (newColor->def.getR() != oldColor->def.getR()) ||
734                      (newColor->def.getG() != oldColor->def.getG()) ||
735                      (newColor->def.getB() != oldColor->def.getB()) ) {
736                     oldColor->def.setRGB(newColor->def.getR(), newColor->def.getG(), newColor->def.getB());
737                 }
738                 if (tmpGrads.find(newColor) != tmpGrads.end()) {
739                     oldColor->setGradient(tmpGrads[newColor]);
740                 }
741                 if ( tmpPrevs.find(newColor) != tmpPrevs.end() ) {
742                     oldColor->setPixData(tmpPrevs[newColor], PREVIEW_PIXBUF_WIDTH, VBLOCK);
743                 }
744             }
745         }
746     }
747 #endif // USE_DOCUMENT_PALETTE
750 void SwatchesPanel::_updateFromSelection()
752 #if USE_DOCUMENT_PALETTE
753     if ( _ptr ) {
754         JustForNow *docPalette = reinterpret_cast<JustForNow *>(_ptr);
756         Glib::ustring fillId;
757         Glib::ustring strokeId;
759         SPStyle *tmpStyle = sp_style_new( sp_desktop_document(_currentDesktop) );
760         int result = sp_desktop_query_style( _currentDesktop, tmpStyle, QUERY_STYLE_PROPERTY_FILL );
761         switch (result) {
762             case QUERY_STYLE_SINGLE:
763             case QUERY_STYLE_MULTIPLE_AVERAGED:
764             case QUERY_STYLE_MULTIPLE_SAME:
765             {
766                 if (tmpStyle->fill.set && tmpStyle->fill.isPaintserver()) {
767                     SPPaintServer* server = tmpStyle->getFillPaintServer();
768                     if ( SP_IS_GRADIENT(server) ) {
769                         SPGradient* target = 0;
770                         SPGradient* grad = SP_GRADIENT(server);
771                         if (grad->repr->attribute("osb:paint")) {
772                             target = grad;
773                         } else if ( grad->ref ) {
774                             SPGradient *tmp = grad->ref->getObject();
775                             if ( tmp && tmp->repr->attribute("osb:paint") ) {
776                                 target = tmp;
777                             }
778                         }
779                         if ( target ) {
780                             gchar const* id = target->repr->attribute("id");
781                             if ( id ) {
782                                 fillId = id;
783                             }
784                         }
785                     }
786                 }
787                 break;
788             }
789         }
791         result = sp_desktop_query_style( _currentDesktop, tmpStyle, QUERY_STYLE_PROPERTY_STROKE );
792         switch (result) {
793             case QUERY_STYLE_SINGLE:
794             case QUERY_STYLE_MULTIPLE_AVERAGED:
795             case QUERY_STYLE_MULTIPLE_SAME:
796             {
797                 if (tmpStyle->stroke.set && tmpStyle->stroke.isPaintserver()) {
798                     SPPaintServer* server = tmpStyle->getStrokePaintServer();
799                     if ( SP_IS_GRADIENT(server) ) {
800                         SPGradient* target = 0;
801                         SPGradient* grad = SP_GRADIENT(server);
802                         if (grad->repr->attribute("osb:paint")) {
803                             target = grad;
804                         } else if ( grad->ref ) {
805                             SPGradient *tmp = grad->ref->getObject();
806                             if ( tmp && tmp->repr->attribute("osb:paint") ) {
807                                 target = tmp;
808                             }
809                         }
810                         if ( target ) {
811                             gchar const* id = target->repr->attribute("id");
812                             if ( id ) {
813                                 strokeId = id;
814                             }
815                         }
816                     }
817                 }
818                 break;
819             }
820         }
821         sp_style_unref(tmpStyle);
823         for ( std::vector<ColorItem*>::iterator it = docPalette->_colors.begin(); it != docPalette->_colors.end(); ++it ) {
824             ColorItem* item = *it;
825             bool isFill = (fillId == item->def.descr);
826             bool isStroke = (strokeId == item->def.descr);
827             item->setState( isFill, isStroke );
828         }
829     }
830 #endif // USE_DOCUMENT_PALETTE
833 void SwatchesPanel::_handleAction( int setId, int itemId )
835     switch( setId ) {
836         case 3:
837         {
838             if ( itemId >= 0 && itemId < static_cast<int>(possible.size()) ) {
839                 _currentIndex = itemId;
841                 if ( !_prefs_path.empty() ) {
842                     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
843                     prefs->setString(_prefs_path + "/palette", possible[_currentIndex]->_name);
844                 }
846                 _rebuild();
847             }
848         }
849         break;
850     }
853 void SwatchesPanel::_rebuild()
855     JustForNow* curr = possible[_currentIndex];
856     _holder->clear();
858     if ( curr->_prefWidth > 0 ) {
859         _holder->setColumnPref( curr->_prefWidth );
860     }
861     _holder->freezeUpdates();
862     // TODO restore once 'clear' works _holder->addPreview(_clear);
863     _holder->addPreview(_remove);
864     for ( std::vector<ColorItem*>::iterator it = curr->_colors.begin(); it != curr->_colors.end(); it++ ) {
865         _holder->addPreview(*it);
866     }
867     _holder->thawUpdates();
873 } //namespace Dialogs
874 } //namespace UI
875 } //namespace Inkscape
878 /*
879   Local Variables:
880   mode:c++
881   c-file-style:"stroustrup"
882   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
883   indent-tabs-mode:nil
884   fill-column:99
885   End:
886 */
887 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :