Code

Initial support for icc color selection including CMYK
[inkscape.git] / src / widgets / sp-color-notebook.cpp
1 #define __SP_COLOR_NOTEBOOK_C__
3 /*
4  * A block of 3 color sliders plus spinbuttons
5  *
6  * Author:
7  *       Lauris Kaplinski <lauris@kaplinski.com>
8  *   bulia byak <buliabyak@users.sf.net>
9  *
10  * Copyright (C) 2001-2002 Lauris Kaplinski
11  *
12  * This code is in public domain
13  */
15 #undef SPCS_PREVIEW
16 #define noDUMP_CHANGE_INFO
18 #ifdef HAVE_CONFIG_H
19 # include "config.h"
20 #endif
21 #include <string.h>
22 #include <stdlib.h>
23 #include <gtk/gtk.h>
24 #include <glibmm/i18n.h>
25 #include "../dialogs/dialog-events.h"
26 #include "../prefs-utils.h"
27 #include "sp-color-notebook.h"
28 #include "spw-utilities.h"
30 #include "sp-color-scales.h"
31 #include "sp-color-wheel-selector.h"
32 #include "sp-color-icc-selector.h"
34 struct SPColorNotebookTracker {
35         const gchar* name;
36         const gchar* className;
37         GType type;
38         guint submode;
39         gboolean enabledFull;
40         gboolean enabledBrief;
41         SPColorNotebook *backPointer;
42 };
44 static void sp_color_notebook_class_init (SPColorNotebookClass *klass);
45 static void sp_color_notebook_init (SPColorNotebook *colorbook);
46 static void sp_color_notebook_destroy (GtkObject *object);
48 static void sp_color_notebook_show_all (GtkWidget *widget);
49 static void sp_color_notebook_hide_all (GtkWidget *widget);
51 static SPColorSelectorClass *parent_class;
53 #define XPAD 4
54 #define YPAD 1
56 GtkType
57 sp_color_notebook_get_type (void)
58 {
59         static GtkType type = 0;
60         if (!type) {
61                 GtkTypeInfo info = {
62                         "SPColorNotebook",
63                         sizeof (SPColorNotebook),
64                         sizeof (SPColorNotebookClass),
65                         (GtkClassInitFunc) sp_color_notebook_class_init,
66                         (GtkObjectInitFunc) sp_color_notebook_init,
67                         NULL, NULL, NULL
68                 };
69                 type = gtk_type_unique (SP_TYPE_COLOR_SELECTOR, &info);
70         }
71         return type;
72 }
74 static void
75 sp_color_notebook_class_init (SPColorNotebookClass *klass)
76 {
77         GtkObjectClass *object_class;
78         GtkWidgetClass *widget_class;
79         SPColorSelectorClass *selector_class;
81         object_class = (GtkObjectClass *) klass;
82         widget_class = (GtkWidgetClass *) klass;
83         selector_class = SP_COLOR_SELECTOR_CLASS (klass);
85         parent_class = SP_COLOR_SELECTOR_CLASS (g_type_class_peek_parent (klass));
87         object_class->destroy = sp_color_notebook_destroy;
89         widget_class->show_all = sp_color_notebook_show_all;
90         widget_class->hide_all = sp_color_notebook_hide_all;
91 }
93 static void
94 sp_color_notebook_switch_page(GtkNotebook *notebook,
95                                                           GtkNotebookPage *page,
96                                                           guint page_num,
97                                                           SPColorNotebook *colorbook)
98 {
99         if ( colorbook )
100         {
101         ColorNotebook* nb = (ColorNotebook*)(SP_COLOR_SELECTOR(colorbook)->base);
102         nb->switchPage( notebook, page, page_num );
104         // remember the page we seitched to
105         prefs_set_int_attribute ("colorselector", "page", page_num);
107         }
110 void ColorNotebook::switchPage(GtkNotebook*,
111                               GtkNotebookPage*,
112                               guint page_num)
114     SPColorSelector* csel;
115     GtkWidget* widget;
117     if ( gtk_notebook_get_current_page (GTK_NOTEBOOK (_book)) >= 0 )
118     {
119         csel = getCurrentSelector();
120         csel->base->getColorAlpha(_color, &_alpha);
121     }
122     widget = gtk_notebook_get_nth_page (GTK_NOTEBOOK (_book), page_num);
123     if ( widget && SP_IS_COLOR_SELECTOR (widget) )
124     {
125         csel = SP_COLOR_SELECTOR (widget);
126         csel->base->setColorAlpha( _color, _alpha );
128         // Temporary workaround to undo a spurious GRABBED
129         _released();
130     }
133 static gint sp_color_notebook_menu_handler( GtkWidget *widget, GdkEvent *event )
135     if (event->type == GDK_BUTTON_PRESS)
136     {
137         SPColorSelector* csel = SP_COLOR_SELECTOR(widget);
138         ((ColorNotebook*)(csel->base))->menuHandler( event );
140         /* Tell calling code that we have handled this event; the buck
141          * stops here. */
142         return TRUE;
143     }
145     /* Tell calling code that we have not handled this event; pass it on. */
146     return FALSE;
149 gint ColorNotebook::menuHandler( GdkEvent* event )
151     GdkEventButton *bevent = (GdkEventButton *) event;
152     gtk_menu_popup (GTK_MENU( _popup ), NULL, NULL, NULL, NULL,
153                     bevent->button, bevent->time);
154     return TRUE;
157 static void sp_color_notebook_menuitem_response (GtkMenuItem *menuitem, gpointer user_data)
159         gboolean active = FALSE;
161         active = gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menuitem));
162         SPColorNotebookTracker *entry = reinterpret_cast< SPColorNotebookTracker* > (user_data);
163         if ( entry )
164         {
165                 if ( active )
166                 {
167                         ((ColorNotebook*)(SP_COLOR_SELECTOR(entry->backPointer)->base))->addPage(entry->type, entry->submode);
168                 }
169                 else
170                 {
171                         ((ColorNotebook*)(SP_COLOR_SELECTOR(entry->backPointer)->base))->removePage(entry->type, entry->submode);
172                 }
173         }
176 static void
177 sp_color_notebook_init (SPColorNotebook *colorbook)
179     SP_COLOR_SELECTOR(colorbook)->base = new ColorNotebook( SP_COLOR_SELECTOR(colorbook) );
181     if ( SP_COLOR_SELECTOR(colorbook)->base )
182     {
183         SP_COLOR_SELECTOR(colorbook)->base->init();
184     }
187 void ColorNotebook::init()
189         GtkWidget* table = 0;
190         guint row = 0;
191         guint i = 0;
192         guint j = 0;
193         GType *selector_types = 0;
194         guint   selector_type_count = 0;
196         GtkTooltips *tt = gtk_tooltips_new ();
198         /* tempory hardcoding to get types loaded */
199         SP_TYPE_COLOR_SCALES;
200         SP_TYPE_COLOR_WHEEL_SELECTOR;
201 #if ENABLE_LCMS
202         SP_TYPE_COLOR_ICC_SELECTOR;
203 #endif // ENABLE_LCMS
205         /* REJON: Comment out the next line to not use the normal GTK Color
206            wheel. */
208 //        SP_TYPE_COLOR_GTKSELECTOR;
210         _updating = FALSE;
211         _updatingrgba = FALSE;
212         _btn = 0;
213         _popup = 0;
214         _trackerList = g_ptr_array_new ();
216         _book = gtk_notebook_new ();
217         gtk_widget_show (_book);
219         selector_types = g_type_children (SP_TYPE_COLOR_SELECTOR, &selector_type_count);
221         for ( i = 0; i < selector_type_count; i++ )
222         {
223                 if (!g_type_is_a (selector_types[i], SP_TYPE_COLOR_NOTEBOOK))
224                 {
225                         guint howmany = 1;
226                         gpointer klass = gtk_type_class (selector_types[i]);
227                         if ( klass && SP_IS_COLOR_SELECTOR_CLASS (klass) )
228                         {
229                                 SPColorSelectorClass *ck = SP_COLOR_SELECTOR_CLASS (klass);
230                                 howmany = MAX (1, ck->submode_count);
231                                 for ( j = 0; j < howmany; j++ )
232                                 {
233                                         SPColorNotebookTracker *entry = reinterpret_cast< SPColorNotebookTracker* > (malloc(sizeof(SPColorNotebookTracker)));
234                                         if ( entry )
235                                         {
236                                                 memset( entry, 0, sizeof(SPColorNotebookTracker) );
237                                                 entry->name = ck->name[j];
238                                                 entry->type = selector_types[i];
239                                                 entry->submode = j;
240                                                 entry->enabledFull = TRUE;
241                                                 entry->enabledBrief = TRUE;
242                                                 entry->backPointer = SP_COLOR_NOTEBOOK(_csel);
244                                                 g_ptr_array_add (_trackerList, entry);
245                                         }
246                                 }
247                         }
248                 }
249         }
251         for ( i = 0; i < _trackerList->len; i++ )
252         {
253                 SPColorNotebookTracker *entry =
254           reinterpret_cast< SPColorNotebookTracker* > (g_ptr_array_index (_trackerList, i));
255                 if ( entry )
256                 {
257                         addPage(entry->type, entry->submode);
258                 }
259         }
261         table = gtk_table_new (2, 3, FALSE);
262         gtk_widget_show (table);
264         gtk_box_pack_start (GTK_BOX (_csel), table, TRUE, TRUE, 0);
266         gtk_table_attach (GTK_TABLE (table), _book, 0, 2, row, row + 1,
267                       static_cast<GtkAttachOptions>(GTK_EXPAND|GTK_FILL),
268                       static_cast<GtkAttachOptions>(GTK_EXPAND|GTK_FILL),
269                       XPAD, YPAD);
271         // restore the last active page
272         gtk_notebook_set_current_page (GTK_NOTEBOOK (_book), prefs_get_int_attribute ("colorselector", "page", 0));
274         {
275                 gboolean found = FALSE;
277                 _popup = gtk_menu_new();
278                 GtkMenu *menu = GTK_MENU (_popup);
280                 for ( i = 0; i < _trackerList->len; i++ )
281                 {
282                         SPColorNotebookTracker *entry = reinterpret_cast< SPColorNotebookTracker* > (g_ptr_array_index (_trackerList, i));
283                         if ( entry )
284                         {
285                                 GtkWidget *item = gtk_check_menu_item_new_with_label (_(entry->name));
286                                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), entry->enabledFull);
287                                 gtk_widget_show (item);
288                                 gtk_menu_append (menu, item);
290                                 g_signal_connect (G_OBJECT (item), "activate",
291                                                                   G_CALLBACK (sp_color_notebook_menuitem_response),
292                                                                   reinterpret_cast< gpointer > (entry) );
293                                 found = TRUE;
294                         }
295                 }
297                 GtkWidget *arrow = gtk_arrow_new(GTK_ARROW_RIGHT, GTK_SHADOW_NONE);
298                 gtk_widget_show (arrow);
300                 _btn = gtk_button_new ();
301                 gtk_widget_show (_btn);
302                 gtk_container_add (GTK_CONTAINER (_btn), arrow);
304                 GtkWidget *align = gtk_alignment_new (1.0, 0.0, 0.0, 0.0);
305                 gtk_widget_show (align);
306                 gtk_container_add (GTK_CONTAINER (align), _btn);
308                 // uncomment to reenable the "show/hide modes" menu,
309                 // but first fix it so it remembers its settings in prefs and does not take that much space (entire vertical column!)
310                 //gtk_table_attach (GTK_TABLE (table), align, 2, 3, row, row + 1, GTK_FILL, GTK_FILL, XPAD, YPAD);
312                 gtk_signal_connect_object(GTK_OBJECT(_btn), "event", GTK_SIGNAL_FUNC (sp_color_notebook_menu_handler), GTK_OBJECT(_csel));
313                 if ( !found )
314                 {
315                         gtk_widget_set_sensitive (_btn, FALSE);
316                 }
317         }
319         row++;
321         /* Create RGBA entry and color preview */
322         GtkWidget *rgbabox = gtk_hbox_new (FALSE, 0);
324         _rgbal = gtk_label_new_with_mnemonic (_("RGBA_:"));
325         gtk_misc_set_alignment (GTK_MISC (_rgbal), 1.0, 0.5);
326         gtk_box_pack_start(GTK_BOX(rgbabox), _rgbal, TRUE, TRUE, 2);
328         _rgbae = gtk_entry_new ();
329         sp_dialog_defocus_on_enter (_rgbae);
330         gtk_entry_set_max_length (GTK_ENTRY (_rgbae), 8);
331         gtk_entry_set_width_chars (GTK_ENTRY (_rgbae), 8);
332         gtk_tooltips_set_tip (tt, _rgbae, _("Hexadecimal RGBA value of the color"), NULL);
333         gtk_box_pack_start(GTK_BOX(rgbabox), _rgbae, FALSE, FALSE, 0);
334         gtk_label_set_mnemonic_widget (GTK_LABEL(_rgbal), _rgbae);
336         sp_set_font_size_smaller (rgbabox);
337         gtk_widget_show_all (rgbabox);
338         gtk_table_attach (GTK_TABLE (table), rgbabox, 1, 2, row, row + 1, GTK_FILL, GTK_SHRINK, XPAD, YPAD);
340 #ifdef SPCS_PREVIEW
341         _p = sp_color_preview_new (0xffffffff);
342         gtk_widget_show (_p);
343         gtk_table_attach (GTK_TABLE (table), _p, 2, 3, row, row + 1, GTK_FILL, GTK_FILL, XPAD, YPAD);
344 #endif
346         _switchId = g_signal_connect(GTK_OBJECT (_book), "switch-page",
347                                                                 GTK_SIGNAL_FUNC (sp_color_notebook_switch_page), SP_COLOR_NOTEBOOK(_csel));
349         _entryId = gtk_signal_connect (GTK_OBJECT (_rgbae), "changed", GTK_SIGNAL_FUNC (ColorNotebook::_rgbaEntryChangedHook), _csel);
352 static void
353 sp_color_notebook_destroy (GtkObject *object)
355         if (((GtkObjectClass *) (parent_class))->destroy)
356                 (* ((GtkObjectClass *) (parent_class))->destroy) (object);
359 ColorNotebook::~ColorNotebook()
361         if ( _trackerList )
362         {
363                 g_ptr_array_free (_trackerList, TRUE);
364                 _trackerList = 0;
365         }
367         if ( _switchId )
368         {
369                 if ( _book )
370                 {
371                         g_signal_handler_disconnect (_book, _switchId);
372                         _switchId = 0;
373                 }
374         }
377 static void
378 sp_color_notebook_show_all (GtkWidget *widget)
380         gtk_widget_show (widget);
383 static void
384 sp_color_notebook_hide_all (GtkWidget *widget)
386         gtk_widget_hide (widget);
389 GtkWidget *
390 sp_color_notebook_new (void)
392         SPColorNotebook *colorbook;
394         colorbook = (SPColorNotebook*)gtk_type_new (SP_TYPE_COLOR_NOTEBOOK);
396         return GTK_WIDGET (colorbook);
399 ColorNotebook::ColorNotebook( SPColorSelector* csel )
400     : ColorSelector( csel )
404 SPColorSelector* ColorNotebook::getCurrentSelector()
406     SPColorSelector* csel = NULL;
407     gint current_page = gtk_notebook_get_current_page (GTK_NOTEBOOK (_book));
409     if ( current_page >= 0 )
410     {
411         GtkWidget* widget = gtk_notebook_get_nth_page (GTK_NOTEBOOK (_book), current_page);
412         if ( SP_IS_COLOR_SELECTOR (widget) )
413         {
414             csel = SP_COLOR_SELECTOR (widget);
415         }
416     }
418     return csel;
421 void ColorNotebook::_colorChanged(const SPColor& color, gfloat alpha)
423         SPColorSelector* cselPage = 0;
425         g_return_if_fail (_csel != NULL);
426         g_return_if_fail (SP_IS_COLOR_NOTEBOOK (_csel));
427         g_return_if_fail( ( 0.0 <= alpha ) && ( alpha <= 1.0 ) );
429         cselPage = getCurrentSelector();
430         if ( cselPage )
431         {
432                 cselPage->base->setColorAlpha( color, alpha );
433         }
435     _updateRgbaEntry( color, alpha );
438 void ColorNotebook::_rgbaEntryChangedHook(GtkEntry *entry, SPColorNotebook *colorbook)
440     ((ColorNotebook*)(SP_COLOR_SELECTOR(colorbook)->base))->_rgbaEntryChanged( entry );
443 void ColorNotebook::_rgbaEntryChanged(GtkEntry* entry)
445     if (_updating) return;
446     if (_updatingrgba) return;
448     const gchar *t = gtk_entry_get_text( entry );
450     if (t) {
451         gchar *e = 0;
452         guint rgba = strtoul (t, &e, 16);
453         if ( e != t ) {
454             ptrdiff_t len=e-t;
455             if ( len < 8 ) {
456                 rgba = rgba << ( 4 * ( 8 - len ) );
457             }
458             _updatingrgba = TRUE;
459             SPColor color( rgba );
460             setColorAlpha( color, SP_RGBA32_A_F(rgba), true );
461             _updatingrgba = FALSE;
462         }
463     }
466 void ColorNotebook::_updateRgbaEntry( const SPColor& color, gfloat alpha )
468     g_return_if_fail( ( 0.0 <= alpha ) && ( alpha <= 1.0 ) );
470     if ( !_updatingrgba )
471     {
472         gchar s[32];
473         guint32 rgba;
475         /* Update RGBA entry */
476         rgba = color.toRGBA32( alpha );
478         g_snprintf (s, 32, "%08x", rgba);
479         const gchar* oldText = gtk_entry_get_text( GTK_ENTRY( _rgbae ) );
480         if ( strcmp( oldText, s ) != 0 )
481         {
482             g_signal_handler_block( _rgbae, _entryId );
483             gtk_entry_set_text( GTK_ENTRY(_rgbae), s );
484             g_signal_handler_unblock( _rgbae, _entryId );
485         }
486     }
489 void ColorNotebook::_entryGrabbed (SPColorSelector *, SPColorNotebook *colorbook)
491     ColorNotebook* nb = (ColorNotebook*)(SP_COLOR_SELECTOR(colorbook)->base);
492     nb->_grabbed();
495 void ColorNotebook::_entryDragged (SPColorSelector *csel, SPColorNotebook *colorbook)
497         gboolean oldState;
498     ColorNotebook* nb = (ColorNotebook*)(SP_COLOR_SELECTOR(colorbook)->base);
500         oldState = nb->_dragging;
502         nb->_dragging = TRUE;
503         nb->_entryModified( csel, colorbook );
505         nb->_dragging = oldState;
508 void ColorNotebook::_entryReleased (SPColorSelector *, SPColorNotebook *colorbook)
510     ColorNotebook* nb = (ColorNotebook*)(SP_COLOR_SELECTOR(colorbook)->base);
511     nb->_released();
514 void ColorNotebook::_entryChanged (SPColorSelector *csel, SPColorNotebook *colorbook)
516         gboolean oldState;
517     ColorNotebook* nb = (ColorNotebook*)(SP_COLOR_SELECTOR(colorbook)->base);
519         oldState = nb->_dragging;
521         nb->_dragging = FALSE;
522         nb->_entryModified( csel, colorbook );
524         nb->_dragging = oldState;
527 void ColorNotebook::_entryModified (SPColorSelector *csel, SPColorNotebook *colorbook)
529         g_return_if_fail (colorbook != NULL);
530         g_return_if_fail (SP_IS_COLOR_NOTEBOOK (colorbook));
531         g_return_if_fail (csel != NULL);
532         g_return_if_fail (SP_IS_COLOR_SELECTOR (csel));
534     ColorNotebook* nb = (ColorNotebook*)(SP_COLOR_SELECTOR(colorbook)->base);
535     SPColor color;
536     gfloat alpha = 1.0;
538     csel->base->getColorAlpha( color, &alpha );
539     nb->_updateRgbaEntry( color, alpha );
540     nb->_updateInternals( color, alpha, nb->_dragging );
543 GtkWidget* ColorNotebook::addPage(GType page_type, guint submode)
545         GtkWidget *page;
547         page = sp_color_selector_new( page_type );
548         if ( page )
549         {
550                 GtkWidget* tab_label = 0;
551                 SPColorSelector* csel;
553                 csel = SP_COLOR_SELECTOR (page);
554                 if ( submode > 0 )
555                 {
556                         csel->base->setSubmode( submode );
557                 }
558                 gtk_widget_show (page);
559         int index = csel->base ? csel->base->getSubmode() : 0;
560         const gchar* str = _(SP_COLOR_SELECTOR_GET_CLASS (csel)->name[index]);
561 //         g_message( "Hitting up for tab for '%s'", str );
562                 tab_label = gtk_label_new(_(str));
563                 gtk_notebook_append_page( GTK_NOTEBOOK (_book), page, tab_label );
564                 gtk_signal_connect (GTK_OBJECT (page), "grabbed", GTK_SIGNAL_FUNC (_entryGrabbed), _csel);
565                 gtk_signal_connect (GTK_OBJECT (page), "dragged", GTK_SIGNAL_FUNC (_entryDragged), _csel);
566                 gtk_signal_connect (GTK_OBJECT (page), "released", GTK_SIGNAL_FUNC (_entryReleased), _csel);
567                 gtk_signal_connect (GTK_OBJECT (page), "changed", GTK_SIGNAL_FUNC (_entryChanged), _csel);
568         }
570         return page;
573 GtkWidget* ColorNotebook::getPage(GType page_type, guint submode)
575         gint count = 0;
576         gint i = 0;
577         GtkWidget* page = 0;
579 //        count = gtk_notebook_get_n_pages (_book);
580         count = 200;
581         for ( i = 0; i < count && !page; i++ )
582         {
583                 page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (_book), i);
584                 if ( page )
585                 {
586                         SPColorSelector* csel;
587                         guint pagemode;
588                         csel = SP_COLOR_SELECTOR (page);
589                         pagemode = csel->base->getSubmode();
590                         if ( G_TYPE_FROM_INSTANCE (page) == page_type
591                                  && pagemode == submode )
592                         {
593                                 // found it.
594                                 break;
595                         }
596                         else
597                         {
598                                 page = 0;
599                         }
600                 }
601                 else
602                 {
603                         break;
604                 }
605         }
606         return page;
609 void ColorNotebook::removePage( GType page_type, guint submode )
611         GtkWidget *page = 0;
613         page = getPage(page_type, submode);
614         if ( page )
615         {
616                 gint where = gtk_notebook_page_num (GTK_NOTEBOOK (_book), page);
617                 if ( where >= 0 )
618                 {
619                         if ( gtk_notebook_get_current_page (GTK_NOTEBOOK (_book)) == where )
620                         {
621 //                 getColorAlpha(_color, &_alpha);
622                         }
623                         gtk_notebook_remove_page (GTK_NOTEBOOK (_book), where);
624                 }
625         }