Code

Refactoring SPColor to C++ and removing legacy CMYK implementation
[inkscape.git] / src / dialogs / swatches.cpp
index 757a15d25244e92fbadc180ad13f5c1468f415c6..3a41c1ec4a4629b096f828952bd921657a997711 100644 (file)
@@ -29,6 +29,8 @@
 #include "io/sys.h"
 #include "path-prefix.h"
 #include "swatches.h"
+#include "sp-item.h"
+#include "prefs-utils.h"
 
 #include "eek-preview.h"
 
@@ -41,6 +43,7 @@ SwatchesPanel* SwatchesPanel::instance = 0;
 
 ColorItem::ColorItem( unsigned int r, unsigned int g, unsigned int b, Glib::ustring& name ) :
     def( r, g, b, name ),
+    _isLive(false),
     _linkIsTone(false),
     _linkPercent(0),
     _linkGray(0),
@@ -72,6 +75,21 @@ ColorItem &ColorItem::operator=(ColorItem const &other)
     return *this;
 }
 
+
+class JustForNow
+{
+public:
+    JustForNow() : _prefWidth(0) {}
+
+    Glib::ustring _name;
+    int _prefWidth;
+    std::vector<ColorItem*> _colors;
+};
+
+static std::vector<JustForNow*> possible;
+
+
+
 typedef enum {
     APP_X_INKY_COLOR_ID = 0,
     APP_X_INKY_COLOR = 0,
@@ -80,19 +98,24 @@ typedef enum {
 } colorFlavorType;
 
 static const GtkTargetEntry sourceColorEntries[] = {
+#if ENABLE_MAGIC_COLORS
 //    {"application/x-inkscape-color-id", GTK_TARGET_SAME_APP, APP_X_INKY_COLOR_ID},
     {"application/x-inkscape-color", 0, APP_X_INKY_COLOR},
+#endif // ENABLE_MAGIC_COLORS
     {"application/x-color", 0, APP_X_COLOR},
     {"text/plain", 0, TEXT_DATA},
 };
 
-static void dragGetColorData( GtkWidget *widget,
-                              GdkDragContext *drag_context,
-                              GtkSelectionData *data,
-                              guint info,
-                              guint time,
-                              gpointer user_data)
+void ColorItem::_dragGetColorData( GtkWidget *widget,
+                                   GdkDragContext *drag_context,
+                                   GtkSelectionData *data,
+                                   guint info,
+                                   guint time,
+                                   gpointer user_data)
 {
+    (void)widget;
+    (void)drag_context;
+    (void)time;
     static GdkAtom typeXColor = gdk_atom_intern("application/x-color", FALSE);
     static GdkAtom typeText = gdk_atom_intern("text/plain", FALSE);
 
@@ -107,6 +130,51 @@ static void dragGetColorData( GtkWidget *widget,
                                 strlen((const char*)tmp) + 1);
         g_free(tmp);
         tmp = 0;
+    } else if ( info == APP_X_INKY_COLOR ) {
+        Glib::ustring paletteName;
+
+        // Find where this thing came from
+        bool found = false;
+        int index = 0;
+        for ( std::vector<JustForNow*>::iterator it = possible.begin(); it != possible.end() && !found; ++it ) {
+            JustForNow* curr = *it;
+            index = 0;
+            for ( std::vector<ColorItem*>::iterator zz = curr->_colors.begin(); zz != curr->_colors.end(); ++zz ) {
+                if ( item == *zz ) {
+                    found = true;
+                    paletteName = curr->_name;
+                    break;
+                } else {
+                    index++;
+                }
+            }
+        }
+
+//         if ( found ) {
+//             g_message("Found the color at entry %d in palette '%s'", index, paletteName.c_str() );
+//         } else {
+//             g_message("Unable to find the color");
+//         }
+        int itemCount = 4 + 2 + 1 + paletteName.length();
+
+        guint16* tmp = new guint16[itemCount];
+        tmp[0] = (item->def.getR() << 8) | item->def.getR();
+        tmp[1] = (item->def.getG() << 8) | item->def.getG();
+        tmp[2] = (item->def.getB() << 8) | item->def.getB();
+        tmp[3] = 0xffff;
+        tmp[4] = (item->_isLive || !item->_listeners.empty() || (item->_linkSrc != 0) ) ? 1 : 0;
+
+        tmp[5] = index;
+        tmp[6] = paletteName.length();
+        for ( unsigned int i = 0; i < paletteName.length(); i++ ) {
+            tmp[7 + i] = paletteName[i];
+        }
+        gtk_selection_data_set( data,
+                                typeXColor,
+                                16, // format
+                                reinterpret_cast<const guchar*>(tmp),
+                                itemCount * 2);
+        delete[] tmp;
     } else {
         guint16 tmp[4];
         tmp[0] = (item->def.getR() << 8) | item->def.getR();
@@ -123,6 +191,7 @@ static void dragGetColorData( GtkWidget *widget,
 
 static void dragBegin( GtkWidget *widget, GdkDragContext* dc, gpointer data )
 {
+    (void)widget;
     ColorItem* item = reinterpret_cast<ColorItem*>(data);
     if ( item )
     {
@@ -149,18 +218,31 @@ static void dragBegin( GtkWidget *widget, GdkDragContext* dc, gpointer data )
 //     return TRUE;
 // }
 
-static void bouncy( GtkWidget* widget, gpointer callback_data ) {
-    ColorItem* item = reinterpret_cast<ColorItem*>(callback_data);
-    if ( item ) {
-        item->buttonClicked(false);
+static gboolean onButtonPressed (GtkWidget *widget, GdkEventButton *event, gpointer userdata)
+{
+    (void)widget;
+    /* single click with the right mouse button? */
+    if(event->type == GDK_BUTTON_RELEASE)
+    {
+        ColorItem* item = reinterpret_cast<ColorItem*>(userdata);
+        if(item)
+        {
+            if (event->button == 1)
+            { 
+                               if(event->state & GDK_SHIFT_MASK)
+                                       item->buttonClicked(true);      /* the button was pressed with shift held down. set the stroke */
+                else item->buttonClicked(false);
+                return TRUE; /* we handled this */    
+            }
+            else if (event->button == 3)
+            {
+                item->buttonClicked(true);
+                return TRUE; /* we handled this */
+            }
+        }
     }
-}
 
-static void bouncy2( GtkWidget* widget, gint arg1, gpointer callback_data ) {
-    ColorItem* item = reinterpret_cast<ColorItem*>(callback_data);
-    if ( item ) {
-        item->buttonClicked(true);
-    }
+    return FALSE; /* we did not handle this */
 }
 
 static void dieDieDie( GtkObject *obj, gpointer user_data )
@@ -169,8 +251,10 @@ static void dieDieDie( GtkObject *obj, gpointer user_data )
 }
 
 static const GtkTargetEntry destColorTargets[] = {
+#if ENABLE_MAGIC_COLORS
 //    {"application/x-inkscape-color-id", GTK_TARGET_SAME_APP, APP_X_INKY_COLOR_ID},
     {"application/x-inkscape-color", 0, APP_X_INKY_COLOR},
+#endif // ENABLE_MAGIC_COLORS
     {"application/x-color", 0, APP_X_COLOR},
 };
 
@@ -184,12 +268,27 @@ void ColorItem::_dropDataIn( GtkWidget *widget,
                              guint event_time,
                              gpointer user_data)
 {
+    (void)widget;
+    (void)drag_context;
+    (void)x;
+    (void)y;
+    (void)event_time;
 //     g_message("    droppy droppy   %d", info);
      switch (info) {
          case APP_X_INKY_COLOR:
          {
-//              g_message("inky color");
-             // Fallthrough
+             if ( data->length >= 8 ) {
+                 // Careful about endian issues.
+                 guint16* dataVals = (guint16*)data->data;
+                 if ( user_data ) {
+                     ColorItem* item = reinterpret_cast<ColorItem*>(user_data);
+                     if ( item->def.isEditable() ) {
+                         // Shove on in the new value
+                         item->def.setRGB( 0x0ff & (dataVals[0] >> 8), 0x0ff & (dataVals[1] >> 8), 0x0ff & (dataVals[2] >> 8) );
+                     }
+                 }
+             }
+             break;
          }
          case APP_X_COLOR:
          {
@@ -223,6 +322,50 @@ void ColorItem::_dropDataIn( GtkWidget *widget,
 
 }
 
+static bool bruteForce( SPDocument* document, Inkscape::XML::Node* node, Glib::ustring const& match, int r, int g, int b )
+{
+    bool changed = false;
+
+    if ( node ) {
+        gchar const * val = node->attribute("inkscape:x-fill-tag");
+        if ( val  && (match == val) ) {
+            SPObject *obj = document->getObjectByRepr( node );
+
+            gchar c[64] = {0};
+            sp_svg_write_color( c, 64, SP_RGBA32_U_COMPOSE( r, g, b, 0xff ) );
+            SPCSSAttr *css = sp_repr_css_attr_new();
+            sp_repr_css_set_property( css, "fill", c );
+
+            sp_desktop_apply_css_recursive( (SPItem*)obj, css, true );
+            ((SPItem*)obj)->updateRepr();
+
+            changed = true;
+        }
+
+        val = node->attribute("inkscape:x-stroke-tag");
+        if ( val  && (match == val) ) {
+            SPObject *obj = document->getObjectByRepr( node );
+
+            gchar c[64] = {0};
+            sp_svg_write_color( c, 64, SP_RGBA32_U_COMPOSE( r, g, b, 0xff ) );
+            SPCSSAttr *css = sp_repr_css_attr_new();
+            sp_repr_css_set_property( css, "stroke", c );
+
+            sp_desktop_apply_css_recursive( (SPItem*)obj, css, true );
+            ((SPItem*)obj)->updateRepr();
+
+            changed = true;
+        }
+
+        Inkscape::XML::Node* first = node->firstChild();
+        changed |= bruteForce( document, first, match, r, g, b );
+
+        changed |= bruteForce( document, node->next(), match, r, g, b );
+    }
+
+    return changed;
+}
+
 void ColorItem::_colorDefChanged(void* data)
 {
     ColorItem* item = reinterpret_cast<ColorItem*>(data);
@@ -236,7 +379,9 @@ void ColorItem::_colorDefChanged(void* data)
                                        (item->def.getG() << 8) | item->def.getG(),
                                        (item->def.getB() << 8) | item->def.getB() );
 
-                eek_preview_set_linked( preview, (item->_linkSrc ? PREVIEW_LINK_IN:0) | (item->_listeners.empty() ? 0:PREVIEW_LINK_OUT) );
+                eek_preview_set_linked( preview, (LinkType)((item->_linkSrc ? PREVIEW_LINK_IN:0)
+                                                            | (item->_listeners.empty() ? 0:PREVIEW_LINK_OUT)
+                                                            | (item->_isLive ? PREVIEW_LINK_OTHER:0)) );
 
                 widget->queue_draw();
             }
@@ -259,11 +404,53 @@ void ColorItem::_colorDefChanged(void* data)
 
             (*it)->def.setRGB( r, g, b );
         }
+
+
+        // Look for objects using this color
+        {
+            SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+            if ( desktop ) {
+                SPDocument* document = sp_desktop_document( desktop );
+                Inkscape::XML::Node *rroot =  sp_document_repr_root( document );
+                if ( rroot ) {
+
+                    // Find where this thing came from
+                    Glib::ustring paletteName;
+                    bool found = false;
+                    int index = 0;
+                    for ( std::vector<JustForNow*>::iterator it2 = possible.begin(); it2 != possible.end() && !found; ++it2 ) {
+                        JustForNow* curr = *it2;
+                        index = 0;
+                        for ( std::vector<ColorItem*>::iterator zz = curr->_colors.begin(); zz != curr->_colors.end(); ++zz ) {
+                            if ( item == *zz ) {
+                                found = true;
+                                paletteName = curr->_name;
+                                break;
+                            } else {
+                                index++;
+                            }
+                        }
+                    }
+
+                    if ( !paletteName.empty() ) {
+                        gchar* str = g_strdup_printf("%d|", index);
+                        paletteName.insert( 0, str );
+                        g_free(str);
+                        str = 0;
+
+                        if ( bruteForce( document, rroot, paletteName, item->def.getR(), item->def.getG(), item->def.getB() ) ) {
+                            sp_document_done( document , SP_VERB_DIALOG_SWATCHES, 
+                                              _("Change color definition"));
+                        }
+                    }
+                }
+            }
+        }
     }
 }
 
 
-Gtk::Widget* ColorItem::getPreview(PreviewStyle style, ViewType view, Gtk::BuiltinIconSize size)
+Gtk::Widget* ColorItem::getPreview(PreviewStyle style, ViewType view, Inkscape::IconSize size)
 {
     Gtk::Widget* widget = 0;
     if ( style == PREVIEW_STYLE_BLURB ) {
@@ -272,7 +459,7 @@ Gtk::Widget* ColorItem::getPreview(PreviewStyle style, ViewType view, Gtk::Built
         widget = lbl;
     } else {
         Glib::ustring blank("          ");
-        if ( size == Gtk::ICON_SIZE_MENU ) {
+        if ( size == Inkscape::ICON_SIZE_MENU || size == Inkscape::ICON_SIZE_DECORATION ) {
             blank = " ";
         }
 
@@ -283,7 +470,9 @@ Gtk::Widget* ColorItem::getPreview(PreviewStyle style, ViewType view, Gtk::Built
         eek_preview_set_color( preview, (def.getR() << 8) | def.getR(), (def.getG() << 8) | def.getG(), (def.getB() << 8) | def.getB());
 
         eek_preview_set_details( preview, (::PreviewStyle)style, (::ViewType)view, (::GtkIconSize)size );
-        eek_preview_set_linked( preview, (_linkSrc ? PREVIEW_LINK_IN:0) | (_listeners.empty() ? 0:PREVIEW_LINK_OUT) );
+        eek_preview_set_linked( preview, (LinkType)((_linkSrc ? PREVIEW_LINK_IN:0)
+                                                    | (_listeners.empty() ? 0:PREVIEW_LINK_OUT)
+                                                    | (_isLive ? PREVIEW_LINK_OTHER:0)) );
 
         def.addCallback( _colorDefChanged, this );
 
@@ -312,15 +501,10 @@ Gtk::Widget* ColorItem::getPreview(PreviewStyle style, ViewType view, Gtk::Built
         sigc::signal<void> type_signal_something;
 */
         g_signal_connect( G_OBJECT(newBlot->gobj()),
-                          "clicked",
-                          G_CALLBACK(bouncy),
-                          this);
-
-        g_signal_connect( G_OBJECT(newBlot->gobj()),
-                          "alt-clicked",
-                          G_CALLBACK(bouncy2),
+                          "button-release-event",
+                          G_CALLBACK(onButtonPressed),
                           this);
-
+                          
         gtk_drag_source_set( GTK_WIDGET(newBlot->gobj()),
                              GDK_BUTTON1_MASK,
                              sourceColorEntries,
@@ -329,7 +513,7 @@ Gtk::Widget* ColorItem::getPreview(PreviewStyle style, ViewType view, Gtk::Built
 
         g_signal_connect( G_OBJECT(newBlot->gobj()),
                           "drag-data-get",
-                          G_CALLBACK(dragGetColorData),
+                          G_CALLBACK(ColorItem::_dragGetColorData),
                           this);
 
         g_signal_connect( G_OBJECT(newBlot->gobj()),
@@ -385,7 +569,8 @@ void ColorItem::buttonClicked(bool secondary)
         sp_desktop_set_style(desktop, css);
 
         sp_repr_css_attr_unref(css);
-        sp_document_done (SP_DT_DOCUMENT (desktop));
+        sp_document_done (sp_desktop_document (desktop), SP_VERB_DIALOG_SWATCHES, 
+                          secondary? _("Set stroke color from swatch") : _("Set fill color from swatch"));
     }
 }
 
@@ -425,27 +610,15 @@ bool parseNum( char*& str, int& val ) {
 }
 
 
-class JustForNow
-{
-public:
-    JustForNow() : _prefWidth(0) {}
-
-    Glib::ustring _name;
-    int _prefWidth;
-    std::vector<ColorItem*> _colors;
-};
-
-static std::vector<JustForNow*> possible;
-
 static bool getBlock( std::string& dst, guchar ch, std::string const str )
 {
     bool good = false;
-    size_t pos = str.find(ch);
+    std::string::size_type pos = str.find(ch);
     if ( pos != std::string::npos )
     {
-        size_t pos2 = str.find( '(', pos );
+        std::string::size_type pos2 = str.find( '(', pos );
         if ( pos2 != std::string::npos ) {
-            size_t endPos = str.find( ')', pos2 );
+            std::string::size_type endPos = str.find( ')', pos2 );
             if ( endPos != std::string::npos ) {
                 dst = str.substr( pos2 + 1, (endPos - pos2 - 1) );
                 good = true;
@@ -458,7 +631,7 @@ static bool getBlock( std::string& dst, guchar ch, std::string const str )
 static bool popVal( guint64& numVal, std::string& str )
 {
     bool good = false;
-    size_t endPos = str.find(',');
+    std::string::size_type endPos = str.find(',');
     if ( endPos == std::string::npos ) {
         endPos = str.length();
     }
@@ -488,11 +661,11 @@ void ColorItem::_wireMagicColors( void* p )
     {
         for ( std::vector<ColorItem*>::iterator it = onceMore->_colors.begin(); it != onceMore->_colors.end(); ++it )
         {
-            size_t pos = (*it)->def.descr.find("*{");
+            std::string::size_type pos = (*it)->def.descr.find("*{");
             if ( pos != std::string::npos )
             {
                 std::string subby = (*it)->def.descr.substr( pos + 2 );
-                size_t endPos = subby.find("}*");
+                std::string::size_type endPos = subby.find("}*");
                 if ( endPos != std::string::npos )
                 {
                     subby.erase( endPos );
@@ -501,10 +674,14 @@ void ColorItem::_wireMagicColors( void* p )
 
                     if ( subby.find('E') != std::string::npos )
                     {
-                        //g_message("                   HOT!");
                         (*it)->def.setEditable( true );
                     }
 
+                    if ( subby.find('L') != std::string::npos )
+                    {
+                        (*it)->_isLive = true;
+                    }
+
                     std::string part;
                     // Tint. index + 1 more val.
                     if ( getBlock( part, 'T', subby ) ) {
@@ -679,7 +856,9 @@ void _loadPaletteFile( gchar const *filename )
                 } while ( result && !hasErr );
                 if ( !hasErr ) {
                     possible.push_back(onceMore);
+#if ENABLE_MAGIC_COLORS
                     ColorItem::_wireMagicColors( onceMore );
+#endif // ENABLE_MAGIC_COLORS
                 } else {
                     delete onceMore;
                 }
@@ -699,6 +878,7 @@ static void loadEmUp()
         std::list<gchar *> sources;
         sources.push_back( profile_path("palettes") );
         sources.push_back( g_strdup(INKSCAPE_PALETTESDIR) );
+        sources.push_back( g_strdup(CREATE_PALETTESDIR) );
 
         // Use this loop to iterate through a list of possible document locations.
         while (!sources.empty()) {
@@ -715,13 +895,13 @@ static void loadEmUp()
                     gchar *filename = 0;
                     while ((filename = (gchar *)g_dir_read_name(directory)) != NULL) {
                         gchar* lower = g_ascii_strdown( filename, -1 );
-                        if ( g_str_has_suffix(lower, ".gpl") ) {
+//                        if ( g_str_has_suffix(lower, ".gpl") ) {
                             gchar* full = g_build_filename(dirname, filename, NULL);
                             if ( !Inkscape::IO::file_test( full, (GFileTest)(G_FILE_TEST_IS_DIR ) ) ) {
                                 _loadPaletteFile(full);
                             }
                             g_free(full);
-                        }
+//                      }
                         g_free(lower);
                     }
                     g_dir_close(directory);
@@ -757,15 +937,33 @@ SwatchesPanel& SwatchesPanel::getInstance()
 /**
  * Constructor
  */
-SwatchesPanel::SwatchesPanel() :
-    Inkscape::UI::Widget::Panel ("dialogs.swatches"),
+SwatchesPanel::SwatchesPanel(gchar const* prefsPath) :
+    Inkscape::UI::Widget::Panel( Glib::ustring(), prefsPath, true ),
     _holder(0)
 {
+    Gtk::RadioMenuItem* hotItem = 0;
     _holder = new PreviewHolder();
     loadEmUp();
 
     if ( !possible.empty() ) {
-        JustForNow* first = possible.front();
+        JustForNow* first = 0;
+        gchar const* targetName = 0;
+        if ( _prefs_path ) {
+            targetName = prefs_get_string_attribute( _prefs_path, "palette" );
+            if ( targetName ) {
+                for ( std::vector<JustForNow*>::iterator iter = possible.begin(); iter != possible.end(); ++iter ) {
+                    if ( (*iter)->_name == targetName ) {
+                        first = *iter;
+                        break;
+                    }
+                }
+            }
+        }
+
+        if ( !first ) {
+            first = possible.front();
+        }
+
         if ( first->_prefWidth > 0 ) {
             _holder->setColumnPref( first->_prefWidth );
         }
@@ -780,6 +978,9 @@ SwatchesPanel::SwatchesPanel() :
         for ( std::vector<JustForNow*>::iterator it = possible.begin(); it != possible.end(); it++ ) {
             JustForNow* curr = *it;
             Gtk::RadioMenuItem* single = manage(new Gtk::RadioMenuItem(groupOne, curr->_name));
+            if ( curr == first ) {
+                hotItem = single;
+            }
             _regItem( single, 3, i );
             i++;
         }
@@ -793,6 +994,9 @@ SwatchesPanel::SwatchesPanel() :
     show_all_children();
 
     restorePanelPrefs();
+    if ( hotItem ) {
+        hotItem->set_active();
+    }
 }
 
 SwatchesPanel::~SwatchesPanel()
@@ -818,6 +1022,11 @@ void SwatchesPanel::_handleAction( int setId, int itemId )
             if ( itemId >= 0 && itemId < static_cast<int>(possible.size()) ) {
                 _holder->clear();
                 JustForNow* curr = possible[itemId];
+
+                if ( _prefs_path ) {
+                    prefs_set_string_attribute( _prefs_path, "palette", curr->_name.c_str() );
+                }
+
                 if ( curr->_prefWidth > 0 ) {
                     _holder->setColumnPref( curr->_prefWidth );
                 }