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