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  * $Revision$ *
45  * $Author$ *
46  * $Date$ *
47  * *
48 \*===========================================================================*/
49 
50 
51 
52 //=============================================================================
53 //
54 // CLASS QtSceneGraphWidget - IMPLEMENTATION
55 //
56 //=============================================================================
57 
58 //== INCLUDES =================================================================
59 
60 
61 #include "QtSceneGraphWidget.hh"
62 #include "QtMaterialDialog.hh"
63 #include "QtTextureDialog.hh"
64 #include "QtClippingDialog.hh"
65 #include "QtCoordFrameDialog.hh"
66 #include "QtShaderDialog.hh"
67 
68 #include "../Scenegraph/MaterialNode.hh"
69 #include "../Scenegraph/TextureNode.hh"
70 #include "../Scenegraph/ClippingNode.hh"
71 #include "../Scenegraph/ShaderNode.hh"
72 #include "../Scenegraph/CoordFrameNode.hh"
73 
74 #include <stdint.h>
75 
76 
77 //== FORWARDDECLARATIONS ======================================================
78 
80 
81 
82 //== NAMESPACES ===============================================================
83 
84 namespace ACG {
85 namespace QtWidgets {
86 
87 
88 //== IMPLEMENTATION ==========================================================
89 
90 SceneGraphWidgetGenerator::SceneGraphWidgetGenerator() {
91 }
92 
94  // Warn as this you have to derive from this class before it can be used!
95  std::cerr << "SceneGraphWidgetGenerator::getWidget not implemented!" << std::endl;
96  return 0;
97 }
98 
99 bool SceneGraphWidgetGenerator::canHandle(std::string _className) {
100  // Warn as this you have to derive from this class before it can be used!
101  std::cerr << "SceneGraphWidgetGenerator::canHandle not implemented!" << _className << std::endl;
102  return false;
103 }
104 
106  // Warn as this you have to derive from this class before it can be used!
107  std::cerr << "SceneGraphWidgetGenerator::canHandle not implemented!" << std::endl;
108  return std::string("Unset Type");
109 }
110 
112  // Warn as this you have to derive from this class before it can be used!
113  std::cerr << "SceneGraphWidgetGenerator::contextMenuName not implemented!" << std::endl;
114  return QString("Context Menu name unset");
115 }
116 
118 QtSceneGraphWidget( QWidget * _parent,
119  SceneGraph::BaseNode * _rootNode ) :
120  QTreeWidget( _parent ),
121  rootNode_(0),
122  curItem_(0),
123  shiftPressed_(false)
124 
125 {
126  setRootIsDecorated(true);
127 
128  setSortingEnabled( false );
129 
130  setSelectionMode( QAbstractItemView::SingleSelection );
131 
132 
133  setColumnCount( 4 );
134 
135  QStringList column_names;
136  column_names.append( "Node" );
137  column_names.append( "Type" );
138  column_names.append( "Status" );
139  column_names.append( "Mode" );
140 
141  setHeaderLabels( column_names );
142 
143  modeMenu_ = new QMenu( this );
144 
145 
146  //
147  // Setup the 'status' actions
148  //
149 
150  statusActions_.menu_ = new QMenu( this );
151 
152  QActionGroup * status_ag = new QActionGroup( statusActions_.menu_ );
153  status_ag->setExclusive( true );
154 
155  statusActions_.actionActive_ = new QAction( "Active", status_ag );
156  statusActions_.actionActive_->setCheckable( true );
157  statusActions_.actionActive_->setData( QVariant( BaseNode::Active ) );
158 
159  statusActions_.actionHideNode_ = new QAction( "Hide Node", status_ag );
160  statusActions_.actionHideNode_->setCheckable( true );
161  statusActions_.actionHideNode_->setData( QVariant( BaseNode::HideNode ) );
162 
163  statusActions_.actionHideChildren_ = new QAction( "Hide Children", status_ag );
164  statusActions_.actionHideChildren_->setCheckable( true );
165  statusActions_.actionHideChildren_->setData( QVariant( BaseNode::HideChildren ) );
166 
167  statusActions_.actionHideSubtree_ = new QAction( "Hide Subtree", status_ag );
168  statusActions_.actionHideSubtree_->setCheckable( true );
169  statusActions_.actionHideSubtree_->setData( QVariant( BaseNode::HideSubtree ) );
170 
171  statusActions_.menu_->addActions( status_ag->actions() );
172 
173  connect( status_ag, SIGNAL( triggered( QAction * ) ),
174  this, SLOT( slotStatusMenu( QAction * ) ) );
175 
176 
177 
178  connect( this, SIGNAL(itemPressed(QTreeWidgetItem*,int) ),
179  this, SLOT(slotItemPressed(QTreeWidgetItem*,int)) );
180 
181  connect( this, SIGNAL(itemExpanded(QTreeWidgetItem*) ),
182  this, SLOT(slotItemExpandedOrCollapsed(QTreeWidgetItem*)) );
183  connect( this, SIGNAL(itemCollapsed(QTreeWidgetItem*) ),
184  this, SLOT(slotItemExpandedOrCollapsed(QTreeWidgetItem*)) );
185 
186  update(_rootNode);
187 
188  setMinimumWidth( 600 );
189  setMinimumHeight( 400 );
190 
191 }
192 
193 
194 //-----------------------------------------------------------------------------
195 
196 
197 void
200 {
201  rootNode_ = _node;
202 
203  clear();
204 
205  Item * item = new Item( this, _node );
206 
208  cREnd(_node->childrenREnd());
209  for (; cRIt != cREnd; ++cRIt)
210  update(*cRIt, item);
211 
212  expandToDepth ( 0 );
213 
214  resizeColumnToContents( 0 );
215  resizeColumnToContents( 1 );
216  resizeColumnToContents( 2 );
217  resizeColumnToContents( 3 );
218 
219  setMinimumWidth( columnWidth(0) + columnWidth(1) + columnWidth(2) + columnWidth(3) );
220 }
221 
222 
223 //-----------------------------------------------------------------------------
224 
225 
226 void
229 {
230  // create new item
231  Item* item = new Item( _parent, _node );
232 
233  // process children
235  cREnd(_node->childrenREnd());
236  for (; cRIt != cREnd; ++cRIt)
237  update(*cRIt, item);
238 }
239 
240 
241 //-----------------------------------------------------------------------------
242 
243 
244 void
245 QtSceneGraphWidget::
246 slotItemExpandedOrCollapsed( QTreeWidgetItem* /*_item*/ )
247 {
248  resizeColumnToContents( 0 );
249 }
250 
251 
252 //-----------------------------------------------------------------------------
253 
254 
255 void
256 QtSceneGraphWidget::
257 slotItemPressed( QTreeWidgetItem * _item,
258  int _col)
259 {
260 
261  if ( _item )
262  {
263  curItem_ = static_cast<Item* >(_item);
264  BaseNode * node = curItem_->node();
265 
266  switch ( _col )
267  {
268  case 2:
269  {
270  statusActions_.actionActive_ ->setChecked( false );
271  statusActions_.actionHideNode_ ->setChecked( false );
272  statusActions_.actionHideChildren_->setChecked( false );
273  statusActions_.actionHideSubtree_ ->setChecked( false );
274 
275  switch ( node->status() )
276  {
277  case BaseNode::Active:
278  statusActions_.actionActive_->setChecked( true );
279  break;
280  case BaseNode::HideNode:
281  statusActions_.actionHideNode_->setChecked( true );
282  break;
284  statusActions_.actionHideChildren_->setChecked( true );
285  break;
287  statusActions_.actionHideSubtree_->setChecked( true );
288  break;
289  }
290  statusActions_.menu_->popup( QCursor::pos() );
291  break;
292  }
293  case 0: break;
294  case 1: break;
295  case 3:
296  {
297  modeMenu_->clear();
298 
299  QActionGroup * modeGroup = new QActionGroup( modeMenu_ );
300  modeGroup->setExclusive( true );
301  connect( modeGroup, SIGNAL( triggered( QAction * ) ),
302  this, SLOT( slotModeMenu( QAction * ) ) );
303 
305  availDrawModes |= SceneGraph::DrawModes::DEFAULT;
306 
307  ACG::SceneGraph::DrawModes::DrawMode currentDrawMode( node->drawMode() );
308 
309  std::vector< ACG::SceneGraph::DrawModes::DrawMode > available_modes( availDrawModes.getAtomicDrawModes() );
310 
311 
312  for ( unsigned int i = 0; i < available_modes.size(); ++i )
313  {
314  ACG::SceneGraph::DrawModes::DrawMode id = available_modes[i];
315  std::string descr = id.description();
316 
317  QAction * action = new QAction( descr.c_str(), modeGroup );
318  action->setCheckable( true );
319  action->setChecked ( currentDrawMode.containsAtomicDrawMode(id ) ) ;
320  action->setData( QVariant( quint64(id.getIndex()) ) );
321  }
322 
323  modeMenu_->addActions( modeGroup->actions() );
324 
325  if ( dynamic_cast<SceneGraph::MaterialNode*>( node ) )
326  {
327  modeMenu_->addSeparator();
328  QAction * action = modeMenu_->addAction( "Edit material" );
329  connect( action, SIGNAL( triggered() ),
330  this, SLOT( slotEditMaterial() ) );
331  }
332 
333  if ( dynamic_cast<SceneGraph::TextureNode*>( node ) )
334  {
335  modeMenu_->addSeparator();
336  QAction * action = modeMenu_->addAction( "Edit texture" );
337  connect( action, SIGNAL( triggered() ),
338  this, SLOT( slotEditTexture() ) );
339  }
340 
341  if ( dynamic_cast<SceneGraph::ShaderNode*>( node ) )
342  {
343  modeMenu_->addSeparator();
344  QAction * action = modeMenu_->addAction( "Edit shaders" );
345  connect( action, SIGNAL( triggered() ),
346  this, SLOT( slotEditShader() ) );
347  }
348 
349  if ( dynamic_cast<SceneGraph::ClippingNode*>( node ) )
350  {
351  modeMenu_->addSeparator();
352  QAction * action = modeMenu_->addAction( "Edit clip planes" );
353  connect( action, SIGNAL( triggered() ),
354  this, SLOT( slotEditClipPlanes() ) );
355  }
356 
357  if ( dynamic_cast<SceneGraph::CoordFrameNode*>( node ) )
358  {
359  modeMenu_->addSeparator();
360  QAction * action = modeMenu_->addAction( "Edit coord frame" );
361  connect( action, SIGNAL( triggered() ),
362  this, SLOT( slotEditCoordinateFrame() ) );
363  }
364 
365  // Add widgets through generator
366  if ( generatorMap_.contains( node->className() ) ) {
367  QWidget* widget = generatorMap_[node->className()]->getWidget( node );
368  modeMenu_->addAction( generatorMap_[node->className()]->contextMenuName() , widget, SLOT(show()) );
369  }
370 
371  modeMenu_->popup( QCursor::pos() );
372 
373  break;
374  }
375  default: break;
376  }
377  }
378 }
379 
380 
381 //-----------------------------------------------------------------------------
382 
383 
384 void QtSceneGraphWidget::slotEditMaterial()
385 {
386  if ( curItem_ )
387  {
388  SceneGraph::MaterialNode * node =
389  dynamic_cast< SceneGraph::MaterialNode * >( curItem_->node() );
390 
391  QtMaterialDialog* dialog = new QtMaterialDialog( this, node );
392 
393  connect(dialog,
395  this,
396  SLOT(slotNodeChanged(ACG::SceneGraph::BaseNode*)));
397 
398  dialog->show();
399  }
400 }
401 
402 //-----------------------------------------------------------------------------
403 
404 
405 void QtSceneGraphWidget::slotEditTexture()
406 {
407  if ( curItem_ )
408  {
409  SceneGraph::TextureNode * node =
410  dynamic_cast< SceneGraph::TextureNode * >( curItem_->node() );
411 
412  QtTextureDialog* dialog = new QtTextureDialog( this, node );
413 
414  connect(dialog,
416  this,
417  SLOT(slotNodeChanged(ACG::SceneGraph::BaseNode*)));
418 
419  dialog->show();
420  }
421 }
422 
423 //-----------------------------------------------------------------------------
424 
425 
426 void QtSceneGraphWidget::slotEditShader()
427 {
428  if ( curItem_ )
429  {
430  SceneGraph::ShaderNode * node =
431  dynamic_cast< SceneGraph::ShaderNode * >( curItem_->node() );
432 
433  QtShaderDialog* dialog = new QtShaderDialog( this, node );
434 
435  connect(dialog,
437  this,
438  SLOT(slotNodeChanged(ACG::SceneGraph::BaseNode*)));
439 
440  dialog->show();
441  }
442 }
443 
444 
445 //-----------------------------------------------------------------------------
446 
447 
448 void QtSceneGraphWidget::slotEditClipPlanes()
449 {
450  if ( curItem_ )
451  {
452  SceneGraph::ClippingNode * node =
453  dynamic_cast< SceneGraph::ClippingNode * >( curItem_->node() );
454 
455  QtClippingDialog * dialog = new QtClippingDialog( this, node );
456 
457  connect(dialog,
459  this,
460  SLOT(slotNodeChanged(ACG::SceneGraph::BaseNode*)));
461 
462  dialog->show();
463  }
464 }
465 
466 
467 //-----------------------------------------------------------------------------
468 
469 
470 void QtSceneGraphWidget::slotEditCoordinateFrame()
471 {
472  if ( curItem_ )
473  {
475  dynamic_cast< SceneGraph::CoordFrameNode * >( curItem_->node() );
476 
477  QtCoordFrameDialog * dialog = new QtCoordFrameDialog( this, node );
478 
479  connect(dialog,
481  this,
482  SLOT(slotNodeChanged(ACG::SceneGraph::BaseNode*)));
483 
484  dialog->show();
485  }
486 }
487 
488 
489 //-----------------------------------------------------------------------------
490 
491 
492 void QtSceneGraphWidget::slotModeMenu( QAction * _action )
493 {
494  SceneGraph::DrawModes::DrawMode new_drawmode( _action->data().toUInt());
495 
496  curItem_->node()->drawMode( new_drawmode );
497  curItem_->update();
498  emit signalNodeChanged( curItem_->node() );
499 }
500 
501 
502 //-----------------------------------------------------------------------------
503 
504 
505 void QtSceneGraphWidget::slotStatusMenu( QAction * _action )
506 {
507  if ( curItem_ )
508  {
509  unsigned int status = _action->data().toUInt();
510  BaseNode * node = curItem_->node();
511 
513  curItem_->update();
514  emit signalNodeChanged( node );
515  }
516 }
517 
518 
519 //-----------------------------------------------------------------------------
520 
521 
522 void QtSceneGraphWidget::keyPressEvent(QKeyEvent* _event)
523 {
524  switch(_event->key())
525  {
526  case Qt::Key_Shift: shiftPressed_ = true; break;
527  default : _event->ignore();
528  }
529 }
530 
531 
532 void QtSceneGraphWidget::keyReleaseEvent(QKeyEvent *_event)
533 {
534  switch(_event->key())
535  {
536  case Qt::Key_Shift: shiftPressed_ = false; break;
537  default : _event->ignore();
538  }
539 }
540 
541 
542 //-----------------------------------------------------------------------------
543 
544 void QtSceneGraphWidget::expandAll() {
545 
546  QTreeWidget::expandAll();
547 
548  resizeColumnToContents(0);
549 }
550 
551 void QtSceneGraphWidget::updateAll() {
552 
553  if(rootNode_) {
554  update(rootNode_);
555  QTreeWidget::expandAll();
556  }
557 
558  resizeColumnToContents(0);
559 }
560 
561 //-----------------------------------------------------------------------------
562 
563 void
564 QtSceneGraphWidget::
565 slotNodeChanged(ACG::SceneGraph::BaseNode* _node)
566 {
567  emit signalNodeChanged(_node);
568 }
569 
570 //-----------------------------------------------------------------------------
571 
573  // Check if we already have a generator for this type.
574  if ( generatorMap_.contains( _generator->handles() ) ) {
575  std::cerr << "Already handled" << std::endl;
576  return false;
577  }
578 
579  // Store the generator
580  generatorMap_[_generator->handles() ] = _generator;
581 
582  return true;
583 }
584 
585 
586 //=============================================================================
587 
588 
589 
590 
591 QtSceneGraphWidget::Item::Item( QTreeWidget * _parent,
592  SceneGraph::BaseNode* _node )
593  : QTreeWidgetItem(_parent), node_(_node)
594 {
595  update();
596 }
597 
598 
599 //-----------------------------------------------------------------------------
600 
601 
602 QtSceneGraphWidget::Item::Item( Item * _parent,
603  SceneGraph::BaseNode* _node )
604  : QTreeWidgetItem(_parent), node_(_node)
605 {
606  update();
607 }
608 
609 
610 //-----------------------------------------------------------------------------
611 
612 
613 void
614 QtSceneGraphWidget::Item::update()
615 {
616  QString name = tr("%1 @ 0x%2")
617  .arg(node_->name().c_str())
618  .arg(reinterpret_cast<uintptr_t>(node_), 0, 16);
619  setText( 0, name.toStdString().c_str());
620  setText( 1, node_->className().c_str());
621 
622  switch (node_->status())
623  {
624  case BaseNode::Active: setText( 2, "Active"); break;
625  case BaseNode::HideNode: setText( 2, "HideNode"); break;
626  case BaseNode::HideChildren: setText( 2, "HideChildren"); break;
627  case BaseNode::HideSubtree: setText( 2, "HideSubtree"); break;
628  }
629 
630  setText( 3, node_->drawMode().description().c_str());
631 }
632 
633 
634 //-----------------------------------------------------------------------------
635 
636 
637 QtSceneGraphDialog::
638 QtSceneGraphDialog( QWidget* _parent,
639  SceneGraph::BaseNode* _rootNode )
640  : QDialog(_parent)
641 {
642  setModal( false );
643 
644  QVBoxLayout* l = new QVBoxLayout( this );
645 
646  QWidget* buttons = new QWidget(this);
647  QHBoxLayout* butLayout = new QHBoxLayout(buttons);
648 
649  sgw_ =
650  new QtSceneGraphWidget( this, _rootNode );
651 
652  // Add buttons to hbox layout
653  QPushButton* expAll = new QPushButton("Expand all");
654  QPushButton* collAll = new QPushButton("Collapse all");
655  QPushButton* updAll = new QPushButton("Update all");
656 
657  butLayout->addWidget(expAll);
658  butLayout->addWidget(collAll);
659  butLayout->addWidget(updAll);
660 
661  l->addWidget(buttons);
662  l->addWidget(sgw_);
663 
664  connect(sgw_,
666  this,
667  SLOT(slotNodeChanged(ACG::SceneGraph::BaseNode*)) );
668 
669  connect(expAll, SIGNAL(pressed()), sgw_, SLOT(expandAll()));
670  connect(collAll, SIGNAL(pressed()), sgw_, SLOT(collapseAll()));
671  connect(updAll, SIGNAL(pressed()), sgw_, SLOT(updateAll()));
672 }
673 
674 
675 //-----------------------------------------------------------------------------
676 
677 
678 void
679 QtSceneGraphDialog::
680 slotNodeChanged(ACG::SceneGraph::BaseNode* _node)
681 {
682  emit(signalNodeChanged(_node));
683 }
684 
685 
686 //-----------------------------------------------------------------------------
687 
688 
689 void
692 {
693  sgw_->update(_rootNode);
694 }
695 
696 
697 //=============================================================================
698 } // namespace QtWidgets
699 } // namespace ACG
700 //=============================================================================
void keyReleaseEvent(QKeyEvent *_event)
key events
StatusMode status() const
Get node&#39;s status.
Definition: BaseNode.hh:432
virtual DrawModes::DrawMode availableDrawModes() const
Definition: BaseNode.hh:167
DrawMode DEFAULT
use the default (global) draw mode and not the node&#39;s own.
Definition: DrawModes.cc:78
DrawModes::DrawMode drawMode() const
Return the own draw modes of this node.
Definition: BaseNode.hh:461
Draw node & children.
Definition: BaseNode.hh:423
Hide this node and its children.
Definition: BaseNode.hh:429
void update(ACG::SceneGraph::BaseNode *_rootNode)
Update recursively from _rootNode on.
virtual QString contextMenuName()
Return a name for your widget in the context menu.
QtSceneGraphWidget(QWidget *_parent=0, SceneGraph::BaseNode *_rootNode=0)
default constructor
bool addWidgetGenerator(SceneGraphWidgetGenerator *_generator)
Add a node widget handler.
void set_status(StatusMode _s)
Set the status of this node.
Definition: BaseNode.hh:434
Draw this node, but hide children.
Definition: BaseNode.hh:427
virtual bool canHandle(std::string _className)
returns if the widgets can handle the given class
virtual QWidget * getWidget(SceneGraph::BaseNode *_node)
Get a widget for this Node.
virtual const std::string & className() const =0
Return class name (implemented by the ACG_CLASSNAME macro)
Hide this node, but draw children.
Definition: BaseNode.hh:425
StatusMode
Status modi.
Definition: BaseNode.hh:420
void update(ACG::SceneGraph::BaseNode *_rootNode)
Update recursively from _rootNode on.
ChildRIter childrenRBegin()
Returns: reverse begin-iterator of children.
Definition: BaseNode.hh:334
Namespace providing different geometric functions concerning angles.
Definition: DBSCANT.cc:51
virtual std::string handles()
return the type this generator handles
void signalNodeChanged(ACG::SceneGraph::BaseNode *_node)
std::vector< BaseNode * >::reverse_iterator ChildRIter
allows to reverse iterate over children
Definition: BaseNode.hh:322
void keyPressEvent(QKeyEvent *_event)
key events
ChildRIter childrenREnd()
Returns: reverse end-iterator of children.
Definition: BaseNode.hh:338
ACG::SceneGraph::BaseNode BaseNode
Base Node.