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 }
106 }
108 void ColorNotebook::switchPage(GtkNotebook*,
109 GtkNotebookPage*,
110 guint page_num)
111 {
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 }
129 }
131 static gint sp_color_notebook_menu_handler( GtkWidget *widget, GdkEvent *event )
132 {
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;
145 }
147 gint ColorNotebook::menuHandler( GdkEvent* event )
148 {
149 GdkEventButton *bevent = (GdkEventButton *) event;
150 gtk_menu_popup (GTK_MENU( _popup ), NULL, NULL, NULL, NULL,
151 bevent->button, bevent->time);
152 return TRUE;
153 }
155 static void sp_color_notebook_menuitem_response (GtkMenuItem *menuitem, gpointer user_data)
156 {
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 }
172 }
174 static void
175 sp_color_notebook_init (SPColorNotebook *colorbook)
176 {
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 }
183 }
185 void ColorNotebook::init()
186 {
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);
345 }
347 static void
348 sp_color_notebook_destroy (GtkObject *object)
349 {
350 if (((GtkObjectClass *) (parent_class))->destroy)
351 (* ((GtkObjectClass *) (parent_class))->destroy) (object);
352 }
354 ColorNotebook::~ColorNotebook()
355 {
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 }
370 }
372 static void
373 sp_color_notebook_show_all (GtkWidget *widget)
374 {
375 gtk_widget_show (widget);
376 }
378 static void
379 sp_color_notebook_hide_all (GtkWidget *widget)
380 {
381 gtk_widget_hide (widget);
382 }
384 GtkWidget *
385 sp_color_notebook_new (void)
386 {
387 SPColorNotebook *colorbook;
389 colorbook = (SPColorNotebook*)gtk_type_new (SP_TYPE_COLOR_NOTEBOOK);
391 return GTK_WIDGET (colorbook);
392 }
394 ColorNotebook::ColorNotebook( SPColorSelector* csel )
395 : ColorSelector( csel )
396 {
397 }
399 SPColorSelector* ColorNotebook::getCurrentSelector()
400 {
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;
414 }
416 void ColorNotebook::_colorChanged(const SPColor& color, gfloat alpha)
417 {
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 );
431 }
433 void ColorNotebook::_rgbaEntryChangedHook(GtkEntry *entry, SPColorNotebook *colorbook)
434 {
435 ((ColorNotebook*)(SP_COLOR_SELECTOR(colorbook)->base))->_rgbaEntryChanged( entry );
436 }
438 void ColorNotebook::_rgbaEntryChanged(GtkEntry* entry)
439 {
440 const gchar *t;
441 gchar *e;
442 SPColor color;
443 guint rgba;
445 if (_updating) return;
446 if (_updatingrgba) return;
448 t = gtk_entry_get_text (entry);
450 if (t) {
451 rgba = strtoul (t, &e, 16);
452 if ( e != t ) {
453 ptrdiff_t len=e-t;
454 if ( len < 8 ) {
455 rgba = rgba << ( 4 * ( 8 - len ) );
456 }
457 _updatingrgba = TRUE;
458 sp_color_set_rgb_rgba32 (&color, rgba);
459 setColorAlpha( color, SP_RGBA32_A_F(rgba), true);
460 _updatingrgba = FALSE;
461 }
462 }
463 }
465 void ColorNotebook::_updateRgbaEntry( const SPColor& color, gfloat alpha )
466 {
467 g_return_if_fail( ( 0.0 <= alpha ) && ( alpha <= 1.0 ) );
469 if ( !_updatingrgba )
470 {
471 gchar s[32];
472 guint32 rgba;
474 /* Update RGBA entry */
475 rgba = sp_color_get_rgba32_falpha (&color, alpha);
477 g_snprintf (s, 32, "%08x", rgba);
478 const gchar* oldText = gtk_entry_get_text( GTK_ENTRY( _rgbae ) );
479 if ( strcmp( oldText, s ) != 0 )
480 {
481 g_signal_handler_block( _rgbae, _entryId );
482 gtk_entry_set_text( GTK_ENTRY(_rgbae), s );
483 g_signal_handler_unblock( _rgbae, _entryId );
484 }
485 }
486 }
488 void ColorNotebook::_entryGrabbed (SPColorSelector *, SPColorNotebook *colorbook)
489 {
490 ColorNotebook* nb = (ColorNotebook*)(SP_COLOR_SELECTOR(colorbook)->base);
491 nb->_grabbed();
492 }
494 void ColorNotebook::_entryDragged (SPColorSelector *csel, SPColorNotebook *colorbook)
495 {
496 gboolean oldState;
497 ColorNotebook* nb = (ColorNotebook*)(SP_COLOR_SELECTOR(colorbook)->base);
499 oldState = nb->_dragging;
501 nb->_dragging = TRUE;
502 nb->_entryModified( csel, colorbook );
504 nb->_dragging = oldState;
505 }
507 void ColorNotebook::_entryReleased (SPColorSelector *, SPColorNotebook *colorbook)
508 {
509 ColorNotebook* nb = (ColorNotebook*)(SP_COLOR_SELECTOR(colorbook)->base);
510 nb->_released();
511 }
513 void ColorNotebook::_entryChanged (SPColorSelector *csel, SPColorNotebook *colorbook)
514 {
515 gboolean oldState;
516 ColorNotebook* nb = (ColorNotebook*)(SP_COLOR_SELECTOR(colorbook)->base);
518 oldState = nb->_dragging;
520 nb->_dragging = FALSE;
521 nb->_entryModified( csel, colorbook );
523 nb->_dragging = oldState;
524 }
526 void ColorNotebook::_entryModified (SPColorSelector *csel, SPColorNotebook *colorbook)
527 {
528 g_return_if_fail (colorbook != NULL);
529 g_return_if_fail (SP_IS_COLOR_NOTEBOOK (colorbook));
530 g_return_if_fail (csel != NULL);
531 g_return_if_fail (SP_IS_COLOR_SELECTOR (csel));
533 ColorNotebook* nb = (ColorNotebook*)(SP_COLOR_SELECTOR(colorbook)->base);
534 SPColor color;
535 gfloat alpha = 1.0;
537 csel->base->getColorAlpha( color, &alpha );
538 nb->_updateRgbaEntry( color, alpha );
539 nb->_updateInternals( color, alpha, nb->_dragging );
540 }
542 GtkWidget* ColorNotebook::addPage(GType page_type, guint submode)
543 {
544 GtkWidget *page;
546 page = sp_color_selector_new ( page_type, SP_COLORSPACE_TYPE_NONE);
547 if ( page )
548 {
549 GtkWidget* tab_label = 0;
550 SPColorSelector* csel;
552 csel = SP_COLOR_SELECTOR (page);
553 if ( submode > 0 )
554 {
555 csel->base->setSubmode( submode );
556 }
557 gtk_widget_show (page);
558 int index = csel->base ? csel->base->getSubmode() : 0;
559 const gchar* str = _(SP_COLOR_SELECTOR_GET_CLASS (csel)->name[index]);
560 // g_message( "Hitting up for tab for '%s'", str );
561 tab_label = gtk_label_new(_(str));
562 gtk_notebook_append_page( GTK_NOTEBOOK (_book), page, tab_label );
563 gtk_signal_connect (GTK_OBJECT (page), "grabbed", GTK_SIGNAL_FUNC (_entryGrabbed), _csel);
564 gtk_signal_connect (GTK_OBJECT (page), "dragged", GTK_SIGNAL_FUNC (_entryDragged), _csel);
565 gtk_signal_connect (GTK_OBJECT (page), "released", GTK_SIGNAL_FUNC (_entryReleased), _csel);
566 gtk_signal_connect (GTK_OBJECT (page), "changed", GTK_SIGNAL_FUNC (_entryChanged), _csel);
567 }
569 return page;
570 }
572 GtkWidget* ColorNotebook::getPage(GType page_type, guint submode)
573 {
574 gint count = 0;
575 gint i = 0;
576 GtkWidget* page = 0;
578 // count = gtk_notebook_get_n_pages (_book);
579 count = 200;
580 for ( i = 0; i < count && !page; i++ )
581 {
582 page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (_book), i);
583 if ( page )
584 {
585 SPColorSelector* csel;
586 guint pagemode;
587 csel = SP_COLOR_SELECTOR (page);
588 pagemode = csel->base->getSubmode();
589 if ( G_TYPE_FROM_INSTANCE (page) == page_type
590 && pagemode == submode )
591 {
592 // found it.
593 break;
594 }
595 else
596 {
597 page = 0;
598 }
599 }
600 else
601 {
602 break;
603 }
604 }
605 return page;
606 }
608 void ColorNotebook::removePage( GType page_type, guint submode )
609 {
610 GtkWidget *page = 0;
612 page = getPage(page_type, submode);
613 if ( page )
614 {
615 gint where = gtk_notebook_page_num (GTK_NOTEBOOK (_book), page);
616 if ( where >= 0 )
617 {
618 if ( gtk_notebook_get_current_page (GTK_NOTEBOOK (_book)) == where )
619 {
620 // getColorAlpha(_color, &_alpha);
621 }
622 gtk_notebook_remove_page (GTK_NOTEBOOK (_book), where);
623 }
624 }
625 }