Code

Made text entry handle standard web-hex values. Fixes bug #168121.
[inkscape.git] / src / widgets / sp-color-notebook.cpp
1 #define __SP_COLOR_NOTEBOOK_C__
3 /*
4  * A notebook with RGB, CMYK, CMS, HSL, and Wheel pages
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
22 #include <cstring>
23 #include <string>
24 #include <cstdlib>
25 #include <gtk/gtk.h>
26 #include <glibmm/i18n.h>
28 #include "../dialogs/dialog-events.h"
29 #include "../preferences.h"
30 #include "sp-color-notebook.h"
31 #include "spw-utilities.h"
32 #include "sp-color-scales.h"
33 #include "sp-color-icc-selector.h"
34 #include "sp-color-wheel-selector.h"
36 struct SPColorNotebookTracker {
37         const gchar* name;
38         const gchar* className;
39         GType type;
40         guint submode;
41         gboolean enabledFull;
42         gboolean enabledBrief;
43         SPColorNotebook *backPointer;
44 };
46 static void sp_color_notebook_class_init (SPColorNotebookClass *klass);
47 static void sp_color_notebook_init (SPColorNotebook *colorbook);
48 static void sp_color_notebook_destroy (GtkObject *object);
50 static void sp_color_notebook_show_all (GtkWidget *widget);
51 static void sp_color_notebook_hide_all (GtkWidget *widget);
53 static SPColorSelectorClass *parent_class;
55 #define XPAD 4
56 #define YPAD 1
58 GType sp_color_notebook_get_type(void)
59 {
60     static GtkType type = 0;
61     if (!type) {
62         GTypeInfo info = {
63             sizeof(SPColorNotebookClass),
64             0, // base_init
65             0, // base_finalize
66             (GClassInitFunc)sp_color_notebook_class_init,
67             0, // class_finalize
68             0, // class_data
69             sizeof(SPColorNotebook),
70             0, // n_preallocs
71             (GInstanceInitFunc)sp_color_notebook_init,
72             0 // value_table
73         };
74         type = g_type_register_static(SP_TYPE_COLOR_SELECTOR, "SPColorNotebook", &info, static_cast<GTypeFlags>(0));
75     }
76     return type;
77 }
79 static void
80 sp_color_notebook_class_init (SPColorNotebookClass *klass)
81 {
82         GtkObjectClass *object_class;
83         GtkWidgetClass *widget_class;
84         SPColorSelectorClass *selector_class;
86         object_class = (GtkObjectClass *) klass;
87         widget_class = (GtkWidgetClass *) klass;
88         selector_class = SP_COLOR_SELECTOR_CLASS (klass);
90         parent_class = SP_COLOR_SELECTOR_CLASS (g_type_class_peek_parent (klass));
92         object_class->destroy = sp_color_notebook_destroy;
94         widget_class->show_all = sp_color_notebook_show_all;
95         widget_class->hide_all = sp_color_notebook_hide_all;
96 }
98 static void
99 sp_color_notebook_switch_page(GtkNotebook *notebook,
100                               GtkNotebookPage *page,
101                               guint page_num,
102                               SPColorNotebook *colorbook)
104     if ( colorbook )
105     {
106         ColorNotebook* nb = (ColorNotebook*)(SP_COLOR_SELECTOR(colorbook)->base);
107         nb->switchPage( notebook, page, page_num );
109         // remember the page we seitched to
110         Inkscape::Preferences *prefs = Inkscape::Preferences::get();
111         prefs->setInt("/colorselector/page", page_num);
112     }
115 void ColorNotebook::switchPage(GtkNotebook*,
116                               GtkNotebookPage*,
117                               guint page_num)
119     SPColorSelector* csel;
120     GtkWidget* widget;
122     if ( gtk_notebook_get_current_page (GTK_NOTEBOOK (_book)) >= 0 )
123     {
124         csel = getCurrentSelector();
125         csel->base->getColorAlpha(_color, &_alpha);
126     }
127     widget = gtk_notebook_get_nth_page (GTK_NOTEBOOK (_book), page_num);
128     if ( widget && SP_IS_COLOR_SELECTOR (widget) )
129     {
130         csel = SP_COLOR_SELECTOR (widget);
131         csel->base->setColorAlpha( _color, _alpha );
133         // Temporary workaround to undo a spurious GRABBED
134         _released();
135     }
138 static gint sp_color_notebook_menu_handler( GtkWidget *widget, GdkEvent *event )
140     if (event->type == GDK_BUTTON_PRESS)
141     {
142         SPColorSelector* csel = SP_COLOR_SELECTOR(widget);
143         ((ColorNotebook*)(csel->base))->menuHandler( event );
145         /* Tell calling code that we have handled this event; the buck
146          * stops here. */
147         return TRUE;
148     }
150     /* Tell calling code that we have not handled this event; pass it on. */
151     return FALSE;
154 gint ColorNotebook::menuHandler( GdkEvent* event )
156     GdkEventButton *bevent = (GdkEventButton *) event;
157     gtk_menu_popup (GTK_MENU( _popup ), NULL, NULL, NULL, NULL,
158                     bevent->button, bevent->time);
159     return TRUE;
162 static void sp_color_notebook_menuitem_response (GtkMenuItem *menuitem, gpointer user_data)
164         gboolean active = FALSE;
166         active = gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menuitem));
167         SPColorNotebookTracker *entry = reinterpret_cast< SPColorNotebookTracker* > (user_data);
168         if ( entry )
169         {
170                 if ( active )
171                 {
172                         ((ColorNotebook*)(SP_COLOR_SELECTOR(entry->backPointer)->base))->addPage(entry->type, entry->submode);
173                 }
174                 else
175                 {
176                         ((ColorNotebook*)(SP_COLOR_SELECTOR(entry->backPointer)->base))->removePage(entry->type, entry->submode);
177                 }
178         }
181 static void
182 sp_color_notebook_init (SPColorNotebook *colorbook)
184     SP_COLOR_SELECTOR(colorbook)->base = new ColorNotebook( SP_COLOR_SELECTOR(colorbook) );
186     if ( SP_COLOR_SELECTOR(colorbook)->base )
187     {
188         SP_COLOR_SELECTOR(colorbook)->base->init();
189     }
192 void ColorNotebook::init()
194         GtkWidget* table = 0;
195         guint row = 0;
196         guint i = 0;
197         guint j = 0;
198         GType *selector_types = 0;
199         guint   selector_type_count = 0;
201         GtkTooltips *tt = gtk_tooltips_new ();
203         /* tempory hardcoding to get types loaded */
204         SP_TYPE_COLOR_SCALES;
205         SP_TYPE_COLOR_WHEEL_SELECTOR;
206 #if ENABLE_LCMS
207         SP_TYPE_COLOR_ICC_SELECTOR;
208 #endif // ENABLE_LCMS
210         /* REJON: Comment out the next line to not use the normal GTK Color
211            wheel. */
213 //        SP_TYPE_COLOR_GTKSELECTOR;
215         _updating = FALSE;
216         _updatingrgba = FALSE;
217         _btn = 0;
218         _popup = 0;
219         _trackerList = g_ptr_array_new ();
221         _book = gtk_notebook_new ();
222         gtk_widget_show (_book);
224         selector_types = g_type_children (SP_TYPE_COLOR_SELECTOR, &selector_type_count);
226         for ( i = 0; i < selector_type_count; i++ )
227         {
228                 if (!g_type_is_a (selector_types[i], SP_TYPE_COLOR_NOTEBOOK))
229                 {
230                         guint howmany = 1;
231                         gpointer klass = gtk_type_class (selector_types[i]);
232                         if ( klass && SP_IS_COLOR_SELECTOR_CLASS (klass) )
233                         {
234                                 SPColorSelectorClass *ck = SP_COLOR_SELECTOR_CLASS (klass);
235                                 howmany = MAX (1, ck->submode_count);
236                                 for ( j = 0; j < howmany; j++ )
237                                 {
238                                         SPColorNotebookTracker *entry = reinterpret_cast< SPColorNotebookTracker* > (malloc(sizeof(SPColorNotebookTracker)));
239                                         if ( entry )
240                                         {
241                                                 memset( entry, 0, sizeof(SPColorNotebookTracker) );
242                                                 entry->name = ck->name[j];
243                                                 entry->type = selector_types[i];
244                                                 entry->submode = j;
245                                                 entry->enabledFull = TRUE;
246                                                 entry->enabledBrief = TRUE;
247                                                 entry->backPointer = SP_COLOR_NOTEBOOK(_csel);
249                                                 g_ptr_array_add (_trackerList, entry);
250                                         }
251                                 }
252                         }
253                 }
254         }
256         for ( i = 0; i < _trackerList->len; i++ )
257         {
258                 SPColorNotebookTracker *entry =
259           reinterpret_cast< SPColorNotebookTracker* > (g_ptr_array_index (_trackerList, i));
260                 if ( entry )
261                 {
262                         addPage(entry->type, entry->submode);
263                 }
264         }
266         table = gtk_table_new (2, 3, FALSE);
267         gtk_widget_show (table);
269         gtk_box_pack_start (GTK_BOX (_csel), table, TRUE, TRUE, 0);
271         gtk_table_attach (GTK_TABLE (table), _book, 0, 2, row, row + 1,
272                       static_cast<GtkAttachOptions>(GTK_EXPAND|GTK_FILL),
273                       static_cast<GtkAttachOptions>(GTK_EXPAND|GTK_FILL),
274                       XPAD, YPAD);
276         // restore the last active page
277         Inkscape::Preferences *prefs = Inkscape::Preferences::get();
278         gtk_notebook_set_current_page (GTK_NOTEBOOK (_book), prefs->getInt("/colorselector/page", 0));
280         {
281                 gboolean found = FALSE;
283                 _popup = gtk_menu_new();
284                 GtkMenu *menu = GTK_MENU (_popup);
286                 for ( i = 0; i < _trackerList->len; i++ )
287                 {
288                         SPColorNotebookTracker *entry = reinterpret_cast< SPColorNotebookTracker* > (g_ptr_array_index (_trackerList, i));
289                         if ( entry )
290                         {
291                                 GtkWidget *item = gtk_check_menu_item_new_with_label (_(entry->name));
292                                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), entry->enabledFull);
293                                 gtk_widget_show (item);
294                                 gtk_menu_append (menu, item);
296                                 g_signal_connect (G_OBJECT (item), "activate",
297                                                                   G_CALLBACK (sp_color_notebook_menuitem_response),
298                                                                   reinterpret_cast< gpointer > (entry) );
299                                 found = TRUE;
300                         }
301                 }
303                 GtkWidget *arrow = gtk_arrow_new(GTK_ARROW_RIGHT, GTK_SHADOW_NONE);
304                 gtk_widget_show (arrow);
306                 _btn = gtk_button_new ();
307                 gtk_widget_show (_btn);
308                 gtk_container_add (GTK_CONTAINER (_btn), arrow);
310                 GtkWidget *align = gtk_alignment_new (1.0, 0.0, 0.0, 0.0);
311                 gtk_widget_show (align);
312                 gtk_container_add (GTK_CONTAINER (align), _btn);
314                 // uncomment to reenable the "show/hide modes" menu,
315                 // but first fix it so it remembers its settings in prefs and does not take that much space (entire vertical column!)
316                 //gtk_table_attach (GTK_TABLE (table), align, 2, 3, row, row + 1, GTK_FILL, GTK_FILL, XPAD, YPAD);
318                 gtk_signal_connect_object(GTK_OBJECT(_btn), "event", GTK_SIGNAL_FUNC (sp_color_notebook_menu_handler), GTK_OBJECT(_csel));
319                 if ( !found )
320                 {
321                         gtk_widget_set_sensitive (_btn, FALSE);
322                 }
323         }
325         row++;
327         /* Create RGBA entry and color preview */
328         GtkWidget *rgbabox = gtk_hbox_new (FALSE, 0);
330         _rgbal = gtk_label_new_with_mnemonic (_("RGBA_:"));
331         gtk_misc_set_alignment (GTK_MISC (_rgbal), 1.0, 0.5);
332         gtk_box_pack_start(GTK_BOX(rgbabox), _rgbal, TRUE, TRUE, 2);
334         _rgbae = gtk_entry_new ();
335         sp_dialog_defocus_on_enter (_rgbae);
336         gtk_entry_set_max_length (GTK_ENTRY (_rgbae), 8);
337         gtk_entry_set_width_chars (GTK_ENTRY (_rgbae), 8);
338         gtk_tooltips_set_tip (tt, _rgbae, _("Hexadecimal RGBA value of the color"), NULL);
339         gtk_box_pack_start(GTK_BOX(rgbabox), _rgbae, FALSE, FALSE, 0);
340         gtk_label_set_mnemonic_widget (GTK_LABEL(_rgbal), _rgbae);
342         sp_set_font_size_smaller (rgbabox);
343         gtk_widget_show_all (rgbabox);
344         gtk_table_attach (GTK_TABLE (table), rgbabox, 1, 2, row, row + 1, GTK_FILL, GTK_SHRINK, XPAD, YPAD);
346 #ifdef SPCS_PREVIEW
347         _p = sp_color_preview_new (0xffffffff);
348         gtk_widget_show (_p);
349         gtk_table_attach (GTK_TABLE (table), _p, 2, 3, row, row + 1, GTK_FILL, GTK_FILL, XPAD, YPAD);
350 #endif
352         _switchId = g_signal_connect(GTK_OBJECT (_book), "switch-page",
353                                                                 GTK_SIGNAL_FUNC (sp_color_notebook_switch_page), SP_COLOR_NOTEBOOK(_csel));
355         _entryId = gtk_signal_connect (GTK_OBJECT (_rgbae), "changed", GTK_SIGNAL_FUNC (ColorNotebook::_rgbaEntryChangedHook), _csel);
358 static void
359 sp_color_notebook_destroy (GtkObject *object)
361         if (((GtkObjectClass *) (parent_class))->destroy)
362                 (* ((GtkObjectClass *) (parent_class))->destroy) (object);
365 ColorNotebook::~ColorNotebook()
367         if ( _trackerList )
368         {
369                 g_ptr_array_free (_trackerList, TRUE);
370                 _trackerList = 0;
371         }
373         if ( _switchId )
374         {
375                 if ( _book )
376                 {
377                         g_signal_handler_disconnect (_book, _switchId);
378                         _switchId = 0;
379                 }
380         }
383 static void
384 sp_color_notebook_show_all (GtkWidget *widget)
386         gtk_widget_show (widget);
389 static void
390 sp_color_notebook_hide_all (GtkWidget *widget)
392         gtk_widget_hide (widget);
395 GtkWidget *
396 sp_color_notebook_new (void)
398         SPColorNotebook *colorbook;
400         colorbook = (SPColorNotebook*)gtk_type_new (SP_TYPE_COLOR_NOTEBOOK);
402         return GTK_WIDGET (colorbook);
405 ColorNotebook::ColorNotebook( SPColorSelector* csel )
406     : ColorSelector( csel )
410 SPColorSelector* ColorNotebook::getCurrentSelector()
412     SPColorSelector* csel = NULL;
413     gint current_page = gtk_notebook_get_current_page (GTK_NOTEBOOK (_book));
415     if ( current_page >= 0 )
416     {
417         GtkWidget* widget = gtk_notebook_get_nth_page (GTK_NOTEBOOK (_book), current_page);
418         if ( SP_IS_COLOR_SELECTOR (widget) )
419         {
420             csel = SP_COLOR_SELECTOR (widget);
421         }
422     }
424     return csel;
427 void ColorNotebook::_colorChanged()
429     SPColorSelector* 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         Glib::ustring text = t;
452         bool changed = false;
453         if (!text.empty() && text[0] == '#') {
454             changed = true;
455             text.erase(0,1);
456             if (text.size() == 6) {
457                 // it was a standard RGB hex
458                 unsigned int alph = SP_COLOR_F_TO_U(_alpha);
459                 gchar* tmp = g_strdup_printf("%02x", alph);
460                 text += tmp;
461                 g_free(tmp);
462             }
463         }
464         gchar* str = g_strdup(text.c_str());
465         gchar* end = 0;
466         guint64 rgba = g_ascii_strtoull( str, &end, 16 );
467         if ( end != str ) {
468             ptrdiff_t len = end - str;
469             if ( len < 8 ) {
470                 rgba = rgba << ( 4 * ( 8 - len ) );
471             }
472             _updatingrgba = TRUE;
473             if ( changed ) {
474                 gtk_entry_set_text( entry, str );
475             }
476             SPColor color( rgba );
477             setColorAlpha( color, SP_RGBA32_A_F(rgba), true );
478             _updatingrgba = FALSE;
479         }
480         g_free(str);
481     }
484 void ColorNotebook::_updateRgbaEntry( const SPColor& color, gfloat alpha )
486     g_return_if_fail( ( 0.0 <= alpha ) && ( alpha <= 1.0 ) );
488     if ( !_updatingrgba )
489     {
490         gchar s[32];
491         guint32 rgba;
493         /* Update RGBA entry */
494         rgba = color.toRGBA32( alpha );
496         g_snprintf (s, 32, "%08x", rgba);
497         const gchar* oldText = gtk_entry_get_text( GTK_ENTRY( _rgbae ) );
498         if ( strcmp( oldText, s ) != 0 )
499         {
500             g_signal_handler_block( _rgbae, _entryId );
501             gtk_entry_set_text( GTK_ENTRY(_rgbae), s );
502             g_signal_handler_unblock( _rgbae, _entryId );
503         }
504     }
507 void ColorNotebook::_entryGrabbed (SPColorSelector *, SPColorNotebook *colorbook)
509     ColorNotebook* nb = (ColorNotebook*)(SP_COLOR_SELECTOR(colorbook)->base);
510     nb->_grabbed();
513 void ColorNotebook::_entryDragged (SPColorSelector *csel, SPColorNotebook *colorbook)
515         gboolean oldState;
516     ColorNotebook* nb = (ColorNotebook*)(SP_COLOR_SELECTOR(colorbook)->base);
518         oldState = nb->_dragging;
520         nb->_dragging = TRUE;
521         nb->_entryModified( csel, colorbook );
523         nb->_dragging = oldState;
526 void ColorNotebook::_entryReleased (SPColorSelector *, SPColorNotebook *colorbook)
528     ColorNotebook* nb = (ColorNotebook*)(SP_COLOR_SELECTOR(colorbook)->base);
529     nb->_released();
532 void ColorNotebook::_entryChanged (SPColorSelector *csel, SPColorNotebook *colorbook)
534         gboolean oldState;
535     ColorNotebook* nb = (ColorNotebook*)(SP_COLOR_SELECTOR(colorbook)->base);
537         oldState = nb->_dragging;
539         nb->_dragging = FALSE;
540         nb->_entryModified( csel, colorbook );
542         nb->_dragging = oldState;
545 void ColorNotebook::_entryModified (SPColorSelector *csel, SPColorNotebook *colorbook)
547         g_return_if_fail (colorbook != NULL);
548         g_return_if_fail (SP_IS_COLOR_NOTEBOOK (colorbook));
549         g_return_if_fail (csel != NULL);
550         g_return_if_fail (SP_IS_COLOR_SELECTOR (csel));
552     ColorNotebook* nb = (ColorNotebook*)(SP_COLOR_SELECTOR(colorbook)->base);
553     SPColor color;
554     gfloat alpha = 1.0;
556     csel->base->getColorAlpha( color, &alpha );
557     nb->_updateRgbaEntry( color, alpha );
558     nb->_updateInternals( color, alpha, nb->_dragging );
561 GtkWidget* ColorNotebook::addPage(GType page_type, guint submode)
563         GtkWidget *page;
565         page = sp_color_selector_new( page_type );
566         if ( page )
567         {
568                 GtkWidget* tab_label = 0;
569                 SPColorSelector* csel;
571                 csel = SP_COLOR_SELECTOR (page);
572                 if ( submode > 0 )
573                 {
574                         csel->base->setSubmode( submode );
575                 }
576                 gtk_widget_show (page);
577         int index = csel->base ? csel->base->getSubmode() : 0;
578         const gchar* str = _(SP_COLOR_SELECTOR_GET_CLASS (csel)->name[index]);
579 //         g_message( "Hitting up for tab for '%s'", str );
580                 tab_label = gtk_label_new(_(str));
581                 gtk_notebook_append_page( GTK_NOTEBOOK (_book), page, tab_label );
582                 gtk_signal_connect (GTK_OBJECT (page), "grabbed", GTK_SIGNAL_FUNC (_entryGrabbed), _csel);
583                 gtk_signal_connect (GTK_OBJECT (page), "dragged", GTK_SIGNAL_FUNC (_entryDragged), _csel);
584                 gtk_signal_connect (GTK_OBJECT (page), "released", GTK_SIGNAL_FUNC (_entryReleased), _csel);
585                 gtk_signal_connect (GTK_OBJECT (page), "changed", GTK_SIGNAL_FUNC (_entryChanged), _csel);
586         }
588         return page;
591 GtkWidget* ColorNotebook::getPage(GType page_type, guint submode)
593         gint count = 0;
594         gint i = 0;
595         GtkWidget* page = 0;
597 //        count = gtk_notebook_get_n_pages (_book);
598         count = 200;
599         for ( i = 0; i < count && !page; i++ )
600         {
601                 page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (_book), i);
602                 if ( page )
603                 {
604                         SPColorSelector* csel;
605                         guint pagemode;
606                         csel = SP_COLOR_SELECTOR (page);
607                         pagemode = csel->base->getSubmode();
608                         if ( G_TYPE_FROM_INSTANCE (page) == page_type
609                                  && pagemode == submode )
610                         {
611                                 // found it.
612                                 break;
613                         }
614                         else
615                         {
616                                 page = 0;
617                         }
618                 }
619                 else
620                 {
621                         break;
622                 }
623         }
624         return page;
627 void ColorNotebook::removePage( GType page_type, guint submode )
629         GtkWidget *page = 0;
631         page = getPage(page_type, submode);
632         if ( page )
633         {
634                 gint where = gtk_notebook_page_num (GTK_NOTEBOOK (_book), page);
635                 if ( where >= 0 )
636                 {
637                         if ( gtk_notebook_get_current_page (GTK_NOTEBOOK (_book)) == where )
638                         {
639 //                 getColorAlpha(_color, &_alpha);
640                         }
641                         gtk_notebook_remove_page (GTK_NOTEBOOK (_book), where);
642                 }
643         }
646 /*
647   Local Variables:
648   mode:c++
649   c-file-style:"stroustrup"
650   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
651   indent-tabs-mode:nil
652   fill-column:99
653   End:
654 */
655 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :