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 // ************************************************************************
34
35 // Class is documented in common/viewers/SoGuiFullViewer.cpp.in.
36
37 // ************************************************************************
38
39 // FIXME: this sourcefile is way too large -- this reeks of bad
40 // design. Should try to factor out lots of stuff. 20010821 mortene.
41
42 // FIXME: can hide more stuff from the public header file into
43 // SoQtFullViewerP -- most or all of the private methods, for
44 // instance. 20010821 mortene.
45
46 // FIXME, low priority:
47 // * add tooltips to the widgets?
48 // * trim length of edit fields
49
50 #ifdef HAVE_CONFIG_H
51 #include <config.h>
52 #endif // HAVE_CONFIG_H
53 #include <qt-config.h>
54
55 #include <qbuttongroup.h>
56 #include <qcheckbox.h>
57 #include <qframe.h>
58 #include <qlabel.h>
59 #include <qlayout.h>
60 #include <qlineedit.h>
61 #include <qmetaobject.h>
62 #include <qpixmap.h>
63 #include <qpushbutton.h>
64 #include <qradiobutton.h>
65 #include <qslider.h>
66
67 #ifdef HAVE_QSTYLEFACTORY_H
68 #include <qstylefactory.h>
69 #endif // HAVE_QSTYLEFACTORY_H
70
71 #include <Inventor/nodes/SoPerspectiveCamera.h>
72 #include <Inventor/nodes/SoOrthographicCamera.h>
73 #include <Inventor/errors/SoDebugError.h>
74
75 #include <Inventor/Qt/viewers/SoQtFullViewerP.h>
76 #include <Inventor/Qt/viewers/moc_SoQtFullViewerP.icc>
77
78 #include <soqtdefs.h>
79 #include <Inventor/Qt/SoQt.h>
80 #include <Inventor/Qt/widgets/SoQtThumbWheel.h>
81 #include <Inventor/Qt/widgets/SoQtPopupMenu.h>
82 #include <Inventor/Qt/viewers/SoQtFullViewer.h>
83 #include <Inventor/Qt/SoAny.h>
84
85 // Button icons.
86 #include <Inventor/Qt/common/pixmaps/pick.xpm>
87 #include <Inventor/Qt/common/pixmaps/view.xpm>
88 #include <Inventor/Qt/common/pixmaps/home.xpm>
89 #include <Inventor/Qt/common/pixmaps/set_home.xpm>
90 #include <Inventor/Qt/common/pixmaps/view_all.xpm>
91 #include <Inventor/Qt/common/pixmaps/seek.xpm>
92
93
94 // ************************************************************************
95
96 // Take care of namespace incompatibilities between Qt 3 and Qt 4.
97
98 #if QT_VERSION < 0x040000 // pre Qt 4
99 #define QTWIDGET_NOFOCUS QWidget::NoFocus
100 #else // Qt 4.0.0+
101 #define QTWIDGET_NOFOCUS Qt::NoFocus
102 #endif // Qt 4.0.0+
103
104 // *************************************************************************
105
106 SOQT_OBJECT_ABSTRACT_SOURCE(SoQtFullViewer);
107
108 // *************************************************************************
109
110 static const int VIEWERBORDER = 2;
111 static const int ZOOMSLIDERRESOLUTION = 200;
112
113 // *************************************************************************
114
115 // Button index values.
116 enum {
117 INTERACT_BUTTON = 0,
118 EXAMINE_BUTTON,
119 HOME_BUTTON,
120 SET_HOME_BUTTON,
121 VIEW_ALL_BUTTON,
122 SEEK_BUTTON
123 };
124
125 // *************************************************************************
126
127 #define PUBLIC(o) (o->pub)
128 #define PRIVATE(o) (o->pimpl)
129
130 // *************************************************************************
131
132 // Documented in common/viewers/SoGuiFullViewer.cpp.in.
SoQtFullViewer(QWidget * parent,const char * name,SbBool embed,SoQtFullViewer::BuildFlag buildFlag,SoQtViewer::Type type,SbBool build)133 SoQtFullViewer::SoQtFullViewer(QWidget * parent,
134 const char * name,
135 SbBool embed,
136 SoQtFullViewer::BuildFlag buildFlag,
137 SoQtViewer::Type type,
138 SbBool build)
139 : inherited(parent, name, embed, type, FALSE)
140 {
141 PRIVATE(this) = new SoQtFullViewerP(this);
142
143 PRIVATE(this)->viewerwidget = NULL;
144 PRIVATE(this)->canvas = NULL;
145 // PRIVATE(this)->canvasparent = NULL;
146
147 PRIVATE(this)->viewbutton = NULL;
148 PRIVATE(this)->interactbutton = NULL;
149
150 this->leftDecoration = NULL;
151 this->bottomDecoration = NULL;
152 this->rightDecoration = NULL;
153
154 this->leftWheel = NULL;
155 this->leftWheelLabel = NULL;
156 this->leftWheelStr = NULL;
157 this->leftWheelVal = 0.0f;
158
159 this->bottomWheel = NULL;
160 this->bottomWheelLabel = NULL;
161 this->bottomWheelStr = NULL;
162 this->bottomWheelVal = 0.0f;
163
164 this->rightWheel = NULL;
165 this->rightWheelLabel = NULL;
166 this->rightWheelStr = NULL;
167 this->rightWheelVal = 0.0f;
168
169 this->setLeftWheelString("Motion X");
170 this->setBottomWheelString("Motion Y");
171 this->setRightWheelString("Dolly");
172
173 PRIVATE(this)->mainlayout = NULL;
174 PRIVATE(this)->appbuttonlayout = NULL;
175
176 PRIVATE(this)->menuenabled = buildFlag & SoQtFullViewer::BUILD_POPUP;
177 PRIVATE(this)->decorations =
178 (buildFlag & SoQtFullViewer::BUILD_DECORATION) ? TRUE : FALSE;
179
180 this->prefmenu = NULL;
181 PRIVATE(this)->menutitle = "Viewer Menu";
182
183 PRIVATE(this)->viewerbuttons = new SbPList;
184 PRIVATE(this)->appbuttonlist = new SbPList;
185 PRIVATE(this)->appbuttonform = NULL;
186
187 this->setSize(SbVec2s(500, 390));
188
189 if (! build) return;
190
191 this->setClassName("SoQtFullViewer");
192 QWidget * viewer = this->buildWidget(this->getParentWidget());
193 this->setBaseWidget(viewer);
194 }
195
196 // *************************************************************************
197
198 // Documented in common/viewers/SoGuiFullViewer.cpp.in.
~SoQtFullViewer()199 SoQtFullViewer::~SoQtFullViewer()
200 {
201 if (PRIVATE(this)->viewerwidget) {
202 this->unregisterWidget(PRIVATE(this)->viewerwidget);
203 }
204
205 delete PRIVATE(this)->viewerbuttons;
206 delete PRIVATE(this)->appbuttonlist;
207
208 delete [] this->leftWheelStr;
209 delete [] this->rightWheelStr;
210 delete [] this->bottomWheelStr;
211
212 delete this->prefmenu;
213
214 delete PRIVATE(this);
215 }
216
217 // *************************************************************************
218
219 // Documented in common/viewers/SoGuiFullViewer.cpp.in.
220 void
setDecoration(const SbBool enable)221 SoQtFullViewer::setDecoration(const SbBool enable)
222 {
223 #if SOQT_DEBUG
224 if ((enable && this->isDecoration()) ||
225 (!enable && !this->isDecoration())) {
226 SoDebugError::postWarning("SoQtFullViewer::setDecoration",
227 "decorations already turned %s",
228 enable ? "on" : "off");
229 return;
230 }
231 #endif // SOQT_DEBUG
232
233 PRIVATE(this)->decorations = enable;
234 if (PRIVATE(this)->viewerwidget)
235 PRIVATE(this)->showDecorationWidgets(enable);
236 }
237
238 // *************************************************************************
239
240 // Documented in common/viewers/SoGuiFullViewer.cpp.in.
241 SbBool
isDecoration(void) const242 SoQtFullViewer::isDecoration(void) const
243 {
244 return PRIVATE(this)->decorations;
245 }
246
247 // *************************************************************************
248
249 // Documented in common/viewers/SoGuiFullViewer.cpp.in.
250 void
setPopupMenuEnabled(const SbBool enable)251 SoQtFullViewer::setPopupMenuEnabled(const SbBool enable)
252 {
253 #if SOQT_DEBUG
254 if ((enable && this->isPopupMenuEnabled()) ||
255 (!enable && !this->isPopupMenuEnabled())) {
256 SoDebugError::postWarning("SoQtFullViewer::setPopupMenuEnabled",
257 "popup menu already turned %s",
258 enable ? "on" : "off");
259 return;
260 }
261 #endif // SOQT_DEBUG
262 PRIVATE(this)->menuenabled = enable;
263 }
264
265 // *************************************************************************
266
267 // Documented in common/viewers/SoGuiFullViewer.cpp.in.
268 SbBool
isPopupMenuEnabled(void) const269 SoQtFullViewer::isPopupMenuEnabled(void) const
270 {
271 return PRIVATE(this)->menuenabled;
272 }
273
274 // *************************************************************************
275
276 // Documented in common/viewers/SoGuiFullViewer.cpp.in.
277 QWidget *
getAppPushButtonParent(void) const278 SoQtFullViewer::getAppPushButtonParent(void) const
279 {
280 return PRIVATE(this)->appbuttonform;
281 }
282
283 // *************************************************************************
284
285 // Documented in common/viewers/SoGuiFullViewer.cpp.in.
286 void
addAppPushButton(QWidget * newButton)287 SoQtFullViewer::addAppPushButton(QWidget * newButton)
288 {
289 PRIVATE(this)->appbuttonlist->append(newButton);
290 PRIVATE(this)->layoutAppButtons(this->getAppPushButtonParent());
291 }
292
293 // *************************************************************************
294
295 // Documented in common/viewers/SoGuiFullViewer.cpp.in.
296 void
insertAppPushButton(QWidget * newButton,int index)297 SoQtFullViewer::insertAppPushButton(QWidget * newButton, int index)
298 {
299 #if SOQT_DEBUG
300 if ((index < 0) || (index > this->lengthAppPushButton())) {
301 SoDebugError::postWarning("SoQtFullViewer::insertAppPushButton",
302 "index %d out of bounds", index);
303 return;
304 }
305 #endif // SOQT_DEBUG
306 PRIVATE(this)->appbuttonlist->insert(newButton, index);
307 PRIVATE(this)->layoutAppButtons(this->getAppPushButtonParent());
308 }
309
310 // *************************************************************************
311
312 // Documented in common/viewers/SoGuiFullViewer.cpp.in.
313 void
removeAppPushButton(QWidget * oldButton)314 SoQtFullViewer::removeAppPushButton(QWidget * oldButton)
315 {
316 int idx = PRIVATE(this)->appbuttonlist->find(oldButton);
317
318 #if SOQT_DEBUG
319 if (idx == -1) {
320 SoDebugError::postWarning("SoQtFullViewer::removeAppPushButton",
321 "tried to remove non-existant button");
322 return;
323 }
324 #endif // SOQT_DEBUG
325
326 PRIVATE(this)->appbuttonlist->remove(idx);
327 PRIVATE(this)->layoutAppButtons(this->getAppPushButtonParent());
328 }
329
330 // *************************************************************************
331
332 // Documented in common/viewers/SoGuiFullViewer.cpp.in.
333 int
findAppPushButton(QWidget * oldButton) const334 SoQtFullViewer::findAppPushButton(QWidget * oldButton) const
335 {
336 return PRIVATE(this)->appbuttonlist->find(oldButton);
337 }
338
339 // *************************************************************************
340
341 // Documented in common/viewers/SoGuiFullViewer.cpp.in.
342 int
lengthAppPushButton(void) const343 SoQtFullViewer::lengthAppPushButton(void) const
344 {
345 return PRIVATE(this)->appbuttonlist->getLength();
346 }
347
348 // *************************************************************************
349
350 // Documented in common/viewers/SoGuiFullViewer.cpp.in.
351 QWidget *
getRenderAreaWidget(void) const352 SoQtFullViewer::getRenderAreaWidget(void) const
353 {
354 return PRIVATE(this)->canvas;
355 }
356
357 // *************************************************************************
358
359 // Documented in superclass. Overridden from parent class to correctly
360 // set the user interface indicators on the current state, i.e. to
361 // flip the examine and interact pushbuttons and to grey out the seek
362 // mode activation button iff in interact mode.
363 void
setViewing(SbBool enable)364 SoQtFullViewer::setViewing(SbBool enable)
365 {
366 if ((enable && this->isViewing()) ||
367 (!enable && !this->isViewing())) {
368 #if SOQT_DEBUG && 0 // debug
369 SoDebugError::postWarning("SoQtFullViewer::setViewing",
370 "view mode already %s", on ? "on" : "off");
371 #endif // debug
372 return;
373 }
374
375 inherited::setViewing(enable);
376
377 // Must check that buttons have been built, in case this viewer
378 // component was made without decorations.
379 if (PRIVATE(this)->viewerbuttons->getLength() > 0) {
380 #if QT_VERSION >= 0x040000
381 PRIVATE(this)->getViewerbutton(EXAMINE_BUTTON)->setChecked(enable);
382 PRIVATE(this)->getViewerbutton(INTERACT_BUTTON)->setChecked(enable ? FALSE : TRUE);
383 #else
384 PRIVATE(this)->getViewerbutton(EXAMINE_BUTTON)->setOn(enable);
385 PRIVATE(this)->getViewerbutton(INTERACT_BUTTON)->setOn(enable ? FALSE : TRUE);
386 #endif
387 PRIVATE(this)->getViewerbutton(SEEK_BUTTON)->setEnabled(enable);
388 }
389 }
390
391 // *************************************************************************
392
393 // Documented in superclass.
394 QWidget *
buildWidget(QWidget * parent)395 SoQtFullViewer::buildWidget(QWidget * parent)
396 {
397 // This will build the main view widgets, along with the decorations
398 // widgets and popup menu if they are enabled.
399
400 #if SOQT_DEBUG && 0
401 SoDebugError::postInfo("SoQtFullViewer::buildWidget", "[invoked]");
402 #endif
403
404 PRIVATE(this)->viewerwidget = new QWidget(parent);
405 this->registerWidget(PRIVATE(this)->viewerwidget);
406
407 PRIVATE(this)->viewerwidget->move(0, 0);
408
409 #if SOQT_DEBUG && 0
410 PRIVATE(this)->viewerwidget->setBackgroundColor(QColor(250, 0, 0));
411 #endif
412
413 PRIVATE(this)->canvas = inherited::buildWidget(PRIVATE(this)->viewerwidget);
414
415 QSize s(PRIVATE(this)->viewerwidget->size().width(),
416 PRIVATE(this)->viewerwidget->size().height());
417
418 PRIVATE(this)->canvas->resize(s);
419
420 this->buildDecoration( PRIVATE(this)->viewerwidget );
421 PRIVATE(this)->showDecorationWidgets( PRIVATE(this)->decorations );
422
423 if (PRIVATE(this)->menuenabled)
424 this->buildPopupMenu();
425
426 return PRIVATE(this)->viewerwidget;
427 }
428
429 // *************************************************************************
430
431 // Documented in common/viewers/SoGuiFullViewer.cpp.in.
432 void
buildDecoration(QWidget * parent)433 SoQtFullViewer::buildDecoration(QWidget * parent)
434 {
435 this->leftDecoration = this->buildLeftTrim(parent);
436 this->bottomDecoration = this->buildBottomTrim(parent);
437 this->rightDecoration = this->buildRightTrim(parent);
438 }
439
440 // *************************************************************************
441
442 // Documented in common/viewers/SoGuiFullViewer.cpp.in.
443 QWidget *
buildLeftTrim(QWidget * parent)444 SoQtFullViewer::buildLeftTrim(QWidget * parent)
445 {
446 QWidget * w = new QWidget(parent);
447 w->setFixedWidth(30);
448
449 QGridLayout * gl = new QGridLayout(w);
450 #if QT_VERSION >= 0x040000
451 gl->setContentsMargins(0,0,0,0);
452 #endif
453 gl->addWidget(this->buildAppButtons(w), 0, 0);
454
455 SoQtThumbWheel * t = new SoQtThumbWheel(SoQtThumbWheel::Vertical, w);
456 this->leftWheel = t;
457 t->setRangeBoundaryHandling(SoQtThumbWheel::ACCUMULATE);
458 this->leftWheelVal = t->value();
459
460 QObject::connect(t, SIGNAL(wheelMoved(float)), PRIVATE(this), SLOT(leftWheelChanged(float)));
461 QObject::connect(t, SIGNAL(wheelPressed()), PRIVATE(this), SLOT(leftWheelPressed()));
462 QObject::connect(t, SIGNAL(wheelReleased()), PRIVATE(this), SLOT(leftWheelReleased()));
463
464 gl->addWidget(t, 1, 0, Qt::AlignBottom | Qt::AlignHCenter);
465 gl->activate();
466
467 return w;
468 }
469
470 // *************************************************************************
471
472 // Documented in common/viewers/SoGuiFullViewer.cpp.in.
473 QWidget *
buildBottomTrim(QWidget * parent)474 SoQtFullViewer::buildBottomTrim(QWidget * parent)
475 {
476 QWidget * w = new QWidget(parent);
477 w->setFixedHeight(30);
478
479 QLabel * label = new QLabel(this->leftWheelStr, w);
480 label->adjustSize();
481 label->setAlignment(Qt::AlignLeft | Qt::AlignTop);
482 label->setMargin(2);
483 this->leftWheelLabel = label;
484
485 label = new QLabel(this->bottomWheelStr, w);
486 label->adjustSize();
487 label->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
488 label->setMargin(2);
489 this->bottomWheelLabel = label;
490
491 label = new QLabel(this->rightWheelStr, w);
492 label->adjustSize();
493 label->setAlignment(Qt::AlignRight | Qt::AlignTop);
494 label->setMargin(2);
495 this->rightWheelLabel = label;
496
497 SoQtThumbWheel * t = new SoQtThumbWheel(SoQtThumbWheel::Horizontal, w);
498 this->bottomWheel = t;
499 t->setRangeBoundaryHandling(SoQtThumbWheel::ACCUMULATE);
500
501 QObject::connect(t, SIGNAL(wheelMoved(float)),
502 PRIVATE(this), SLOT(bottomWheelChanged(float)));
503 QObject::connect(t, SIGNAL(wheelPressed()),
504 PRIVATE(this), SLOT(bottomWheelPressed()));
505 QObject::connect(t, SIGNAL(wheelReleased()),
506 PRIVATE(this), SLOT(bottomWheelReleased()));
507
508 this->bottomWheelVal = t->value();
509
510 QGridLayout * layout = new QGridLayout(w);
511 #if QT_VERSION >= 0x040000
512 layout->setContentsMargins(0,0,0,0);
513 #endif
514 layout->addWidget(this->leftWheelLabel, 0, 0, Qt::AlignVCenter | Qt::AlignHCenter);
515 layout->addWidget(this->bottomWheelLabel, 0,1, Qt::AlignVCenter | Qt::AlignRight);
516 layout->addWidget(t, 0,2, Qt::AlignVCenter | Qt::AlignLeft);
517 layout->addItem(new QSpacerItem(0,0,QSizePolicy::MinimumExpanding,QSizePolicy::MinimumExpanding),0, 3);
518 layout->addWidget(this->rightWheelLabel, 0, 4,Qt::AlignVCenter | Qt::AlignRight);
519
520 layout->activate();
521 return w;
522 }
523
524 // *************************************************************************
525
526 // Documented in common/viewers/SoGuiFullViewer.cpp.in.
527 QWidget *
buildRightTrim(QWidget * parent)528 SoQtFullViewer::buildRightTrim(QWidget * parent)
529 {
530 QWidget * w = new QWidget(parent);
531 // FIXME: should be set according to width of viewer
532 // buttons. 20000424 mortene.
533 w->setFixedWidth(30);
534 // FIXME: nope, trims are actually guaranteed to be 30 pixels wide
535
536 SoQtThumbWheel * t = new SoQtThumbWheel(SoQtThumbWheel::Vertical, w);
537 this->rightWheel = t;
538 t->setRangeBoundaryHandling(SoQtThumbWheel::ACCUMULATE);
539 this->rightWheelVal = t->value();
540
541 QObject::connect(t, SIGNAL(wheelMoved(float)),
542 PRIVATE(this), SLOT(rightWheelChanged(float)));
543 QObject::connect(t, SIGNAL(wheelPressed()),
544 PRIVATE(this), SLOT(rightWheelPressed()));
545 QObject::connect(t, SIGNAL(wheelReleased()),
546 PRIVATE(this), SLOT(rightWheelReleased()));
547
548 QGridLayout * l = new QGridLayout(w);
549 #if QT_VERSION >= 0x040000
550 l->setContentsMargins(0,0,0,0);
551 l->setVerticalSpacing(0);
552 #endif
553 l->setMargin(0);
554 l->addWidget(this->buildViewerButtons(w), 0, 0);
555 l->addWidget(t, 2, 0, Qt::AlignBottom | Qt::AlignHCenter);
556 l->activate();
557
558 return w;
559 }
560
561 // *************************************************************************
562
563 // Documented in common/viewers/SoGuiFullViewer.cpp.in.
564 QWidget *
buildAppButtons(QWidget * parent)565 SoQtFullViewer::buildAppButtons(QWidget * parent)
566 {
567 PRIVATE(this)->appbuttonform = new QWidget(parent);
568 PRIVATE(this)->appbuttonform->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
569
570 if (this->lengthAppPushButton() > 0)
571 PRIVATE(this)->layoutAppButtons(PRIVATE(this)->appbuttonform);
572
573 return PRIVATE(this)->appbuttonform;
574 }
575
576 // *************************************************************************
577
578 // Documented in common/viewers/SoGuiFullViewer.cpp.in.
579 QWidget *
buildViewerButtons(QWidget * parent)580 SoQtFullViewer::buildViewerButtons(QWidget * parent)
581 {
582 QWidget * w = new QWidget(parent);
583 this->createViewerButtons(w, PRIVATE(this)->viewerbuttons);
584 w->move(0, 0);
585 w->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
586
587 // assert(PRIVATE(this)->viewerbuttons->getLength() != 0);
588 QGridLayout * l =
589 new QGridLayout(w);
590 l->setMargin(0);
591 #if QT_VERSION >= 0x040000
592 l->setVerticalSpacing(0);
593 #endif
594
595 const int numViewerButtons = PRIVATE(this)->viewerbuttons->getLength();
596 for (int i = 0; i < numViewerButtons; i++) {
597 QPushButton * b = PRIVATE(this)->getViewerbutton(i);
598 b->setFixedSize(30, 30);
599 b->setFocusPolicy(QTWIDGET_NOFOCUS);
600 l->addWidget(b, i, 0);
601 }
602
603 l->activate();
604 return w;
605 }
606
607 // *************************************************************************
608
609 // Documented in common/viewers/SoGuiFullViewer.cpp.in.
610 void
createViewerButtons(QWidget * parent,SbPList * buttonlist)611 SoQtFullViewer::createViewerButtons(QWidget * parent, SbPList * buttonlist)
612 {
613 for (int i=0; i <= SEEK_BUTTON; i++) {
614 QPushButton * p = new QPushButton(parent);
615 // Button focus doesn't really make sense in the way we're using
616 // the pushbuttons.
617 p->setFocusPolicy(QTWIDGET_NOFOCUS);
618
619 #if QT_VERSION >= 0x040000 // Qt 4.*
620 // In some GUI styles in Qt4, a default button is drawn with an
621 // extra frame around it, up to 3 pixels or more. This causes
622 // pixmaps on buttons to look tiny, which is not what we want.
623 p->setIconSize(QSize(24, 24));
624 #endif
625
626 #if (defined Q_OS_MAC && QT_VERSION >= 0x030100) && defined(HAVE_QSTYLEFACTORY_H)
627 // Since Qt/Mac 3.1.x, all pushbuttons (even those < 32x32) are drawn
628 // using the Aqua style, i.e. with rounded edges and shading. This
629 // looks really ugly in the viewer decoration. Drawing the buttons
630 // in the Windows style gives us the flat, square buttons we want.
631 QStyle * style = QStyleFactory::create("windows");
632 if (style) { p->setStyle(style); }
633 #endif
634
635 // FIXME: its wrong to cast xpm data to (const char **), it
636 // _should_ be (const char * const []), but this is not valid ANSI
637 // C++. Not sure what to do about this (and the wrong cast can
638 // (and has) in fact lead to bugs, so the situation should be
639 // resolved). 20000505 mortene.
640
641 switch (i) {
642 case INTERACT_BUTTON:
643 PRIVATE(this)->interactbutton = p;
644 #if QT_VERSION >= 0x040000
645 p->setCheckable(TRUE);
646 p->setChecked(this->isViewing() ? FALSE : TRUE);
647 p->setIcon(QPixmap((const char **)pick_xpm));
648 #else
649 p->setToggleButton(TRUE);
650 p->setOn(this->isViewing() ? FALSE : TRUE);
651 p->setPixmap(QPixmap((const char **)pick_xpm));
652 #endif
653 QObject::connect(p, SIGNAL(clicked()),
654 PRIVATE(this), SLOT(interactbuttonClicked()));
655 break;
656 case EXAMINE_BUTTON:
657 PRIVATE(this)->viewbutton = p;
658 #if QT_VERSION >= 0x040000
659 p->setCheckable(TRUE);
660 p->setChecked(this->isViewing());
661 p->setIcon(QPixmap((const char **)view_xpm));
662 #else
663 p->setToggleButton(TRUE);
664 p->setOn(this->isViewing());
665 p->setPixmap(QPixmap((const char **)view_xpm));
666 #endif
667 QObject::connect(p, SIGNAL(clicked()),
668 PRIVATE(this), SLOT(viewbuttonClicked()));
669 break;
670 case HOME_BUTTON:
671 QObject::connect(p, SIGNAL(clicked()), PRIVATE(this), SLOT(homebuttonClicked()));
672 #if QT_VERSION >= 0x040000
673 p->setIcon(QPixmap((const char **)home_xpm));
674 #else
675 p->setPixmap(QPixmap((const char **)home_xpm));
676 #endif
677 break;
678 case SET_HOME_BUTTON:
679 QObject::connect(p, SIGNAL(clicked()),
680 PRIVATE(this), SLOT(sethomebuttonClicked()));
681 #if QT_VERSION >= 0x040000
682 p->setIcon(QPixmap((const char **)set_home_xpm));
683 #else
684 p->setPixmap(QPixmap((const char **)set_home_xpm));
685 #endif
686 break;
687 case VIEW_ALL_BUTTON:
688 QObject::connect(p, SIGNAL(clicked()),
689 PRIVATE(this), SLOT(viewallbuttonClicked()));
690 #if QT_VERSION >= 0x040000
691 p->setIcon(QPixmap((const char **)view_all_xpm));
692 #else
693 p->setPixmap(QPixmap((const char **)view_all_xpm));
694 #endif
695 break;
696 case SEEK_BUTTON:
697 QObject::connect(p, SIGNAL(clicked()), PRIVATE(this), SLOT(seekbuttonClicked()));
698 #if QT_VERSION >= 0x040000
699 p->setIcon(QPixmap((const char **)seek_xpm));
700 #else
701 p->setPixmap(QPixmap((const char **)seek_xpm));
702 #endif
703 break;
704 default:
705 assert(0);
706 break;
707 }
708
709 p->adjustSize();
710 buttonlist->append(p);
711 }
712 }
713
714 // *************************************************************************
715
716 // Documented in common/viewers/SoGuiFullViewer.cpp.in.
717 void
buildPopupMenu(void)718 SoQtFullViewer::buildPopupMenu(void)
719 {
720 this->prefmenu = PRIVATE(this)->setupStandardPopupMenu();
721 }
722
723 // *************************************************************************
724
725 // Documented in common/viewers/SoGuiFullViewer.cpp.in.
726 void
openPopupMenu(const SbVec2s position)727 SoQtFullViewer::openPopupMenu(const SbVec2s position)
728 {
729 if (! this->isPopupMenuEnabled()) return;
730 if (this->prefmenu == NULL)
731 this->buildPopupMenu();
732 int x = 2 + position[0];
733 int y = 2 + this->getGLSize()[1] - position[1] - 1;
734
735 PRIVATE(this)->prepareMenu(this->prefmenu);
736 this->prefmenu->popUp(this->getGLWidget(), x, y);
737 }
738
739 // *************************************************************************
740
741 // Documented in common/viewers/SoGuiFullViewer.cpp.in.
742 void
setLeftWheelString(const char * const string)743 SoQtFullViewer::setLeftWheelString(const char * const string)
744 {
745 delete [] this->leftWheelStr;
746 this->leftWheelStr = NULL;
747
748 if (string)
749 this->leftWheelStr = strcpy(new char [strlen(string)+1], string);
750 if (this->leftWheelLabel)
751 ((QLabel *)this->leftWheelLabel)->setText(string ? string : "");
752 }
753
754 // *************************************************************************
755
756 // Documented in common/viewers/SoGuiFullViewer.cpp.in.
757 void
setBottomWheelString(const char * const string)758 SoQtFullViewer::setBottomWheelString(const char * const string)
759 {
760 delete [] this->bottomWheelStr;
761 this->bottomWheelStr = NULL;
762
763 if (string)
764 this->bottomWheelStr = strcpy(new char [strlen(string)+1], string);
765 if (this->bottomWheelLabel)
766 ((QLabel *)this->bottomWheelLabel)->setText(string ? string : "");
767 }
768
769 // *************************************************************************
770
771 // Documented in common/viewers/SoGuiFullViewer.cpp.in.
772 const char *
getRightWheelString() const773 SoQtFullViewer::getRightWheelString() const
774 {
775 return this->rightWheelStr;
776 }
777
778 // Documented in common/viewers/SoGuiFullViewer.cpp.in.
779 void
setRightWheelString(const char * const string)780 SoQtFullViewer::setRightWheelString(const char * const string)
781 {
782 delete [] this->rightWheelStr;
783 this->rightWheelStr = NULL;
784
785 if (string)
786 this->rightWheelStr = strcpy(new char [strlen(string)+1], string);
787 if (this->rightWheelLabel)
788 ((QLabel *)this->rightWheelLabel)->setText(string ? string : "");
789 }
790
791 // *************************************************************************
792
793 // doc in super
794 void
sizeChanged(const SbVec2s & size)795 SoQtFullViewer::sizeChanged(const SbVec2s & size)
796 {
797
798 #if SOQT_DEBUG && 0
799 SoDebugError::postInfo("SoQtFullViewer::sizeChanged", "(%d, %d)",
800 size[0], size[1]);
801 #endif
802
803 SbVec2s newsize(size);
804 if (PRIVATE(this)->decorations) {
805 newsize[0] -= this->leftDecoration ? this->leftDecoration->width() : 0;
806 newsize[0] -= this->rightDecoration ? this->rightDecoration->width() : 0;
807 newsize[1] -= this->bottomDecoration ? this->bottomDecoration->height() : 0;
808 }
809
810 // Workaround for a bug in Qt/Mac 3.1.0 and 3.1.1 (which has been
811 // confirmed fixed in 3.1.2):
812 //
813 // If the OpenGL context overlaps with the QSizeGrip widget
814 // (generated by default), resizing does not work any more. The
815 // workaround is to leave 15 pixels at the lower border of the
816 // window blank...
817 #if defined Q_OS_MAC && ((QT_VERSION == 0x030100) || (QT_VERSION == 0x030101))
818
819 // Environment variable to override Qt/Mac 3.1.x workarounds.
820 const char * forcenoresizeworkaround =
821 SoAny::si()->getenv("FORCE_NO_QTMAC_31_RESIZE_WORKAROUND");
822 if (!forcenoresizeworkaround || (atoi(forcenoresizeworkaround) == 0)) {
823
824 if (!PRIVATE(this)->decorations) { // GL context would fill whole window
825 newsize -= SbVec2s(0, 15); // -> leave lowermost 15 px blank
826
827 // spit out a warning that this is a Qt/Mac bug, not an SoQt problem
828 const char * env = SoAny::si()->getenv("SOQT_NO_QTMAC_BUG_WARNINGS");
829 if (!env || !atoi(env)) {
830 SoDebugError::postWarning("SoQtFullViewer::sizeChanged",
831 "\nThis version of Qt/Mac contains a bug "
832 "that makes it necessary to leave the\n"
833 "lowermost 15 pixels of the viewer window "
834 "blank. Set the environment variable\n"
835 "FORCE_NO_QTMAC_31_RESIZE_WORKAROUND=1 to "
836 "override this workaround. \n"
837 "You can turn off warnings about Qt/Mac "
838 "bugs permanently by setting \n"
839 "SOQT_NO_QTMAC_BUG_WARNINGS=1.\n");
840 }
841 }
842 }
843
844 #endif
845
846 newsize = SbVec2s(SoQtMax(newsize[0], (short)1),
847 SoQtMax(newsize[1], (short)1));
848
849 inherited::sizeChanged(newsize);
850 }
851
852 // *************************************************************************
853
854 #ifndef DOXYGEN_SKIP_THIS
855
856 // Show or hide decorations. Will make and activate a Qt layout grid
857 // if we're turning the decorations on.
858 void
showDecorationWidgets(SbBool onOff)859 SoQtFullViewerP::showDecorationWidgets(SbBool onOff)
860 {
861 #if SOQT_DEBUG && 0
862 SoDebugError::postInfo("SoQtFullViewerP::showDecorationWidgets", "[invoked]");
863 #endif // SOQT_DEBUG
864
865 if (this->mainlayout) delete this->mainlayout;
866
867 assert(this->viewerwidget);
868
869 assert(PUBLIC(this)->leftDecoration && PUBLIC(this)->bottomDecoration && PUBLIC(this)->rightDecoration);
870 if (onOff) {
871 PUBLIC(this)->leftDecoration->show();
872 PUBLIC(this)->bottomDecoration->show();
873 PUBLIC(this)->rightDecoration->show();
874
875 #if QT_VERSION >= 0x040000
876 this->viewerwidget->setContentsMargins(0,0,0,0);
877 #endif
878
879 QGridLayout * g = new QGridLayout(this->viewerwidget); // VIEWERBORDER);
880 g->setSpacing(0);
881 #if QT_VERSION >= 0x040000
882 g->setContentsMargins(0,0,0,0);
883 #endif
884
885 g->addWidget(PUBLIC(this)->bottomDecoration, 1, 0);
886
887 QGridLayout * subLayout = new QGridLayout();
888 g->addLayout(subLayout, 0, 0);
889 #if QT_VERSION >= 0x040000
890 subLayout->setVerticalSpacing(0);
891 subLayout->setContentsMargins(0,0,0,0);
892 #endif
893
894 PUBLIC(this)->leftDecoration->setSizePolicy(QSizePolicy(QSizePolicy::Minimum,QSizePolicy::Minimum));
895
896 subLayout->addWidget(PUBLIC(this)->leftDecoration, 0, 0);
897 this->canvas->setSizePolicy(QSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding));
898 subLayout->addWidget(this->canvas, 0, 1);
899 subLayout->addWidget(PUBLIC(this)->rightDecoration, 0, 2);
900
901 this->mainlayout = g;
902 } else {
903 QGridLayout * g = new QGridLayout(this->viewerwidget);
904 g->addWidget(this->canvas, 0, 0);
905 #if QT_VERSION >= 0x040000
906 g->setContentsMargins(0,0,0,0);
907 #endif
908 this->mainlayout = g;
909
910 PUBLIC(this)->leftDecoration->hide();
911 PUBLIC(this)->bottomDecoration->hide();
912 PUBLIC(this)->rightDecoration->hide();
913 }
914
915 this->mainlayout->activate();
916 QSize size = this->viewerwidget->size();
917 SbVec2s rasize = SbVec2s(size.width(), size.height());
918 PUBLIC(this)->sizeChanged(rasize);
919 }
920
921 // *************************************************************************
922
923 // Layout application specified buttons.
924 void
layoutAppButtons(QWidget * form)925 SoQtFullViewerP::layoutAppButtons(QWidget * form)
926 {
927 delete this->appbuttonlayout; this->appbuttonlayout = NULL;
928
929 int nrbuttons = this->appbuttonlist->getLength();
930 if (nrbuttons == 0) return;
931
932 this->appbuttonlayout = new QGridLayout(form);
933 #if QT_VERSION >= 0x040000
934 this->appbuttonlayout->setContentsMargins(0,0,0,0);
935 #endif
936 this->appbuttonlayout->setSpacing(0);
937
938 for (int i=0; i < nrbuttons; i++) {
939 QWidget * button = (QWidget *)((*(this->appbuttonlist))[i]);
940 ((QGridLayout *)this->appbuttonlayout)->addWidget(button, i, 0);
941 button->show();
942 }
943
944 this->appbuttonlayout->activate();
945 }
946
947 // *************************************************************************
948
949 // Qt slot.
950 void
interactbuttonClicked(void)951 SoQtFullViewerP::interactbuttonClicked(void)
952 {
953 if (this->interactbutton)
954 #if QT_VERSION >= 0x040000
955 ((QPushButton *)this->interactbutton)->setChecked(TRUE);
956 #else
957 ((QPushButton *)this->interactbutton)->setOn(TRUE);
958 #endif
959 if (this->viewbutton)
960 #if QT_VERSION >= 0x040000
961 ((QPushButton *)this->viewbutton)->setChecked(FALSE);
962 #else
963 ((QPushButton *)this->viewbutton)->setOn(FALSE);
964 #endif
965 if (PUBLIC(this)->isViewing())
966 PUBLIC(this)->setViewing(FALSE);
967 }
968
969 // *************************************************************************
970
971 // Qt slot.
972 void
viewbuttonClicked(void)973 SoQtFullViewerP::viewbuttonClicked(void)
974 {
975 if (this->interactbutton)
976 #if QT_VERSION >= 0x040000
977 ((QPushButton *)this->interactbutton)->setChecked(FALSE);
978 #else
979 ((QPushButton *)this->interactbutton)->setOn(FALSE);
980 #endif
981 if (this->viewbutton)
982 #if QT_VERSION >= 0x040000
983 ((QPushButton *)this->viewbutton)->setChecked(TRUE);
984 #else
985 ((QPushButton *)this->viewbutton)->setOn(TRUE);
986 #endif
987 if (!PUBLIC(this)->isViewing())
988 PUBLIC(this)->setViewing(TRUE);
989 }
990
991 // *************************************************************************
992
993 // Qt slot.
994 void
homebuttonClicked()995 SoQtFullViewerP::homebuttonClicked()
996 {
997 PUBLIC(this)->resetToHomePosition();
998 }
999
1000 // *************************************************************************
1001
1002 // Qt slot.
1003 void
sethomebuttonClicked()1004 SoQtFullViewerP::sethomebuttonClicked()
1005 {
1006 PUBLIC(this)->saveHomePosition();
1007 }
1008
1009 // *************************************************************************
1010
1011 // Qt slot.
1012 void
viewallbuttonClicked()1013 SoQtFullViewerP::viewallbuttonClicked()
1014 {
1015 PUBLIC(this)->viewAll();
1016 }
1017
1018 // *************************************************************************
1019
1020 // Qt slot.
1021 void
seekbuttonClicked()1022 SoQtFullViewerP::seekbuttonClicked()
1023 {
1024 PUBLIC(this)->setSeekMode(PUBLIC(this)->isSeekMode() ? FALSE : TRUE);
1025 }
1026
1027 // *************************************************************************
1028
1029 // Qt slot.
1030 void
selectedViewing()1031 SoQtFullViewerP::selectedViewing()
1032 {
1033 PUBLIC(this)->setViewing(PUBLIC(this)->isViewing() ? FALSE : TRUE);
1034 }
1035
1036 // *************************************************************************
1037
1038 // Qt slot.
1039 void
selectedDecoration()1040 SoQtFullViewerP::selectedDecoration()
1041 {
1042 PUBLIC(this)->setDecoration(PUBLIC(this)->isDecoration() ? FALSE : TRUE);
1043 }
1044
1045 // *************************************************************************
1046
1047 // Qt slot.
1048 void
selectedHeadlight()1049 SoQtFullViewerP::selectedHeadlight()
1050 {
1051 PUBLIC(this)->setHeadlight(PUBLIC(this)->isHeadlight() ? FALSE : TRUE);
1052 }
1053
1054 // *************************************************************************
1055
1056 // Qt slot.
1057 void
increaseInteractiveCount()1058 SoQtFullViewerP::increaseInteractiveCount()
1059 {
1060 PUBLIC(this)->interactiveCountInc();
1061 }
1062
1063 // *************************************************************************
1064
1065 // Qt slot.
1066 void
decreaseInteractiveCount()1067 SoQtFullViewerP::decreaseInteractiveCount()
1068 {
1069 PUBLIC(this)->interactiveCountDec();
1070 }
1071
1072 // *************************************************************************
1073
SoQtFullViewerP(SoQtFullViewer * publ)1074 SoQtFullViewerP::SoQtFullViewerP(SoQtFullViewer * publ)
1075 : SoGuiFullViewerP(publ)
1076 {
1077 }
1078
~SoQtFullViewerP()1079 SoQtFullViewerP::~SoQtFullViewerP()
1080 {
1081 }
1082
1083 void
setThumbWheelValue(void * wheel,float val)1084 SoQtFullViewerP::setThumbWheelValue(void * wheel, float val)
1085 {
1086 ((SoQtThumbWheel *)wheel)->setValue(val);
1087 }
1088
1089 // *************************************************************************
1090
1091 // These are all private slots for catching Qt events.
leftWheelPressed(void)1092 void SoQtFullViewerP::leftWheelPressed(void) { PUBLIC(this)->leftWheelStart(); }
leftWheelChanged(float v)1093 void SoQtFullViewerP::leftWheelChanged(float v) { PUBLIC(this)->leftWheelMotion(v); }
leftWheelReleased(void)1094 void SoQtFullViewerP::leftWheelReleased(void) { PUBLIC(this)->leftWheelFinish(); }
bottomWheelPressed(void)1095 void SoQtFullViewerP::bottomWheelPressed(void) { PUBLIC(this)->bottomWheelStart(); }
bottomWheelChanged(float v)1096 void SoQtFullViewerP::bottomWheelChanged(float v) { PUBLIC(this)->bottomWheelMotion(v);}
bottomWheelReleased(void)1097 void SoQtFullViewerP::bottomWheelReleased(void) { PUBLIC(this)->bottomWheelFinish(); }
rightWheelPressed(void)1098 void SoQtFullViewerP::rightWheelPressed(void) { PUBLIC(this)->rightWheelStart(); }
rightWheelChanged(float v)1099 void SoQtFullViewerP::rightWheelChanged(float v) { PUBLIC(this)->rightWheelMotion(v); }
rightWheelReleased(void)1100 void SoQtFullViewerP::rightWheelReleased(void) { PUBLIC(this)->rightWheelFinish(); }
1101
1102 // *************************************************************************
1103
1104 #endif // DOXYGEN_SKIP_THIS
1105
1106 #undef PUBLIC
1107 #undef PRIVATE
1108