QGIS API Documentation  2.10.1-Pisa
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
qgseffectstackpropertieswidget.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgseffectstackpropertieswidget.h
3  --------------------------------
4  begin : January 2015
5  copyright : (C) 2015 by Nyall Dawson
6  email : nyall dot dawson at gmail.com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
17 #include "qgspainteffectregistry.h"
18 #include "qgspainteffect.h"
19 #include "qgseffectstack.h"
21 #include "qgspainteffectwidget.h"
22 #include "qgsapplication.h"
23 #include "qgssymbollayerv2utils.h"
24 
25 #include <QPicture>
26 #include <QPainter>
27 #include <QStandardItemModel>
28 #include <QStandardItem>
29 #include <QCheckBox>
30 #include <QToolButton>
31 
32 static const int EffectItemType = QStandardItem::UserType + 1;
33 
34 class EffectItem : public QStandardItem
35 {
36  public:
38  {
39  setEffect( effect );
40  setCheckable( true );
41  mWidget = propertiesWidget;
42  }
43 
45  {
46  mEffect = effect;
48  }
49 
50  int type() const override { return EffectItemType; }
51 
53  {
54  return mEffect;
55  }
56 
57  QVariant data( int role ) const override
58  {
59  if ( role == Qt::DisplayRole || role == Qt::EditRole )
60  {
61  return QgsPaintEffectRegistry::instance()->effectMetadata( mEffect->type() )->visibleName();
62  }
63  if ( role == Qt::CheckStateRole )
64  {
65  return mEffect->enabled() ? Qt::Checked : Qt::Unchecked;
66  }
67  return QStandardItem::data( role );
68  }
69 
70  void setData( const QVariant & value, int role ) override
71  {
72  if ( role == Qt::CheckStateRole )
73  {
74  mEffect->setEnabled( value.toBool() );
76  }
77  else
78  {
79  QStandardItem::setData( value, role );
80  }
81  }
82 
83  protected:
86 };
87 
88 //
89 // QgsEffectStackPropertiesWidget
90 //
91 
93  : QWidget( parent )
94  , mStack( stack )
95  , mPreviewPicture( 0 )
96 {
97 
98 // TODO
99 #ifdef Q_OS_MAC
100  //setWindowModality( Qt::WindowModal );
101 #endif
102 
103  mPresentWidget = NULL;
104 
105  setupUi( this );
106 
107  mAddButton->setIcon( QIcon( QgsApplication::iconPath( "symbologyAdd.svg" ) ) );
108  mRemoveButton->setIcon( QIcon( QgsApplication::iconPath( "symbologyRemove.svg" ) ) );
109  mUpButton->setIcon( QIcon( QgsApplication::iconPath( "symbologyUp.svg" ) ) );
110  mDownButton->setIcon( QIcon( QgsApplication::iconPath( "symbologyDown.svg" ) ) );
111 
112  mModel = new QStandardItemModel();
113  // Set the effect
114  mEffectsList->setModel( mModel );
115 
116  QItemSelectionModel* selModel = mEffectsList->selectionModel();
117  connect( selModel, SIGNAL( currentChanged( const QModelIndex&, const QModelIndex& ) ), this, SLOT( effectChanged() ) );
118 
119  loadStack( stack );
120  updatePreview();
121 
122  connect( mUpButton, SIGNAL( clicked() ), this, SLOT( moveEffectUp() ) );
123  connect( mDownButton, SIGNAL( clicked() ), this, SLOT( moveEffectDown() ) );
124  connect( mAddButton, SIGNAL( clicked() ), this, SLOT( addEffect() ) );
125  connect( mRemoveButton, SIGNAL( clicked() ), this, SLOT( removeEffect() ) );
126 
127  updateUi();
128 
129  // set effect as active item in the tree
130  QModelIndex newIndex = mEffectsList->model()->index( 0, 0 );
131  mEffectsList->setCurrentIndex( newIndex );
132 }
133 
135 {
136  delete mPreviewPicture;
137 }
138 
140 {
141  if ( mPreviewPicture )
142  {
143  delete mPreviewPicture;
144  }
145 
146  mPreviewPicture = new QPicture( picture );
147  updatePreview();
148 }
149 
151 {
152  if ( !stack )
153  {
154  return;
155  }
156 
157  EffectItem* parent = static_cast<EffectItem*>( mModel->invisibleRootItem() );
158 
159  int count = stack->count();
160  for ( int i = count - 1; i >= 0; i-- )
161  {
162  EffectItem* effectItem = new EffectItem( stack->effect( i ), this );
163  effectItem->setEditable( false );
164  parent->appendRow( effectItem );
165  }
166 }
167 
168 
170 {
171  mModel->clear();
172  loadStack( mStack );
173 }
174 
176 {
177  QModelIndex currentIdx = mEffectsList->currentIndex();
178  if ( !currentIdx.isValid() )
179  return;
180 
181  EffectItem *item = static_cast<EffectItem*>( mModel->itemFromIndex( currentIdx ) );
182 
184  int rowCount = root->rowCount();
185  int currentRow = item ? item->row() : 0;
186 
187  mUpButton->setEnabled( currentRow > 0 );
188  mDownButton->setEnabled( currentRow < rowCount - 1 );
189  mRemoveButton->setEnabled( rowCount > 1 );
190 }
191 
193 {
194  QPainter painter;
195  QImage previewImage( 150, 150, QImage::Format_ARGB32 );
196  previewImage.fill( Qt::transparent );
197  painter.begin( &previewImage );
198  painter.setRenderHint( QPainter::Antialiasing );
200  if ( !mPreviewPicture )
201  {
202  QPicture previewPic;
203  QPainter previewPicPainter;
204  previewPicPainter.begin( &previewPic );
205  previewPicPainter.setPen( Qt::red );
206  previewPicPainter.setBrush( QColor( 255, 100, 100, 255 ) );
207  previewPicPainter.drawEllipse( QPoint( 75, 75 ), 30, 30 );
208  previewPicPainter.end();
209  mStack->render( previewPic, context );
210  }
211  else
212  {
213  context.painter()->translate( 35, 35 );
214  mStack->render( *mPreviewPicture, context );
215  }
216  painter.end();
217 
218  lblPreview->setPixmap( QPixmap::fromImage( previewImage ) );
219 }
220 
222 {
223  QModelIndex idx = mEffectsList->currentIndex();
224  if ( !idx.isValid() )
225  return NULL;
226 
227  EffectItem *item = static_cast<EffectItem*>( mModel->itemFromIndex( idx ) );
228  return item;
229 }
230 
232 {
233  updateUi();
234 
235  EffectItem* currentItem = currentEffectItem();
236  if ( !currentItem )
237  return;
238 
239  QWidget *effectPropertiesWidget = new QgsPaintEffectPropertiesWidget( currentItem->effect() );
240  setWidget( effectPropertiesWidget );
241 
242  connect( effectPropertiesWidget, SIGNAL( changeEffect( QgsPaintEffect* ) ), this, SLOT( changeEffect( QgsPaintEffect* ) ) );
243  connect( effectPropertiesWidget, SIGNAL( changed() ), this, SLOT( updatePreview() ) );
244 
245 }
246 
248 {
249  int index = stackedWidget->addWidget( widget );
250  stackedWidget->setCurrentIndex( index );
251  if ( mPresentWidget )
252  {
253  stackedWidget->removeWidget( mPresentWidget );
254  QWidget *dummy = mPresentWidget;
255  mPresentWidget = widget;
256  delete dummy; // auto disconnects all signals
257  }
258 }
259 
261 {
262  QgsPaintEffect* newEffect = new QgsDrawSourceEffect();
263  mStack->insertEffect( 0, newEffect );
264 
265  EffectItem *newEffectItem = new EffectItem( newEffect, this );
266  mModel->invisibleRootItem()->insertRow( mStack->count() - 1, newEffectItem );
267 
268  mEffectsList->setCurrentIndex( mModel->indexFromItem( newEffectItem ) );
269  updateUi();
270  updatePreview();
271 }
272 
274 {
275  EffectItem *item = currentEffectItem();
276  int row = item->row();
278 
279  int layerIdx = root->rowCount() - row - 1;
280  QgsPaintEffect *tmpEffect = mStack->takeEffect( layerIdx );
281 
283 
284  int newSelection = qMin( row, root->rowCount() - 1 );
285  QModelIndex newIdx = root->child( newSelection )->index();
286  mEffectsList->setCurrentIndex( newIdx );
287 
288  updateUi();
289  updatePreview();
290 
291  delete tmpEffect;
292 }
293 
295 {
296  moveEffectByOffset( + 1 );
297 }
298 
300 {
301  moveEffectByOffset( -1 );
302 }
303 
305 {
306  EffectItem *item = currentEffectItem();
307  if ( !item )
308  return;
309 
310  int row = item->row();
311 
313 
314  int layerIdx = root->rowCount() - row - 1;
315  // switch effects
316  QgsPaintEffect* tmpEffect = mStack->takeEffect( layerIdx );
317  mStack->insertEffect( layerIdx - offset, tmpEffect );
318 
319  QList<QStandardItem *> toMove = root->takeRow( row );
320  root->insertRows( row + offset, toMove );
321 
322  QModelIndex newIdx = toMove[ 0 ]->index();
323  mEffectsList->setCurrentIndex( newIdx );
324 
325  updatePreview();
326  updateUi();
327 }
328 
330 {
331  EffectItem *item = currentEffectItem();
332  item->setEffect( newEffect );
333 
335  int effectIdx = root->rowCount() - item->row() - 1;
336  mStack->changeEffect( effectIdx, newEffect );
337 
338  updatePreview();
339  // Important: This lets the effect to have its own effect properties widget
340  effectChanged();
341 }
342 
343 
344 //
345 // QgsEffectStackPropertiesDialog
346 //
347 
349  : QgsDialog( parent, f, QDialogButtonBox::Ok | QDialogButtonBox::Cancel )
350  , mPropertiesWidget( 0 )
351 {
352  setWindowTitle( tr( "Effect Properties" ) );
355 }
356 
358 {
359 
360 }
361 
363 {
364  return mPropertiesWidget->stack();
365 }
366 
368 {
370 }
371 
372 //
373 // QgsEffectStackCompactWidget
374 //
375 
377  : QWidget( parent )
378  , mEnabledCheckBox( 0 )
379  , mButton( 0 )
380  , mPreviewPicture( 0 )
381 {
382  QHBoxLayout* layout = new QHBoxLayout();
383  layout->setContentsMargins( 0, 0, 0, 0 );
384  layout->setSpacing( 0 );
385  setLayout( layout );
386 
387  mEnabledCheckBox = new QCheckBox( this );
388  mEnabledCheckBox->setText( tr( "Draw effects" ) );
389  layout->addWidget( mEnabledCheckBox );
390 
391  mButton = new QToolButton( this );
392  mButton->setIcon( QgsApplication::getThemeIcon( "mIconPaintEffects.svg" ) );
393  mButton->setToolTip( tr( "Customise effects" ) );
394  layout->addWidget( mButton );
395 
396  setFocusPolicy( Qt::StrongFocus );
397  setFocusProxy( mEnabledCheckBox );
398 
399  connect( mButton, SIGNAL( clicked() ), this, SLOT( showDialog() ) );
400  connect( mEnabledCheckBox, SIGNAL( toggled( bool ) ), this, SLOT( enableToggled( bool ) ) );
401 
402  setPaintEffect( effect );
403 }
404 
406 {
407  delete mPreviewPicture;
408 }
409 
411 {
412  if ( !effect )
413  {
414  mEnabledCheckBox->setChecked( false );
415  mEnabledCheckBox->setEnabled( false );
416  mButton->setEnabled( false );
417  mStack = 0;
418  return;
419  }
420 
421  //is effect a stack?
422  QgsEffectStack* stack = dynamic_cast<QgsEffectStack*>( effect );
423  if ( !stack )
424  {
425  //not already a stack, so promote to stack
426  stack = new QgsEffectStack( *effect );
427  }
428 
429  mStack = stack;
430  mEnabledCheckBox->setChecked( mStack->enabled() );
431  mEnabledCheckBox->setEnabled( true );
432  mButton->setEnabled( mStack->enabled() );
433 }
434 
436 {
437  delete mPreviewPicture;
438  mPreviewPicture = new QPicture( picture );
439 }
440 
441 void QgsEffectStackCompactWidget::showDialog()
442 {
443  if ( !mStack )
444  return;
445 
446  QgsEffectStack* clone = static_cast<QgsEffectStack*>( mStack->clone() );
447  QgsEffectStackPropertiesDialog dialog( clone, this );
448  if ( mPreviewPicture )
449  {
450  dialog.setPreviewPicture( *mPreviewPicture );
451  }
452  if ( dialog.exec() == QDialog::Accepted )
453  {
454  *mStack = *clone;
455  emit changed();
456  }
457 
458  delete clone;
459 }
460 
461 void QgsEffectStackCompactWidget::enableToggled( bool checked )
462 {
463  if ( !mStack )
464  {
465  return;
466  }
467 
468  mStack->setEnabled( checked );
469  mButton->setEnabled( checked );
470  emit changed();
471 }
QLayout * layout() const
static const int EffectItemType
void addEffect()
Adds a new effect to the stack.
EffectItem * currentEffectItem()
Returns the currently selected effect within the stack.
static unsigned index
void setContentsMargins(int left, int top, int right, int bottom)
void setEnabled(const bool enabled)
Sets whether the effect is enabled.
void setupUi(QWidget *widget)
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const =0
bool end()
void setRenderHint(RenderHint hint, bool on)
void setPaintEffect(QgsPaintEffect *effect)
Sets paint effect attached to the widget.
QStandardItem * invisibleRootItem() const
QList< QStandardItem * > takeRow(int row)
void emitDataChanged()
static QString iconPath(QString iconFile)
Returns path to the desired icon file.
void setFocusPolicy(Qt::FocusPolicy policy)
static QIcon getThemeIcon(const QString &theName)
Helper to get a theme icon.
A dialog for modifying the properties of a QgsEffectStack, including adding and reordering effects wi...
bool enabled() const
Returns whether the effect is enabled.
Base class for visual effects which can be applied to QPicture drawings.
EffectItem(QgsPaintEffect *effect, QgsEffectStackPropertiesWidget *propertiesWidget)
void removeRow(int row)
A generic dialog with layout and button box.
Definition: qgsdialog.h:30
QPixmap fromImage(const QImage &image, QFlags< Qt::ImageConversionFlag > flags)
QgsEffectStackPropertiesWidget * mWidget
void updatePreview()
Updates the effect preview icon.
void setIcon(const QIcon &icon)
QString tr(const char *sourceText, const char *disambiguation, int n)
int type() const override
A widget for modifying the properties of a QgsEffectStack, including adding and reordering effects wi...
virtual void setData(const QVariant &value, int role)
void changeEffect(QgsPaintEffect *newEffect)
Updates the effect stack when the currently selected effect changes properties.
bool isValid() const
static QgsRenderContext createRenderContext(QPainter *p)
Creates a render context for a pixel based device.
void setEnabled(bool)
void addWidget(QWidget *widget, int stretch, QFlags< Qt::AlignmentFlag > alignment)
int count() const
Returns count of effects contained by the stack.
void setLayout(QLayout *layout)
void setPreviewPicture(const QPicture &picture)
Sets the picture to use for effect previews for the dialog.
QModelIndex indexFromItem(const QStandardItem *item) const
void fill(uint pixelValue)
static QgsPaintEffectRegistry * instance()
virtual QString type() const =0
Returns the effect type.
void setPen(const QColor &color)
void drawEllipse(const QRectF &rectangle)
QgsEffectStack * stack()
Returns effect stack attached to the widget.
void appendRow(const QList< QStandardItem * > &items)
void insertRows(int row, const QList< QStandardItem * > &items)
void setFocusProxy(QWidget *w)
A widget which modifies the properties of a QgsPaintEffect.
void setBrush(const QBrush &brush)
virtual QgsPaintEffect * clone() const override
Duplicates an effect by creating a deep copy of the effect.
A paint effect which consists of a stack of other chained paint effects.
bool changeEffect(const int index, QgsPaintEffect *effect)
Replaces the effect at a specified position within the stack.
bool insertEffect(const int index, QgsPaintEffect *effect)
Inserts an effect at a specified index within the stack.
void setPreviewPicture(const QPicture &picture)
Sets the picture to use for effect previews for the dialog.
void loadStack()
Refreshes the widget to reflect the current state of the stack.
QgsPaintEffectAbstractMetadata * effectMetadata(const QString &name) const
Returns the metadata for a specific effect.
QStandardItem * child(int row, int column) const
void setPreviewPicture(const QPicture &picture)
Sets the picture to use for effect previews for the dialog.
QgsEffectStack * stack()
Returns effect stack attached to the dialog.
QgsEffectStackPropertiesDialog(QgsEffectStack *stack, QWidget *parent=0, Qt::WindowFlags f=0)
QgsEffectStackPropertiesDialog constructor.
void updateUi()
Enables or disables widgets depending on the selected effect within the stack.
void setChecked(bool)
QgsPaintEffect * effect()
Contains information about the context of a rendering operation.
QPainter * painter()
const QAbstractItemModel * model() const
QStandardItem * itemFromIndex(const QModelIndex &index) const
void changed()
Emitted when the paint effect properties change.
void setWindowTitle(const QString &)
void moveEffectUp()
Moves the currently selected effect up in the stack.
QVBoxLayout * layout()
Returns the central layout. Widgets added to it must have this dialog as parent.
Definition: qgsdialog.h:40
bool toBool() const
void translate(const QPointF &offset)
QModelIndex index() const
void setText(const QString &text)
void setWidget(QWidget *widget)
Sets the effect properties widget.
QgsEffectStackPropertiesWidget * mPropertiesWidget
int rowCount() const
QVariant data(int role) const override
typedef WindowFlags
void setEffect(QgsPaintEffect *effect)
void setData(const QVariant &value, int role) override
virtual void render(QPicture &picture, QgsRenderContext &context)
Renders a picture using the effect.
void effectChanged()
Updates the widget when the selected effect changes type.
void moveEffectDown()
Moves the currently selected effect down in the stack.
void setToolTip(const QString &)
A paint effect which draws the source picture with minor or no alterations.
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QObject * parent() const
bool begin(QPaintDevice *device)
QgsPaintEffect * effect(int index) const
Returns a pointer to the effect at a specified index within the stack.
void removeEffect()
Removes the currently selected effect from the stack.
void moveEffectByOffset(int offset)
Moves the currently selected effect within the stack by a specified offset.
void setCheckable(bool checkable)
int row() const
virtual QVariant data(int role) const
void insertRow(int row, const QList< QStandardItem * > &items)
void setEditable(bool editable)
void setSpacing(int spacing)
QgsEffectStackCompactWidget(QWidget *parent=0, QgsPaintEffect *effect=0)
QgsEffectStackCompactWidget constructor.
QgsEffectStackPropertiesWidget(QgsEffectStack *stack, QWidget *parent=0)
QgsEffectStackPropertiesWidget constructor.
QgsPaintEffect * takeEffect(const int index)
Removes an effect from the stack and returns a pointer to it.