Salome HOME
Merge from V6_main (04/10/2012)
[modules/gui.git] / src / VTKViewer / VTKViewer_MarkerWidget.cxx
index cc0f0d0353547823fd6f0a38cee496258b783fd4..a28417ceba1ee3920716e4b0ac6c7a7e92c61fc4 100644 (file)
 #include "VTKViewer_MarkerWidget.h"
 #include "VTKViewer_MarkerUtils.h"
 
-#include <QtxComboBox.h>
-
 #include <SUIT_ResourceMgr.h>
 #include <SUIT_Session.h>
 
 #include <vtkImageData.h>
 
-#include <QButtonGroup>
-#include <QGridLayout>
+#include <QComboBox>
 #include <QHBoxLayout>
 #include <QLabel>
-#include <QPushButton>
-#include <QRadioButton>
-#include <QStackedWidget>
+#include <QSpinBox>
 
-#define MARGIN  9
-#define SPACING 6
+const int SPACING = 6;
+enum { TypeRole = Qt::UserRole, IdRole };
 
 /*!
* Class       : VTKViewer_MarkerWidget
* Description : Widget for specifying point marker parameters
- */
 \class VTKViewer_MarkerWidget
 \brief Widget for specifying point marker parameters
+*/
 
 /*!
-  Constructor
+  \brief Constructor
+  \param parent parent widget
 */
-VTKViewer_MarkerWidget::VTKViewer_MarkerWidget( QWidget* theParent )
-: QWidget( theParent )
+VTKViewer_MarkerWidget::VTKViewer_MarkerWidget( QWidget* parent )
+  : QWidget( parent ), myCurrentIdx( -1 )
 {
-  QRadioButton* aStandardTypeRB = new QRadioButton( tr( "STANDARD_MARKER" ), this );
-  QRadioButton* aCustomTypeRB   = new QRadioButton( tr( "CUSTOM_MARKER" ), this );
-  myTypeGroup = new QButtonGroup( this );
-  myTypeGroup->addButton( aStandardTypeRB, 0 );
-  myTypeGroup->addButton( aCustomTypeRB,   1 );
-
-  QHBoxLayout* aRadioLayout = new QHBoxLayout;
-  aRadioLayout->setMargin( 0 );
-  aRadioLayout->setSpacing( SPACING );
-  aRadioLayout->addWidget( aStandardTypeRB );
-  aRadioLayout->addWidget( aCustomTypeRB );
-
-  // ---
-
-  myWGStack = new QStackedWidget( this );
-  myWGStack->setFrameStyle( QFrame::Box | QFrame::Sunken );
-
-  // ---
-
-  QWidget* aStdWidget = new QWidget( myWGStack );
-
-  QLabel* aTypeLab  = new QLabel( tr( "TYPE" ),  aStdWidget );
-  QLabel* aScaleLab = new QLabel( tr( "SCALE" ), aStdWidget );
-
-  myStdTypeCombo  = new QtxComboBox( aStdWidget );
-  myStdScaleCombo = new QtxComboBox( aStdWidget );
-
-  QGridLayout* aStdLayout = new QGridLayout;
-  aStdLayout->setMargin( MARGIN );
-  aStdLayout->setSpacing( SPACING );
-  aStdLayout->addWidget( aTypeLab,        0, 0 );
-  aStdLayout->addWidget( myStdTypeCombo,  0, 1 );
-  aStdLayout->addWidget( aScaleLab,       1, 0 );
-  aStdLayout->addWidget( myStdScaleCombo, 1, 1 );
-  aStdWidget->setLayout( aStdLayout );
-
-  // ---
-
-  QWidget* aCustomWidget = new QWidget( myWGStack );
-
-  QLabel* aCustomLab = new QLabel( tr( "CUSTOM" ), aCustomWidget );
-  myCustomTypeCombo = new QtxComboBox( aCustomWidget );
-  QPushButton* aBrowseBtn = new QPushButton( tr( "BROWSE" ), aCustomWidget );
-
-  QGridLayout* aCustomLayout = new QGridLayout;
-  aCustomLayout->setMargin( MARGIN );
-  aCustomLayout->setSpacing( SPACING );
-  aCustomLayout->addWidget( aCustomLab,        0, 0 );
-  aCustomLayout->addWidget( myCustomTypeCombo, 0, 1 );
-  aCustomLayout->addWidget( aBrowseBtn,        0, 2 );
-  aCustomLayout->setRowStretch( 1, 5 );
-  aCustomWidget->setLayout( aCustomLayout );
-
-  // ---
-  
-  myWGStack->insertWidget( 0, aStdWidget );
-  myWGStack->insertWidget( 1, aCustomWidget );
-
-  // ---
-
-  QVBoxLayout* aTopLayout = new QVBoxLayout;
-  aTopLayout->setMargin( MARGIN );
-  aTopLayout->setSpacing( SPACING );
-  aTopLayout->addLayout( aRadioLayout );
-  aTopLayout->addWidget( myWGStack );
-  setLayout( aTopLayout );
-
-  // ---
-
-  connect( myTypeGroup, SIGNAL( buttonClicked( int ) ), myWGStack, SLOT( setCurrentIndex( int ) ) );
-  connect( myStdTypeCombo, SIGNAL( currentIndexChanged( int ) ), this, SLOT( onStdMarkerChanged( int ) ) );
-  connect( aBrowseBtn,  SIGNAL( clicked() ), this, SLOT( onBrowse() ) );
-
-  // ---
-
-  aStandardTypeRB->setChecked( true );
+  // create widgets
+  myTypeLab  = new QLabel( tr( "TYPE" ),  this );
+  myScaleLab = new QLabel( tr( "SCALE" ), this );
+  myType     = new QComboBox( this );
+  myScale    = new QSpinBox( this );
+  // layouting
+  QHBoxLayout* ml = new QHBoxLayout( this );
+  ml->setMargin( 0 );
+  ml->setSpacing( SPACING );
+  ml->addWidget( myTypeLab );
+  ml->addWidget( myType );
+  ml->addWidget( myScaleLab );
+  ml->addWidget( myScale );
+  myType->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed );
+  myScale->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed );
+  // connect signals/slots
+  connect( myType, SIGNAL( currentIndexChanged( int ) ), this, SLOT( onTypeChanged( int ) ) );
+  // initialize
   init();
 }
 
 /*!
-  Destructor
+  \brief Destructor
 */
 VTKViewer_MarkerWidget::~VTKViewer_MarkerWidget()
 {
 }
 
-void VTKViewer_MarkerWidget::setCustomMarkerMap( VTK::MarkerMap theMarkerMap )
+/*!
+  \brief Set custom markers data
+  \param markerMap custom marker data (a map {index:texture})
+*/
+void VTKViewer_MarkerWidget::setCustomMarkers( const VTK::MarkerMap& markerMap )
 {
-  myCustomMarkerMap = theMarkerMap;
-
-  VTK::MarkerMap::const_iterator it = theMarkerMap.begin(), itEnd = theMarkerMap.end();
-  for( ; it != itEnd; it++ )
+  // store custom markers data
+  myCustomMarkers = markerMap;
+  // clear current custom markers
+  for ( int i = myType->count()-1; i >= 0; i-- ) {
+    int type = myType->itemData( i, TypeRole ).toInt();
+    if ( type == VTK::MT_USER )
+      myType->removeItem( i );
+  }
+  // add custom markers
+  VTK::MarkerMap::const_iterator it;
+  for ( it = myCustomMarkers.begin(); it != myCustomMarkers.end(); ++it )
   {
-    int anId = it->first;
-    VTK::MarkerData aMarkerData = it->second;
-    QPixmap aPixmap = markerFromData( aMarkerData );
-    if( !aPixmap.isNull() )
+    int id = it->first;
+    VTK::MarkerData markerData = it->second;
+    QPixmap icon = markerFromData( markerData );
+    if( !icon.isNull() )
     {
-      myCustomTypeCombo->addItem( aPixmap, QString::number( anId ) );
-      myCustomTypeCombo->setId( myCustomTypeCombo->count()-1, anId );
+      int idx = myType->count()-1;
+      myType->insertItem( idx, icon, QString() );
+      myType->setItemData( idx, VTK::MT_USER, TypeRole );
+      myType->setItemData( idx, id, IdRole );
     }
   }
 }
 
-VTK::MarkerMap VTKViewer_MarkerWidget::getCustomMarkerMap()
+/*!
+  \brief Get custom markers data
+  \return custom marker data
+*/
+VTK::MarkerMap VTKViewer_MarkerWidget::customMarkers() const
 {
-  return myCustomMarkerMap;
+  return myCustomMarkers;
 }
 
-void VTKViewer_MarkerWidget::setStandardMarker( VTK::MarkerType theMarkerType, VTK::MarkerScale theMarkerScale )
+/*!
+  \brief Add standard marker
+  The marker type specified with \a type must be > VTK::MT_USER
+  \param type marker type
+  \param icon marker icon
+*/
+void VTKViewer_MarkerWidget::addMarker( VTK::MarkerType type, const QPixmap& icon )
 {
-  if ( ( theMarkerType > VTK::MT_NONE && theMarkerType < VTK::MT_USER ) ||
-       myExtraMarkerList.contains( theMarkerType ) ) {
-    myTypeGroup->button( 0 )->setChecked( true );
-    myWGStack->setCurrentIndex( 0 );
-    myStdTypeCombo->setCurrentId( theMarkerType );
-    int aMarkerScale = std::max( (int)VTK::MS_10, std::min( (int)VTK::MS_70, (int)theMarkerScale ) );
-    myStdScaleCombo->setCurrentId( aMarkerScale );
+  if ( type > VTK::MT_USER ) {
+    int idx = (int)VTK::MT_USER - 1;
+    // find insertion index
+    while ( idx < myType->count()-1 ) {
+      if ( myType->itemData( idx, TypeRole ) == VTK::MT_USER )
+       break;
+      ++idx;
+    }
+    myType->insertItem( idx, icon, QString() );
+    myType->setItemData( idx, type, TypeRole );
   }
 }
 
-void VTKViewer_MarkerWidget::setCustomMarker( int theId )
+/*!
+  \brief Select specified standard marker as current one
+  \param type marker type
+  \param scale marker scale (optional parameter; can be omitted for extended markers)
+*/
+void VTKViewer_MarkerWidget::setMarker( VTK::MarkerType type, VTK::MarkerScale scale )
 {
-  if ( theId > 0 ) {
-    myTypeGroup->button( 1 )->setChecked( true );
-    myWGStack->setCurrentIndex( 1 );
-    addTexture( theId );
-    myCustomTypeCombo->setCurrentId( theId );
+  if ( type != VTK::MT_USER ) {
+    for ( int i = 0; i < myType->count()-1; i++ ) {
+      if ( type == myType->itemData( i, TypeRole ).toInt() ) {
+       myType->setCurrentIndex( i );
+       break;
+      }
+    }
   }
+  if ( scale != VTK::MS_NONE )
+    myScale->setValue( qMax( (int)VTK::MS_10, qMin( (int)VTK::MS_70, (int)scale ) ) );
 }
 
-VTK::MarkerType VTKViewer_MarkerWidget::getMarkerType() const
+/*!
+  \brief Select specified custom marker as current one
+  \param id custom marker identifier
+*/
+void VTKViewer_MarkerWidget::setCustomMarker( int id )
 {
-  return myWGStack->currentIndex() == 0 ? (VTK::MarkerType)myStdTypeCombo->currentId() : VTK::MT_USER;
+  for ( int i = 0; i < myType->count()-1; i++ ) {
+    int type = myType->itemData( i, TypeRole ).toInt();
+    if ( type == VTK::MT_USER && id == myType->itemData( i, IdRole ).toInt() ) {
+      myType->setCurrentIndex( i );
+      break;
+    }
+  }
 }
 
-VTK::MarkerScale VTKViewer_MarkerWidget::getStandardMarkerScale() const
+/*!
+  \brief Get current marker's type.
+  For custom marker, VTK::MT_USER is returned and markerId() function 
+  then returns its identifier.
+  \return currently selected marker type
+*/
+VTK::MarkerType VTKViewer_MarkerWidget::markerType() const
 {
-  return myWGStack->currentIndex() == 0 ? (VTK::MarkerScale)myStdScaleCombo->currentId() : VTK::MS_NONE;
+  return myType->itemData( myType->currentIndex(), TypeRole ).toInt();
 }
 
-int VTKViewer_MarkerWidget::getCustomMarkerID() const
+/*!
+  \brief Get current marker's scale size.
+  For custom marker return value is undefined.
+  \return currently selected marker scale size
+*/
+VTK::MarkerScale VTKViewer_MarkerWidget::markerScale() const
 {
-  return myWGStack->currentIndex() == 1 ? myCustomTypeCombo->currentId() : 0;
+  return myScale->value();
 }
 
-void VTKViewer_MarkerWidget::addExtraStdMarker( VTK::MarkerType theMarkerType, const QPixmap& thePixmap )
+/*!
+  \bried Get currently selected custom marker's identifier.
+  For standard markers return value is VTK::MT_NONE.
+*/
+int VTKViewer_MarkerWidget::markerId() const
 {
-  if( myExtraMarkerList.isEmpty() )
-    myStdTypeCombo->insertSeparator( myStdTypeCombo->count() );
-  myStdTypeCombo->addItem( thePixmap, QString() );
-  myStdTypeCombo->setId( myStdTypeCombo->count()-1, theMarkerType );
-
-  myExtraMarkerList.append( theMarkerType );
+  int type = myType->itemData( myType->currentIndex(), TypeRole ).toInt();
+  return type == VTK::MT_USER ? myType->itemData( myType->currentIndex(), IdRole ).toInt() : VTK::MT_NONE;
 }
 
-void VTKViewer_MarkerWidget::init()
+/*!
+  \brief Get access to the internal marker type label
+  \return marker type label widget
+*/
+QLabel* VTKViewer_MarkerWidget::typeLabel()
 {
-  SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
-
-  for ( int i = VTK::MT_POINT; i < VTK::MT_USER; i++ ) {
-    QString icoFile = QString( "ICON_VERTEX_MARKER_%1" ).arg( i );
-    QPixmap pixmap = resMgr->loadPixmap( "VTKViewer", tr( qPrintable( icoFile ) ) );
-    myStdTypeCombo->addItem( pixmap, QString() );
-    myStdTypeCombo->setId( myStdTypeCombo->count()-1, i );
-  }
-
-  for ( int i = VTK::MS_10; i <= VTK::MS_70; i++ ) {
-    myStdScaleCombo->addItem( QString::number( (i-1)*0.5 + 1.0 ) );
-    myStdScaleCombo->setId( myStdScaleCombo->count()-1, i );
-  }
+  return myTypeLab;
 }
 
-void VTKViewer_MarkerWidget::addTexture( int id, bool select )
+/*!
+  \brief Get access to the internal marker scale label
+  \return marker scale label widget
+*/
+QLabel* VTKViewer_MarkerWidget::scaleLabel()
 {
-  if ( id > 0 && myCustomTypeCombo->index( id ) == -1 &&
-       myCustomMarkerMap.find( id ) != myCustomMarkerMap.end() ) {
-    VTK::MarkerData aMarkerData = myCustomMarkerMap[ id ];
-    QPixmap pixmap = markerFromData( aMarkerData );
-    if( !pixmap.isNull() ) {
-      myCustomTypeCombo->addItem( pixmap, QString::number( id ) );
-      myCustomTypeCombo->setId( myCustomTypeCombo->count()-1, id );
-      if ( select ) myCustomTypeCombo->setCurrentId( id );
-    }
-  }
+  return myScaleLab;
 }
 
-QPixmap VTKViewer_MarkerWidget::markerFromData( const VTK::MarkerData& theMarkerData )
+/*!
+  \brief Internal initialization
+*/
+void VTKViewer_MarkerWidget::init()
 {
-  const VTK::MarkerTexture& aMarkerTexture = theMarkerData.second;
-  vtkSmartPointer<vtkImageData> anImageData = VTK::MakeVTKImage( aMarkerTexture, false );
+  myType->blockSignals( true );
 
-  QImage anImage = VTK::ConvertToQImage( anImageData.GetPointer() );
-  if( anImage.isNull() )
-    return QPixmap();
+  SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
+  // standard marker types
+  for ( int type = VTK::MT_POINT; type < VTK::MT_USER; type++ ) {
+    QString icoFile = QString( "ICON_VERTEX_MARKER_%1" ).arg( type );
+    QPixmap pixmap = resMgr->loadPixmap( "VTKViewer", tr( qPrintable( icoFile ) ) );
+    myType->addItem( pixmap, QString() );
+    myType->setItemData( myType->count()-1, type, TypeRole );
+  }
+  // standard marker sizes
+  myScale->setMinimum( (int)VTK::MS_10 );
+  myScale->setMaximum( (int)VTK::MS_70 );
+  // add item for loading custom textures
+  myType->addItem( "..." );
+  myType->setItemData( myType->count()-1, VTK::MT_NONE, TypeRole );
 
-  return QPixmap::fromImage( anImage );
+  myType->blockSignals( false );
+
+  // set current item to first type in the list
+  myType->setCurrentIndex( 0 );
 }
 
-void VTKViewer_MarkerWidget::onStdMarkerChanged( int index )
+/*!
+  \brief Create icon from the custom marker data (texture)
+  \param markerData custom marker data
+  \return icon generated from texture specified with marker data
+*/
+QPixmap VTKViewer_MarkerWidget::markerFromData( const VTK::MarkerData& markerData )
 {
-  VTK::MarkerType aMarkerType = (VTK::MarkerType)myStdTypeCombo->id( index );
-  bool anIsExtraMarker = myExtraMarkerList.contains( aMarkerType );
-  myStdScaleCombo->setEnabled( !anIsExtraMarker );
+  // get texture data
+  const VTK::MarkerTexture& texture = markerData.second;
+  // generate VTK image
+  vtkSmartPointer<vtkImageData> image = VTK::MakeVTKImage( texture, false );
+  // convert VTK image to icon
+  QImage qimage = VTK::ConvertToQImage( image.GetPointer() );
+  return qimage.isNull() ? QPixmap() : QPixmap::fromImage( qimage );
 }
 
-void VTKViewer_MarkerWidget::onBrowse()
+/*!
+  \brief Called when marker type is changed (by the user or programmatically)
+  \param index index of item being selected
+*/
+void VTKViewer_MarkerWidget::onTypeChanged( int index )
 {
-  QStringList filters;
-  filters << tr( "Texture files (*.dat)" ) << tr( "All files (*)" );
-  QString aFileName = SUIT_Session::session()->activeApplication()->getFileName( true, QString(), filters.join( ";;" ), tr( "LOAD_TEXTURE_TLT" ), this );
-  if ( !aFileName.isEmpty() ) {
-    VTK::MarkerTexture aMarkerTexture;
-    if ( VTK::LoadTextureData( aFileName, VTK::MS_NONE, aMarkerTexture ) ) {
-      int anId = VTK::GetUniqueId( myCustomMarkerMap );
-      VTK::MarkerData& aMarkerData = myCustomMarkerMap[ anId ];
-      aMarkerData.first = aFileName.toStdString();
-      aMarkerData.second = aMarkerTexture;
-      addTexture( anId, true );
+  if ( index == myType->count()-1 ) {
+    // browse new custom texture file item is selected
+    QStringList filters;
+    filters << tr( "Texture files (*.dat)" ) << tr( "All files (*)" );
+    QString fileName = SUIT_Session::session()->activeApplication()->getFileName( true, 
+                                                                                 QString(), 
+                                                                                 filters.join( ";;" ), 
+                                                                                 tr( "LOAD_TEXTURE_TLT" ), 
+                                                                                 parentWidget() );
+    if ( !fileName.isEmpty() ) {
+      // load texture and add new marker
+      VTK::MarkerTexture texture;
+      if ( VTK::LoadTextureData( fileName, VTK::MS_NONE, texture ) ) {
+       int id = VTK::GetUniqueId( myCustomMarkers );
+       VTK::MarkerData& markerData = myCustomMarkers[ id ];
+       markerData.first  = fileName.toStdString();
+       markerData.second = texture;
+       QPixmap icon = markerFromData( markerData );
+       if( !icon.isNull() ) {
+         int idx = myType->count()-1;
+         myType->blockSignals( true );
+         myType->insertItem( idx, icon, QString() );
+         myType->blockSignals( false );
+         myType->setItemData( idx, VTK::MT_USER, TypeRole );
+         myType->setItemData( idx, id, IdRole );
+         myType->setCurrentIndex( idx );
+         return;
+       }
+      }
     }
+    // if user cancelled texture loading or there was an error when loading texture
+    // reset to the previous item
+    myType->setCurrentIndex( myCurrentIdx );
+    return;
+  }
+  else {
+    myCurrentIdx = index;
   }
+  int type = myType->itemData( index, TypeRole ).toInt();
+  myScale->setEnabled( type < VTK::MT_USER );
+  myScaleLab->setEnabled( type < VTK::MT_USER );
 }