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