Exemple #1
0
void smoothMesh( Polyhedron & poly, unsigned int nTimes )
{
    int nV = poly.size_of_vertices();
    const double lambda = SMOOTHING_LAMBDA;
    const double mu	= SMOOTHING_MU;

    vector< Point3 > shrink  ( nV );
    vector< Point3 > expand  ( nV );

    for ( unsigned int k = 0; k < nTimes; ++k ) {
	// copy the vertex coordinates
	for ( Vertex_iterator vi = poly.vertices_begin(); vi != poly.vertices_end(); ++vi ) {
	    shrink  [ vi->id() ] = vi->point();
	}
	// shrinking stage
	for ( Vertex_iterator vi = poly.vertices_begin(); vi != poly.vertices_end(); ++vi ) {
	    moveVertex( vi, shrink[ vi->id() ], lambda );
	}
	// copy back the vertex coordinates
	for ( Vertex_iterator vi = poly.vertices_begin(); vi != poly.vertices_end(); ++vi ) {
	    vi->point()		= shrink[ vi->id() ];
	    expand[ vi->id() ]	= shrink[ vi->id() ];
	}
	// expanding stage
	for ( Vertex_iterator vi = poly.vertices_begin(); vi != poly.vertices_end(); ++vi ) {
	    moveVertex( vi, expand[ vi->id() ], mu );
	}
	// copy back the vertex coordinates
	for ( Vertex_iterator vi = poly.vertices_begin(); vi != poly.vertices_end(); ++vi ) {
	    vi->point()		= expand[ vi->id() ];
	}
    }
}
void LevelDesignerController::alignToGrid(void) {
  PolygonList polygonList = _model->getPolygonList();
  for (int k = 0; k < _model->rowCount(); ++k) {
    TreeItem* polygonItem = _model->getItem(_model->index(k, 0));
    std::vector<Point2d> vertices = polygonList.at(k).getVertices();
    for (int i = 0; i < polygonItem->childCount(); ++i) {
      Point2d currVertex = vertices.at(i);

      int oldX = currVertex.getX();
      int oldY = currVertex.getY();

      int extraX = static_cast<int>(oldX)%50;
      int extraY = static_cast<int>(oldY)%50;

      int newX = oldX;
      int newY = oldY;

      if (extraY < 50/3)
        newY = oldY - extraY;// + 5;
      else if (extraY > 50 - 50/3)
        newY = oldY + (50 - extraY);// + 5;

      if (extraX < 50/3)
        newX = oldX - extraX;// + 5;
      else if (extraX > 50 - 50/3)
        newX = oldX + (50 - extraX);// + 5;

      if (oldX != newX || oldY != newY)
        moveVertex(k, i, oldX, oldY, newX, newY);
    }
  }
}
Exemple #3
0
//------------------------------------------------------------------------------
//!
void DFPolygonEditor::updateAttributes( const DFNodeAttrStates& attribs )
{
   for( auto cur = attribs.begin(); cur != attribs.end(); ++cur )
   {
      if( cur->_id == 0 )
      {
         moveVertex( cur->_value.getVec3() );
      }
   }
}
Exemple #4
0
void MeshManipulator::perform(const Ray * r)
{
    if(!m_started) return;
	if(!m_intersect->m_success) return;

	switch(m_mode) {
		case 1:
			smoothSurface(r);
			break;
		default:
			moveVertex(r);
			break;
	}
}
void ProfileScene::mousePressEvent(QGraphicsSceneMouseEvent* mouseEvent)
{

    if (!isProfileSelected) {
        return;
    }

    if (mouseEvent->button() ==  Qt::RightButton){
        if(ctrl_pressed){
            addVertex(mouseEvent->lastScenePos().toPoint());
        } else if (shift_pressed) {
            //remove point if clicked on a point
            removeVertex();
        } else {
            moveVertex();
        }
    }
}
CoordType SpatialModelMaximalRepulsion3D<CoordType>::computeBeta()
{
  const int n = 100;
  const int numPoints = this->getHardcoreDistances().getSize();
  const CoordType maxRadius = this->getTriMesh().equivalentRadius() / 50.0;
  RandomGenerator& randomGenerator = this->getRandomGenerator();
  Vertices<CoordType> vertices1;
  Vertices<CoordType> vertices2;
  CoordType sumDelta = 0.0;

  for (int i = 0; i < n; ++i)
  {
    vertices1 = SpatialModelHardcoreDistance3D<CoordType>::drawSample( numPoints );
    vertices2 = vertices1;
    vertices2.detach();
    int v = randomGenerator.uniformL( numPoints );
    moveVertex( vertices2, v, maxRadius );
    sumDelta += fabs( energy(vertices1) - energy(vertices2) );
  }

  return log( 20.0 ) / ( sumDelta/n );
}
Exemple #7
0
void QgsGrassEdit::keyPress( QKeyEvent *e )
{
  QgsDebugMsg( "entered." );
  // This does not work:
  //keyPressEvent(e);

  // TODO: this is not optimal
  switch ( e->key() )
  {
    case Qt::Key_F1: newPoint(); break;
    case Qt::Key_F2: newLine(); break;
    case Qt::Key_F3: newBoundary(); break;
    case Qt::Key_F4: newCentroid(); break;
    case Qt::Key_F5: moveVertex(); break;
    case Qt::Key_F6: addVertex(); break;
    case Qt::Key_F7: deleteVertex(); break;
    case Qt::Key_F9: moveLine(); break;
    case Qt::Key_F10: splitLine(); break;
    case Qt::Key_F11: deleteLine(); break;
    default: break;
  }
}
void FloorScene::mousePressEvent(QGraphicsSceneMouseEvent* mouseEvent)
{
    if (mouseEvent->button() ==  Qt::RightButton){
        if(ctrl_pressed){
            addVertex(mouseEvent->lastScenePos().toPoint());
        } else if (shift_pressed) {
            removeVertex();
        } else {
            unsigned int floorPlanSize = mesh->getFloorPlanSize();

            // we have have at least one vertex on the floor plan, if we click on it, we can move it
            // and we draw his profile
            if (floorPlanSize != 0) {
                moveVertex();
            // else if we do not have any vertices on the floor plan, we create a floor plan
            } else {
                QPoint mousePos = mouseEvent->lastScenePos().toPoint();
                // no point defined thus we add an initial geometric structure
                basicCircle(&mousePos, 10);
            }
        }
    }
}
void ProfileScene::mousePressEvent(QGraphicsSceneMouseEvent* mouseEvent) {
    float tmpx = mouseEvent->lastScenePos().toPoint().x();
    float tmpy = mouseEvent->lastScenePos().toPoint().y();
    QRectF thisSize = this->sceneRect();
    Utils::adjustCoordinatesSceneTo3D(tmpx, tmpy, thisSize.width(), thisSize.height());
    std::cerr << "P: " << tmpx << ", " << tmpy << std::endl;

    if (!isProfileSelected) {
        return;
    }

    if (mouseEvent->button() ==  Qt::RightButton){
        // if user use right click + ctrl
        if(mouseEvent->modifiers() == Qt::ControlModifier){
            addVertex(mouseEvent->lastScenePos().toPoint());
        // if user use right click + shift
        } else if (mouseEvent->modifiers() == Qt::ShiftModifier) {
            //remove point if clicked on a point
            removeVertex();
        } else {
            moveVertex();
        }
    }
}
Vertices<CoordType> SpatialModelMaximalRepulsion3D<CoordType>::drawSample(const int numPoints)
{
  ENTER("Vertices<CoordType> SpatialModelMaximalRepulsion3D<CoordType>::drawSample(const int)");

  const int outerSteps = getNumMonteCarloCycles();
  const int innerSteps = numPoints;
  const CoordType beta = computeBeta();
  const CoordType maxRadius = this->getTriMesh().equivalentRadius() / 50.0;
  Vertices<CoordType> vertices = SpatialModelHardcoreDistance3D<CoordType>::drawSample( numPoints );
  RandomGenerator& randomGenerator = this->getRandomGenerator();
  CoordType currentEnergy, newEnergy, deltaEnergy;
  Vector<CoordType> vertex;
  bool acceptTransition;
  int i, j, v;

  ConvergenceTest<CoordType> convergenceTest;  
  CoordType sumEnergy;
  bool converged = false;
  _energyProfile.setZeros( outerSteps );
  convergenceTest.setData( _energyProfile );
  convergenceTest.setRange( 100 );

  for (i = 0; !converged && i < outerSteps; ++i)
  {
#if 0
    if ( (i%20)==0 )
    {
      string filename = "max-repulsion-vertices-" + StringTools::toString(i,4,'0') + ".vx";
      vertices.save( filename, true );
    }
#endif
    for (j = 0, sumEnergy = 0.0; j < innerSteps; ++j)
    {
      v = randomGenerator.uniformL( numPoints );
      vertex = vertices[v];
      if ( j == 0 ) currentEnergy = energy( vertices );
      moveVertex( vertices, v, maxRadius );
      newEnergy = energy( vertices );
      deltaEnergy = newEnergy - currentEnergy;
      acceptTransition = deltaEnergy <= .0 || randomGenerator.uniformLF() < exp( -beta*deltaEnergy );

      if ( acceptTransition )
        currentEnergy = newEnergy;
      else vertices[v] = vertex;
      sumEnergy += currentEnergy;
    }

    _energyProfile[i] = sumEnergy / innerSteps;
    converged = convergenceTest.isPositive( i );
  }

  if ( !converged )
  {
    Exception exception;
    exception.setWhere( "Vertices<CoordType> SpatialModelMaximalRepulsion3D<CoordType>::drawSample(const int)" );
    exception.setWhat( "Convergence not reached after " + StringTools::toString(outerSteps) + " iterations" );
    throw exception;
  }

  LEAVE();

  return vertices;
}
bool QgsVectorLayerEditUtils::moveVertex( double x, double y, QgsFeatureId atFeatureId, int atVertex )
{
  QgsPointV2 p( x, y );
  return moveVertex( p, atFeatureId, atVertex );
}
Exemple #12
0
void QgsGrassEdit::init()
{
  if ( !( mProvider->isGrassEditable() ) )
  {
    QMessageBox::warning( 0, tr( "Warning" ),
                          tr( "You are not owner of the mapset, cannot open the vector for editing." ) );
    return;
  }

  if ( !( mProvider->startEdit() ) )
  {
    QMessageBox::warning( 0, tr( "Warning" ), tr( "Cannot open vector for update." ) );
    return;
  }

  mRubberBandLine = new QgsRubberBand( mCanvas );
  mRubberBandIcon = new QgsVertexMarker( mCanvas );
  mRubberBandLine->setZValue( 20 );
  mRubberBandIcon->setZValue( 20 );

  connect( mCanvas, SIGNAL( keyPressed( QKeyEvent * ) ), this, SLOT( keyPress( QKeyEvent * ) ) );


  mToolBar = addToolBar( tr( "Edit tools" ) );

  mNewPointAction = new QAction(
    QgsGrassPlugin::getThemeIcon( "grass_new_point.png" ), tr( "New point" ), this );
  mNewPointAction->setShortcut( QKeySequence( Qt::Key_F1 ) );
  mToolBar->addAction( mNewPointAction );
  connect( mNewPointAction, SIGNAL( triggered() ), this, SLOT( newPoint() ) );

  mNewLineAction = new QAction(
    QgsGrassPlugin::getThemeIcon( "grass_new_line.png" ), tr( "New line" ), this );
  mNewLineAction->setShortcut( QKeySequence( Qt::Key_F2 ) );
  mToolBar->addAction( mNewLineAction );
  connect( mNewLineAction, SIGNAL( triggered() ), this, SLOT( newLine() ) );

  mNewBoundaryAction = new QAction(
    QgsGrassPlugin::getThemeIcon( "grass_new_boundary.png" ), tr( "New boundary" ), this );
  mNewBoundaryAction->setShortcut( QKeySequence( Qt::Key_F3 ) );
  mToolBar->addAction( mNewBoundaryAction );
  connect( mNewBoundaryAction, SIGNAL( triggered() ), this, SLOT( newBoundary() ) );

  mNewCentroidAction = new QAction(
    QgsGrassPlugin::getThemeIcon( "grass_new_centroid.png" ), tr( "New centroid" ), this );
  mNewCentroidAction->setShortcut( QKeySequence( Qt::Key_F4 ) );
  mToolBar->addAction( mNewCentroidAction );
  connect( mNewCentroidAction, SIGNAL( triggered() ), this, SLOT( newCentroid() ) );

  mMoveVertexAction = new QAction(
    QgsGrassPlugin::getThemeIcon( "grass_move_vertex.png" ), tr( "Move vertex" ), this );
  mMoveVertexAction->setShortcut( QKeySequence( Qt::Key_F5 ) );
  mToolBar->addAction( mMoveVertexAction );
  connect( mMoveVertexAction, SIGNAL( triggered() ), this, SLOT( moveVertex() ) );

  mAddVertexAction = new QAction(
    QgsGrassPlugin::getThemeIcon( "grass_add_vertex.png" ), tr( "Add vertex" ), this );
  mAddVertexAction->setShortcut( QKeySequence( Qt::Key_F6 ) );
  mToolBar->addAction( mAddVertexAction );
  connect( mAddVertexAction, SIGNAL( triggered() ), this, SLOT( addVertex() ) );

  mDeleteVertexAction = new QAction(
    QgsGrassPlugin::getThemeIcon( "grass_delete_vertex.png" ), tr( "Delete vertex" ), this );
  mDeleteVertexAction->setShortcut( QKeySequence( Qt::Key_F7 ) );
  mToolBar->addAction( mDeleteVertexAction );
  connect( mDeleteVertexAction, SIGNAL( triggered() ), this, SLOT( deleteVertex() ) );

  mMoveLineAction = new QAction(
    QgsGrassPlugin::getThemeIcon( "grass_move_line.png" ), tr( "Move element" ), this );
  mMoveLineAction->setShortcut( QKeySequence( Qt::Key_F9 ) );
  mToolBar->addAction( mMoveLineAction );
  connect( mMoveLineAction, SIGNAL( triggered() ), this, SLOT( moveLine() ) );

  mSplitLineAction = new QAction(
    QgsGrassPlugin::getThemeIcon( "grass_split_line.png" ), tr( "Split line" ), this );
  mSplitLineAction->setShortcut( QKeySequence( Qt::Key_F10 ) );
  mToolBar->addAction( mSplitLineAction );
  connect( mSplitLineAction, SIGNAL( triggered() ), this, SLOT( splitLine() ) );

  mDeleteLineAction = new QAction(
    QgsGrassPlugin::getThemeIcon( "grass_delete_line.png" ), tr( "Delete element" ), this );
  mDeleteLineAction->setShortcut( QKeySequence( Qt::Key_F11 ) );
  mToolBar->addAction( mDeleteLineAction );
  connect( mDeleteLineAction, SIGNAL( triggered() ), this, SLOT( deleteLine() ) );

  mEditAttributesAction = new QAction(
    QgsGrassPlugin::getThemeIcon( "grass_edit_attributes.png" ), tr( "Edit attributes" ), this );
  mToolBar->addAction( mEditAttributesAction );
  connect( mEditAttributesAction, SIGNAL( triggered() ), this, SLOT( editAttributes() ) );

  mCloseEditAction = new QAction(
    QgsGrassPlugin::getThemeIcon( "grass_close_edit.png" ), tr( "Close" ), this );
  mToolBar->addAction( mCloseEditAction );
  connect( mCloseEditAction, SIGNAL( triggered() ), this, SLOT( closeEdit() ) );

  mNewPointAction->setCheckable( true );
  mNewLineAction->setCheckable( true );
  mNewBoundaryAction->setCheckable( true );
  mNewCentroidAction->setCheckable( true );
  mMoveVertexAction->setCheckable( true );
  mAddVertexAction->setCheckable( true );
  mDeleteVertexAction->setCheckable( true );
  mMoveLineAction->setCheckable( true );
  mSplitLineAction->setCheckable( true );
  mDeleteLineAction->setCheckable( true );
  mEditAttributesAction->setCheckable( true );

  QActionGroup *ag = new QActionGroup( this );
  ag->addAction( mNewPointAction );
  ag->addAction( mNewLineAction );
  ag->addAction( mNewBoundaryAction );
  ag->addAction( mNewCentroidAction );
  ag->addAction( mMoveVertexAction );
  ag->addAction( mAddVertexAction );
  ag->addAction( mDeleteVertexAction );
  ag->addAction( mMoveLineAction );
  ag->addAction( mSplitLineAction );
  ag->addAction( mDeleteLineAction );
  ag->addAction( mEditAttributesAction );

  mEditPoints = Vect_new_line_struct();
  mPoints = Vect_new_line_struct();
  mCats = Vect_new_cats_struct();

  // Set lines symbology from map
  int nlines = mProvider->numLines();
  mLineSymb.resize( nlines + 1000 );
  for ( int line = 1; line <= nlines; line++ )
  {
    mLineSymb[line] = lineSymbFromMap( line );
  }

  // Set nodes symbology from map
  int nnodes = mProvider->numNodes();
  mNodeSymb.resize( nnodes + 1000 );
  for ( int node = 1; node <= nnodes; node++ )
  {
    mNodeSymb[node] = nodeSymbFromMap( node );
  }

  // Set default colors
  mSymb.resize( SYMB_COUNT );
  mSymb[SYMB_BACKGROUND].setColor( QColor( 255, 255, 255 ) );       // white
  mSymb[SYMB_HIGHLIGHT].setColor( QColor( 255, 255,   0 ) );        // yellow
  mSymb[SYMB_DYNAMIC].setColor( QColor( 125, 125, 125 ) );          // grey
  mSymb[SYMB_POINT].setColor( QColor( 0,   0,   0 ) );              // black
  mSymb[SYMB_LINE].setColor( QColor( 0,   0,   0 ) );               // black
  mSymb[SYMB_BOUNDARY_0].setColor( QColor( 255,   0,   0 ) );       // red
  mSymb[SYMB_BOUNDARY_1].setColor( QColor( 255, 125,   0 ) );       // orange
  mSymb[SYMB_BOUNDARY_2].setColor( QColor( 0, 255,   0 ) );         // green
  mSymb[SYMB_CENTROID_IN].setColor( QColor( 0, 255,   0 ) );        // green
  mSymb[SYMB_CENTROID_OUT].setColor( QColor( 255,   0,   0 ) );     // red
  mSymb[SYMB_CENTROID_DUPL].setColor( QColor( 255,   0, 255 ) );    // magenta
  mSymb[SYMB_NODE_1].setColor( QColor( 255,   0,   0 ) );           // red
  mSymb[SYMB_NODE_2].setColor( QColor( 0, 255,   0 ) );             // green

  // Set mSymbDisplay
  mSymbDisplay.resize( SYMB_COUNT );
  mSymbDisplay[SYMB_BACKGROUND] = true;
  mSymbDisplay[SYMB_HIGHLIGHT] = true;
  mSymbDisplay[SYMB_DYNAMIC] = true;
  mSymbDisplay[SYMB_POINT] = true;
  mSymbDisplay[SYMB_LINE] = true;
  mSymbDisplay[SYMB_BOUNDARY_0] = true;
  mSymbDisplay[SYMB_BOUNDARY_1] = true;
  mSymbDisplay[SYMB_BOUNDARY_2] = true;
  mSymbDisplay[SYMB_CENTROID_IN] = true;
  mSymbDisplay[SYMB_CENTROID_OUT] = true;
  mSymbDisplay[SYMB_CENTROID_DUPL] = true;
  mSymbDisplay[SYMB_NODE_1] = true;
  mSymbDisplay[SYMB_NODE_2] = true;

  // Set symbology names
  mSymbName.resize( SYMB_COUNT );
  mSymbName[SYMB_BACKGROUND]    = tr( "Background" );
  mSymbName[SYMB_HIGHLIGHT]     = tr( "Highlight" );
  mSymbName[SYMB_DYNAMIC]       = tr( "Dynamic" );
  mSymbName[SYMB_POINT]         = tr( "Point" );
  mSymbName[SYMB_LINE]          = tr( "Line" );
  mSymbName[SYMB_BOUNDARY_0]    = tr( "Boundary (no area)" );
  mSymbName[SYMB_BOUNDARY_1]    = tr( "Boundary (1 area)" );
  mSymbName[SYMB_BOUNDARY_2]    = tr( "Boundary (2 areas)" );
  mSymbName[SYMB_CENTROID_IN]   = tr( "Centroid (in area)" );
  mSymbName[SYMB_CENTROID_OUT]  = tr( "Centroid (outside area)" );
  mSymbName[SYMB_CENTROID_DUPL] = tr( "Centroid (duplicate in area)" );
  mSymbName[SYMB_NODE_1]        = tr( "Node (1 line)" );
  mSymbName[SYMB_NODE_2]        = tr( "Node (2 lines)" );

  // Restore symbology
  QString spath = "/GRASS/edit/symb/";
  QSettings settings;

  mLineWidth = settings.value(
                 spath + "lineWidth", 1 ).toInt();
  mSize = settings.value(
            spath + "markerSize", 9 ).toInt();
  mLineWidthSpinBox->setValue( mLineWidth );
  mMarkerSizeSpinBox->setValue( mSize );

  for ( int i = 0; i < SYMB_COUNT; i++ )
  {
    bool ok = settings.contains(
                spath + "display/" + QString::number( i ) );
    bool displ = settings.value(
                   spath + "display/" + QString::number( i ),
                   true ).toBool();
    if ( ok )
    {
      mSymbDisplay[i] = displ;
    }

    ok = settings.contains(
           spath + "color/" + QString::number( i ) );
    QString colorName = settings.value(
                          spath + "color/" + QString::number( i ),
                          "" ).toString();
    if ( ok )
    {
      QColor color( colorName );
      mSymb[i].setColor( color );
      // Use the 'dynamic' color for mRubberBand
      if ( i == SYMB_DYNAMIC )
      {
        mRubberBandLine->setColor( QColor( colorName ) );
      }
    }
    mSymb[i].setWidth( mLineWidth );
  }

  // Set Symbology in dialog
  symbologyList->setColumnWidth( 0, 40 );
  symbologyList->setColumnWidth( 1, 50 );
  symbologyList->setColumnWidth( 2, 200 );

  for ( int i = 0; i < SYMB_COUNT; i++ )
  {
    if ( i == SYMB_NODE_0 )
      continue;

    QPixmap pm( 40, 15 );
    pm.fill( mSymb[i].color() );
    QString index;
    index.sprintf( "%d", i );

    QTreeWidgetItem *item = new QTreeWidgetItem( symbologyList );
    if ( !( i == SYMB_BACKGROUND || i == SYMB_HIGHLIGHT || i == SYMB_DYNAMIC ) )
    {
      item->setCheckState( 0, mSymbDisplay[i] ? Qt::Checked : Qt::Unchecked );
    }
    item->setIcon( 1, pm );
    item->setText( 2, mSymbName[i] );
    item->setText( 3, index );
  }

  connect( symbologyList, SIGNAL( itemPressed( QTreeWidgetItem *, int ) ),
           this, SLOT( changeSymbology( QTreeWidgetItem *, int ) ) );

  // Init table tab
  mAttributeTable->setItemDelegate( new QgsGrassEditAttributeTableItemDelegate( this ) );
  mAttributeTable->verticalHeader()->hide();

  int ndblinks = mProvider->numDbLinks();

  if ( ndblinks > 0 )
  {
    for ( int i = 0; i < ndblinks; i++ )
    {
      int f = mProvider->dbLinkField( i );

      QString str;
      str.sprintf( "%d", f );
      mTableField->addItem( str );
      mFieldBox->addItem( str );
      if ( i == 0 )
      {
        setAttributeTable( f );
      }
    }
    mTableField->setCurrentIndex( 0 );
    mFieldBox->setCurrentIndex( 0 );
  }
  else
  {
    mTableField->addItem( "1" );
    setAttributeTable( 1 );

    mFieldBox->addItem( "1" );
  }

  connect( mAttributeTable, SIGNAL( cellChanged( int, int ) ), this, SLOT( columnTypeChanged( int, int ) ) );

  // Set variables
  mSelectedLine = 0;
  mAttributes = 0;

  // Read max cats
  for ( int i = 0; i < mProvider->cidxGetNumFields(); i++ )
  {
    int field = mProvider->cidxGetFieldNumber( i );
    if ( field > 0 )
    {
      int cat = mProvider->cidxGetMaxCat( i );
      MaxCat mc;
      mc.field = field;
      mc.maxCat = cat;
      mMaxCats.push_back( mc );
    }
  }

  connect( mCanvas, SIGNAL( renderComplete( QPainter * ) ), this, SLOT( postRender( QPainter * ) ) );

  mCanvasEdit = new QgsGrassEditLayer( mCanvas );

  mPixmap = &mCanvasEdit->pixmap();

  // Init GUI values
  mCatModeBox->addItem( tr( "Next not used" ), CAT_MODE_NEXT );
  mCatModeBox->addItem( tr( "Manual entry" ), CAT_MODE_MANUAL );
  mCatModeBox->addItem( tr( "No category" ), CAT_MODE_NOCAT );
  catModeChanged( );

  // TODO: how to get keyboard events from canvas (shortcuts)

  restorePosition();

  mValid = true;
  mInited = true;
}