Code

Refactoring SPColor to C++ and removing legacy CMYK implementation
[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
17 #ifdef HAVE_CONFIG_H
18 # include "config.h"
19 #endif
20 #include <string.h>
21 #include <stdlib.h>
22 #include <gtk/gtk.h>
23 #include <glibmm/i18n.h>
24 #include "../dialogs/dialog-events.h"
25 #include "../prefs-utils.h"
26 #include "sp-color-notebook.h"
27 #include "spw-utilities.h"
29 #include "sp-color-scales.h"
30 #include "sp-color-wheel-selector.h"
32 struct SPColorNotebookTracker {
33         const gchar* name;
34         const gchar* className;
35         GType type;
36         guint submode;
37         gboolean enabledFull;
38         gboolean enabledBrief;
39         SPColorNotebook *backPointer;
40 };
42 static void sp_color_notebook_class_init (SPColorNotebookClass *klass);
43 static void sp_color_notebook_init (SPColorNotebook *slider);
44 static void sp_color_notebook_destroy (GtkObject *object);
46 static void sp_color_notebook_show_all (GtkWidget *widget);
47 static void sp_color_notebook_hide_all (GtkWidget *widget);
49 static SPColorSelectorClass *parent_class;
51 #define XPAD 4
52 #define YPAD 1
54 GtkType
55 sp_color_notebook_get_type (void)
56 {
57         static GtkType type = 0;
58         if (!type) {
59                 GtkTypeInfo info = {
60                         "SPColorNotebook",
61                         sizeof (SPColorNotebook),
62                         sizeof (SPColorNotebookClass),
63                         (GtkClassInitFunc) sp_color_notebook_class_init,
64                         (GtkObjectInitFunc) sp_color_notebook_init,
65                         NULL, NULL, NULL
66                 };
67                 type = gtk_type_unique (SP_TYPE_COLOR_SELECTOR, &info);
68         }
69         return type;
70 }
72 static void
73 sp_color_notebook_class_init (SPColorNotebookClass *klass)
74 {
75         GtkObjectClass *object_class;
76         GtkWidgetClass *widget_class;
77         SPColorSelectorClass *selector_class;
79         object_class = (GtkObjectClass *) klass;
80         widget_class = (GtkWidgetClass *) klass;
81         selector_class = SP_COLOR_SELECTOR_CLASS (klass);
83         parent_class = SP_COLOR_SELECTOR_CLASS (g_type_class_peek_parent (klass));
85         object_class->destroy = sp_color_notebook_destroy;
87         widget_class->show_all = sp_color_notebook_show_all;
88         widget_class->hide_all = sp_color_notebook_hide_all;
89 }
91 static void
92 sp_color_notebook_switch_page(GtkNotebook *notebook,
93                                                           GtkNotebookPage *page,
94                                                           guint page_num,
95                                                           SPColorNotebook *colorbook)
96 {
97         if ( colorbook )
98         {
99         ColorNotebook* nb = (ColorNotebook*)(SP_COLOR_SELECTOR(colorbook)->base);
100         nb->switchPage( notebook, page, page_num );
102         // remember the page we seitched to
103         prefs_set_int_attribute ("colorselector", "page", page_num);
105         }
108 void ColorNotebook::switchPage(GtkNotebook*,
109                               GtkNotebookPage*,
110                               guint page_num)
112     SPColorSelector* csel;
113     GtkWidget* widget;
115     if ( gtk_notebook_get_current_page (GTK_NOTEBOOK (_book)) >= 0 )
116     {
117         csel = getCurrentSelector();
118         csel->base->getColorAlpha(_color, &_alpha);
119     }
120     widget = gtk_notebook_get_nth_page (GTK_NOTEBOOK (_book), page_num);
121     if ( widget && SP_IS_COLOR_SELECTOR (widget) )
122     {
123         csel = SP_COLOR_SELECTOR (widget);
124         csel->base->setColorAlpha( _color, _alpha );
126         // Temporary workaround to undo a spurious GRABBED
127         _released();
128     }
131 static gint sp_color_notebook_menu_handler( GtkWidget *widget, GdkEvent *event )
133     if (event->type == GDK_BUTTON_PRESS)
134     {
135         SPColorSelector* csel = SP_COLOR_SELECTOR(widget);
136         ((ColorNotebook*)(csel->base))->menuHandler( event );
138         /* Tell calling code that we have handled this event; the buck
139          * stops here. */
140         return TRUE;
141     }
143     /* Tell calling code that we have not handled this event; pass it on. */
144     return FALSE;
147 gint ColorNotebook::menuHandler( GdkEvent* event )
149     GdkEventButton *bevent = (GdkEventButton *) event;
150     gtk_menu_popup (GTK_MENU( _popup ), NULL, NULL, NULL, NULL,
151                     bevent->button, bevent->time);
152     return TRUE;
155 static void sp_color_notebook_menuitem_response (GtkMenuItem *menuitem, gpointer user_data)
157         gboolean active = FALSE;
159         active = gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menuitem));
160         SPColorNotebookTracker *entry = reinterpret_cast< SPColorNotebookTracker* > (user_data);
161         if ( entry )
162         {
163                 if ( active )
164                 {
165                         ((ColorNotebook*)(SP_COLOR_SELECTOR(entry->backPointer)->base))->addPage(entry->type, entry->submode);
166                 }
167                 else
168                 {
169                         ((ColorNotebook*)(SP_COLOR_SELECTOR(entry->backPointer)->base))->removePage(entry->type, entry->submode);
170                 }
171         }
174 static void
175 sp_color_notebook_init (SPColorNotebook *colorbook)
177     SP_COLOR_SELECTOR(colorbook)->base = new ColorNotebook( SP_COLOR_SELECTOR(colorbook) );
179     if ( SP_COLOR_SELECTOR(colorbook)->base )
180     {
181         SP_COLOR_SELECTOR(colorbook)->base->init();
182     }
185 void ColorNotebook::init()
187         GtkWidget* table = 0;
188         guint row = 0;
189         guint i = 0;
190         guint j = 0;
191         GType *selector_types = 0;
192         guint   selector_type_count = 0;
194         GtkTooltips *tt = gtk_tooltips_new ();
196         /* tempory hardcoding to get types loaded */
197         SP_TYPE_COLOR_SCALES;
198         SP_TYPE_COLOR_WHEEL_SELECTOR;
200         /* REJON: Comment out the next line to not use the normal GTK Color
201            wheel. */
203 //        SP_TYPE_COLOR_GTKSELECTOR;
205         _updating = FALSE;
206         _updatingrgba = FALSE;
207         _btn = 0;
208         _popup = 0;
209         _trackerList = g_ptr_array_new ();
211         _book = gtk_notebook_new ();
212         gtk_widget_show (_book);
214         selector_types = g_type_children (SP_TYPE_COLOR_SELECTOR, &selector_type_count);
216         for ( i = 0; i < selector_type_count; i++ )
217         {
218                 if (!g_type_is_a (selector_types[i], SP_TYPE_COLOR_NOTEBOOK))
219                 {
220                         guint howmany = 1;
221                         gpointer klass = gtk_type_class (selector_types[i]);
222                         if ( klass && SP_IS_COLOR_SELECTOR_CLASS (klass) )
223                         {
224                                 SPColorSelectorClass *ck = SP_COLOR_SELECTOR_CLASS (klass);
225                                 howmany = MAX (1, ck->submode_count);
226                                 for ( j = 0; j < howmany; j++ )
227                                 {
228                                         SPColorNotebookTracker *entry = reinterpret_cast< SPColorNotebookTracker* > (malloc(sizeof(SPColorNotebookTracker)));
229                                         if ( entry )
230                                         {
231                                                 memset( entry, 0, sizeof(SPColorNotebookTracker) );
232                                                 entry->name = ck->name[j];
233                                                 entry->type = selector_types[i];
234                                                 entry->submode = j;
235                                                 entry->enabledFull = TRUE;
236                                                 entry->enabledBrief = TRUE;
237                                                 entry->backPointer = SP_COLOR_NOTEBOOK(_csel);
239                                                 g_ptr_array_add (_trackerList, entry);
240                                         }
241                                 }
242                         }
243                 }
244         }
246         for ( i = 0; i < _trackerList->len; i++ )
247         {
248                 SPColorNotebookTracker *entry =
249           reinterpret_cast< SPColorNotebookTracker* > (g_ptr_array_index (_trackerList, i));
250                 if ( entry )
251                 {
252                         addPage(entry->type, entry->submode);
253                 }
254         }
256         table = gtk_table_new (2, 3, FALSE);
257         gtk_widget_show (table);
259         gtk_box_pack_start (GTK_BOX (_csel), table, TRUE, TRUE, 0);
261         gtk_table_attach (GTK_TABLE (table), _book, 0, 2, row, row + 1,
262                       static_cast<GtkAttachOptions>(GTK_EXPAND|GTK_FILL),
263                       static_cast<GtkAttachOptions>(GTK_EXPAND|GTK_FILL),
264                       XPAD, YPAD);
266         // restore the last active page
267         gtk_notebook_set_current_page (GTK_NOTEBOOK (_book), prefs_get_int_attribute ("colorselector", "page", 0));
269         {
270                 gboolean found = FALSE;
272                 _popup = gtk_menu_new();
273                 GtkMenu *menu = GTK_MENU (_popup);
275                 for ( i = 0; i < _trackerList->len; i++ )
276                 {
277                         SPColorNotebookTracker *entry = reinterpret_cast< SPColorNotebookTracker* > (g_ptr_array_index (_trackerList, i));
278                         if ( entry )
279                         {
280                                 GtkWidget *item = gtk_check_menu_item_new_with_label (_(entry->name));
281                                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), entry->enabledFull);
282                                 gtk_widget_show (item);
283                                 gtk_menu_append (menu, item);
285                                 g_signal_connect (G_OBJECT (item), "activate",
286                                                                   G_CALLBACK (sp_color_notebook_menuitem_response),
287                                                                   reinterpret_cast< gpointer > (entry) );
288                                 found = TRUE;
289                         }
290                 }
292                 GtkWidget *arrow = gtk_arrow_new(GTK_ARROW_RIGHT, GTK_SHADOW_NONE);
293                 gtk_widget_show (arrow);
295                 _btn = gtk_button_new ();
296                 gtk_widget_show (_btn);
297                 gtk_container_add (GTK_CONTAINER (_btn), arrow);
299                 GtkWidget *align = gtk_alignment_new (1.0, 0.0, 0.0, 0.0);
300                 gtk_widget_show (align);
301                 gtk_container_add (GTK_CONTAINER (align), _btn);
303                 // uncomment to reenable the "show/hide modes" menu,
304                 // but first fix it so it remembers its settings in prefs and does not take that much space (entire vertical column!)
305                 //gtk_table_attach (GTK_TABLE (table), align, 2, 3, row, row + 1, GTK_FILL, GTK_FILL, XPAD, YPAD);
307                 gtk_signal_connect_object(GTK_OBJECT(_btn), "event", GTK_SIGNAL_FUNC (sp_color_notebook_menu_handler), GTK_OBJECT(_csel));
308                 if ( !found )
309                 {
310                         gtk_widget_set_sensitive (_btn, FALSE);
311                 }
312         }
314         row++;
316         /* Create RGBA entry and color preview */
317         GtkWidget *rgbabox = gtk_hbox_new (FALSE, 0);
319         _rgbal = gtk_label_new_with_mnemonic (_("RGBA_:"));
320         gtk_misc_set_alignment (GTK_MISC (_rgbal), 1.0, 0.5);
321         gtk_box_pack_start(GTK_BOX(rgbabox), _rgbal, TRUE, TRUE, 2);
323         _rgbae = gtk_entry_new ();
324         sp_dialog_defocus_on_enter (_rgbae);
325         gtk_entry_set_max_length (GTK_ENTRY (_rgbae), 8);
326         gtk_entry_set_width_chars (GTK_ENTRY (_rgbae), 8);
327         gtk_tooltips_set_tip (tt, _rgbae, _("Hexadecimal RGBA value of the color"), NULL);
328         gtk_box_pack_start(GTK_BOX(rgbabox), _rgbae, FALSE, FALSE, 0);
329         gtk_label_set_mnemonic_widget (GTK_LABEL(_rgbal), _rgbae);
331         sp_set_font_size_smaller (rgbabox);
332         gtk_widget_show_all (rgbabox);
333         gtk_table_attach (GTK_TABLE (table), rgbabox, 1, 2, row, row + 1, GTK_FILL, GTK_SHRINK, XPAD, YPAD);
335 #ifdef SPCS_PREVIEW
336         _p = sp_color_preview_new (0xffffffff);
337         gtk_widget_show (_p);
338         gtk_table_attach (GTK_TABLE (table), _p, 2, 3, row, row + 1, GTK_FILL, GTK_FILL, XPAD, YPAD);
339 #endif
341         _switchId = g_signal_connect(GTK_OBJECT (_book), "switch-page",
342                                                                 GTK_SIGNAL_FUNC (sp_color_notebook_switch_page), SP_COLOR_NOTEBOOK(_csel));
344         _entryId = gtk_signal_connect (GTK_OBJECT (_rgbae), "changed", GTK_SIGNAL_FUNC (ColorNotebook::_rgbaEntryChangedHook), _csel);
347 static void
348 sp_color_notebook_destroy (GtkObject *object)
350         if (((GtkObjectClass *) (parent_class))->destroy)
351                 (* ((GtkObjectClass *) (parent_class))->destroy) (object);
354 ColorNotebook::~ColorNotebook()
356         if ( _trackerList )
357         {
358                 g_ptr_array_free (_trackerList, TRUE);
359                 _trackerList = 0;
360         }
362         if ( _switchId )
363         {
364                 if ( _book )
365                 {
366                         g_signal_handler_disconnect (_book, _switchId);
367                         _switchId = 0;
368                 }
369         }
372 static void
373 sp_color_notebook_show_all (GtkWidget *widget)
375         gtk_widget_show (widget);
378 static void
379 sp_color_notebook_hide_all (GtkWidget *widget)
381         gtk_widget_hide (widget);
384 GtkWidget *
385 sp_color_notebook_new (void)
387         SPColorNotebook *colorbook;
389         colorbook = (SPColorNotebook*)gtk_type_new (SP_TYPE_COLOR_NOTEBOOK);
391         return GTK_WIDGET (colorbook);
394 ColorNotebook::ColorNotebook( SPColorSelector* csel )
395     : ColorSelector( csel )
399 SPColorSelector* ColorNotebook::getCurrentSelector()
401     SPColorSelector* csel = NULL;
402     gint current_page = gtk_notebook_get_current_page (GTK_NOTEBOOK (_book));
404     if ( current_page >= 0 )
405     {
406         GtkWidget* widget = gtk_notebook_get_nth_page (GTK_NOTEBOOK (_book), current_page);
407         if ( SP_IS_COLOR_SELECTOR (widget) )
408         {
409             csel = SP_COLOR_SELECTOR (widget);
410         }
411     }
413     return csel;
416 void ColorNotebook::_colorChanged(const SPColor& color, gfloat alpha)
418         SPColorSelector* cselPage = 0;
420         g_return_if_fail (_csel != NULL);
421         g_return_if_fail (SP_IS_COLOR_NOTEBOOK (_csel));
422         g_return_if_fail( ( 0.0 <= alpha ) && ( alpha <= 1.0 ) );
424         cselPage = getCurrentSelector();
425         if ( cselPage )
426         {
427                 cselPage->base->setColorAlpha( color, alpha );
428         }
430     _updateRgbaEntry( color, alpha );
433 void ColorNotebook::_rgbaEntryChangedHook(GtkEntry *entry, SPColorNotebook *colorbook)
435     ((ColorNotebook*)(SP_COLOR_SELECTOR(colorbook)->base))->_rgbaEntryChanged( entry );
438 void ColorNotebook::_rgbaEntryChanged(GtkEntry* entry)
440     if (_updating) return;
441     if (_updatingrgba) return;
443     const gchar *t = gtk_entry_get_text( entry );
445     if (t) {
446         gchar *e = 0;
447         guint rgba = strtoul (t, &e, 16);
448         if ( e != t ) {
449             ptrdiff_t len=e-t;
450             if ( len < 8 ) {
451                 rgba = rgba << ( 4 * ( 8 - len ) );
452             }
453             _updatingrgba = TRUE;
454             SPColor color( rgba );
455             setColorAlpha( color, SP_RGBA32_A_F(rgba), true );
456             _updatingrgba = FALSE;
457         }
458     }
461 void ColorNotebook::_updateRgbaEntry( const SPColor& color, gfloat alpha )
463     g_return_if_fail( ( 0.0 <= alpha ) && ( alpha <= 1.0 ) );
465     if ( !_updatingrgba )
466     {
467         gchar s[32];
468         guint32 rgba;
470         /* Update RGBA entry */
471         rgba = color.toRGBA32( alpha );
473         g_snprintf (s, 32, "%08x", rgba);
474         const gchar* oldText = gtk_entry_get_text( GTK_ENTRY( _rgbae ) );
475         if ( strcmp( oldText, s ) != 0 )
476         {
477             g_signal_handler_block( _rgbae, _entryId );
478             gtk_entry_set_text( GTK_ENTRY(_rgbae), s );
479             g_signal_handler_unblock( _rgbae, _entryId );
480         }
481     }
484 void ColorNotebook::_entryGrabbed (SPColorSelector *, SPColorNotebook *colorbook)
486     ColorNotebook* nb = (ColorNotebook*)(SP_COLOR_SELECTOR(colorbook)->base);
487     nb->_grabbed();
490 void ColorNotebook::_entryDragged (SPColorSelector *csel, SPColorNotebook *colorbook)
492         gboolean oldState;
493     ColorNotebook* nb = (ColorNotebook*)(SP_COLOR_SELECTOR(colorbook)->base);
495         oldState = nb->_dragging;
497         nb->_dragging = TRUE;
498         nb->_entryModified( csel, colorbook );
500         nb->_dragging = oldState;
503 void ColorNotebook::_entryReleased (SPColorSelector *, SPColorNotebook *colorbook)
505     ColorNotebook* nb = (ColorNotebook*)(SP_COLOR_SELECTOR(colorbook)->base);
506     nb->_released();
509 void ColorNotebook::_entryChanged (SPColorSelector *csel, SPColorNotebook *colorbook)
511         gboolean oldState;
512     ColorNotebook* nb = (ColorNotebook*)(SP_COLOR_SELECTOR(colorbook)->base);
514         oldState = nb->_dragging;
516         nb->_dragging = FALSE;
517         nb->_entryModified( csel, colorbook );
519         nb->_dragging = oldState;
522 void ColorNotebook::_entryModified (SPColorSelector *csel, SPColorNotebook *colorbook)
524         g_return_if_fail (colorbook != NULL);
525         g_return_if_fail (SP_IS_COLOR_NOTEBOOK (colorbook));
526         g_return_if_fail (csel != NULL);
527         g_return_if_fail (SP_IS_COLOR_SELECTOR (csel));
529     ColorNotebook* nb = (ColorNotebook*)(SP_COLOR_SELECTOR(colorbook)->base);
530     SPColor color;
531     gfloat alpha = 1.0;
533     csel->base->getColorAlpha( color, &alpha );
534     nb->_updateRgbaEntry( color, alpha );
535     nb->_updateInternals( color, alpha, nb->_dragging );
538 GtkWidget* ColorNotebook::addPage(GType page_type, guint submode)
540         GtkWidget *page;
542         page = sp_color_selector_new( page_type );
543         if ( page )
544         {
545                 GtkWidget* tab_label = 0;
546                 SPColorSelector* csel;
548                 csel = SP_COLOR_SELECTOR (page);
549                 if ( submode > 0 )
550                 {
551                         csel->base->setSubmode( submode );
552                 }
553                 gtk_widget_show (page);
554         int index = csel->base ? csel->base->getSubmode() : 0;
555         const gchar* str = _(SP_COLOR_SELECTOR_GET_CLASS (csel)->name[index]);
556 //         g_message( "Hitting up for tab for '%s'", str );
557                 tab_label = gtk_label_new(_(str));
558                 gtk_notebook_append_page( GTK_NOTEBOOK (_book), page, tab_label );
559                 gtk_signal_connect (GTK_OBJECT (page), "grabbed", GTK_SIGNAL_FUNC (_entryGrabbed), _csel);
560                 gtk_signal_connect (GTK_OBJECT (page), "dragged", GTK_SIGNAL_FUNC (_entryDragged), _csel);
561                 gtk_signal_connect (GTK_OBJECT (page), "released", GTK_SIGNAL_FUNC (_entryReleased), _csel);
562                 gtk_signal_connect (GTK_OBJECT (page), "changed", GTK_SIGNAL_FUNC (_entryChanged), _csel);
563         }
565         return page;
568 GtkWidget* ColorNotebook::getPage(GType page_type, guint submode)
570         gint count = 0;
571         gint i = 0;
572         GtkWidget* page = 0;
574 //        count = gtk_notebook_get_n_pages (_book);
575         count = 200;
576         for ( i = 0; i < count && !page; i++ )
577         {
578                 page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (_book), i);
579                 if ( page )
580                 {
581                         SPColorSelector* csel;
582                         guint pagemode;
583                         csel = SP_COLOR_SELECTOR (page);
584                         pagemode = csel->base->getSubmode();
585                         if ( G_TYPE_FROM_INSTANCE (page) == page_type
586                                  && pagemode == submode )
587                         {
588                                 // found it.
589                                 break;
590                         }
591                         else
592                         {
593                                 page = 0;
594                         }
595                 }
596                 else
597                 {
598                         break;
599                 }
600         }
601         return page;
604 void ColorNotebook::removePage( GType page_type, guint submode )
606         GtkWidget *page = 0;
608         page = getPage(page_type, submode);
609         if ( page )
610         {
611                 gint where = gtk_notebook_page_num (GTK_NOTEBOOK (_book), page);
612                 if ( where >= 0 )
613                 {
614                         if ( gtk_notebook_get_current_page (GTK_NOTEBOOK (_book)) == where )
615                         {
616 //                 getColorAlpha(_color, &_alpha);
617                         }
618                         gtk_notebook_remove_page (GTK_NOTEBOOK (_book), where);
619                 }
620         }