Code

merging gsoc 2009 color management work by Felipe Sanches (a.k.a. JucaBlues)
[inkscape.git] / src / ui / dialog / swatches.cpp
index fdf320c06cf5c99880c1cc306a1b79a6f4e841d9..1f708e3de3534c1c84f8387ecc391d7da91c0f2b 100644 (file)
 #include "sp-gradient.h"
 #include "sp-gradient-vector.h"
 #include "swatches.h"
+#include "style.h"
 #include "widgets/gradient-vector.h"
 #include "widgets/eek-preview.h"
 #include "display/nr-plain-stuff.h"
+#include "sp-gradient-reference.h"
+
+//#define USE_DOCUMENT_PALETTE 1
 
 namespace Inkscape {
 namespace UI {
 namespace Dialogs {
 
+#define VBLOCK 16
 
 void _loadPaletteFile( gchar const *filename );
 
@@ -70,6 +75,11 @@ public:
                                     ::PreviewSize size,
                                     guint ratio);
     void buttonClicked(bool secondary = false);
+
+    void setState( bool fill, bool stroke );
+    bool isFill() { return _isFill; }
+    bool isStroke() { return _isStroke; }
+
     ege::PaintDef def;
     void* ptr;
 
@@ -98,6 +108,8 @@ private:
     Gtk::Tooltips tips;
     std::vector<Gtk::Widget*> _previews;
 
+    bool _isFill;
+    bool _isStroke;
     bool _isLive;
     bool _linkIsTone;
     int _linkPercent;
@@ -105,12 +117,14 @@ private:
     ColorItem* _linkSrc;
     std::vector<ColorItem*> _listeners;
 };
-       
+
 
 
 ColorItem::ColorItem(ege::PaintDef::ColorType type) :
     def(type),
     ptr(0),
+    _isFill(false),
+    _isStroke(false),
     _isLive(false),
     _linkIsTone(false),
     _linkPercent(0),
@@ -122,6 +136,8 @@ ColorItem::ColorItem(ege::PaintDef::ColorType type) :
 ColorItem::ColorItem( unsigned int r, unsigned int g, unsigned int b, Glib::ustring& name ) :
     def( r, g, b, name ),
     ptr(0),
+    _isFill(false),
+    _isStroke(false),
     _isLive(false),
     _linkIsTone(false),
     _linkPercent(0),
@@ -154,6 +170,31 @@ ColorItem &ColorItem::operator=(ColorItem const &other)
     return *this;
 }
 
