1 /**************************************************************************\
2 * Copyright (c) Kongsberg Oil & Gas Technologies AS
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 *
12 * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * Neither the name of the copyright holder nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 \**************************************************************************/
32
33 #include <qlayout.h>
34 #include <qbutton.h>
35 #include <qchkbox.h>
36 #include <qradiobt.h>
37 #include <qlabel.h>
38 #include <qbttngrp.h>
39 #include <qpopmenu.h>
40 #include <qpushbt.h>
41 #include <qmenubar.h>
42 #include <qgl.h>
43
44 #include <Inventor/nodes/SoMaterial.h>
45 #include <Inventor/fields/SoField.h>
46 #include <Inventor/fields/SoMFColor.h>
47
48 #include <soqtdefs.h>
49 #include <Inventor/Qt/SoQtColorSlider.h>
50 #include <Inventor/Qt/SoGLMaterialSphere.h>
51 #include <Inventor/Qt/QColorSelection.h>
52 #include <Inventor/Qt/SoQtMaterialList.h>
53
54 #include <Inventor/Qt/SoQtMaterialEditor.h>
55
56 static char * colorStrings[] = {
57 "Ambient", "Diffuse", "Specular", "Emission"
58 };
59
60 #ifndef _GCC_
61 # define true TRUE
62 # define false FALSE
63 #endif
64
65 #define colors2QColor(index) \
66 QColor((int)(colors[index]->getValues(0)->getValue()[0] * 255.0), \
67 (int)(colors[index]->getValues(0)->getValue()[1] * 255.0), \
68 (int) (colors[index]->getValues(0)->getValue()[2] * 255.0))
69
SoQtMaterialEditor(QWidget * parent,const char * name,SbBool buildInsideParent)70 SoQtMaterialEditor::SoQtMaterialEditor(QWidget *parent, const char *name, SbBool buildInsideParent) : SoQtComponent(parent)
71 {
72 materialList = NULL;
73
74 mgrWidget = new QWidget(buildInsideParent ? parent : (QWidget*) NULL, name);
75 widget = mgrWidget;
76
77 QHBoxLayout* hbox = new QHBoxLayout(widget, 5);
78
79 /*
80 * The Menu
81 */
82 menu = new QPopupMenu;
83
84 menu->insertItem("Material List", this, SLOT(material_list()));
85 menu->insertSeparator();
86 contId = menu->insertItem("Continuous", this, SLOT(continuous()));
87 menu->setItemChecked(contId, true);
88 manuId = menu->insertItem("Manual", this, SLOT(manual()));
89
90 QMenuBar* bar = new QMenuBar(widget);
91 bar->insertItem("&Edit", menu);
92
93 hbox->setMenuBar(bar);
94
95 /*
96 * The Sphere and Accept-button
97 */
98 QVBoxLayout *bbox = new QVBoxLayout/*(widget)*/;
99 hbox->addLayout(bbox);
100 QFrame* frame = new QFrame(widget, NULL, QFrame::Panel | QFrame::Sunken);
101 // frame->setMidLineWidth(2);
102 // frame->setLineWidth(3);
103 frame->setBackgroundColor(QColor("blue"));
104
105 ball = new SoGLMaterialSphere(frame);
106 ball->setFixedSize(150, 150);
107 frame->setFixedSize(ball->size());
108
109 // frame->setMinimumSize(frame->sizeHint());
110
111 bbox->addStretch(5);
112 bbox->addWidget(frame);
113
114 acceptButton = new QPushButton("Accept", widget);
115 acceptButton->setFixedSize(acceptButton->sizeHint());
116 connect(acceptButton, SIGNAL(pressed()), this, SLOT(accept()));
117
118
119 bbox->addStretch(4);
120 bbox->addWidget(acceptButton);
121 bbox->addStretch(5);
122
123 acceptButton->hide();
124
125
126
127 /*
128 * Sliders and checkboxes
129 */
130
131 #if 0
132 QGridLayout *grid;
133 grid = new QGridLayout(7, 3, 5);
134 #else
135 QVBoxLayout *grid;
136 grid = new QVBoxLayout(widget, 0, -1, "grid");
137 #endif
138
139 #if 0
140 grid->setColStretch(0, 1);
141 grid->setColStretch(1, 1);
142 grid->setColStretch(2, 10);
143 #endif
144
145 QLabel * lab = new QLabel("Edit Color", widget);
146 lab->setMinimumSize(lab->sizeHint());
147 #if 0
148 grid->addMultiCellWidget(lab, 0, 0, 0, 2);
149 #else
150 grid->addWidget(lab, AlignLeft);
151 #endif
152
153 QButtonGroup *buttonGroup;
154 buttonGroup = new QButtonGroup;
155
156 #if 0
157 radioButtons[0] = new QRadioButton(widget);
158 radioButtons[0]->setMinimumSize(radioButtons[0]->sizeHint());
159 grid->addWidget(radioButtons[0], 1, 0);
160 buttonGroup->insert(radioButtons[0]);
161
162 radioButtons[1] = new QRadioButton(widget);
163 radioButtons[1]->setMinimumSize(radioButtons[1]->sizeHint());
164 grid->addWidget(radioButtons[1], 2, 0);
165 buttonGroup->insert(radioButtons[1]);
166
167 radioButtons[2] = new QRadioButton(widget);
168 radioButtons[2]->setMinimumSize(radioButtons[2]->sizeHint());
169 grid->addWidget(radioButtons[2], 3, 0);
170 buttonGroup->insert(radioButtons[2]);
171
172 radioButtons[3] = new QRadioButton(widget);
173 radioButtons[3]->setMinimumSize(radioButtons[3]->sizeHint());
174 grid->addWidget(radioButtons[3], 4, 0);
175 buttonGroup->insert(radioButtons[3]);
176 #else
177 for (int i = 0; i < 4; i++) {
178 radioButtons[i] = new QRadioButton(widget);
179 radioButtons[i]->setMinimumSize(radioButtons[i]->sizeHint());
180 buttonGroup->insert(radioButtons[i]);
181 #if 0
182 grid->addWidget(radioButtons[i], i + 1, 0);
183 #endif
184 }
185 #endif
186
187
188 #if 0
189 checkButtons[0] = new QCheckBox(widget);
190 checkButtons[0]->setMinimumSize(checkButtons[0]->sizeHint());
191 grid->addWidget(checkButtons[0], 1, 1);
192 checkButtons[1] = new QCheckBox(widget);
193 checkButtons[1]->setMinimumSize(checkButtons[1]->sizeHint());
194 grid->addWidget(checkButtons[1], 2, 1);
195 checkButtons[2] = new QCheckBox(widget);
196 checkButtons[2]->setMinimumSize(checkButtons[2]->sizeHint());
197 grid->addWidget(checkButtons[2], 3, 1);
198 checkButtons[3] = new QCheckBox(widget);
199 checkButtons[3]->setMinimumSize(checkButtons[3]->sizeHint());
200 grid->addWidget(checkButtons[3], 4, 1);
201 #else
202 for (int i = 0; i < 4; i++) {
203 checkButtons[i] = new QCheckBox(widget);
204 checkButtons[i]->setMinimumSize(checkButtons[i]->sizeHint());
205 #if 0
206 grid->addWidget(checkButtons[i], i+1, 1);
207 #endif
208 }
209 #endif
210
211
212 sliders[0] = new _SoQtColorSlider(0, 100, widget, "Amb:");
213 sliders[0]->setMinimumSize( sliders[0]->sizeHint());
214 sliders[0]->setFixedHeight(sliders[0]->sizeHint().height());
215 sliders[1] = new _SoQtColorSlider(0, 100, widget, "Diff:");
216 sliders[1]->setMinimumSize( sliders[1]->sizeHint());
217 sliders[1]->setFixedHeight(sliders[1]->sizeHint().height());
218 sliders[2] = new _SoQtColorSlider(0, 100, widget, "Spec:");
219 sliders[2]->setMinimumSize( sliders[2]->sizeHint());
220 sliders[2]->setFixedHeight(sliders[2]->sizeHint().height());
221 sliders[3] = new _SoQtColorSlider(0, 100, widget, "Emis:");
222 sliders[3]->setMinimumSize( sliders[3]->sizeHint());
223 sliders[3]->setFixedHeight(sliders[3]->sizeHint().height());
224 sliders[4] = new _SoQtColorSlider(0, 100, widget, "Shininess:");
225 sliders[4]->setMinimumSize( sliders[0]->sizeHint());
226 sliders[4]->setFixedHeight(sliders[0]->height());
227 sliders[5] = new _SoQtColorSlider(0, 100, widget, "Transp:");
228 sliders[5]->setMinimumSize( sliders[0]->sizeHint());
229 sliders[5]->setFixedHeight(sliders[0]->height());
230
231 #if 0
232 grid->addWidget(sliders[0], 1, 2);
233 grid->addWidget(sliders[1], 2, 2);
234 grid->addWidget(sliders[2], 3, 2);
235 grid->addWidget(sliders[3], 4, 2);
236 grid->addWidget(sliders[4], 5, 2);
237 grid->addWidget(sliders[5], 6, 2);
238 #endif
239 QHBoxLayout *tempBox;
240 for (int i = 0; i < 4; i++) {
241 tempBox = new QHBoxLayout(5, "tempBox");
242 grid->addLayout(tempBox, 10);
243 tempBox->addWidget(radioButtons[i]);
244 tempBox->addWidget(checkButtons[i]);
245 tempBox->addWidget(sliders[i], 10, AlignRight);
246 }
247 grid->addStretch(5);
248 tempBox = new QHBoxLayout(5, "lastBox");
249 grid->addLayout(tempBox, 10);
250 tempBox->addStretch(1);
251 tempBox->addWidget(sliders[4], 10, AlignRight);
252 tempBox = new QHBoxLayout(5, "lastBox");
253 grid->addLayout(tempBox, 10);
254 tempBox->addStretch(1);
255 tempBox->addWidget(sliders[5], 10, AlignRight);
256
257 hbox->addLayout(grid, 10);
258 hbox->activate();
259
260 widget->setMinimumHeight(sliders[0]->sizeHint().height() * 6 + lab->sizeHint().height());
261 widget->setMinimumWidth(150 + lab->width());
262
263 colorSelection = new QColorSelection;
264 colorSelection->hide();
265 QObject::connect(colorSelection, SIGNAL(closed()), this, SLOT(clearAllButtons()));
266
267 for (int i = 0; i < 4; i++) {
268 QObject::connect(radioButtons[i], SIGNAL(clicked()), this, SLOT(rButtonPressed()));
269 QObject::connect(checkButtons[i], SIGNAL(clicked()), this, SLOT(cButtonPressed()));
270 }
271
272 QObject::connect(colorSelection, SIGNAL(colorChanged(QColor&)), this, SLOT(colorChanged(QColor&)));
273
274 connectUpdaters();
275
276 dummyMaterial = new SoMaterial;
277 // dummyMaterial->setToDefaults(); <--- causes a segfault
278 attach(dummyMaterial);
279
280 }
281
~SoQtMaterialEditor()282 SoQtMaterialEditor::~SoQtMaterialEditor()
283 {
284 // delete dummyMaterial;
285 }
286
componentClassName() const287 const char* SoQtMaterialEditor::componentClassName() const
288 {
289 return "SoQtMaterialEditor";
290 }
291
material_list()292 void SoQtMaterialEditor::material_list()
293 {
294 menu->hide();
295 if (materialList == NULL) {
296 materialList = new SoQtMaterialList;
297 QObject::connect(materialList, SIGNAL(materialSelected(SoMaterial *)),
298 this, SLOT(setMaterial(SoMaterial *)));
299 }
300 materialList->show();
301 }
302
continuous()303 void SoQtMaterialEditor::continuous()
304 {
305 menu->hide();
306 if (updatefreq == SoQtMaterialEditor::CONTINUOUS) return;
307 updatefreq = SoQtMaterialEditor::CONTINUOUS;
308
309 menu->setItemChecked(contId, true);
310 menu->setItemChecked(manuId, false);
311 acceptButton->hide();
312 connectUpdaters();
313 }
314
manual()315 void SoQtMaterialEditor::manual()
316 {
317 menu->hide();
318 if (updatefreq == SoQtMaterialEditor::AFTER_ACCEPT) return;
319 updatefreq = SoQtMaterialEditor::AFTER_ACCEPT;
320 if (menu->isItemChecked(manuId)) return;
321 menu->setItemChecked(contId, false);
322 menu->setItemChecked(manuId, true);
323 acceptButton->show();
324 connectUpdaters(false);
325 }
326
accept()327 void SoQtMaterialEditor::accept()
328 {
329 ball->setAmbient(sliders[0]->getValue() / 100.0);
330 ball->setDiffuse(sliders[1]->getValue() / 100.0);
331 ball->setSpecular(sliders[2]->getValue() / 100.0);
332 ball->setEmission(sliders[3]->getValue() / 100.0);
333 ball->setShininess(sliders[4]->getValue() / 100.0);
334 ball->setTransparency(sliders[5]->getValue() / 100.0);
335 emit materialChanged();
336 }
337
menu_popup()338 void SoQtMaterialEditor::menu_popup()
339 {
340 QPoint pos;
341 pos = menuButton->mapToGlobal(menuButton->pos());
342 pos.setY(pos.y() + menuButton->height());
343 menu->popup(pos);
344 }
345
attach(SoMaterial * mat,int index)346 void SoQtMaterialEditor::attach(SoMaterial *mat, int index)
347 {
348 printf("attach %p\n", mat);
349 material = mat;
350 printf("ball->setMaterial...");
351 ball->setMaterial(material);
352 printf("done\n");
353 colors[0] = &(material->ambientColor);
354 colors[1] = &(material->diffuseColor);
355 colors[2] = &(material->specularColor);
356 colors[3] = &(material->emissiveColor);
357
358 ball->setRepaint(false);
359 printf("sliders - setvalues...");
360 sliders[0]->setValue((int) (colors[0]->getValues(0)->getValue()[0] * 100.0f));
361 sliders[1]->setValue((int) (colors[1]->getValues(0)->getValue()[0] * 100.0f));
362 sliders[2]->setValue((int) (colors[2]->getValues(0)->getValue()[0] * 100.0f));
363 sliders[3]->setValue((int) (colors[3]->getValues(0)->getValue()[0] * 100.0f));
364 sliders[4]->setValue((int) (material->shininess[0] * 100.0f));
365 printf("transparency = %f\n", material->transparency[0]);
366 if (material != dummyMaterial) {
367 printf("\tsetValue sliders[5]...");
368 sliders[5]->setValue((int) (material->transparency[0] * 100.0f));
369 printf("\tdone\n");
370 }
371 printf("done\n");
372 // ball->setRepaint(true);
373 // ball->repaintSphere();
374
375 printf("sliders - setcolor...");
376 sliders[0]->setColor(colors2QColor(0));
377 sliders[1]->setColor(colors2QColor(1));
378 sliders[2]->setColor(colors2QColor(2));
379 sliders[3]->setColor(colors2QColor(3));
380 printf("done\n");
381 }
382
detach()383 void SoQtMaterialEditor::detach()
384 {
385 attach(dummyMaterial);
386 }
387
isAttached()388 SbBool SoQtMaterialEditor::isAttached()
389 {
390 if (material == dummyMaterial) return false;
391 else return true;
392 }
393
setUpdateFrequency(SoQtMaterialEditor::UpdateFrequency freq)394 void SoQtMaterialEditor::setUpdateFrequency(
395 SoQtMaterialEditor::UpdateFrequency freq)
396 {
397 switch (freq) {
398 case SoQtMaterialEditor::CONTINUOUS:
399 continuous();
400 break;
401 case SoQtMaterialEditor::AFTER_ACCEPT:
402 manual();
403 break;
404 }
405 }
406
getUpdateFrequency()407 SoQtMaterialEditor::UpdateFrequency SoQtMaterialEditor::getUpdateFrequency()
408 {
409 return updatefreq;
410 }
411
setMaterial(SoMaterial * mat)412 void SoQtMaterialEditor::setMaterial(SoMaterial *mat)
413 {
414 printf("setMaterial\n");
415 attach(mat);
416 }
417
getMaterial() const418 const SoMaterial& SoQtMaterialEditor::getMaterial() const
419 {
420 return *material;
421 }
422
423
rButtonPressed()424 void SoQtMaterialEditor::rButtonPressed()
425 {
426 int i;
427 for (i = 0; i < 4; i++) {
428 if (((QRadioButton*)(radioButtons[i]))->isChecked()) break;
429 }
430 if (i == 4) {
431 /*
432 * No button is checked, remove dialog if present.
433 */
434 if (colorSelection->isVisible()) colorSelection->hide();
435 clearAllButtons();
436 } else {
437 for (int j = 0; j < 4; j++) {
438 checkButtons[j]->setChecked(j == i ? true : false);
439 }
440 colorSelection->setType(colorStrings[i]);
441 // colorSelection->setColor(QColor((int)colors[i]->getValues(0)->getValue()[0] * 255, (int)colors[i]->getValues(0)->getValue()[1] * 255, (int) colors[i]->getValues(0)->getValue()[2] * 255));
442 printf("color2QColor\n"); \
443 colorSelection->setColor(colors2QColor(i));
444 colorSelection->show();
445 }
446 }
447
cButtonPressed()448 void SoQtMaterialEditor::cButtonPressed()
449 {
450 bool pressed[] = { false, false, false, false };
451 int numPressed = 0;
452 int i;
453 for (i = 0; i < 4; i++) {
454 if (checkButtons[i]->isChecked()) {
455 pressed[i] = true;
456 numPressed++;
457 }
458 }
459 if (numPressed == 0) {
460 clearAllButtons();
461 colorSelection->hide();
462 } else if (numPressed == 1) {
463 for (i = 0; pressed[i] == false; i++);
464 radioButtons[i]->setChecked(true);
465 if (colorSelection->isVisible() == false) colorSelection->show();
466 colorSelection->setType(colorStrings[i]);
467 printf("color2QColor\n"); \
468 colorSelection->setColor(colors2QColor(i));
469 } else {
470 char colorString[41];
471 int length = 0;
472 for (i = 0; i < 4; i++) {
473 radioButtons[i]->setChecked(false);
474 if (pressed[i]) {
475 #ifdef linux
476 snprintf(colorString + length, 40 - length, "%s", colorStrings[i]);
477 #else
478 sprintf(colorString + length, "%s", colorStrings[i]);
479 #endif
480 length += strlen(colorStrings[i]);
481 }
482 colorString[length] = '\0';
483 }
484 colorSelection->setType(colorString);
485 if (colorSelection->isVisible() == false) colorSelection->show();
486 }
487 }
488
clearAllButtons()489 void SoQtMaterialEditor::clearAllButtons()
490 {
491 for (int i = 0; i < 4; i++) {
492 radioButtons[i]->setChecked(false);
493 checkButtons[i]->setChecked(false);
494 }
495 }
496
colorChanged(QColor & col)497 void SoQtMaterialEditor::colorChanged(QColor &col)
498 {
499 printf("colorChanged(%i, %i, %i)\n", col.red(), col.green(), col.blue());
500 bool pressed[] = { false, false, false, false };
501 for (int i = 0; i < 4; i++) {
502 if (checkButtons[i]->isChecked()) {
503 pressed[i] = true;
504 float cols[3];
505 float factor;
506 cols[0] = (float) col.red() / 255.0f;
507 cols[1] = (float) col.green() / 255.0f;
508 cols[2] = (float) col.blue() / 255.0f;
509 printf("colors[%i] = %f, %f, %f\n", i, cols[0], cols[1], cols[2]);
510 #if 0
511 factor = cols[0];
512 if (factor == 0.0f) {
513 factor = 1.0f;
514 cols[0] = 0.0f;
515 } else {
516 cols[0] = 1.0f;
517 cols[1] = cols[1] / factor;
518 cols[2] = cols[2] / factor;
519 }
520 sliders[i]->setValue((int)(factor * 100.f));
521 #endif
522 printf("cols[%i] = %f, %f, %f, factor = %f\n", i, cols[0], cols[1], cols[2], factor);
523 colors[i]->setValue(cols);
524 sliders[i]->setColor(col);
525 }
526 }
527 emit materialChanged();
528 }
529
connectUpdaters(bool connect)530 void SoQtMaterialEditor::connectUpdaters(bool connect)
531 {
532 bool (*connectFunc) (const QObject *, const char *, const QObject *, const char*);
533
534 if (connect) connectFunc = &QObject::connect;
535 else connectFunc = &QObject::disconnect;
536 (*connectFunc)(sliders[0], SIGNAL(valueChanged(float)), ball, SLOT(setAmbient(float)));
537 (*connectFunc)(sliders[1], SIGNAL(valueChanged(float)), ball, SLOT(setDiffuse(float)));
538 (*connectFunc)(sliders[2], SIGNAL(valueChanged(float)), ball, SLOT(setSpecular(float)));
539 (*connectFunc)(sliders[3], SIGNAL(valueChanged(float)), ball, SLOT(setEmission(float)));
540 (*connectFunc)(sliders[4], SIGNAL(valueChanged(float)), ball, SLOT(setShininess(float)));
541 (*connectFunc)(sliders[5], SIGNAL(valueChanged(float)), ball, SLOT(setTransparency(float)));
542
543 (*connectFunc)(sliders[0], SIGNAL(valueChanged(float)), this, SIGNAL(materialChanged()));
544 (*connectFunc)(sliders[1], SIGNAL(valueChanged(float)), this, SIGNAL(materialChanged()));
545 (*connectFunc)(sliders[2], SIGNAL(valueChanged(float)), this, SIGNAL(materialChanged()));
546 (*connectFunc)(sliders[3], SIGNAL(valueChanged(float)), this, SIGNAL(materialChanged()));
547 (*connectFunc)(sliders[4], SIGNAL(valueChanged(float)), this, SIGNAL(materialChanged()));
548 (*connectFunc)(sliders[5], SIGNAL(valueChanged(float)), this, SIGNAL(materialChanged()));
549 (*connectFunc)(this, SIGNAL(materialChanged()), ball, SLOT(repaintSphere()));
550 }
551