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 )
101 {
102 if ( gr ) {
103 GtkWidget *dialog = sp_gradient_vector_editor_new( gr );
104 gtk_widget_show( dialog );
105 }
106 }
108 static void editGradient( GtkMenuItem */*menuitem*/, gpointer /*user_data*/ )
109 {
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 }
126 }
128 static void addNewGradient( GtkMenuItem */*menuitem*/, gpointer /*user_data*/ )
129 {
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 }
159 }
160 #endif // USE_DOCUMENT_PALETTE
162 gboolean colorItemHandleButtonPress( GtkWidget* /*widget*/, GdkEventButton* event, gpointer user_data)
163 {
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;
244 }
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;
261 }
263 void skipWhitespace( char*& str ) {
264 while ( *str == ' ' || *str == '\t' ) {
265 str++;
266 }
267 }
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;
277 }
280 void _loadPaletteFile( gchar const *filename )
281 {
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 }
394 }
396 static void loadEmUp()
397 {
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 }
441 }
451 SwatchesPanel& SwatchesPanel::getInstance()
452 {
453 return *new SwatchesPanel();
454 }
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)
469 {
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 }
538 }
540 SwatchesPanel::~SwatchesPanel()
541 {
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 }
559 }
561 void SwatchesPanel::setOrientation( Gtk::AnchorType how )
562 {
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 }
570 }
572 void SwatchesPanel::setDesktop( SPDesktop* desktop )
573 {
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 }
604 }
606 void SwatchesPanel::_setDocument( SPDocument *document )
607 {
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 }
627 }
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)
635 {
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 }
680 }
681 #endif // USE_DOCUMENT_PALETTE
683 void SwatchesPanel::handleGradientsChange()
684 {
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
715 }
717 void SwatchesPanel::handleDefsModified()
718 {
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
748 }
750 void SwatchesPanel::_updateFromSelection()
751 {
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
831 }
833 void SwatchesPanel::_handleAction( int setId, int itemId )
834 {
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 }
851 }
853 void SwatchesPanel::_rebuild()
854 {
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();
868 }
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 :