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 }
108 }
110 void ColorNotebook::switchPage(GtkNotebook*,
111 GtkNotebookPage*,
112 guint page_num)
113 {
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 }
131 }
133 static gint sp_color_notebook_menu_handler( GtkWidget *widget, GdkEvent *event )
134 {
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;
147 }
149 gint ColorNotebook::menuHandler( GdkEvent* event )
150 {
151 GdkEventButton *bevent = (GdkEventButton *) event;
152 gtk_menu_popup (GTK_MENU( _popup ), NULL, NULL, NULL, NULL,
153 bevent->button, bevent->time);
154 return TRUE;
155 }
157 static void sp_color_notebook_menuitem_response (GtkMenuItem *menuitem, gpointer user_data)
158 {
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 }
174 }
176 static void
177 sp_color_notebook_init (SPColorNotebook *colorbook)
178 {
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 }
185 }
187 void ColorNotebook::init()
188 {
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);
350 }
352 static void
353 sp_color_notebook_destroy (GtkObject *object)
354 {
355 if (((GtkObjectClass *) (parent_class))->destroy)
356 (* ((GtkObjectClass *) (parent_class))->destroy) (object);
357 }
359 ColorNotebook::~ColorNotebook()
360 {
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 }
375 }
377 static void
378 sp_color_notebook_show_all (GtkWidget *widget)
379 {
380 gtk_widget_show (widget);
381 }
383 static void
384 sp_color_notebook_hide_all (GtkWidget *widget)
385 {
386 gtk_widget_hide (widget);
387 }
389 GtkWidget *
390 sp_color_notebook_new (void)
391 {
392 SPColorNotebook *colorbook;
394 colorbook = (SPColorNotebook*)gtk_type_new (SP_TYPE_COLOR_NOTEBOOK);
396 return GTK_WIDGET (colorbook);
397 }
399 ColorNotebook::ColorNotebook( SPColorSelector* csel )
400 : ColorSelector( csel )
401 {
402 }
404 SPColorSelector* ColorNotebook::getCurrentSelector()
405 {
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;
419 }
421 void ColorNotebook::_colorChanged()
422 {
423 SPColorSelector* cselPage = getCurrentSelector();
424 if ( cselPage )
425 {
426 cselPage->base->setColorAlpha( _color, _alpha );
427 }
429 _updateRgbaEntry( _color, _alpha );
430 }
432 void ColorNotebook::_rgbaEntryChangedHook(GtkEntry *entry, SPColorNotebook *colorbook)
433 {
434 ((ColorNotebook*)(SP_COLOR_SELECTOR(colorbook)->base))->_rgbaEntryChanged( entry );
435 }
437 void ColorNotebook::_rgbaEntryChanged(GtkEntry* entry)
438 {
439 if (_updating) return;
440 if (_updatingrgba) return;
442 const gchar *t = gtk_entry_get_text( entry );
444 if (t) {
445 gchar *e = 0;
446 guint rgba = strtoul (t, &e, 16);
447 if ( e != t ) {
448 ptrdiff_t len=e-t;
449 if ( len < 8 ) {
450 rgba = rgba << ( 4 * ( 8 - len ) );
451 }
452 _updatingrgba = TRUE;
453 SPColor color( rgba );
454 setColorAlpha( color, SP_RGBA32_A_F(rgba), true );
455 _updatingrgba = FALSE;
456 }
457 }
458 }
460 void ColorNotebook::_updateRgbaEntry( const SPColor& color, gfloat alpha )
461 {
462 g_return_if_fail( ( 0.0 <= alpha ) && ( alpha <= 1.0 ) );
464 if ( !_updatingrgba )
465 {
466 gchar s[32];
467 guint32 rgba;
469 /* Update RGBA entry */
470 rgba = color.toRGBA32( alpha );
472 g_snprintf (s, 32, "%08x", rgba);
473 const gchar* oldText = gtk_entry_get_text( GTK_ENTRY( _rgbae ) );
474 if ( strcmp( oldText, s ) != 0 )
475 {
476 g_signal_handler_block( _rgbae, _entryId );
477 gtk_entry_set_text( GTK_ENTRY(_rgbae), s );
478 g_signal_handler_unblock( _rgbae, _entryId );
479 }
480 }
481 }
483 void ColorNotebook::_entryGrabbed (SPColorSelector *, SPColorNotebook *colorbook)
484 {
485 ColorNotebook* nb = (ColorNotebook*)(SP_COLOR_SELECTOR(colorbook)->base);
486 nb->_grabbed();
487 }
489 void ColorNotebook::_entryDragged (SPColorSelector *csel, SPColorNotebook *colorbook)
490 {
491 gboolean oldState;
492 ColorNotebook* nb = (ColorNotebook*)(SP_COLOR_SELECTOR(colorbook)->base);
494 oldState = nb->_dragging;
496 nb->_dragging = TRUE;
497 nb->_entryModified( csel, colorbook );
499 nb->_dragging = oldState;
500 }
502 void ColorNotebook::_entryReleased (SPColorSelector *, SPColorNotebook *colorbook)
503 {
504 ColorNotebook* nb = (ColorNotebook*)(SP_COLOR_SELECTOR(colorbook)->base);
505 nb->_released();
506 }
508 void ColorNotebook::_entryChanged (SPColorSelector *csel, SPColorNotebook *colorbook)
509 {
510 gboolean oldState;
511 ColorNotebook* nb = (ColorNotebook*)(SP_COLOR_SELECTOR(colorbook)->base);
513 oldState = nb->_dragging;
515 nb->_dragging = FALSE;
516 nb->_entryModified( csel, colorbook );
518 nb->_dragging = oldState;
519 }
521 void ColorNotebook::_entryModified (SPColorSelector *csel, SPColorNotebook *colorbook)
522 {
523 g_return_if_fail (colorbook != NULL);
524 g_return_if_fail (SP_IS_COLOR_NOTEBOOK (colorbook));
525 g_return_if_fail (csel != NULL);
526 g_return_if_fail (SP_IS_COLOR_SELECTOR (csel));
528 ColorNotebook* nb = (ColorNotebook*)(SP_COLOR_SELECTOR(colorbook)->base);
529 SPColor color;
530 gfloat alpha = 1.0;
532 csel->base->getColorAlpha( color, &alpha );
533 nb->_updateRgbaEntry( color, alpha );
534 nb->_updateInternals( color, alpha, nb->_dragging );
535 }
537 GtkWidget* ColorNotebook::addPage(GType page_type, guint submode)
538 {
539 GtkWidget *page;
541 page = sp_color_selector_new( page_type );
542 if ( page )
543 {
544 GtkWidget* tab_label = 0;
545 SPColorSelector* csel;
547 csel = SP_COLOR_SELECTOR (page);
548 if ( submode > 0 )
549 {
550 csel->base->setSubmode( submode );
551 }
552 gtk_widget_show (page);
553 int index = csel->base ? csel->base->getSubmode() : 0;
554 const gchar* str = _(SP_COLOR_SELECTOR_GET_CLASS (csel)->name[index]);
555 // g_message( "Hitting up for tab for '%s'", str );
556 tab_label = gtk_label_new(_(str));
557 gtk_notebook_append_page( GTK_NOTEBOOK (_book), page, tab_label );
558 gtk_signal_connect (GTK_OBJECT (page), "grabbed", GTK_SIGNAL_FUNC (_entryGrabbed), _csel);
559 gtk_signal_connect (GTK_OBJECT (page), "dragged", GTK_SIGNAL_FUNC (_entryDragged), _csel);
560 gtk_signal_connect (GTK_OBJECT (page), "released", GTK_SIGNAL_FUNC (_entryReleased), _csel);
561 gtk_signal_connect (GTK_OBJECT (page), "changed", GTK_SIGNAL_FUNC (_entryChanged), _csel);
562 }
564 return page;
565 }
567 GtkWidget* ColorNotebook::getPage(GType page_type, guint submode)
568 {
569 gint count = 0;
570 gint i = 0;
571 GtkWidget* page = 0;
573 // count = gtk_notebook_get_n_pages (_book);
574 count = 200;
575 for ( i = 0; i < count && !page; i++ )
576 {
577 page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (_book), i);
578 if ( page )
579 {
580 SPColorSelector* csel;
581 guint pagemode;
582 csel = SP_COLOR_SELECTOR (page);
583 pagemode = csel->base->getSubmode();
584 if ( G_TYPE_FROM_INSTANCE (page) == page_type
585 && pagemode == submode )
586 {
587 // found it.
588 break;
589 }
590 else
591 {
592 page = 0;
593 }
594 }
595 else
596 {
597 break;
598 }
599 }
600 return page;
601 }
603 void ColorNotebook::removePage( GType page_type, guint submode )
604 {
605 GtkWidget *page = 0;
607 page = getPage(page_type, submode);
608 if ( page )
609 {
610 gint where = gtk_notebook_page_num (GTK_NOTEBOOK (_book), page);
611 if ( where >= 0 )
612 {
613 if ( gtk_notebook_get_current_page (GTK_NOTEBOOK (_book)) == where )
614 {
615 // getColorAlpha(_color, &_alpha);
616 }
617 gtk_notebook_remove_page (GTK_NOTEBOOK (_book), where);
618 }
619 }
620 }
622 /*
623 Local Variables:
624 mode:c++
625 c-file-style:"stroustrup"
626 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
627 indent-tabs-mode:nil
628 fill-column:99
629 End:
630 */
631 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :