100923_data_defined_label_position.diff

Marco Hugentobler, 2010-09-23 12:11 AM

Download (45.2 KB)

View differences:

src/app/qgslabelinggui.h (Arbeitskopie)
45 45
    void updatePreview();
46 46
    void updateOptions();
47 47

  
48
    void on_mFontSizeSpinBox_valueChanged ( double d );
49
    void on_mFontSizeUnitComboBox_currentIndexChanged ( int index );
50
    void on_mXCoordinateComboBox_currentIndexChanged( const QString & text );
51
    void on_mYCoordinateComboBox_currentIndexChanged( const QString & text );
52

  
48 53
  protected:
49 54
    void populatePlacementMethods();
50 55
    void populateFieldNames();
......
57 62
  private:
58 63
    QgsPalLabeling* mLBL;
59 64
    QgsVectorLayer* mLayer;
65

  
66
    void disableDataDefinedAlignment();
67
    void enableDataDefinedAlignment();
60 68
};
61 69

  
62 70
#endif
src/app/qgslabelinggui.cpp (Arbeitskopie)
123 123
  chkMergeLines->setChecked( lyr.mergeLines );
124 124
  chkMultiLine->setChecked( lyr.multiLineLabels );
125 125
  mMinSizeSpinBox->setValue( lyr.minFeatureSize );
126
  chkAddDirectionSymbol->setChecked( lyr.addDirectionSymbol );
126 127

  
127 128
  bool scaleBased = ( lyr.scaleMin != 0 && lyr.scaleMax != 0 );
128 129
  chkScaleBasedVisibility->setChecked( scaleBased );
......
139 140

  
140 141
  btnTextColor->setColor( lyr.textColor );
141 142
  btnBufferColor->setColor( lyr.bufferColor );
142
  updateFont( lyr.textFont );
143

  
144
  if( lyr.fontSizeInMapUnits )
145
  {
146
    mFontSizeUnitComboBox->setCurrentIndex( 1 );
147
  }
148
  else
149
  {
150
    mFontSizeUnitComboBox->setCurrentIndex( 0 );
151
  }
152

  
153
  QFont textFont = lyr.textFont;
154
  updateFont( textFont );
155
  mFontSizeSpinBox->setValue( textFont.pointSizeF() );
143 156
  updateUi();
144 157

  
145 158
  updateOptions();
......
238 251
  {
239 252
    lyr.bufferSize = 0;
240 253
  }
254
  if ( chkAddDirectionSymbol->isChecked() )
255
  {
256
    lyr.addDirectionSymbol = true;
257
  }
258
  else
259
  {
260
    lyr.addDirectionSymbol = false;
261
  }
241 262
  lyr.minFeatureSize = mMinSizeSpinBox->value();
263
  lyr.fontSizeInMapUnits = ( mFontSizeUnitComboBox->currentIndex() == 1 );
242 264

  
265

  
243 266
  //data defined labeling
244 267
  setDataDefinedProperty( mSizeAttributeComboBox, QgsPalLayerSettings::Size, lyr );
245 268
  setDataDefinedProperty( mColorAttributeComboBox, QgsPalLayerSettings::Color, lyr );
......
250 273
  setDataDefinedProperty( mFontFamilyAttributeComboBox, QgsPalLayerSettings::Family, lyr );
251 274
  setDataDefinedProperty( mBufferSizeAttributeComboBox, QgsPalLayerSettings:: BufferSize, lyr );
252 275
  setDataDefinedProperty( mBufferColorAttributeComboBox, QgsPalLayerSettings::BufferColor, lyr );
276
  setDataDefinedProperty( mXCoordinateComboBox, QgsPalLayerSettings::PositionX, lyr );
277
  setDataDefinedProperty( mYCoordinateComboBox, QgsPalLayerSettings::PositionY, lyr );
278
  setDataDefinedProperty( mHorizontalAlignmentComboBox, QgsPalLayerSettings::Hali, lyr );
279
  setDataDefinedProperty( mVerticalAlignmentComboBox, QgsPalLayerSettings::Vali, lyr );
280
  setDataDefinedProperty( mLabelDistanceComboBox, QgsPalLayerSettings::LabelDistance, lyr );
281
  setDataDefinedProperty( mRotationComboBox, QgsPalLayerSettings::Rotation, lyr );
253 282

  
254 283
  return lyr;
255 284
}
......
308 337
  comboList << mFontFamilyAttributeComboBox;
309 338
  comboList << mBufferSizeAttributeComboBox;
310 339
  comboList << mBufferColorAttributeComboBox;
340
  comboList << mXCoordinateComboBox;
341
  comboList << mYCoordinateComboBox;
342
  comboList << mHorizontalAlignmentComboBox;
343
  comboList << mVerticalAlignmentComboBox;
344
  comboList << mLabelDistanceComboBox;
345
  comboList << mRotationComboBox;
311 346

  
312 347
  QList<QComboBox*>::iterator comboIt = comboList.begin();
313 348
  for ( ; comboIt != comboList.end(); ++comboIt )
......
335 370
  setCurrentComboValue( mFontFamilyAttributeComboBox, s, QgsPalLayerSettings::Family );
336 371
  setCurrentComboValue( mBufferSizeAttributeComboBox, s , QgsPalLayerSettings::BufferSize );
337 372
  setCurrentComboValue( mBufferColorAttributeComboBox, s, QgsPalLayerSettings::BufferColor );
373
  setCurrentComboValue( mXCoordinateComboBox, s, QgsPalLayerSettings::PositionX );
374
  setCurrentComboValue( mYCoordinateComboBox, s, QgsPalLayerSettings::PositionY );
375
  setCurrentComboValue( mHorizontalAlignmentComboBox, s, QgsPalLayerSettings::Hali );
376
  setCurrentComboValue( mVerticalAlignmentComboBox, s, QgsPalLayerSettings::Vali );
377
  setCurrentComboValue( mLabelDistanceComboBox, s, QgsPalLayerSettings::LabelDistance );
378
  setCurrentComboValue( mRotationComboBox, s, QgsPalLayerSettings::Rotation );
338 379
}
339 380

  
340 381
void QgsLabelingGui::changeTextColor()
......
352 393
  bool ok;
353 394
  QFont font = QFontDialog::getFont( &ok, lblFontPreview->font(), this );
354 395
  if ( ok )
396
  {
355 397
    updateFont( font );
398
  }
399
  mFontSizeSpinBox->setValue( font.pointSizeF() );
356 400
}
357 401

  
358 402
void QgsLabelingGui::updateFont( QFont font )
359 403
{
360
  lblFontName->setText( QString( "%1, %2 %3" ).arg( font.family() ).arg( font.pointSize() ).arg( tr( "pt" ) ) );
404
  QString fontSizeUnitString = tr( "pt" );
405
  if( mFontSizeUnitComboBox->currentIndex() == 1 )
406
  {
407
    fontSizeUnitString = tr( "map units" );
408
  }
409
  lblFontName->setText( QString( "%1, %2 %3" ).arg( font.family() ).arg( font.pointSize() ).arg( fontSizeUnitString ) );
361 410
  lblFontPreview->setFont( font );
362

  
363 411
  updatePreview();
364 412
}
365 413

  
......
418 466
    stackedOptions->setCurrentWidget( pageOptionsEmpty );
419 467
  }
420 468
}
469

  
470
void QgsLabelingGui::on_mFontSizeSpinBox_valueChanged ( double d )
471
{
472
  QFont font = lblFontPreview->font();
473
  font.setPointSizeF( d );
474
  lblFontPreview->setFont( font );
475
  updateFont( font );
476
}
477

  
478
void QgsLabelingGui::on_mFontSizeUnitComboBox_currentIndexChanged ( int index )
479
{
480
  updateFont( lblFontPreview->font() );
481
}
482

  
483
void QgsLabelingGui::on_mXCoordinateComboBox_currentIndexChanged( const QString & text )
484
{
485
  if ( text.isEmpty() ) //no data defined alignment without data defined position
486
  {
487
    disableDataDefinedAlignment();
488
  }
489
  else if ( !mYCoordinateComboBox->currentText().isEmpty() )
490
  {
491
    enableDataDefinedAlignment();
492
  }
493
}
494

  
495
void QgsLabelingGui::on_mYCoordinateComboBox_currentIndexChanged( const QString & text )
496
{
497
  if ( text.isEmpty() ) //no data defined alignment without data defined position
498
  {
499
    disableDataDefinedAlignment();
500
  }
501
  else if ( !mXCoordinateComboBox->currentText().isEmpty() )
502
  {
503
    enableDataDefinedAlignment();
504
  }
505
}
506

  
507
void QgsLabelingGui::disableDataDefinedAlignment()
508
{
509
  mHorizontalAlignmentComboBox->setCurrentIndex( mHorizontalAlignmentComboBox->findText( "" ) );
510
  mHorizontalAlignmentComboBox->setEnabled( false );
511
  mVerticalAlignmentComboBox->setCurrentIndex( mVerticalAlignmentComboBox->findText( "" ) );
512
  mVerticalAlignmentComboBox->setEnabled( false );
513
  mRotationComboBox->setCurrentIndex( mRotationComboBox->findText( "" ) );
514
  mRotationComboBox->setEnabled( false );
515
}
516

  
517
void QgsLabelingGui::enableDataDefinedAlignment()
518
{
519
  mHorizontalAlignmentComboBox->setEnabled( true );
520
  mVerticalAlignmentComboBox->setEnabled( true );
521
  mRotationComboBox->setEnabled( true );
522
}
src/core/qgspallabeling.cpp (Arbeitskopie)
132 132
  minFeatureSize = 0.0;
133 133
  vectorScaleFactor = 1.0;
134 134
  rasterCompressFactor = 1.0;
135
  addDirectionSymbol = false;
136
  fontSizeInMapUnits = false;
135 137
}
136 138

  
137 139
QgsPalLayerSettings::QgsPalLayerSettings( const QgsPalLayerSettings& s )
......
156 158
  minFeatureSize = s.minFeatureSize;
157 159
  vectorScaleFactor = s.vectorScaleFactor;
158 160
  rasterCompressFactor = s.rasterCompressFactor;
161
  addDirectionSymbol = s.addDirectionSymbol;
162
  fontSizeInMapUnits = s.fontSizeInMapUnits;
159 163

  
160 164
  dataDefinedProperties = s.dataDefinedProperties;
161 165
  fontMetrics = NULL;
......
193 197
    return;
194 198
  }
195 199

  
196
  for ( int i = 0; i < 9; ++i )
200
  for ( int i = 0; i < 15; ++i )
197 201
  {
198 202
    QMap< QgsPalLayerSettings::DataDefinedProperties, int >::const_iterator it = propertyMap.find(( QgsPalLayerSettings::DataDefinedProperties )i );
199 203
    QVariant propertyValue;
......
242 246
  _readDataDefinedProperty( layer, QgsPalLayerSettings::Family, propertyMap );
243 247
  _readDataDefinedProperty( layer, QgsPalLayerSettings::BufferSize, propertyMap );
244 248
  _readDataDefinedProperty( layer, QgsPalLayerSettings::BufferColor, propertyMap );
249
  _readDataDefinedProperty( layer,  QgsPalLayerSettings::PositionX, propertyMap );
250
  _readDataDefinedProperty( layer,  QgsPalLayerSettings::PositionY, propertyMap );
251
  _readDataDefinedProperty( layer,  QgsPalLayerSettings::Hali, propertyMap );
252
  _readDataDefinedProperty( layer,  QgsPalLayerSettings::Vali, propertyMap );
253
  _readDataDefinedProperty( layer, QgsPalLayerSettings::LabelDistance, propertyMap );
254
  _readDataDefinedProperty( layer, QgsPalLayerSettings::Rotation, propertyMap );
245 255
}
246 256

  
247 257
void QgsPalLayerSettings::readFromLayer( QgsVectorLayer* layer )
......
269 279
  labelPerPart = layer->customProperty( "labeling/labelPerPart" ).toBool();
270 280
  mergeLines = layer->customProperty( "labeling/mergeLines" ).toBool();
271 281
  multiLineLabels = layer->customProperty( "labeling/multiLineLabels" ).toBool();
282
  addDirectionSymbol = layer->customProperty( "labeling/addDirectionSymbol" ).toBool();
272 283
  minFeatureSize = layer->customProperty( "labeling/minFeatureSize" ).toDouble();
284
  fontSizeInMapUnits = layer->customProperty( "labeling/fontSizeInMapUnits").toBool();
273 285
  _readDataDefinedPropertyMap( layer, dataDefinedProperties );
274 286
}
275 287

  
......
299 311
  layer->setCustomProperty( "labeling/labelPerPart", labelPerPart );
300 312
  layer->setCustomProperty( "labeling/mergeLines", mergeLines );
301 313
  layer->setCustomProperty( "labeling/multiLineLabels", multiLineLabels );
314
  layer->setCustomProperty( "labeling/addDirectionSymbol", addDirectionSymbol );
302 315
  layer->setCustomProperty( "labeling/minFeatureSize", minFeatureSize );
316
  layer->setCustomProperty( "labeling/fontSizeInMapUnits", fontSizeInMapUnits );
303 317
  _writeDataDefinedPropertyMap( layer, dataDefinedProperties );
304 318
}
305 319

  
......
358 372
    return;
359 373
  }
360 374

  
375
  if ( addDirectionSymbol && !multiLineLabels && placement == QgsPalLayerSettings::Line ) //consider the space needed for the direction symbol
376
  {
377
    text.append( ">" );
378
  }
361 379
  QRectF labelRect = fm->boundingRect( text );
362 380
  double w, h;
363 381
  if ( !multiLineLabels )
......
391 409
{
392 410
  QString labelText = f.attributeMap()[fieldIndex].toString();
393 411
  double labelX, labelY; // will receive label size
412
  QFont labelFont = textFont;
394 413

  
395 414
  //data defined label size?
396 415
  QMap< DataDefinedProperties, int >::const_iterator it = dataDefinedProperties.find( QgsPalLayerSettings::Size );
397 416
  if ( it != dataDefinedProperties.constEnd() )
398 417
  {
399
    QFont labelFont = textFont;
400 418
    //find out size
401 419
    QVariant size = f.attributeMap().value( *it );
402 420
    if ( size.isValid() )
......
406 424
      {
407 425
        return;
408 426
      }
409
      labelFont.setPointSize( sizeToPixel( sizeDouble, context ) );
427
      labelFont.setPixelSize( sizeToPixel( sizeDouble, context ) );
410 428
    }
411 429
    QFontMetrics labelFontMetrics( labelFont );
412 430
    calculateLabelSize( &labelFontMetrics, labelText, labelX, labelY );
......
430 448
    return;
431 449
  }
432 450

  
451
  //data defined position / alignment / rotation?
452
  bool dataDefinedPosition = false;
453
  bool dataDefinedRotation = false;
454
  double xPos, yPos, angle;
455

  
456
  QMap< DataDefinedProperties, int >::const_iterator dPosXIt = dataDefinedProperties.find( QgsPalLayerSettings::PositionX );
457
  if ( dPosXIt != dataDefinedProperties.constEnd() )
458
  {
459
    QMap< DataDefinedProperties, int >::const_iterator dPosYIt = dataDefinedProperties.find( QgsPalLayerSettings::PositionY );
460
    if ( dPosYIt != dataDefinedProperties.constEnd() )
461
    {
462
      //data defined position
463
      dataDefinedPosition = true;
464
      xPos = f.attributeMap().value( *dPosXIt ).toDouble();
465
      yPos = f.attributeMap().value( *dPosYIt ).toDouble();
466

  
467
      //x/y shift in case of alignment
468
      double xdiff = 0;
469
      double ydiff = 0;
470

  
471
      //horizontal alignment
472
      QMap< DataDefinedProperties, int >::const_iterator haliIt = dataDefinedProperties.find( QgsPalLayerSettings::Hali );
473
      if ( haliIt != dataDefinedProperties.end() )
474
      {
475
        QString haliString = f.attributeMap().value( *haliIt ).toString();
476
        if ( haliString.compare( "Center", Qt::CaseInsensitive ) == 0 )
477
        {
478
          xdiff -= labelX / 2.0;
479
        }
480
        else if ( haliString.compare( "Right", Qt::CaseInsensitive ) == 0 )
481
        {
482
          xdiff -= labelX;
483
        }
484
      }
485

  
486
      //vertical alignment
487
      QMap< DataDefinedProperties, int >::const_iterator valiIt = dataDefinedProperties.find( QgsPalLayerSettings::Vali );
488
      if ( valiIt != dataDefinedProperties.constEnd() )
489
      {
490
        QString valiString = f.attributeMap().value( *valiIt ).toString();
491
        if ( valiString.compare( "Bottom", Qt::CaseInsensitive ) != 0 )
492
        {
493
          if ( valiString.compare( "Top", Qt::CaseInsensitive ) == 0 || valiString.compare( "Cap", Qt::CaseInsensitive ) == 0 )
494
          {
495
            ydiff -= labelY;
496
          }
497
          else
498
          {
499
            QFontMetrics labelFontMetrics( labelFont );
500
            double descentRatio = labelFontMetrics.descent() / labelFontMetrics.height();
501

  
502
            if ( valiString.compare( "Base", Qt::CaseInsensitive ) == 0 )
503
            {
504
              ydiff -= labelY * descentRatio;
505
            }
506
            else if ( valiString.compare( "Half", Qt::CaseInsensitive ) == 0 )
507
            {
508
              ydiff -= labelY * descentRatio;
509
              ydiff -= labelY * 0.5 * ( 1 - descentRatio );
510
            }
511
          }
512
        }
513
      }
514

  
515
      //data defined rotation?
516
      QMap< DataDefinedProperties, int >::const_iterator rotIt = dataDefinedProperties.find( QgsPalLayerSettings::Rotation );
517
      if ( rotIt != dataDefinedProperties.constEnd() )
518
      {
519
        dataDefinedRotation = true;
520
        angle = f.attributeMap().value( *rotIt ).toDouble() * M_PI / 180;
521
        //adjust xdiff and ydiff because the hali/vali point needs to be the rotation center
522
        double xd = xdiff * cos( angle ) - ydiff * sin( angle );
523
        double yd = xdiff * sin( angle ) + ydiff * cos( angle );
524
        xdiff = xd;
525
        ydiff = yd;
526
      }
527

  
528
      yPos += ydiff;
529
      xPos += xdiff;
530
    }
531
  }
532

  
433 533
  QgsPalGeometry* lbl = new QgsPalGeometry( f.id(), labelText, GEOSGeom_clone( geos_geom ) );
434 534

  
435 535
  // record the created geometry - it will be deleted at the end.
......
438 538
  // register feature to the layer
439 539
  try
440 540
  {
441
    if ( !palLayer->registerFeature( lbl->strId(), lbl, labelX, labelY, labelText.toUtf8().constData() ) )
541
    if ( !palLayer->registerFeature( lbl->strId(), lbl, labelX, labelY, labelText.toUtf8().constData(),
542
                                     xPos, yPos, dataDefinedPosition, angle, dataDefinedRotation ) )
442 543
      return;
443 544
  }
444 545
  catch ( std::exception* e )
......
452 553
  feat->setLabelInfo( lbl->info( fontMetrics, xform, rasterCompressFactor ) );
453 554

  
454 555
  // TODO: allow layer-wide feature dist in PAL...?
455
  if ( dist != 0 )
456
    feat->setDistLabel( fabs( ptOne.x() - ptZero.x() )* dist * vectorScaleFactor );
457 556

  
557
  //data defined label-feature distance?
558
  double distance = dist;
559
  QMap< DataDefinedProperties, int >::const_iterator dDistIt = dataDefinedProperties.find( QgsPalLayerSettings::LabelDistance );
560
  if( dDistIt != dataDefinedProperties.constEnd())
561
  {
562
    distance = f.attributeMap().value( *dDistIt ).toDouble();
563
  }
564

  
565
  if ( distance != 0 )
566
  {
567
    feat->setDistLabel( fabs( ptOne.x() - ptZero.x() )* distance * vectorScaleFactor );
568
  }
569

  
458 570
  //add parameters for data defined labeling to QgsPalGeometry
459 571
  QMap< DataDefinedProperties, int >::const_iterator dIt = dataDefinedProperties.constBegin();
460 572
  for ( ; dIt != dataDefinedProperties.constEnd(); ++dIt )
......
465 577

  
466 578
int QgsPalLayerSettings::sizeToPixel( double size, const QgsRenderContext& c ) const
467 579
{
468
  // set font size from points to output size
469
  double pixelSize = 0.3527 * size * c.scaleFactor() * c.rasterScaleFactor() + 0.5;
470
  return ( int )pixelSize;
580
  double pixelSize;
581
  if( fontSizeInMapUnits )
582
  {
583
    pixelSize = size / c.mapToPixel().mapUnitsPerPixel() * c.rasterScaleFactor();
584
  }
585
  else //font size in points
586
  {
587
    // set font size from points to output size
588
    pixelSize = 0.3527 * size * c.scaleFactor() * c.rasterScaleFactor();
589
  }
590
  return ( int )(pixelSize + 0.5);
471 591
}
472 592

  
473 593

  
......
730 850
    QVariant dataDefinedSize = palGeometry->dataDefinedValues().value( QgsPalLayerSettings::Size );
731 851
    if ( dataDefinedSize.isValid() )
732 852
    {
733
      fontForLabel.setPointSize( lyr.sizeToPixel( dataDefinedSize.toDouble(), context ) );
853
      fontForLabel.setPixelSize( lyr.sizeToPixel( dataDefinedSize.toDouble(), context ) );
734 854
    }
735 855
    //font color
736 856
    QVariant dataDefinedColor = palGeometry->dataDefinedValues().value( QgsPalLayerSettings::Color );
......
871 991
  QString text = (( QgsPalGeometry* )label->getFeaturePart()->getUserGeometry() )->text();
872 992
  QString txt = ( label->getPartId() == -1 ? text : QString( text[label->getPartId()] ) );
873 993

  
994
  //add the direction symbol if needed
995
  if ( !txt.isEmpty() && lyr.placement == QgsPalLayerSettings::Line &&
996
       lyr.addDirectionSymbol && !lyr.multiLineLabels )
997
  {
998
    if ( label->getReversed() )
999
    {
1000
      txt.prepend( "<" );
1001
    }
1002
    else
1003
    {
1004
      txt.append( ">" );
1005
    }
1006
  }
1007

  
874 1008
  //QgsDebugMsg( "drawLabel " + QString::number( drawBuffer ) + " " + txt );
875 1009

  
876 1010
  QStringList multiLineList;
......
913 1047
    painter->restore();
914 1048

  
915 1049
    if ( label->getNextPart() )
916
      drawLabel( label->getNextPart(), painter, f, c, xform, drawBuffer );
1050
      drawLabel( label->getNextPart(), painter, f, c, xform, bufferSize, bufferColor, drawBuffer );
917 1051
  }
918 1052
}
919 1053

  
src/core/pal/feature.h (Arbeitskopie)
86 86

  
87 87
      void setLabelInfo( LabelInfo* info ) { labelInfo = info; }
88 88
      void setDistLabel( double dist ) { distlabel = dist; }
89
      //Set label position of the feature to fixed x/y values
90
      void setFixedPosition( double x, double y ) { fixedPos = true; fixedPosX = x; fixedPosY = y;}
91
      bool fixedPosition() const { return fixedPos; }
92
      //Set label rotation to fixed value
93
      void setFixedAngle( double a ) { fixedRotation = true; fixedAngle = a; }
89 94

  
90 95
    protected:
91 96
      Layer *layer;
......
97 102

  
98 103
      char *uid;
99 104

  
105
      bool fixedPos; //true in case of fixed position (only 1 candidate position with cost 0)
106
      double fixedPosX;
107
      double fixedPosY;
108
      //Fixed (e.g. data defined) angle only makes sense together with fixed position
109
      bool fixedRotation;
110
      double fixedAngle; //fixed angle value (in rad)
111

  
100 112
      // array of parts - possibly not necessary
101 113
      //int nPart;
102 114
      //FeaturePart** parts;
src/core/pal/labelposition.cpp (Arbeitskopie)
54 54

  
55 55
namespace pal
56 56
{
57
  LabelPosition::LabelPosition( int id, double x1, double y1, double w, double h, double alpha, double cost, FeaturePart *feature )
58
      : id( id ), cost( cost ), feature( feature ), nbOverlap( 0 ), alpha( alpha ), w( w ), h( h ), nextPart( NULL ), partId( -1 )
57
  LabelPosition::LabelPosition( int id, double x1, double y1, double w, double h, double alpha, double cost, FeaturePart *feature, bool isReversed )
58
      : id( id ), cost( cost ), feature( feature ), nbOverlap( 0 ), alpha( alpha ), w( w ), h( h ), nextPart( NULL ), partId( -1 ), reversed( isReversed )
59 59
  {
60 60

  
61 61
    // alpha take his value bw 0 and 2*pi rad
src/core/pal/labelposition.h (Arbeitskopie)
74 74
      LabelPosition* nextPart;
75 75
      int partId;
76 76

  
77
      //True if label direction is the same as line / polygon ring direction.
78
      //Could be used by the application to draw a directional arrow ('<' or '>')
79
      //if the layer arrangement is P_LINE
80
      bool reversed;
81

  
77 82
      bool isInConflictSinglePart( LabelPosition* lp );
78 83
      bool isInConflictMultiPart( LabelPosition* lp );
79 84

  
......
93 98
      LabelPosition( int id, double x1, double y1,
94 99
                     double w, double h,
95 100
                     double alpha, double cost,
96
                     FeaturePart *feature );
101
                     FeaturePart *feature, bool isReversed = false );
97 102

  
98 103
      /** copy constructor */
99 104
      LabelPosition( const LabelPosition& other );
......
190 195
       * \return alpha to rotate text (in rad)
191 196
       */
192 197
      double getAlpha() const;
198
      bool getReversed() const { return reversed; }
193 199

  
194 200
      void print();
195 201

  
src/core/pal/layer.cpp (Arbeitskopie)
226 226

  
227 227

  
228 228

  
229
  bool Layer::registerFeature( const char *geom_id, PalGeometry *userGeom, double label_x, double label_y, const char* labelText )
229
  bool Layer::registerFeature( const char *geom_id, PalGeometry *userGeom, double label_x, double label_y, const char* labelText,
230
                               double labelPosX, double labelPosY, bool fixedPos, double angle, bool fixedAngle )
230 231
  {
231 232
    if ( !geom_id || label_x < 0 || label_y < 0 )
232 233
      return false;
......
243 244
    GEOSGeometry *the_geom = userGeom->getGeosGeometry();
244 245

  
245 246
    Feature* f = new Feature( this, geom_id, userGeom, label_x, label_y );
247
    if ( fixedPos )
248
    {
249
      f->setFixedPosition( labelPosX, labelPosY );
250
    }
251
    if( fixedAngle )
252
    {
253
      f->setFixedAngle( angle );
254
    }
246 255

  
247 256
    bool first_feat = true;
248 257

  
......
314 323
    modMutex->unlock();
315 324

  
316 325
    // if using only biggest parts...
317
    if ( mode == LabelPerFeature && biggest_part != NULL )
326
    if (( mode == LabelPerFeature || f->fixedPosition() ) && biggest_part != NULL )
318 327
    {
319 328
      addFeaturePart( biggest_part, labelText );
320 329
      first_feat = false;
src/core/pal/layer.h (Arbeitskopie)
283 283
       * @param label_x label width
284 284
       * @param label_y label height
285 285
       * @param userGeom user's geometry that implements the PalGeometry interface
286
       * @param labelPosX x position of the label (in case of fixed label position)
287
       * @param labelPosY y position of the label (in case of fixed label position)
288
       * @param fixedPos true if a single fixed position for this label is needed
286 289
       *
287 290
       * @throws PalException::FeatureExists
288 291
       *
289 292
       * @return true on success (i.e. valid geometry)
290 293
       */
291
      bool registerFeature( const char *geom_id, PalGeometry *userGeom, double label_x = -1, double label_y = -1, const char* labelText = NULL );
294
      bool registerFeature( const char *geom_id, PalGeometry *userGeom, double label_x = -1, double label_y = -1,
295
                            const char* labelText = NULL, double labelPosX = 0.0, double labelPosY = 0.0, bool fixedPos = false, double angle = 0.0, bool fixedAngle = false );
292 296

  
293 297
      /** return pointer to feature or NULL if doesn't exist */
294 298
      Feature* getFeature( const char* geom_id );
src/core/pal/feature.cpp (Arbeitskopie)
61 61
namespace pal
62 62
{
63 63
  Feature::Feature( Layer* l, const char* geom_id, PalGeometry* userG, double lx, double ly )
64
      : layer( l ), userGeom( userG ), label_x( lx ), label_y( ly ), distlabel( 0 ), labelInfo( NULL )
64
      : layer( l ), userGeom( userG ), label_x( lx ), label_y( ly ), distlabel( 0 ), labelInfo( NULL ), fixedPos( false ), fixedRotation( false)
65 65
  {
66 66
    uid = new char[strlen( geom_id ) +1];
67 67
    strcpy( uid, geom_id );
......
599 599
          reversed = ( alpha >= M_PI / 2 || alpha < -M_PI / 2 );
600 600

  
601 601
        if (( !reversed && ( flags & FLAG_ABOVE_LINE ) ) || ( reversed && ( flags & FLAG_BELOW_LINE ) ) )
602
          positions->push_back( new LabelPosition( i, bx + cos( beta ) *distlabel , by + sin( beta ) *distlabel, xrm, yrm, alpha, cost, this ) ); // Line
602
          positions->push_back( new LabelPosition( i, bx + cos( beta ) *distlabel , by + sin( beta ) *distlabel, xrm, yrm, alpha, cost, this, reversed ) ); // Line
603 603
        if (( !reversed && ( flags & FLAG_BELOW_LINE ) ) || ( reversed && ( flags & FLAG_ABOVE_LINE ) ) )
604
          positions->push_back( new LabelPosition( i, bx - cos( beta ) *( distlabel + yrm ) , by - sin( beta ) *( distlabel + yrm ), xrm, yrm, alpha, cost, this ) );   // Line
604
          positions->push_back( new LabelPosition( i, bx - cos( beta ) *( distlabel + yrm ) , by - sin( beta ) *( distlabel + yrm ), xrm, yrm, alpha, cost, this, reversed ) );   // Line
605 605
        if ( flags & FLAG_ON_LINE )
606
          positions->push_back( new LabelPosition( i, bx - yrm*cos( beta ) / 2, by - yrm*sin( beta ) / 2, xrm, yrm, alpha, cost, this ) ); // Line
606
          positions->push_back( new LabelPosition( i, bx - yrm*cos( beta ) / 2, by - yrm*sin( beta ) / 2, xrm, yrm, alpha, cost, this, reversed ) ); // Line
607 607
      }
608 608
      else if ( f->layer->arrangement == P_HORIZ )
609 609
      {
......
1245 1245

  
1246 1246
    double delta = bbox_max[0] - bbox_min[0];
1247 1247

  
1248
    switch ( type )
1248
    if ( f->fixedPosition() )
1249 1249
    {
1250
      case GEOS_POINT:
1251
        if ( f->layer->getArrangement() == P_POINT_OVER )
1252
          nbp = setPositionOverPoint( x[0], y[0], scale, lPos, delta );
1253
        else
1254
          nbp = setPositionForPoint( x[0], y[0], scale, lPos, delta );
1255
        break;
1256
      case GEOS_LINESTRING:
1257
        if ( f->layer->getArrangement() == P_CURVED )
1258
          nbp = setPositionForLineCurved( lPos, mapShape );
1259
        else
1260
          nbp = setPositionForLine( scale, lPos, mapShape, delta );
1261
        break;
1250
      nbp = 1;
1251
      *lPos = new LabelPosition *[nbp];
1252
      double angle = 0.0;
1253
      if( f->fixedRotation )
1254
      {
1255
        angle = f->fixedAngle;
1256
      }
1257
      ( *lPos )[0] = new LabelPosition( 0, f->fixedPosX, f->fixedPosY, f->label_x, f->label_y, angle, 0.0,  this );
1258
    }
1259
    else
1260
    {
1261
      switch ( type )
1262
      {
1263
        case GEOS_POINT:
1264
          if ( f->layer->getArrangement() == P_POINT_OVER )
1265
            nbp = setPositionOverPoint( x[0], y[0], scale, lPos, delta );
1266
          else
1267
            nbp = setPositionForPoint( x[0], y[0], scale, lPos, delta );
1268
          break;
1269
        case GEOS_LINESTRING:
1270
          if ( f->layer->getArrangement() == P_CURVED )
1271
            nbp = setPositionForLineCurved( lPos, mapShape );
1272
          else
1273
            nbp = setPositionForLine( scale, lPos, mapShape, delta );
1274
          break;
1262 1275

  
1263
      case GEOS_POLYGON:
1264
        switch ( f->layer->getArrangement() )
1265
        {
1266
          case P_POINT:
1267
          case P_POINT_OVER:
1268
            double cx, cy;
1269
            mapShape->getCentroid( cx, cy );
1270
            if ( f->layer->getArrangement() == P_POINT_OVER )
1271
              nbp = setPositionOverPoint( cx, cy, scale, lPos, delta );
1272
            else
1273
              nbp = setPositionForPoint( cx, cy, scale, lPos, delta );
1274
            break;
1275
          case P_LINE:
1276
            nbp = setPositionForLine( scale, lPos, mapShape, delta );
1277
            break;
1278
          default:
1279
            nbp = setPositionForPolygon( scale, lPos, mapShape, delta );
1280
            break;
1281
        }
1276
        case GEOS_POLYGON:
1277
          switch ( f->layer->getArrangement() )
1278
          {
1279
            case P_POINT:
1280
            case P_POINT_OVER:
1281
              double cx, cy;
1282
              mapShape->getCentroid( cx, cy );
1283
              if ( f->layer->getArrangement() == P_POINT_OVER )
1284
                nbp = setPositionOverPoint( cx, cy, scale, lPos, delta );
1285
              else
1286
                nbp = setPositionForPoint( cx, cy, scale, lPos, delta );
1287
              break;
1288
            case P_LINE:
1289
              nbp = setPositionForLine( scale, lPos, mapShape, delta );
1290
              break;
1291
            default:
1292
              nbp = setPositionForPolygon( scale, lPos, mapShape, delta );
1293
              break;
1294
          }
1295
      }
1282 1296
    }
1283 1297

  
1284 1298
    int rnbp = nbp;
src/core/qgspallabeling.h (Arbeitskopie)
83 83
      Family,
84 84
      BufferSize,
85 85
      BufferColor,
86
      PositionX, //x-coordinate data defined label position
87
      PositionY, //y-coordinate data defined label position
88
      Hali, //horizontal alignment for data defined label position (Left, Center, Right)
89
      Vali, //vertical alignment for data defined label position (Bottom, Base, Half, Cap, Top)
90
      LabelDistance,
91
      Rotation //data defined rotation (only usefull in connection with data defined position)
86 92
    };
87 93

  
88 94
    QString fieldName;
......
103 109
    bool mergeLines;
104 110
    bool multiLineLabels; //draw labels on multiple lines if they contain '\n'
105 111
    double minFeatureSize; // minimum feature size to be labelled (in mm)
112
    // Adds '<' or '>' to the label string pointing to the direction of the line / polygon ring
113
    // Works only if Placement == Line
114
    bool addDirectionSymbol;
115
    bool fontSizeInMapUnits; //true if font size is in map units (otherwise in points)
106 116

  
107 117
    // called from register feature hook
108 118
    void calculateLabelSize( const QFontMetrics* fm, QString text, double& labelX, double& labelY );
......
130 140
    /**Stores field indices for data defined layer properties*/
131 141
    QMap< DataDefinedProperties, int > dataDefinedProperties;
132 142

  
133
    /**Calculates pixel size (considering scale factors and oversampling)
143
    /**Calculates pixel size (considering output size should be in pixel or map units, scale factors and oversampling)
134 144
     @param label size (pixels, possibily map units in future)
135 145
     @param c rendercontext
136 146
     @return font pixel size*/
src/ui/qgslabelingguibase.ui (Arbeitskopie)
6 6
   <rect>
7 7
    <x>0</x>
8 8
    <y>0</y>
9
    <width>496</width>
10
    <height>659</height>
9
    <width>504</width>
10
    <height>686</height>
11 11
   </rect>
12 12
  </property>
13 13
  <property name="windowTitle">
......
396 396
              </item>
397 397
             </layout>
398 398
            </item>
399
            <item row="1" column="0">
399
            <item row="2" column="0">
400 400
             <widget class="QLabel" name="label_29">
401 401
              <property name="sizePolicy">
402 402
               <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
......
412 412
              </property>
413 413
             </widget>
414 414
            </item>
415
            <item row="1" column="1">
415
            <item row="2" column="1">
416 416
             <layout class="QHBoxLayout" name="horizontalLayout_16">
417 417
              <item>
418 418
               <widget class="QgsColorButton" name="btnTextColor">
......
445 445
              </item>
446 446
             </layout>
447 447
            </item>
448
            <item row="2" column="0">
448
            <item row="3" column="0">
449 449
             <widget class="QLabel" name="label_30">
450 450
              <property name="text">
451 451
               <string>Buffer</string>
......
455 455
              </property>
456 456
             </widget>
457 457
            </item>
458
            <item row="2" column="1">
458
            <item row="3" column="1">
459 459
             <layout class="QHBoxLayout" name="horizontalLayout_17">
460 460
              <item>
461 461
               <widget class="QCheckBox" name="chkBuffer">
......
512 512
              </item>
513 513
             </layout>
514 514
            </item>
515
            <item row="4" column="0">
515
            <item row="5" column="0">
516 516
             <widget class="QLabel" name="label_33">
517 517
              <property name="sizePolicy">
518 518
               <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
......
528 528
              </property>
529 529
             </widget>
530 530
            </item>
531
            <item row="4" column="1">
531
            <item row="5" column="1">
532 532
             <widget class="QgsLabelPreview" name="lblFontPreview">
533
              <property name="sizePolicy">
534
               <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
535
                <horstretch>0</horstretch>
536
                <verstretch>0</verstretch>
537
               </sizepolicy>
538
              </property>
533 539
              <property name="minimumSize">
534 540
               <size>
535 541
                <width>30</width>
......
544 550
              </property>
545 551
             </widget>
546 552
            </item>
547
            <item row="3" column="0" colspan="2">
553
            <item row="4" column="0" colspan="2">
548 554
             <widget class="Line" name="line_4">
549 555
              <property name="orientation">
550 556
               <enum>Qt::Horizontal</enum>
551 557
              </property>
552 558
             </widget>
553 559
            </item>
560
            <item row="1" column="0">
561
             <widget class="QLabel" name="mFontSizeLabel">
562
              <property name="text">
563
               <string>Font size</string>
564
              </property>
565
             </widget>
566
            </item>
567
            <item row="1" column="1">
568
             <layout class="QHBoxLayout" name="horizontalLayout">
569
              <item>
570
               <widget class="QDoubleSpinBox" name="mFontSizeSpinBox">
571
                <property name="maximum">
572
                 <double>999999999.000000000000000</double>
573
                </property>
574
               </widget>
575
              </item>
576
              <item>
577
               <widget class="QComboBox" name="mFontSizeUnitComboBox">
578
                <item>
579
                 <property name="text">
580
                  <string>In points</string>
581
                 </property>
582
                </item>
583
                <item>
584
                 <property name="text">
585
                  <string>In map units</string>
586
                 </property>
587
                </item>
588
               </widget>
589
              </item>
590
             </layout>
591
            </item>
554 592
           </layout>
555 593
          </widget>
556 594
         </item>
......
678 716
         </property>
679 717
        </widget>
680 718
       </item>
681
       <item row="7" column="0">
719
       <item row="8" column="0">
682 720
        <layout class="QHBoxLayout" name="horizontalLayout_19">
683 721
         <item>
684 722
          <widget class="QLabel" name="label_19">
......
696 734
         </item>
697 735
        </layout>
698 736
       </item>
699
       <item row="8" column="0">
737
       <item row="9" column="0">
700 738
        <layout class="QHBoxLayout" name="horizontalLayout_20">
701 739
         <item>
702 740
          <widget class="QCheckBox" name="chkNoObstacle">
......
733 771
         </item>
734 772
        </layout>
735 773
       </item>
774
       <item row="7" column="0">
775
        <widget class="QCheckBox" name="chkAddDirectionSymbol">
776
         <property name="text">
777
          <string>add direction symbol</string>
778
         </property>
779
        </widget>
780
       </item>
736 781
      </layout>
737 782
     </widget>
738 783
     <widget class="QWidget" name="tab_4">
739 784
      <attribute name="title">
740 785
       <string>Data defined settings</string>
741 786
      </attribute>
742
      <layout class="QGridLayout" name="gridLayout_4">
787
      <layout class="QGridLayout" name="gridLayout_3">
743 788
       <item row="0" column="0">
744 789
        <widget class="QGroupBox" name="mFontAttributePropertiesGroupBox">
745 790
         <property name="sizePolicy">
......
753 798
         </property>
754 799
         <layout class="QGridLayout" name="gridLayout">
755 800
          <item row="0" column="0">
756
           <layout class="QGridLayout" name="gridLayout_11">
757
            <item row="0" column="0">
758
             <widget class="QLabel" name="mSizeLabel">
759
              <property name="text">
760
               <string>Size</string>
761
              </property>
762
             </widget>
763
            </item>
764
            <item row="0" column="1">
765
             <widget class="QComboBox" name="mSizeAttributeComboBox"/>
766
            </item>
767
            <item row="2" column="0">
768
             <widget class="QLabel" name="mBoldLabel">
769
              <property name="text">
770
               <string>Bold</string>
771
              </property>
772
             </widget>
773
            </item>
774
            <item row="2" column="1">
775
             <widget class="QComboBox" name="mBoldAttributeComboBox"/>
776
            </item>
777
            <item row="1" column="1">
778
             <widget class="QComboBox" name="mColorAttributeComboBox"/>
779
            </item>
780
            <item row="1" column="0">
781
             <widget class="QLabel" name="mColorLabel">
782
              <property name="text">
783
               <string>Color</string>
784
              </property>
785
             </widget>
786
            </item>
787
            <item row="3" column="1">
788
             <widget class="QComboBox" name="mItalicAttributeComboBox"/>
789
            </item>
790
            <item row="3" column="0">
791
             <widget class="QLabel" name="mItalicLabel">
792
              <property name="text">
793
               <string>Italic</string>
794
              </property>
795
             </widget>
796
            </item>
797
            <item row="4" column="1">
798
             <widget class="QComboBox" name="mUnderlineAttributeComboBox"/>
799
            </item>
800
            <item row="4" column="0">
801
             <widget class="QLabel" name="mUnderlineLabel">
802
              <property name="text">
803
               <string>Underline</string>
804
              </property>
805
             </widget>
806
            </item>
807
            <item row="6" column="1">
808
             <widget class="QComboBox" name="mFontFamilyAttributeComboBox"/>
809
            </item>
810
            <item row="6" column="0">
811
             <widget class="QLabel" name="mFontFamilyLabel">
812
              <property name="text">
813
               <string>Font family</string>
814
              </property>
815
             </widget>
816
            </item>
817
            <item row="5" column="1">
818
             <widget class="QComboBox" name="mStrikeoutAttributeComboBox"/>
819
            </item>
820
            <item row="5" column="0">
821
             <widget class="QLabel" name="mStrikeoutLabel">
822
              <property name="text">
823
               <string>Strikeout</string>
824
              </property>
825
             </widget>
826
            </item>
827
           </layout>
801
           <widget class="QLabel" name="mSizeLabel">
802
            <property name="text">
803
             <string>Size</string>
804
            </property>
805
           </widget>
828 806
          </item>
807
          <item row="0" column="1">
808
           <widget class="QComboBox" name="mSizeAttributeComboBox"/>
809
          </item>
810
          <item row="1" column="0">
811
           <widget class="QLabel" name="mColorLabel">
812
            <property name="text">
813
             <string>Color</string>
814
            </property>
815
           </widget>
816
          </item>
817
          <item row="1" column="1">
818
           <widget class="QComboBox" name="mColorAttributeComboBox"/>
819
          </item>
820
          <item row="2" column="0">
821
           <widget class="QLabel" name="mBoldLabel">
822
            <property name="text">
823
             <string>Bold</string>
824
            </property>
825
           </widget>
826
          </item>
827
          <item row="2" column="1">
828
           <widget class="QComboBox" name="mBoldAttributeComboBox"/>
829
          </item>
830
          <item row="3" column="0">
831
           <widget class="QLabel" name="mItalicLabel">
832
            <property name="text">
833
             <string>Italic</string>
834
            </property>
835
           </widget>
836
          </item>
837
          <item row="3" column="1">
838
           <widget class="QComboBox" name="mItalicAttributeComboBox"/>
839
          </item>
840
          <item row="4" column="0">
841
           <widget class="QLabel" name="mUnderlineLabel">
842
            <property name="text">
843
             <string>Underline</string>
844
            </property>
845
           </widget>
846
          </item>
847
          <item row="4" column="1">
848
           <widget class="QComboBox" name="mUnderlineAttributeComboBox"/>
849
          </item>
850
          <item row="5" column="0">
851
           <widget class="QLabel" name="mStrikeoutLabel">
852
            <property name="text">
853
             <string>Strikeout</string>
854
            </property>
855
           </widget>
856
          </item>
857
          <item row="5" column="1">
858
           <widget class="QComboBox" name="mStrikeoutAttributeComboBox"/>
859
          </item>
860
          <item row="6" column="0">
861
           <widget class="QLabel" name="mFontFamilyLabel">
862
            <property name="text">
863
             <string>Font family</string>
864
            </property>
865
           </widget>
866
          </item>
867
          <item row="6" column="1">
868
           <widget class="QComboBox" name="mFontFamilyAttributeComboBox"/>
869
          </item>
829 870
         </layout>
830 871
        </widget>
831 872
       </item>
......
834 875
         <property name="title">
835 876
          <string>Buffer properties</string>
836 877
         </property>
837
         <layout class="QGridLayout" name="gridLayout_3">
878
         <layout class="QGridLayout" name="gridLayout_2">
838 879
          <item row="0" column="0">
839
           <layout class="QGridLayout" name="gridLayout_2">
840
            <item row="0" column="0">
841
             <widget class="QLabel" name="mBufferSizeLabel">
842
              <property name="text">
843
               <string>Buffer size</string>
844
              </property>
845
             </widget>
846
            </item>
847
            <item row="0" column="1">
848
             <widget class="QComboBox" name="mBufferSizeAttributeComboBox"/>
849
            </item>
850
            <item row="1" column="0">
851
             <widget class="QLabel" name="mBufferColorLabel">
852
              <property name="text">
853
               <string>Buffer color</string>
854
              </property>
855
             </widget>
856
            </item>
857
            <item row="1" column="1">
858
             <widget class="QComboBox" name="mBufferColorAttributeComboBox"/>
859
            </item>
860
           </layout>
880
           <widget class="QLabel" name="mBufferSizeLabel">
881
            <property name="text">
882
             <string>Buffer size</string>
883
            </property>
884
           </widget>
861 885
          </item>
886
          <item row="0" column="1">
887
           <widget class="QComboBox" name="mBufferSizeAttributeComboBox"/>
888
          </item>
889
          <item row="1" column="0">
890
           <widget class="QLabel" name="mBufferColorLabel">
891
            <property name="text">
892
             <string>Buffer color</string>
893
            </property>
894
           </widget>
895
          </item>
896
          <item row="1" column="1">
897
           <widget class="QComboBox" name="mBufferColorAttributeComboBox"/>
898
          </item>
862 899
         </layout>
863 900
        </widget>
864 901
       </item>
865 902
       <item row="2" column="0">
903
        <widget class="QGroupBox" name="mPositionAttributeGroupBox">
904
         <property name="title">
905
          <string>Position</string>
906
         </property>
907
         <layout class="QGridLayout" name="gridLayout_4">
908
          <item row="1" column="0">
909
           <widget class="QLabel" name="mXCoordinateLabel">
910
            <property name="text">
911
             <string>X Coordinate</string>
912
            </property>
913
           </widget>
914
          </item>
915
          <item row="1" column="1">
916
           <widget class="QComboBox" name="mXCoordinateComboBox"/>
917
          </item>
918
          <item row="2" column="0">
919
           <widget class="QLabel" name="mYCoordinateLabel">
920
            <property name="text">
921
             <string>Y Coordinate</string>
922
            </property>
923
           </widget>
924
          </item>
925
          <item row="2" column="1">
926
           <widget class="QComboBox" name="mYCoordinateComboBox"/>
927
          </item>
928
          <item row="3" column="0">
929
           <widget class="QLabel" name="mHorizontalAlignmentLabel">
930
            <property name="text">
931
             <string>Horizontal alignment</string>
932
            </property>
933
           </widget>
934
          </item>
935
          <item row="3" column="1">
936
           <widget class="QComboBox" name="mHorizontalAlignmentComboBox"/>
937
          </item>
938
          <item row="4" column="0">
939
           <widget class="QLabel" name="mVerticalAlignmentLabel">
940
            <property name="text">
941
             <string>Vertical alignment</string>
942
            </property>
943
           </widget>
944
          </item>
945
          <item row="4" column="1">
946
           <widget class="QComboBox" name="mVerticalAlignmentComboBox"/>
947
          </item>
948
          <item row="5" column="1">
949
           <widget class="QComboBox" name="mRotationComboBox"/>
950
          </item>
951
          <item row="5" column="0">
952
           <widget class="QLabel" name="mRotationLabel">
953
            <property name="text">
954
             <string>Rotation</string>
955
            </property>
956
           </widget>
957
          </item>
958
          <item row="0" column="1">
959
           <widget class="QComboBox" name="mLabelDistanceComboBox"/>
960
          </item>
961
          <item row="0" column="0">
962
           <widget class="QLabel" name="mLabelDistanceLabel">
963
            <property name="text">
964
             <string>Label distance</string>
965
            </property>
966
           </widget>
967
          </item>
968
         </layout>
969
        </widget>
970
       </item>
971
       <item row="3" column="0">
866 972
        <spacer name="verticalSpacer">
867 973
         <property name="orientation">
868 974
          <enum>Qt::Vertical</enum>