Developer Documentation
QtSceneGraphWidget.cc
1/*===========================================================================*\
2 * *
3 * OpenFlipper *
4 * Copyright (c) 2001-2015, RWTH-Aachen University *
5 * Department of Computer Graphics and Multimedia *
6 * All rights reserved. *
7 * www.openflipper.org *
8 * *
9 *---------------------------------------------------------------------------*
10 * This file is part of OpenFlipper. *
11 *---------------------------------------------------------------------------*
12 * *
13 * Redistribution and use in source and binary forms, with or without *
14 * modification, are permitted provided that the following conditions *
15 * are met: *
16 * *
17 * 1. Redistributions of source code must retain the above copyright notice, *
18 * this list of conditions and the following disclaimer. *
19 * *
20 * 2. Redistributions in binary form must reproduce the above copyright *
21 * notice, this list of conditions and the following disclaimer in the *
22 * documentation and/or other materials provided with the distribution. *
23 * *
24 * 3. Neither the name of the copyright holder nor the names of its *
25 * contributors may be used to endorse or promote products derived from *
26 * this software without specific prior written permission. *
27 * *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39 * *
40\*===========================================================================*/
41
42//=============================================================================
43//
44// CLASS QtSceneGraphWidget - IMPLEMENTATION
45//
46//=============================================================================
47
48//== INCLUDES =================================================================
49
50
51#include "QtSceneGraphWidget.hh"
52#include "QtMaterialDialog.hh"
53#include "QtTextureDialog.hh"
54#include "QtClippingDialog.hh"
55#include "QtCoordFrameDialog.hh"
56#include "QtShaderDialog.hh"
57#include <QActionGroup>
58
59#include "../Scenegraph/MaterialNode.hh"
60#include "../Scenegraph/TextureNode.hh"
61#include "../Scenegraph/ClippingNode.hh"
62#include "../Scenegraph/ShaderNode.hh"
63#include "../Scenegraph/CoordFrameNode.hh"
64
65#include "ui_QtMaterialDialogUi.h"
66
67#include <stdint.h>
68
69
70//== FORWARDDECLARATIONS ======================================================
71
73
74
75//== NAMESPACES ===============================================================
76
77namespace ACG {
78namespace QtWidgets {
79
80
81//== IMPLEMENTATION ==========================================================
82
83SceneGraphWidgetGenerator::SceneGraphWidgetGenerator() {
84}
85
87 // Warn as this you have to derive from this class before it can be used!
88 std::cerr << "SceneGraphWidgetGenerator::getWidget not implemented!" << std::endl;
89 return 0;
90}
91
92bool SceneGraphWidgetGenerator::canHandle(std::string _className) {
93 // Warn as this you have to derive from this class before it can be used!
94 std::cerr << "SceneGraphWidgetGenerator::canHandle not implemented!" << _className << std::endl;
95 return false;
96}
97
99 // Warn as this you have to derive from this class before it can be used!
100 std::cerr << "SceneGraphWidgetGenerator::canHandle not implemented!" << std::endl;
101 return std::string("Unset Type");
102}
103
105 // Warn as this you have to derive from this class before it can be used!
106 std::cerr << "SceneGraphWidgetGenerator::contextMenuName not implemented!" << std::endl;
107 return QString("Context Menu name unset");
108}
109
111QtSceneGraphWidget( QWidget * _parent,
112 SceneGraph::BaseNode * _rootNode ) :
113 QTreeWidget( _parent ),
114 rootNode_(0),
115 curItem_(0),
116 shiftPressed_(false)
117
118{
119 setRootIsDecorated(true);
120
121 setSortingEnabled( false );
122
123 setSelectionMode( QAbstractItemView::SingleSelection );
124
125
126 setColumnCount( 4 );
127
128 QStringList column_names;
129 column_names.append( "Node" );
130 column_names.append( "Type" );
131 column_names.append( "Status" );
132 column_names.append( "Mode" );
133
134 setHeaderLabels( column_names );
135
136 modeMenu_ = new QMenu( this );
137
138
139 //
140 // Setup the 'status' actions
141 //
142
143 statusActions_.menu_ = new QMenu( this );
144
145 QActionGroup * status_ag = new QActionGroup( statusActions_.menu_ );
146 status_ag->setExclusive( true );
147
148 statusActions_.actionActive_ = new QAction( "Active", status_ag );
149 statusActions_.actionActive_->setCheckable( true );
150 statusActions_.actionActive_->setData( QVariant( BaseNode::Active ) );
151
152 statusActions_.actionHideNode_ = new QAction( "Hide Node", status_ag );
153 statusActions_.actionHideNode_->setCheckable( true );
154 statusActions_.actionHideNode_->setData( QVariant( BaseNode::HideNode ) );
155
156 statusActions_.actionHideChildren_ = new QAction( "Hide Children", status_ag );
157 statusActions_.actionHideChildren_->setCheckable( true );
158 statusActions_.actionHideChildren_->setData( QVariant( BaseNode::HideChildren ) );
159
160 statusActions_.actionHideSubtree_ = new QAction( "Hide Subtree", status_ag );
161 statusActions_.actionHideSubtree_->setCheckable( true );
162 statusActions_.actionHideSubtree_->setData( QVariant( BaseNode::HideSubtree ) );
163
164 statusActions_.menu_->addActions( status_ag->actions() );
165
166 connect( status_ag, SIGNAL( triggered( QAction * ) ),
167 this, SLOT( slotStatusMenu( QAction * ) ) );
168
169
170
171 connect( this, SIGNAL(itemPressed(QTreeWidgetItem*,int) ),
172 this, SLOT(slotItemPressed(QTreeWidgetItem*,int)) );
173
174 connect( this, SIGNAL(itemExpanded(QTreeWidgetItem*) ),
175 this, SLOT(slotItemExpandedOrCollapsed(QTreeWidgetItem*)) );
176 connect( this, SIGNAL(itemCollapsed(QTreeWidgetItem*) ),
177 this, SLOT(slotItemExpandedOrCollapsed(QTreeWidgetItem*)) );
178
179 update(_rootNode);
180
181 setMinimumWidth( 600 );
182 setMinimumHeight( 400 );
183
184}
185
186
187//-----------------------------------------------------------------------------
188
189
190void
193{
194 rootNode_ = _node;
195
196 clear();
197
198 Item * item = new Item( this, _node );
199
201 cREnd(_node->childrenREnd());
202 for (; cRIt != cREnd; ++cRIt)
203 update(*cRIt, item);
204
205 expandToDepth ( 0 );
206
207 resizeColumnToContents( 0 );
208 resizeColumnToContents( 1 );
209 resizeColumnToContents( 2 );
210 resizeColumnToContents( 3 );
211
212 setMinimumWidth( columnWidth(0) + columnWidth(1) + columnWidth(2) + columnWidth(3) );
213}
214
215
216//-----------------------------------------------------------------------------
217
218
219void
221update(SceneGraph::BaseNode* _node, Item* _parent)
222{
223 // create new item
224 Item* item = new Item( _parent, _node );
225
226 // process children
228 cREnd(_node->childrenREnd());
229 for (; cRIt != cREnd; ++cRIt)
230 update(*cRIt, item);
231}
232
233
234//-----------------------------------------------------------------------------
235
236
237void
238QtSceneGraphWidget::
239slotItemExpandedOrCollapsed( QTreeWidgetItem* /*_item*/ )
240{
241 resizeColumnToContents( 0 );
242}
243
244
245//-----------------------------------------------------------------------------
246
247
248void
249QtSceneGraphWidget::
250slotItemPressed( QTreeWidgetItem * _item,
251 int _col)
252{
253
254 if ( _item )
255 {
256 curItem_ = static_cast<Item* >(_item);
257 BaseNode * node = curItem_->node();
258
259 switch ( _col )
260 {
261 case 2:
262 {
263 statusActions_.actionActive_ ->setChecked( false );
264 statusActions_.actionHideNode_ ->setChecked( false );
265 statusActions_.actionHideChildren_->setChecked( false );
266 statusActions_.actionHideSubtree_ ->setChecked( false );
267
268 switch ( node->status() )
269 {
270 case BaseNode::Active:
271 statusActions_.actionActive_->setChecked( true );
272 break;
274 statusActions_.actionHideNode_->setChecked( true );
275 break;
277 statusActions_.actionHideChildren_->setChecked( true );
278 break;
280 statusActions_.actionHideSubtree_->setChecked( true );
281 break;
282 }
283 statusActions_.menu_->popup( QCursor::pos() );
284 break;
285 }
286 case 0: break;
287 case 1: break;
288 case 3:
289 {
290 modeMenu_->clear();
291
292 QActionGroup * modeGroup = new QActionGroup( modeMenu_ );
293 modeGroup->setExclusive( true );
294 connect( modeGroup, SIGNAL( triggered( QAction * ) ),
295 this, SLOT( slotModeMenu( QAction * ) ) );
296
298 availDrawModes |= SceneGraph::DrawModes::DEFAULT;
299
300 ACG::SceneGraph::DrawModes::DrawMode currentDrawMode( node->drawMode() );
301
302 std::vector< ACG::SceneGraph::DrawModes::DrawMode > available_modes( availDrawModes.getAtomicDrawModes() );
303
304
305 for ( unsigned int i = 0; i < available_modes.size(); ++i )
306 {
307 ACG::SceneGraph::DrawModes::DrawMode id = available_modes[i];
308 std::string descr = id.description();
309
310 QAction * action = new QAction( descr.c_str(), modeGroup );
311 action->setCheckable( true );
312 action->setChecked ( currentDrawMode.containsAtomicDrawMode(id ) ) ;
313 action->setData( QVariant( quint64(id.getIndex()) ) );
314 }
315
316 modeMenu_->addActions( modeGroup->actions() );
317
318 if ( dynamic_cast<SceneGraph::MaterialNode*>( node ) )
319 {
320 modeMenu_->addSeparator();
321 QAction * action = modeMenu_->addAction( "Edit material" );
322 connect( action, SIGNAL( triggered() ),
323 this, SLOT( slotEditMaterial() ) );
324 }
325
326 if ( dynamic_cast<SceneGraph::TextureNode*>( node ) )
327 {
328 modeMenu_->addSeparator();
329 QAction * action = modeMenu_->addAction( "Edit texture" );
330 connect( action, SIGNAL( triggered() ),
331 this, SLOT( slotEditTexture() ) );
332 }
333
334 if ( dynamic_cast<SceneGraph::ShaderNode*>( node ) )
335 {
336 modeMenu_->addSeparator();
337 QAction * action = modeMenu_->addAction( "Edit shaders" );
338 connect( action, SIGNAL( triggered() ),
339 this, SLOT( slotEditShader() ) );
340 }
341
342 if ( dynamic_cast<SceneGraph::ClippingNode*>( node ) )
343 {
344 modeMenu_->addSeparator();
345 QAction * action = modeMenu_->addAction( "Edit clip planes" );
346 connect( action, SIGNAL( triggered() ),
347 this, SLOT( slotEditClipPlanes() ) );
348 }
349
350 if ( dynamic_cast<SceneGraph::CoordFrameNode*>( node ) )
351 {
352 modeMenu_->addSeparator();
353 QAction * action = modeMenu_->addAction( "Edit coord frame" );
354 connect( action, SIGNAL( triggered() ),
355 this, SLOT( slotEditCoordinateFrame() ) );
356 }
357
358 // Add widgets through generator
359 if ( generatorMap_.contains( node->className() ) ) {
360 QWidget* widget = generatorMap_[node->className()]->getWidget( node );
361 modeMenu_->addAction( generatorMap_[node->className()]->contextMenuName() , widget, SLOT(show()) );
362 }
363
364 modeMenu_->popup( QCursor::pos() );
365
366 break;
367 }
368 default: break;
369 }
370 }
371}
372
373
374//-----------------------------------------------------------------------------
375
376
377void QtSceneGraphWidget::slotEditMaterial()
378{
379 if ( curItem_ )
380 {
382 dynamic_cast< SceneGraph::MaterialNode * >( curItem_->node() );
383
384 QtMaterialDialog* dialog = new QtMaterialDialog( this, node );
385
386 connect(dialog,
388 this,
389 SLOT(slotNodeChanged(ACG::SceneGraph::BaseNode*)));
390
391 dialog->show();
392 }
393}
394
395//-----------------------------------------------------------------------------
396
397
398void QtSceneGraphWidget::slotEditTexture()
399{
400 if ( curItem_ )
401 {
402 SceneGraph::TextureNode * node =
403 dynamic_cast< SceneGraph::TextureNode * >( curItem_->node() );
404
405 QtTextureDialog* dialog = new QtTextureDialog( this, node );
406
407 connect(dialog,
409 this,
410 SLOT(slotNodeChanged(ACG::SceneGraph::BaseNode*)));
411
412 dialog->show();
413 }
414}
415
416//-----------------------------------------------------------------------------
417
418
419void QtSceneGraphWidget::slotEditShader()
420{
421 if ( curItem_ )
422 {
424 dynamic_cast< SceneGraph::ShaderNode * >( curItem_->node() );
425
426 QtShaderDialog* dialog = new QtShaderDialog( this, node );
427
428 connect(dialog,
430 this,
431 SLOT(slotNodeChanged(ACG::SceneGraph::BaseNode*)));
432
433 dialog->show();
434 }
435}
436
437
438//-----------------------------------------------------------------------------
439
440
441void QtSceneGraphWidget::slotEditClipPlanes()
442{
443 if ( curItem_ )
444 {
445 SceneGraph::ClippingNode * node =
446 dynamic_cast< SceneGraph::ClippingNode * >( curItem_->node() );
447
448 QtClippingDialog * dialog = new QtClippingDialog( this, node );
449
450 connect(dialog,
452 this,
453 SLOT(slotNodeChanged(ACG::SceneGraph::BaseNode*)));
454
455 dialog->show();
456 }
457}
458
459
460//-----------------------------------------------------------------------------
461
462
463void QtSceneGraphWidget::slotEditCoordinateFrame()
464{
465 if ( curItem_ )
466 {
467 SceneGraph::CoordFrameNode * node =
468 dynamic_cast< SceneGraph::CoordFrameNode * >( curItem_->node() );
469
470 QtCoordFrameDialog * dialog = new QtCoordFrameDialog( this, node );
471
472 connect(dialog,
474 this,
475 SLOT(slotNodeChanged(ACG::SceneGraph::BaseNode*)));
476
477 dialog->show();
478 }
479}
480
481
482//-----------------------------------------------------------------------------
483
484
485void QtSceneGraphWidget::slotModeMenu( QAction * _action )
486{
487 SceneGraph::DrawModes::DrawMode new_drawmode( _action->data().toUInt());
488
489 curItem_->node()->drawMode( new_drawmode );
490 curItem_->update();
491 emit signalNodeChanged( curItem_->node() );
492}
493
494
495//-----------------------------------------------------------------------------
496
497
498void QtSceneGraphWidget::slotStatusMenu( QAction * _action )
499{
500 if ( curItem_ )
501 {
502 unsigned int status = _action->data().toUInt();
503 BaseNode * node = curItem_->node();
504
506 curItem_->update();
507 emit signalNodeChanged( node );
508 }
509}
510
511
512//-----------------------------------------------------------------------------
513
514
516{
517 switch(_event->key())
518 {
519 case Qt::Key_Shift: shiftPressed_ = true; break;
520 default : _event->ignore();
521 }
522}
523
524
526{
527 switch(_event->key())
528 {
529 case Qt::Key_Shift: shiftPressed_ = false; break;
530 default : _event->ignore();
531 }
532}
533
534
535//-----------------------------------------------------------------------------
536
537void QtSceneGraphWidget::expandAll() {
538
539 QTreeWidget::expandAll();
540
541 resizeColumnToContents(0);
542}
543
544void QtSceneGraphWidget::updateAll() {
545
546 if(rootNode_) {
547 update(rootNode_);
548 QTreeWidget::expandAll();
549 }
550
551 resizeColumnToContents(0);
552}
553
554//-----------------------------------------------------------------------------
555
556void
557QtSceneGraphWidget::
558slotNodeChanged(ACG::SceneGraph::BaseNode* _node)
559{
560 emit signalNodeChanged(_node);
561}
562
563//-----------------------------------------------------------------------------
564
566 // Check if we already have a generator for this type.
567 if ( generatorMap_.contains( _generator->handles() ) ) {
568 std::cerr << "Already handled" << std::endl;
569 return false;
570 }
571
572 // Store the generator
573 generatorMap_[_generator->handles() ] = _generator;
574
575 return true;
576}
577
578
579//=============================================================================
580
581
582
583
584QtSceneGraphWidget::Item::Item( QTreeWidget * _parent,
585 SceneGraph::BaseNode* _node )
586 : QTreeWidgetItem(_parent), node_(_node)
587{
588 update();
589}
590
591
592//-----------------------------------------------------------------------------
593
594
595QtSceneGraphWidget::Item::Item( Item * _parent,
596 SceneGraph::BaseNode* _node )
597 : QTreeWidgetItem(_parent), node_(_node)
598{
599 update();
600}
601
602
603//-----------------------------------------------------------------------------
604
605
606void
607QtSceneGraphWidget::Item::update()
608{
609 QString name = tr("%1 @ 0x%2")
610 .arg(node_->name().c_str())
611 .arg(reinterpret_cast<uintptr_t>(node_), 0, 16);
612 setText( 0, name.toStdString().c_str());
613 setText( 1, node_->className().c_str());
614
615 switch (node_->status())
616 {
617 case BaseNode::Active: setText( 2, "Active"); break;
618 case BaseNode::HideNode: setText( 2, "HideNode"); break;
619 case BaseNode::HideChildren: setText( 2, "HideChildren"); break;
620 case BaseNode::HideSubtree: setText( 2, "HideSubtree"); break;
621 }
622
623 setText( 3, node_->drawMode().description().c_str());
624}
625
626
627//-----------------------------------------------------------------------------
628
629
630QtSceneGraphDialog::
631QtSceneGraphDialog( QWidget* _parent,
632 SceneGraph::BaseNode* _rootNode )
633 : QDialog(_parent)
634{
635 setModal( false );
636
637 QVBoxLayout* l = new QVBoxLayout( this );
638
639 QWidget* buttons = new QWidget(this);
640 QHBoxLayout* butLayout = new QHBoxLayout(buttons);
641
642 sgw_ =
643 new QtSceneGraphWidget( this, _rootNode );
644
645 // Add buttons to hbox layout
646 QPushButton* expAll = new QPushButton("Expand all");
647 QPushButton* collAll = new QPushButton("Collapse all");
648 QPushButton* updAll = new QPushButton("Update all");
649
650 butLayout->addWidget(expAll);
651 butLayout->addWidget(collAll);
652 butLayout->addWidget(updAll);
653
654 l->addWidget(buttons);
655 l->addWidget(sgw_);
656
657 connect(sgw_,
659 this,
660 SLOT(slotNodeChanged(ACG::SceneGraph::BaseNode*)) );
661
662 connect(expAll, SIGNAL(pressed()), sgw_, SLOT(expandAll()));
663 connect(collAll, SIGNAL(pressed()), sgw_, SLOT(collapseAll()));
664 connect(updAll, SIGNAL(pressed()), sgw_, SLOT(updateAll()));
665}
666
667
668//-----------------------------------------------------------------------------
669
670
671void
672QtSceneGraphDialog::
673slotNodeChanged(ACG::SceneGraph::BaseNode* _node)
674{
675 emit(signalNodeChanged(_node));
676}
677
678
679//-----------------------------------------------------------------------------
680
681
682void
685{
686 sgw_->update(_rootNode);
687}
688
689
690//=============================================================================
691} // namespace QtWidgets
692} // namespace ACG
693//=============================================================================
ACG::SceneGraph::MaterialNode MaterialNode
Materialnode.
ACG::SceneGraph::BaseNode BaseNode
Base Node.
ACG::SceneGraph::ShaderNode ShaderNode
Simple Name for ShaderNode.
void update(ACG::SceneGraph::BaseNode *_rootNode)
Update recursively from _rootNode on.
void signalNodeChanged(ACG::SceneGraph::BaseNode *_node)
QtSceneGraphWidget(QWidget *_parent=0, SceneGraph::BaseNode *_rootNode=0)
default constructor
void signalNodeChanged(ACG::SceneGraph::BaseNode *_node)
bool addWidgetGenerator(SceneGraphWidgetGenerator *_generator)
Add a node widget handler.
void keyPressEvent(QKeyEvent *_event)
key events
void keyReleaseEvent(QKeyEvent *_event)
key events
void update(ACG::SceneGraph::BaseNode *_rootNode)
Update recursively from _rootNode on.
virtual std::string handles()
return the type this generator handles
virtual QWidget * getWidget(SceneGraph::BaseNode *_node)
Get a widget for this Node.
virtual bool canHandle(std::string _className)
returns if the widgets can handle the given class
virtual QString contextMenuName()
Return a name for your widget in the context menu.
std::vector< BaseNode * >::reverse_iterator ChildRIter
allows to reverse iterate over children
Definition: BaseNode.hh:291
DrawModes::DrawMode drawMode() const
Return the own draw modes of this node.
Definition: BaseNode.hh:430
@ HideNode
Hide this node, but draw children.
Definition: BaseNode.hh:394
@ HideChildren
Draw this node, but hide children.
Definition: BaseNode.hh:396
@ HideSubtree
Hide this node and its children.
Definition: BaseNode.hh:398
@ Active
Draw node & children.
Definition: BaseNode.hh:392
ChildRIter childrenREnd()
Returns: reverse end-iterator of children.
Definition: BaseNode.hh:307
ChildRIter childrenRBegin()
Returns: reverse begin-iterator of children.
Definition: BaseNode.hh:303
StatusMode status() const
Get node's status.
Definition: BaseNode.hh:401
void set_status(StatusMode _s)
Set the status of this node.
Definition: BaseNode.hh:403
virtual const std::string & className() const =0
Return class name (implemented by the ACG_CLASSNAME macro)
virtual DrawModes::DrawMode availableDrawModes() const
Definition: BaseNode.hh:136
std::string name() const
Returns: name of node (needs not be unique)
Definition: BaseNode.hh:415
DrawMode DEFAULT
use the default (global) draw mode and not the node's own.
Definition: DrawModes.cc:72
Namespace providing different geometric functions concerning angles.