+void ColorItem::setState( bool fill, bool stroke )
+{
+    if ( (_isFill != fill) || (_isStroke != stroke) ) {
+        _isFill = fill;
+        _isStroke = stroke;
+
+        for ( std::vector<Gtk::Widget*>::iterator it = _previews.begin(); it != _previews.end(); ++it ) {
+            Gtk::Widget* widget = *it;
+            if ( IS_EEK_PREVIEW(widget->gobj()) ) {
+                EekPreview * preview = EEK_PREVIEW(widget->gobj());
+
+                int val = eek_preview_get_linked( preview );
+                val &= ~(PREVIEW_FILL | PREVIEW_STROKE);
+                if ( _isFill ) {
+                    val |= PREVIEW_FILL;
+                }
+                if ( _isStroke ) {
+                    val |= PREVIEW_STROKE;
+                }
+                eek_preview_set_linked( preview, static_cast<LinkType>(val) );
+            }
+        }
+    }
+}
+
 
 class JustForNow
 {
@@ -172,6 +213,7 @@ static std::vector<std::string> mimeStrings;
 static std::map<std::string, guint> mimeToInt;
 
 static std::map<ColorItem*, guchar*> previewMap;
+static std::map<ColorItem*, SPGradient*> gradMap; // very temporary workaround.
 
 void ColorItem::_dragGetColorData( GtkWidget */*widget*/,
                                    GdkDragContext */*drag_context*/,
@@ -209,6 +251,8 @@ static void dragBegin( GtkWidget */*widget*/, GdkDragContext* dc, gpointer data
         using Inkscape::IO::Resource::get_path;
         using Inkscape::IO::Resource::ICONS;
         using Inkscape::IO::Resource::SYSTEM;
+        int width = 32;
+        int height = 24;
 
         if (item->def.getType() != ege::PaintDef::RGB){
             GError *error = NULL;
@@ -219,18 +263,35 @@ static void dragBegin( GtkWidget */*widget*/, GdkDragContext* dc, gpointer data
                                                  &bytesRead,
                                                  &bytesWritten,
                                                  &error);
-            GdkPixbuf* pixbuf = gdk_pixbuf_new_from_file_at_scale(localFilename, 32, 24, FALSE, &error);
+            GdkPixbuf* pixbuf = gdk_pixbuf_new_from_file_at_scale(localFilename, width, height, FALSE, &error);
             g_free(localFilename);
             gtk_drag_set_icon_pixbuf( dc, pixbuf, 0, 0 );
-            return;
-        }
+        } else {
+            GdkPixbuf* pixbuf = 0;
+            if ( gradMap.find(item) == gradMap.end() ){
+                Glib::RefPtr<Gdk::Pixbuf> thumb = Gdk::Pixbuf::create( Gdk::COLORSPACE_RGB, false, 8, width, height );
+                guint32 fillWith = (0xff000000 & (item->def.getR() << 24))
+                    | (0x00ff0000 & (item->def.getG() << 16))
+                    | (0x0000ff00 & (item->def.getB() <<  8));
+                thumb->fill( fillWith );
+                pixbuf = thumb->gobj();
+            } else {
+                SPGradient* grad = gradMap[item];
+
+                guchar* px = g_new( guchar, 3 * height * width );
+                nr_render_checkerboard_rgb( px, width, height, 3 * width, 0, 0 );
 
-        Glib::RefPtr<Gdk::Pixbuf> thumb = Gdk::Pixbuf::create( Gdk::COLORSPACE_RGB, false, 8, 32, 24 );
-        guint32 fillWith = (0xff000000 & (item->def.getR() << 24))
-                         | (0x00ff0000 & (item->def.getG() << 16))
-                         | (0x0000ff00 & (item->def.getB() <<  8));
-        thumb->fill( fillWith );
-        gtk_drag_set_icon_pixbuf( dc, thumb->gobj(), 0, 0 );
+                sp_gradient_render_vector_block_rgb( grad,
+                                                     px, width, height, 3 * width,
+                                                     0, width, TRUE );
+
+                pixbuf = gdk_pixbuf_new_from_data( px, GDK_COLORSPACE_RGB, FALSE, 8,
+                                                   width, height, width * 3,
+                                                   0, // add delete function
+                                                   0 );
+            }
+            gtk_drag_set_icon_pixbuf( dc, pixbuf, 0, 0 );
+        }
     }
 
 }
@@ -305,6 +366,7 @@ static void redirSecondaryClick( GtkMenuItem *menuitem, gpointer /*user_data*/ )
     }
 }
 
+#if USE_DOCUMENT_PALETTE
 static void editGradientImpl( SPGradient* gr )
 {
     if ( gr ) {
@@ -365,6 +427,7 @@ static void addNewGradient( GtkMenuItem */*menuitem*/, gpointer /*user_data*/ )
         }
     }
 }
