bf690e968b5dfc4778f5f44624703173ed3f9c7e
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 "../prefs-utils.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 GtkType
59 sp_color_notebook_get_type (void)
60 {
61 static GtkType type = 0;
62 if (!type) {
63 GtkTypeInfo info = {
64 "SPColorNotebook",
65 sizeof (SPColorNotebook),
66 sizeof (SPColorNotebookClass),
67 (GtkClassInitFunc) sp_color_notebook_class_init,
68 (GtkObjectInitFunc) sp_color_notebook_init,
69 NULL, NULL, NULL
70 };
71 type = gtk_type_unique (SP_TYPE_COLOR_SELECTOR, &info);
72 }
73 return type;
74 }
76 static void
77 sp_color_notebook_class_init (SPColorNotebookClass *klass)
78 {
79 GtkObjectClass *object_class;
80 GtkWidgetClass *widget_class;
81 SPColorSelectorClass *selector_class;
83 object_class = (GtkObjectClass *) klass;
84 widget_class = (GtkWidgetClass *) klass;
85 selector_class = SP_COLOR_SELECTOR_CLASS (klass);
87 parent_class = SP_COLOR_SELECTOR_CLASS (g_type_class_peek_parent (klass));
89 object_class->destroy = sp_color_notebook_destroy;
91 widget_class->show_all = sp_color_notebook_show_all;
92 widget_class->hide_all = sp_color_notebook_hide_all;
93 }
95 static void
96 sp_color_notebook_switch_page(GtkNotebook *notebook,
97 GtkNotebookPage *page,
98 guint page_num,
99 SPColorNotebook *colorbook)
100 {
101 if ( colorbook )
102 {
103 ColorNotebook* nb = (ColorNotebook*)(SP_COLOR_SELECTOR(colorbook)->base);
104 nb->switchPage( notebook, page, page_num );
106 // remember the page we seitched to
107 prefs_set_int_attribute ("colorselector", "page", page_num);
109 }
110 }
112 void ColorNotebook::switchPage(GtkNotebook*,
113 GtkNotebookPage*,
114 guint page_num)
115 {
116 SPColorSelector* csel;
117 GtkWidget* widget;
119 if ( gtk_notebook_get_current_page (GTK_NOTEBOOK (_book)) >= 0 )
120 {
121 csel = getCurrentSelector();
122 csel->base->getColorAlpha(_color, &_alpha);
123 }
124 widget = gtk_notebook_get_nth_page (GTK_NOTEBOOK (_book), page_num);
125 if ( widget && SP_IS_COLOR_SELECTOR (widget) )
126 {
127 csel = SP_COLOR_SELECTOR (widget);
128 csel->base->setColorAlpha( _color, _alpha );
130 // Temporary workaround to undo a spurious GRABBED
131 _released();
132 }
133 }
135 static gint sp_color_notebook_menu_handler( GtkWidget *widget, GdkEvent *event )
136 {
137 if (event->type == GDK_BUTTON_PRESS)
138 {
139 SPColorSelector* csel = SP_COLOR_SELECTOR(widget);
140 ((ColorNotebook*)(csel->base))->menuHandler( event );
142 /* Tell calling code that we have handled this event; the buck
143 * stops here. */
144 return TRUE;
145 }
147 /* Tell calling code that we have not handled this event; pass it on. */
148 return FALSE;
149 }
151 gint ColorNotebook::menuHandler( GdkEvent* event )
152 {
153 GdkEventButton *bevent = (GdkEventButton *) event;
154 gtk_menu_popup (GTK_MENU( _popup ), NULL, NULL, NULL, NULL,
155 bevent->button, bevent->time);
156 return TRUE;
157 }
159 static void sp_color_notebook_menuitem_response (GtkMenuItem *menuitem, gpointer user_data)
160 {
161 gboolean active = FALSE;
163 active = gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menuitem));
164 SPColorNotebookTracker *entry = reinterpret_cast< SPColorNotebookTracker* > (user_data);
165 if ( entry )
166 {
167 if ( active )
168 {
169 ((ColorNotebook*)(SP_COLOR_SELECTOR(entry->backPointer)->base))->addPage(entry->type, entry->submode);
170 }
171 else
172 {
173 ((ColorNotebook*)(SP_COLOR_SELECTOR(entry->backPointer)->base))->removePage(entry->type, entry->submode);
174 }
175 }
176 }
178 static void
179 sp_color_notebook_init (SPColorNotebook *colorbook)
180 {
181 SP_COLOR_SELECTOR(colorbook)->base = new ColorNotebook( SP_COLOR_SELECTOR(colorbook) );
183 if ( SP_COLOR_SELECTOR(colorbook)->base )
184 {
185 SP_COLOR_SELECTOR(colorbook)->base->init();
186 }
187 }
189 void ColorNotebook::init()
190 {
191 GtkWidget* table = 0;
192 guint row = 0;
193 guint i = 0;
194 guint j = 0;
195 GType *selector_types = 0;
196 guint selector_type_count = 0;
198 GtkTooltips *tt = gtk_tooltips_new ();
200 /* tempory hardcoding to get types loaded */
201 SP_TYPE_COLOR_SCALES;
202 SP_TYPE_COLOR_WHEEL_SELECTOR;
203 #if ENABLE_LCMS
204 SP_TYPE_COLOR_ICC_SELECTOR;
205 #endif // ENABLE_LCMS
207 /* REJON: Comment out the next line to not use the normal GTK Color
208 wheel. */
210 // SP_TYPE_COLOR_GTKSELECTOR;
212 _updating = FALSE;
213 _updatingrgba = FALSE;
214 _btn = 0;
215 _popup = 0;
216 _trackerList = g_ptr_array_new ();
218 _book = gtk_notebook_new ();
219 gtk_widget_show (_book);
221 selector_types = g_type_children (SP_TYPE_COLOR_SELECTOR, &selector_type_count);
223 for ( i = 0; i < selector_type_count; i++ )
224 {
225 if (!g_type_is_a (selector_types[i], SP_TYPE_COLOR_NOTEBOOK))
226 {
227 guint howmany = 1;
228 gpointer klass = gtk_type_class (selector_types[i]);
229 if ( klass && SP_IS_COLOR_SELECTOR_CLASS (klass) )
230 {
231 SPColorSelectorClass *ck = SP_COLOR_SELECTOR_CLASS (klass);
232 howmany = MAX (1, ck->submode_count);
233 for ( j = 0; j < howmany; j++ )
234 {
235 SPColorNotebookTracker *entry = reinterpret_cast< SPColorNotebookTracker* > (malloc(sizeof(SPColorNotebookTracker)));
236 if ( entry )
237 {
238 memset( entry, 0, sizeof(SPColorNotebookTracker) );
239 entry->name = ck->name[j];
240 entry->type = selector_types[i];
241 entry->submode = j;
242 entry->enabledFull = TRUE;
243 entry->enabledBrief = TRUE;
244 entry->backPointer = SP_COLOR_NOTEBOOK(_csel);
246 g_ptr_array_add (_trackerList, entry);
247 }
248 }
249 }
250 }
251 }
253 for ( i = 0; i < _trackerList->len; i++ )
254 {
255 SPColorNotebookTracker *entry =
256 reinterpret_cast< SPColorNotebookTracker* > (g_ptr_array_index (_trackerList, i));
257 if ( entry )
258 {
259 addPage(entry->type, entry->submode);
260 }
261 }
263 table = gtk_table_new (2, 3, FALSE);
264 gtk_widget_show (table);
266 gtk_box_pack_start (GTK_BOX (_csel), table, TRUE, TRUE, 0);
268 gtk_table_attach (GTK_TABLE (table), _book, 0, 2, row, row + 1,
269 static_cast<GtkAttachOptions>(GTK_EXPAND|GTK_FILL),
270 static_cast<GtkAttachOptions>(GTK_EXPAND|GTK_FILL),
271 XPAD, YPAD);
273 // restore the last active page
274 gtk_notebook_set_current_page (GTK_NOTEBOOK (_book), prefs_get_int_attribute ("colorselector", "page", 0));
276 {
277 gboolean found = FALSE;
279 _popup = gtk_menu_new();
280 GtkMenu *menu = GTK_MENU (_popup);
282 for ( i = 0; i < _trackerList->len; i++ )
283 {
284 SPColorNotebookTracker *entry = reinterpret_cast< SPColorNotebookTracker* > (g_ptr_array_index (_trackerList, i));
285 if ( entry )
286 {
287 GtkWidget *item = gtk_check_menu_item_new_with_label (_(entry->name));
288 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), entry->enabledFull);
289 gtk_widget_show (item);
290 gtk_menu_append (menu, item);
292 g_signal_connect (G_OBJECT (item), "activate",
293 G_CALLBACK (sp_color_notebook_menuitem_response),
294 reinterpret_cast< gpointer > (entry) );
295 found = TRUE;
296 }
297 }
299 GtkWidget *arrow = gtk_arrow_new(GTK_ARROW_RIGHT, GTK_SHADOW_NONE);
300 gtk_widget_show (arrow);
302 _btn = gtk_button_new ();
303 gtk_widget_show (_btn);
304 gtk_container_add (GTK_CONTAINER (_btn), arrow);
306 GtkWidget *align = gtk_alignment_new (1.0, 0.0, 0.0, 0.0);
307 gtk_widget_show (align);
308 gtk_container_add (GTK_CONTAINER (align), _btn);
310 // uncomment to reenable the "show/hide modes" menu,
311 // but first fix it so it remembers its settings in prefs and does not take that much space (entire vertical column!)
312 //gtk_table_attach (GTK_TABLE (table), align, 2, 3, row, row + 1, GTK_FILL, GTK_FILL, XPAD, YPAD);
314 gtk_signal_connect_object(GTK_OBJECT(_btn), "event", GTK_SIGNAL_FUNC (sp_color_notebook_menu_handler), GTK_OBJECT(_csel));
315 if ( !found )
316 {
317 gtk_widget_set_sensitive (_btn, FALSE);
318 }
319 }
321 row++;
323 /* Create RGBA entry and color preview */
324 GtkWidget *rgbabox = gtk_hbox_new (FALSE, 0);
326 _rgbal = gtk_label_new_with_mnemonic (_("RGBA_:"));
327 gtk_misc_set_alignment (GTK_MISC (_rgbal), 1.0, 0.5);
328 gtk_box_pack_start(GTK_BOX(rgbabox), _rgbal, TRUE, TRUE, 2);
330 _rgbae = gtk_entry_new ();
331 sp_dialog_defocus_on_enter (_rgbae);
332 gtk_entry_set_max_length (GTK_ENTRY (_rgbae), 8);
333 gtk_entry_set_width_chars (GTK_ENTRY (_rgbae), 8);
334 gtk_tooltips_set_tip (tt, _rgbae, _("Hexadecimal RGBA value of the color"), NULL);
335 gtk_box_pack_start(GTK_BOX(rgbabox), _rgbae, FALSE, FALSE, 0);
336 gtk_label_set_mnemonic_widget (GTK_LABEL(_rgbal), _rgbae);
338 sp_set_font_size_smaller (rgbabox);
339 gtk_widget_show_all (rgbabox);
340 gtk_table_attach (GTK_TABLE (table), rgbabox, 1, 2, row, row + 1, GTK_FILL, GTK_SHRINK, XPAD, YPAD);
342 #ifdef SPCS_PREVIEW
343 _p = sp_color_preview_new (0xffffffff);
344 gtk_widget_show (_p);
345 gtk_table_attach (GTK_TABLE (table), _p, 2, 3, row, row + 1, GTK_FILL, GTK_FILL, XPAD, YPAD);
346 #endif
348 _switchId = g_signal_connect(GTK_OBJECT (_book), "switch-page",
349 GTK_SIGNAL_FUNC (sp_color_notebook_switch_page), SP_COLOR_NOTEBOOK(_csel));
351 _entryId = gtk_signal_connect (GTK_OBJECT (_rgbae), "changed", GTK_SIGNAL_FUNC (ColorNotebook::_rgbaEntryChangedHook), _csel);
352 }
354 static void
355 sp_color_notebook_destroy (GtkObject *object)
356 {
357 if (((GtkObjectClass *) (parent_class))->destroy)
358 (* ((GtkObjectClass *) (parent_class))->destroy) (object);
359 }
361 ColorNotebook::~ColorNotebook()
362 {
363 if ( _trackerList )
364 {
365 g_ptr_array_free (_trackerList, TRUE);
366 _trackerList = 0;
367 }
369 if ( _switchId )
370 {
371 if ( _book )
372 {
373 g_signal_handler_disconnect (_book, _switchId);
374 _switchId = 0;
375 }
376 }
377 }
379 static void
380 sp_color_notebook_show_all (GtkWidget *widget)
381 {
382 gtk_widget_show (widget);
383 }
385 static void
386 sp_color_notebook_hide_all (GtkWidget *widget)
387 {
388 gtk_widget_hide (widget);
389 }
391 GtkWidget *
392 sp_color_notebook_new (void)
393 {
394 SPColorNotebook *colorbook;
396 colorbook = (SPColorNotebook*)gtk_type_new (SP_TYPE_COLOR_NOTEBOOK);
398 return GTK_WIDGET (colorbook);
399 }
401 ColorNotebook::ColorNotebook( SPColorSelector* csel )
402 : ColorSelector( csel )
403 {
404 }
406 SPColorSelector* ColorNotebook::getCurrentSelector()
407 {
408 SPColorSelector* csel = NULL;
409 gint current_page = gtk_notebook_get_current_page (GTK_NOTEBOOK (_book));
411 if ( current_page >= 0 )
412 {
413 GtkWidget* widget = gtk_notebook_get_nth_page (GTK_NOTEBOOK (_book), current_page);
414 if ( SP_IS_COLOR_SELECTOR (widget) )
415 {
416 csel = SP_COLOR_SELECTOR (widget);
417 }
418 }
420 return csel;
421 }
423 void ColorNotebook::_colorChanged()
424 {
425 SPColorSelector* cselPage = getCurrentSelector();
426 if ( cselPage )
427 {
428 cselPage->base->setColorAlpha( _color, _alpha );
429 }
431 _updateRgbaEntry( _color, _alpha );
432 }
434 void ColorNotebook::_rgbaEntryChangedHook(GtkEntry *entry, SPColorNotebook *colorbook)
435 {
436 ((ColorNotebook*)(SP_COLOR_SELECTOR(colorbook)->base))->_rgbaEntryChanged( entry );
437 }
439 void ColorNotebook::_rgbaEntryChanged(GtkEntry* entry)
440 {
441 if (_updating) return;
442 if (_updatingrgba) return;
444 const gchar *t = gtk_entry_get_text( entry );
446 if (t) {
447 gchar *e = 0;
448 guint rgba = strtoul (t, &e, 16);
449 if ( e != t ) {
450 ptrdiff_t len=e-t;
451 if ( len < 8 ) {
452 rgba = rgba << ( 4 * ( 8 - len ) );
453 }
454 _updatingrgba = TRUE;
455 SPColor color( rgba );
456 setColorAlpha( color, SP_RGBA32_A_F(rgba), true );
457 _updatingrgba = FALSE;
458 }
459 }
460 }
462 void ColorNotebook::_updateRgbaEntry( const SPColor& color, gfloat alpha )
463 {
464 g_return_if_fail( ( 0.0 <= alpha ) && ( alpha <= 1.0 ) );
466 if ( !_updatingrgba )
467 {
468 gchar s[32];
469 guint32 rgba;
471 /* Update RGBA entry */
472 rgba = color.toRGBA32( alpha );
474 g_snprintf (s, 32, "%08x", rgba);
475 const gchar* oldText = gtk_entry_get_text( GTK_ENTRY( _rgbae ) );
476 if ( strcmp( oldText, s ) != 0 )
477 {
478 g_signal_handler_block( _rgbae, _entryId );
479 gtk_entry_set_text( GTK_ENTRY(_rgbae), s );
480 g_signal_handler_unblock( _rgbae, _entryId );
481 }
482 }
483 }
485 void ColorNotebook::_entryGrabbed (SPColorSelector *, SPColorNotebook *colorbook)
486 {
487 ColorNotebook* nb = (ColorNotebook*)(SP_COLOR_SELECTOR(colorbook)->base);
488 nb->_grabbed();
489 }
491 void ColorNotebook::_entryDragged (SPColorSelector *csel, SPColorNotebook *colorbook)
492 {
493 gboolean oldState;
494 ColorNotebook* nb = (ColorNotebook*)(SP_COLOR_SELECTOR(colorbook)->base);
496 oldState = nb->_dragging;
498 nb->_dragging = TRUE;
499 nb->_entryModified( csel, colorbook );
501 nb->_dragging = oldState;
502 }
504 void ColorNotebook::_entryReleased (SPColorSelector *, SPColorNotebook *colorbook)
505 {
506 ColorNotebook* nb = (ColorNotebook*)(SP_COLOR_SELECTOR(colorbook)->base);
507 nb->_released();
508 }
510 void ColorNotebook::_entryChanged (SPColorSelector *csel, SPColorNotebook *colorbook)
511 {
512 gboolean oldState;
513 ColorNotebook* nb = (ColorNotebook*)(SP_COLOR_SELECTOR(colorbook)->base);
515 oldState = nb->_dragging;
517 nb->_dragging = FALSE;
518 nb->_entryModified( csel, colorbook );
520 nb->_dragging = oldState;
521 }
523 void ColorNotebook::_entryModified (SPColorSelector *csel, SPColorNotebook *colorbook)
524 {
525 g_return_if_fail (colorbook != NULL);
526 g_return_if_fail (SP_IS_COLOR_NOTEBOOK (colorbook));
527 g_return_if_fail (csel != NULL);
528 g_return_if_fail (SP_IS_COLOR_SELECTOR (csel));
530 ColorNotebook* nb = (ColorNotebook*)(SP_COLOR_SELECTOR(colorbook)->base);
531 SPColor color;
532 gfloat alpha = 1.0;
534 csel->base->getColorAlpha( color, &alpha );
535 nb->_updateRgbaEntry( color, alpha );
536 nb->_updateInternals( color, alpha, nb->_dragging );
537 }
539 GtkWidget* ColorNotebook::addPage(GType page_type, guint submode)
540 {
541 GtkWidget *page;
543 page = sp_color_selector_new( page_type );
544 if ( page )
545 {
546 GtkWidget* tab_label = 0;
547 SPColorSelector* csel;
549 csel = SP_COLOR_SELECTOR (page);
550 if ( submode > 0 )
551 {
552 csel->base->setSubmode( submode );
553 }
554 gtk_widget_show (page);
555 int index = csel->base ? csel->base->getSubmode() : 0;
556 const gchar* str = _(SP_COLOR_SELECTOR_GET_CLASS (csel)->name[index]);
557 // g_message( "Hitting up for tab for '%s'", str );
558 tab_label = gtk_label_new(_(str));
559 gtk_notebook_append_page( GTK_NOTEBOOK (_book), page, tab_label );
560 gtk_signal_connect (GTK_OBJECT (page), "grabbed", GTK_SIGNAL_FUNC (_entryGrabbed), _csel);
561 gtk_signal_connect (GTK_OBJECT (page), "dragged", GTK_SIGNAL_FUNC (_entryDragged), _csel);
562 gtk_signal_connect (GTK_OBJECT (page), "released", GTK_SIGNAL_FUNC (_entryReleased), _csel);
563 gtk_signal_connect (GTK_OBJECT (page), "changed", GTK_SIGNAL_FUNC (_entryChanged), _csel);
564 }
566 return page;
567 }
569 GtkWidget* ColorNotebook::getPage(GType page_type, guint submode)
570 {
571 gint count = 0;
572 gint i = 0;
573 GtkWidget* page = 0;
575 // count = gtk_notebook_get_n_pages (_book);
576 count = 200;
577 for ( i = 0; i < count && !page; i++ )
578 {
579 page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (_book), i);
580 if ( page )
581 {
582 SPColorSelector* csel;
583 guint pagemode;
584 csel = SP_COLOR_SELECTOR (page);
585 pagemode = csel->base->getSubmode();
586 if ( G_TYPE_FROM_INSTANCE (page) == page_type
587 && pagemode == submode )
588 {
589 // found it.
590 break;
591 }
592 else
593 {
594 page = 0;
595 }
596 }
597 else
598 {
599 break;
600 }
601 }
602 return page;
603 }
605 void ColorNotebook::removePage( GType page_type, guint submode )
606 {
607 GtkWidget *page = 0;
609 page = getPage(page_type, submode);
610 if ( page )
611 {
612 gint where = gtk_notebook_page_num (GTK_NOTEBOOK (_book), page);
613 if ( where >= 0 )
614 {
615 if ( gtk_notebook_get_current_page (GTK_NOTEBOOK (_book)) == where )
616 {
617 // getColorAlpha(_color, &_alpha);
618 }
619 gtk_notebook_remove_page (GTK_NOTEBOOK (_book), where);
620 }
621 }
622 }
624 /*
625 Local Variables:
626 mode:c++
627 c-file-style:"stroustrup"
628 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
629 indent-tabs-mode:nil
630 fill-column:99
631 End:
632 */
633 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :