1
/**************************************************************************\
3
* This file is part of the Coin 3D visualization library.
4
* Copyright (C) 1998-2005 by Systems in Motion. All rights reserved.
6
* This library is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU General Public License
8
* ("GPL") version 2 as published by the Free Software Foundation.
9
* See the file LICENSE.GPL at the root directory of this source
10
* distribution for additional information about the GNU GPL.
12
* For using Coin with software that can not be combined with the GNU
13
* GPL, and for taking advantage of the additional benefits of our
14
* support services, please contact Systems in Motion about acquiring
15
* a Coin Professional Edition License.
17
* See <URL:http://www.coin3d.org/> for more information.
19
* Systems in Motion, Postboks 1283, Pirsenteret, 7462 Trondheim, NORWAY.
20
* <URL:http://www.sim.no/>.
22
\**************************************************************************/
24
// FIXME: overload the getClassName() type functions
26
#include <Inventor/SbPList.h>
27
#include <Inventor/SoSceneManager.h>
28
#include <Inventor/fields/SoSFColor.h>
29
#include <Inventor/fields/SoMFColor.h>
30
#include <Inventor/fields/SoMFUInt32.h>
31
#include <Inventor/nodes/SoSeparator.h>
32
#include <Inventor/nodes/SoTexture2.h>
33
#include <Inventor/sensors/SoFieldSensor.h>
34
#include <Inventor/actions/SoGLRenderAction.h>
36
#include <Inventor/@Gui@/SoAny.h>
37
#include <Inventor/@Gui@/nodes/SoGuiViewportFix.h>
38
#include <Inventor/@Gui@/nodes/SoGuiColorEditor.h>
39
#include <Inventor/@Gui@/editors/So@Gui@ColorEditor.h>
42
#include <Inventor/@Gui@/nodes/SoGuiPane.h>
43
#include <Inventor/@Gui@/nodes/SoGuiClickCounter.h>
44
#include <Inventor/@Gui@/nodes/SoGuiSlider1.h>
45
#include <Inventor/@Gui@/nodes/SoGuiSlider2.h>
50
\class So@Gui@ColorEditor Inventor/@Gui@/editors/So@Gui@ColorEditor.h
51
\brief The So@Gui@ColorEditor class is a GUI component for interactively
56
\enum So@Gui@ColorEditor::Sliders
60
\val So@Gui@ColorEditor::NONE
64
\val So@Gui@ColorEditor::INTENSITY
68
\val So@Gui@ColorEditor::RGB
72
\val So@Gui@ColorEditor::HSV
76
\val So@Gui@ColorEditor::RGB_V
80
\val So@Gui@ColorEditor::RGB_HSV
84
\enum So@Gui@ColorEditor::UpdateFrequency
88
\val So@Gui@ColorEditor::CONTINUOUS
92
\val So@Gui@ColorEditor::AFTER_ACCEPT
95
// *************************************************************************
97
static const SbBool SGI_ATTACHMENT_REF_COMPATIBILITY = TRUE;
106
// Name suffix used to avoid conflict with private part of the ColorEditor
109
class ColorEditorComponent {
111
So@Gui@ColorEditor * api;
113
static const char * superscene[];
117
// attachment is redundant - the existence of the field sensor, and the
118
// field type it is attached to is all the info needed really
119
Attachment attachment;
120
// the field pointers can actually be dropped since the sensor will have
124
SoMFUInt32 * mfuint32;
127
SoFieldSensor * editor_sensor;
128
static void editor_update_cb(void * closure, SoSensor * sensor);
130
SoFieldSensor * attachment_sensor;
131
static void attachment_update_cb(void * closure, SoSensor * sensor);
133
SoGuiColorEditor * editor;
135
void invokeColorChangeCallbacks(void);
136
SbBool colorsEqual(void);
139
// *************************************************************************
141
SO@GUI@_OBJECT_SOURCE(So@Gui@ColorEditor);
143
#define PRIVATE(obj) ((ColorEditorComponent *) ((So@Gui@ColorEditor *) obj)->internals)
144
#define PUBLIC(obj) (((ColorEditorComponent *) obj)->api)
146
So@Gui@ColorEditor::So@Gui@ColorEditor(@WIDGET@ parent, const char * name, SbBool embed)
147
: inherited(parent, name, embed)
149
this->internals = (void *) new ColorEditorComponent;
150
PRIVATE(this)->api = this;
152
PRIVATE(this)->attachment = DETACHED;
153
PRIVATE(this)->sfcolor = NULL;
154
PRIVATE(this)->sfcolor = NULL;
155
PRIVATE(this)->mfcolor = NULL;
156
PRIVATE(this)->mfuint32 = NULL;
157
PRIVATE(this)->mfindex = 0;
159
PRIVATE(this)->editor_sensor = NULL;
160
PRIVATE(this)->attachment_sensor = NULL;
162
PRIVATE(this)->editor = NULL;
164
this->setSize(SbVec2s(320, 256));
166
SoNode * root = SoAny::loadSceneGraph(ColorEditorComponent::superscene);
167
assert(root != NULL);
168
assert(root->isOfType(SoSeparator::getClassTypeId()));
169
SoSeparator * superscene = (SoSeparator *) root;
171
PRIVATE(this)->editor = new SoGuiColorEditor;
172
superscene->addChild(PRIVATE(this)->editor);
173
this->setSceneGraph(superscene);
175
PRIVATE(this)->attachment_sensor = new SoFieldSensor(ColorEditorComponent::attachment_update_cb, PRIVATE(this));
177
PRIVATE(this)->editor_sensor = new SoFieldSensor(ColorEditorComponent::editor_update_cb, PRIVATE(this));
178
PRIVATE(this)->editor_sensor->attach(&(PRIVATE(this)->editor->color));
181
So@Gui@ColorEditor::~So@Gui@ColorEditor(void)
183
if ( PRIVATE(this)->attachment != DETACHED ) this->detach();
184
delete PRIVATE(this)->attachment_sensor;
185
delete PRIVATE(this)->editor_sensor;
186
this->setSceneGraph(NULL);
187
ColorEditorComponent * instance = PRIVATE(this);
192
Attach the editor to a color single field. Any existing attachments are
195
The node argument defaults to NULL and is ignored. It is part of the
196
argument list for compatibility reasons.
200
So@Gui@ColorEditor::attach(SoSFColor * color, SoBase * node)
202
if ( PRIVATE(this)->attachment != DETACHED ) this->detach();
203
if ( color != NULL ) {
204
if ( SGI_ATTACHMENT_REF_COMPATIBILITY ) {
205
SoFieldContainer * container = color->getContainer();
206
if ( container != NULL ) container->ref();
208
PRIVATE(this)->attachment = SFCOLOR;
209
PRIVATE(this)->sfcolor = color;
210
assert(PRIVATE(this)->attachment_sensor != NULL);
211
PRIVATE(this)->attachment_sensor->attach(color);
212
PRIVATE(this)->editor->color.setValue(color->getValue());
217
Attach the editor to an element in a color multi field. Any existing attachments are
220
The node argument defaults to NULL and is ignored. It is part of the
221
argument list for compatibility reasons.
225
So@Gui@ColorEditor::attach(SoMFColor * color, int idx, SoBase * node)
227
if ( PRIVATE(this)->attachment != DETACHED ) this->detach();
228
if ( color != NULL ) {
229
if ( SGI_ATTACHMENT_REF_COMPATIBILITY ) {
230
SoFieldContainer * container = color->getContainer();
231
if ( container != NULL ) container->ref();
233
PRIVATE(this)->attachment = MFCOLOR;
234
PRIVATE(this)->mfcolor = color;
235
PRIVATE(this)->mfindex = idx;
236
assert(PRIVATE(this)->attachment_sensor != NULL);
237
PRIVATE(this)->attachment_sensor->attach(color);
238
PRIVATE(this)->editor->color.setValue(color->operator[](idx));
243
Attach the editor to an element in an uint32 multi field. The field
244
is assumed to be of the RGBA packed color format. Any existing attachments are
247
The node argument defaults to NULL and is ignored. It is part of the
248
argument list for compatibility reasons.
252
So@Gui@ColorEditor::attach(SoMFUInt32 * color, int idx, SoBase * node)
254
if ( PRIVATE(this)->attachment != DETACHED ) this->detach();
255
if ( color != NULL ) {
256
if ( SGI_ATTACHMENT_REF_COMPATIBILITY ) {
257
SoFieldContainer * container = color->getContainer();
258
if ( container != NULL ) container->ref();
260
PRIVATE(this)->attachment = MFUINT32;
261
PRIVATE(this)->mfuint32 = color;
262
PRIVATE(this)->mfindex = idx;
263
assert(PRIVATE(this)->attachment_sensor != NULL);
264
PRIVATE(this)->attachment_sensor->attach(color);
266
float transparency = 0.0f;
267
col.setPackedValue(color->operator[](idx), transparency);
268
PRIVATE(this)->editor->color.setValue(col);
273
Detach the editor from the field it is attached to.
277
So@Gui@ColorEditor::detach(void)
279
if ( PRIVATE(this)->attachment != DETACHED ) {
280
SoField * field = NULL;
281
switch ( PRIVATE(this)->attachment ) {
283
field = PRIVATE(this)->sfcolor;
284
PRIVATE(this)->sfcolor = NULL;
287
field = PRIVATE(this)->mfcolor;
288
PRIVATE(this)->mfcolor = NULL;
291
field = PRIVATE(this)->mfuint32;
292
PRIVATE(this)->mfuint32 = NULL;
296
assert(0 && "impossible switch case");
299
assert(field != NULL);
300
if ( field != NULL ) {
301
assert(PRIVATE(this)->attachment_sensor != NULL);
302
PRIVATE(this)->attachment_sensor->detach();
303
if ( SGI_ATTACHMENT_REF_COMPATIBILITY ) {
304
SoFieldContainer * container = field->getContainer();
305
if ( container != NULL ) container->unref();
308
PRIVATE(this)->attachment = DETACHED;
313
This method returns whether or not the editor is currently attached to a field.
317
So@Gui@ColorEditor::isAttached(void) const
319
return (PRIVATE(this)->attachment != DETACHED) ? TRUE : FALSE;
323
Add a callback to be triggered when the color value is changed.
325
\sa So@Gui@ColorEditor::setUpdateFrequency
329
So@Gui@ColorEditor::addColorChangedCallback(So@Gui@ColorEditorCB * callback, void * closure)
331
PRIVATE(this)->callbacks.append((void *) callback);
332
PRIVATE(this)->callbacks.append(closure);
336
Remove all color change callbacks matching the given arguments.
340
So@Gui@ColorEditor::removeColorChangedCallback(So@Gui@ColorEditorCB * callback, void * closure)
342
const int len = PRIVATE(this)->callbacks.getLength();
344
for ( i = 0; i < len; i += 2 ) {
345
So@Gui@ColorEditorCB * cb =
346
(So@Gui@ColorEditorCB *) PRIVATE(this)->callbacks[i];
347
if ( (callback == cb) && (closure == PRIVATE(this)->callbacks[i+1]) ) {
348
PRIVATE(this)->callbacks.remove(i+1);
349
PRIVATE(this)->callbacks.remove(i);
356
Set a new color value.
358
If the field value gets updated, the color change callbacks will be triggered.
362
So@Gui@ColorEditor::setColor(const SbColor & color)
364
// callbacks are triggered on the sensor rebound...
365
switch ( PRIVATE(this)->attachment ) {
369
assert(PRIVATE(this)->sfcolor != NULL);
370
if ( PRIVATE(this)->sfcolor->getValue() != color ) {
371
PRIVATE(this)->sfcolor->setValue(color);
375
assert(PRIVATE(this)->mfcolor != NULL);
376
if ( PRIVATE(this)->mfcolor->operator[](PRIVATE(this)->mfindex) != color ) {
377
PRIVATE(this)->mfcolor->set1Value(PRIVATE(this)->mfindex, color);
381
assert(PRIVATE(this)->mfuint32 != NULL);
382
if ( PRIVATE(this)->mfuint32->operator[](PRIVATE(this)->mfindex) != color.getPackedValue() ) {
383
PRIVATE(this)->mfuint32->set1Value(PRIVATE(this)->mfindex, color.getPackedValue());
387
assert(PRIVATE(this)->editor != NULL);
388
PRIVATE(this)->editor->color.setValue(color);
392
Get the current color value.
396
So@Gui@ColorEditor::getColor(void) const
398
assert(PRIVATE(this)->editor != NULL);
399
return PRIVATE(this)->editor->color.getValue();
405
Sets whether or not the color sliders should be in WYSIWYG mode.
406
When enabled, the color backgrounds in the sliders will be updated to
407
reflect what the color will be, taken all color components into account.
408
When disabled, the color backgrounds only reflect the component the slider
413
So@Gui@ColorEditor::setWYSIWYG(SbBool enable)
415
assert(PRIVATE(this)->editor != NULL);
416
PRIVATE(this)->editor->wysiwyg.setValue(enable);
420
Returns whether or not the editor sliders are in WYSIWYG mode.
424
So@Gui@ColorEditor::isWYSIWYG(void) const
426
assert(PRIVATE(this)->editor != NULL);
427
return PRIVATE(this)->editor->wysiwyg.getValue();
431
Sets which if the slider sets is to be used.
433
\sa So@Gui@ColorEditor::Sliders
437
So@Gui@ColorEditor::setCurrentSliders(So@Gui@ColorEditor::Sliders which)
439
assert(PRIVATE(this)->editor != NULL);
440
PRIVATE(this)->editor->sliders.setValue((So@Gui@ColorEditor::Sliders) which);
444
Returns which slider sets is being used.
446
\sa So@Gui@ColorEditor::Sliders
449
So@Gui@ColorEditor::Sliders
450
So@Gui@ColorEditor::getCurrentSliders(void) const
452
assert(PRIVATE(this)->editor != NULL);
453
return (So@Gui@ColorEditor::Sliders) PRIVATE(this)->editor->sliders.getValue();
457
Sets the update-frequency setting, which affects when color change callbacks
460
\sa So@Gui@ColorEditor::UpdateFrequency
464
So@Gui@ColorEditor::setUpdateFrequency(So@Gui@ColorEditor::UpdateFrequency freq)
466
assert(PRIVATE(this)->editor != NULL);
467
PRIVATE(this)->editor->update.setValue((So@Gui@ColorEditor::UpdateFrequency) freq);
471
Returns the update-frequency setting.
473
\sa So@Gui@ColorEditor::UpdateFrequency
476
So@Gui@ColorEditor::UpdateFrequency
477
So@Gui@ColorEditor::getUpdateFrequency(void) const
479
assert(PRIVATE(this)->editor != NULL);
480
return (So@Gui@ColorEditor::UpdateFrequency) PRIVATE(this)->editor->update.getValue();
484
So@Gui@ColorEditor::getEditor(void) const
486
return PRIVATE(this)->editor;
489
// *************************************************************************
492
So@Gui@ColorEditor::getDefaultWidgetName(void) const
494
static const char widgetName[] = "So@Gui@ColorEditor";
499
So@Gui@ColorEditor::getDefaultTitle(void) const
501
static const char title[] = "ColorEditor";
506
So@Gui@ColorEditor::getDefaultIconTitle(void) const
508
static const char iconTitle[] = "ColEd";
512
// *************************************************************************
513
// ColorEditorComponent
514
// *************************************************************************
517
ColorEditorComponent::superscene[] =
519
"#Inventor V2.1 ascii",
522
" DirectionalLight { direction 0 0 -1 color 1 1 1 intensity 0.8 }",
523
" OrthographicCamera { }",
524
" DEF viewportfix SoGuiViewportFix { }",
525
" Material { ambientColor 0.8 0.8 0.8 }",
530
// *************************************************************************
533
ColorEditorComponent::invokeColorChangeCallbacks(void)
536
for ( i = 0; i < this->callbacks.getLength(); i += 2 ) {
537
So@Gui@ColorEditorCB * callback = (So@Gui@ColorEditorCB *) this->callbacks[i];
538
void * closure = this->callbacks[i+1];
539
callback(closure, &this->editor->color.getValue());
544
ColorEditorComponent::colorsEqual(void)
546
SbColor attachmentColor;
547
switch ( this->attachment ) {
549
assert(this->sfcolor != NULL);
550
attachmentColor = this->sfcolor->getValue();
553
assert(this->mfcolor != NULL);
554
attachmentColor = this->mfcolor->operator[](this->mfindex);
557
assert(this->mfcolor != NULL);
559
float transparency = 0.0f;
560
attachmentColor.setPackedValue(this->mfuint32->operator[](this->mfindex), transparency);
567
return (attachmentColor == this->editor->color.getValue()) ? TRUE : FALSE;
571
ColorEditorComponent::attachment_update_cb(void * closure, SoSensor * sensor)
573
assert(closure != NULL);
574
ColorEditorComponent * me = (ColorEditorComponent *) closure;
575
if ( me->colorsEqual() ) return;
577
switch ( me->attachment ) {
579
assert(me->sfcolor != NULL);
580
me->editor->color.setValue(me->sfcolor->getValue());
583
assert(me->mfcolor != NULL);
584
me->editor->color.setValue(me->mfcolor->operator[](me->mfindex));
587
assert(me->mfcolor != NULL);
590
float transparency = 0.0f;
591
color.setPackedValue(me->mfuint32->operator[](me->mfindex), transparency);
592
me->editor->color.setValue(color);
602
ColorEditorComponent::editor_update_cb(void * closure, SoSensor * sensor)
604
assert(closure != NULL);
605
ColorEditorComponent * me = (ColorEditorComponent *) closure;
606
if ( me->colorsEqual() ) return;
608
SbColor color = me->editor->color.getValue();
610
switch ( me->attachment ) {
612
assert(me->sfcolor != NULL);
613
me->sfcolor->setValue(color);
616
assert(me->mfcolor != NULL);
617
me->mfcolor->set1Value(me->mfindex, color);
620
assert(me->mfuint32 != NULL);
621
me->mfuint32->set1Value(me->mfindex, color.getPackedValue());
628
if ( me->editor->update.getValue() == SoGuiColorEditor::CONTINUOUS )
629
me->invokeColorChangeCallbacks();
632
// *************************************************************************