+#endif // USE_DOCUMENT_PALETTE
 
 static gboolean handleButtonPress( GtkWidget* /*widget*/, GdkEventButton* event, gpointer user_data)
 {
@@ -392,6 +455,7 @@ static gboolean handleButtonPress( GtkWidget* /*widget*/, GdkEventButton* event,
                               user_data);
             gtk_menu_shell_append(GTK_MENU_SHELL(popupMenu), child);
 
+#if USE_DOCUMENT_PALETTE
             child = gtk_separator_menu_item_new();
             gtk_menu_shell_append(GTK_MENU_SHELL(popupMenu), child);
             popupExtras.push_back(child);
@@ -425,6 +489,7 @@ static gboolean handleButtonPress( GtkWidget* /*widget*/, GdkEventButton* event,
             gtk_menu_shell_append(GTK_MENU_SHELL(popupMenu), child);
             //popupExtras.push_back(child);
             gtk_widget_set_sensitive( child, FALSE );
+#endif // USE_DOCUMENT_PALETTE
 
             gtk_widget_show_all(popupMenu);
         }
@@ -618,11 +683,10 @@ Gtk::Widget* ColorItem::getPreview(PreviewStyle style, ViewType view, ::PreviewS
             guchar* px = previewMap[this];
             int width = 128;
             int height = 16;
-            GdkPixbuf* pixbuf = gdk_pixbuf_new_from_data( px, GDK_COLORSPACE_RGB, FALSE, 8, 
+            GdkPixbuf* pixbuf = gdk_pixbuf_new_from_data( px, GDK_COLORSPACE_RGB, FALSE, 8,
                                                           width, height, width * 3,
                                                           0, // add delete function
-                                                          0
-                );
+                                                          0 );
             eek_preview_set_pixbuf( preview, pixbuf );
         }
         if ( def.getType() != ege::PaintDef::RGB ) {
@@ -794,11 +858,19 @@ void ColorItem::buttonClicked(bool secondary)
                 break;
             }
             case ege::PaintDef::RGB: {
-                gchar c[64];
-                guint32 rgba = (def.getR() << 24) | (def.getG() << 16) | (def.getB() << 8) | 0xff;
-                sp_svg_write_color(c, sizeof(c), rgba);
-
-                sp_repr_css_set_property( css, attrName, c );
+                Glib::ustring colorspec;
+                if ( gradMap.find(this) == gradMap.end() ){
+                    gchar c[64];
+                    guint32 rgba = (def.getR() << 24) | (def.getG() << 16) | (def.getB() << 8) | 0xff;
+                    sp_svg_write_color(c, sizeof(c), rgba);
+                    colorspec = c;
+                } else {
+                    SPGradient* grad = gradMap[this];
+                    colorspec = "url(#";
+                    colorspec += grad->id;
+                    colorspec += ")";
+                }
+                sp_repr_css_set_property( css, attrName, colorspec.c_str() );
                 descr = secondary? _("Set stroke color from swatch") : _("Set fill color from swatch");
                 break;
             }
@@ -1182,6 +1254,7 @@ SwatchesPanel::SwatchesPanel(gchar const* prefsPath) :
     _clear->ptr = this;
     _remove = new ColorItem( ege::PaintDef::NONE );
     _remove->ptr = this;
+#if USE_DOCUMENT_PALETTE
     {
         JustForNow *docPalette = new JustForNow();
 
@@ -1190,6 +1263,7 @@ SwatchesPanel::SwatchesPanel(gchar const* prefsPath) :
 
         _ptr = docPalette;
     }
+#endif // USE_DOCUMENT_PALETTE
     loadEmUp();
     if ( !possible.empty() ) {
         JustForNow* first = 0;
@@ -1248,6 +1322,9 @@ SwatchesPanel::~SwatchesPanel()
 {
     _documentConnection.disconnect();
     _resourceConnection.disconnect();
+    _selChanged.disconnect();
+    _setModified.disconnect();
+    _subselChanged.disconnect();
 
     if ( _clear ) {
         delete _clear;
@@ -1276,15 +1353,25 @@ void SwatchesPanel::setDesktop( SPDesktop* desktop )
     if ( desktop != _currentDesktop ) {
         if ( _currentDesktop ) {
             _documentConnection.disconnect();
+            _selChanged.disconnect();
+            _setModified.disconnect();
+            _subselChanged.disconnect();
         }
 
         _currentDesktop = desktop;
 
         if ( desktop ) {
-            sigc::bound_mem_functor1<void, Inkscape::UI::Dialogs::SwatchesPanel, SPDocument*> first = sigc::mem_fun(*this, &SwatchesPanel::_setDocument);
+            _currentDesktop->selection->connectChanged(
+                sigc::hide(sigc::mem_fun(*this, &SwatchesPanel::_updateFromSelection)));
 
-            sigc::slot<void, SPDocument*> base2 = first;
+            _currentDesktop->selection->connectModified(
+                sigc::hide(sigc::hide(sigc::mem_fun(*this, &SwatchesPanel::_updateFromSelection))));
+
+            _currentDesktop->connectToolSubselectionChanged(
+                sigc::hide(sigc::mem_fun(*this, &SwatchesPanel::_updateFromSelection)));
 
+            sigc::bound_mem_functor1<void, Inkscape::UI::Dialogs::SwatchesPanel, SPDocument*> first = sigc::mem_fun(*this, &SwatchesPanel::_setDocument);
+            sigc::slot<void, SPDocument*> base2 = first;
             sigc::slot<void,SPDesktop*, SPDocument*> slot2 = sigc::hide<0>( base2 );
             _documentConnection = desktop->connectDocumentReplaced( slot2 );
 
@@ -1324,6 +1411,7 @@ void SwatchesPanel::handleGradientsChange()
         }
     }
 
+#if USE_DOCUMENT_PALETTE
     if ( _ptr ) {
         JustForNow *docPalette = reinterpret_cast<JustForNow *>(_ptr);
         // TODO delete pointed to objects
@@ -1352,6 +1440,7 @@ void SwatchesPanel::handleGradientsChange()
                         ColorItem* item = new ColorItem( r, g, b, name );
                         item->ptr = this;
                         docPalette->_colors.push_back(item);
+                        gradMap[item] = grad;
                     } else {
                         // Treat as gradient
                         Glib::ustring name( grad->id );
@@ -1362,17 +1451,17 @@ void SwatchesPanel::handleGradientsChange()
                         item->ptr = this;
                         docPalette->_colors.push_back(item);
 
-#define VBLOCK 16
                         gint width = 128;
                         gint height = VBLOCK;
                         guchar* px = g_new( guchar, 3 * height * width );
                         nr_render_checkerboard_rgb( px, width, VBLOCK, 3 * width, 0, 0 );
-                        
+
                         sp_gradient_render_vector_block_rgb( grad,
                                                              px, width, height, 3 * width,
                                                              0, width, TRUE );
 
                         previewMap[item] = px;
+                        gradMap[item] = grad;
                     }
                 }
             }
@@ -1382,6 +1471,90 @@ void SwatchesPanel::handleGradientsChange()
             _rebuild();
         }
     }
+#endif // USE_DOCUMENT_PALETTE
+}
+
+void SwatchesPanel::_updateFromSelection()
+{
+#if USE_DOCUMENT_PALETTE
+    if ( _ptr ) {
+        JustForNow *docPalette = reinterpret_cast<JustForNow *>(_ptr);
+
+        Glib::ustring fillId;
+        Glib::ustring strokeId;
+
+        SPStyle *tmpStyle = sp_style_new( sp_desktop_document(_currentDesktop) );
+        int result = sp_desktop_query_style( _currentDesktop, tmpStyle, QUERY_STYLE_PROPERTY_FILL );
+        switch (result) {
+            case QUERY_STYLE_SINGLE:
+            case QUERY_STYLE_MULTIPLE_AVERAGED:
+            case QUERY_STYLE_MULTIPLE_SAME:
+            {
+                if (tmpStyle->fill.set && tmpStyle->fill.isPaintserver()) {
+                    SPPaintServer* server = tmpStyle->getFillPaintServer();
+                    if ( SP_IS_GRADIENT(server) ) {
+                        SPGradient* target = 0;
+                        SPGradient* grad = SP_GRADIENT(server);
+                        if (grad->repr->attribute("osb:paint")) {
+                            target = grad;
+                        } else if ( grad->ref ) {
+                            SPGradient *tmp = grad->ref->getObject();
+                            if ( tmp && tmp->repr->attribute("osb:paint") ) {
+                                target = tmp;
+                            }
+                        }
+                        if ( target ) {
+                            gchar const* id = target->repr->attribute("id");
+                            if ( id ) {
+                                fillId = id;
+                            }
+                        }
+                    }
+                }
+                break;
+            }
+        }
+
+        result = sp_desktop_query_style( _currentDesktop, tmpStyle, QUERY_STYLE_PROPERTY_STROKE );
+        switch (result) {
+            case QUERY_STYLE_SINGLE:
+            case QUERY_STYLE_MULTIPLE_AVERAGED:
+            case QUERY_STYLE_MULTIPLE_SAME:
+            {
+                if (tmpStyle->stroke.set && tmpStyle->stroke.isPaintserver()) {
+                    SPPaintServer* server = tmpStyle->getStrokePaintServer();
+                    if ( SP_IS_GRADIENT(server) ) {
+                        SPGradient* target = 0;
+                        SPGradient* grad = SP_GRADIENT(server);
+                        if (grad->repr->attribute("osb:paint")) {
+                            target = grad;
+                        } else if ( grad->ref ) {
+                            SPGradient *tmp = grad->ref->getObject();
+                            if ( tmp && tmp->repr->attribute("osb:paint") ) {
+                                target = tmp;
+                            }
+                        }
+                        if ( target ) {
+                            gchar const* id = target->repr->attribute("id");
+                            if ( id ) {
+                                strokeId = id;
+                            }
+                        }
+                    }
+                }
+                break;
+            }
+        }
+        sp_style_unref(tmpStyle);
+
+        for ( std::vector<ColorItem*>::iterator it = docPalette->_colors.begin(); it != docPalette->_colors.end(); ++it ) {
+            ColorItem* item = *it;
+            bool isFill = (fillId == item->def.descr);
+            bool isStroke = (strokeId == item->def.descr);
+            item->setState( isFill, isStroke );
+        }
+    }
+#endif // USE_DOCUMENT_PALETTE
 }
 
 void SwatchesPanel::_handleAction( int setId, int itemId )