pqColorScaleEditor.cxx 101 KB
Newer Older
1
2
3
4
5
/*=========================================================================

   Program: ParaView
   Module:    pqColorScaleEditor.cxx

6
   Copyright (c) 2005-2008 Sandia Corporation, Kitware Inc.
7
8
9
   All rights reserved.

   ParaView is a free software; you can redistribute it and/or modify it
10
   under the terms of the ParaView license version 1.2.
11

12
   See License_v1.2.txt for the full ParaView license.
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
   A copy of this license can be obtained by contacting
   Kitware Inc.
   28 Corporate Drive
   Clifton Park, NY 12065
   USA

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

=========================================================================*/

/// \file pqColorScaleEditor.cxx
/// \date 2/14/2007

#include "pqColorScaleEditor.h"
#include "ui_pqColorScaleDialog.h"

#include "pqApplicationCore.h"
40
#include "pqBuiltinColorMaps.h"
41
#include "pqChartValue.h"
42
43
#include "pqColorMapModel.h"
#include "pqColorPresetManager.h"
44
#include "pqColorPresetModel.h"
45
#include "pqCoreUtilities.h"
46
#include "pqDataRepresentation.h"
47
#include "pqLookupTableManager.h"
48
#include "pqOutputPort.h"
49
#include "pqPipelineRepresentation.h"
50
#include "pqPropertyLinks.h"
51
#include "pqRenderViewBase.h"
52
#include "pqRescaleRange.h"
53
#include "pqScalarBarRepresentation.h"
54
#include "pqScalarOpacityFunction.h"
55
#include "pqScalarsToColors.h"
56
#include "pqServerManagerModel.h"
57
#include "pqSettings.h"
58
59
#include "pqSignalAdaptors.h"
#include "pqSMAdaptor.h"
60
#include "pqStandardColorLinkAdaptor.h"
61
#include "pqTransferFunctionChartViewWidget.h"
62
#include "vtkAbstractArray.h"
63
64
#include "vtkAxis.h"
#include "vtkChartXY.h"
65
66
67
68
#include "vtkColorTransferControlPointsItem.h"
#include "vtkCompositeControlPointsItem.h"
#include "vtkPiecewiseControlPointsItem.h"
#include "vtkTransferFunctionViewer.h"
69
70
71
#include "vtkColorTransferFunction.h"
#include "vtkEventQtSlotConnect.h"
#include "vtkPiecewiseFunction.h"
72
#include "vtkPVArrayInformation.h"
73
74
#include "vtkPVXMLElement.h"
#include "vtkPVXMLParser.h"
75
#include "vtkPVTemporalDataInformation.h"
76
#include "vtkSMDoubleVectorProperty.h"
77
78
#include "vtkSMProperty.h"
#include "vtkSMProxy.h"
79
#include "vtkSMStringVectorProperty.h"
80
81
#include "vtkSMPVRepresentationProxy.h"
#include "vtkType.h"
82
#include "vtkSmartPointer.h"
83
84

#include <QCloseEvent>
85
86
#include <QColor>
#include <QColorDialog>
87
#include <QDoubleValidator>
88
#include <QGridLayout>
89
#include <QIntValidator>
90
#include <QItemSelectionModel>
91
92
#include <QList>
#include <QMenu>
93
#include <QMessageBox>
94
#include <QPointer>
95
96
97
98
#include <QSpacerItem>
#include <QString>
#include <QtDebug>
#include <QVariant>
99
#include "QVTKWidget.h"
100

101
#include <set>
102
#include <sstream>
103
104
105
106
107
108
109
110

#define PQ_INTERPRET_INTERVAL 0
#define PQ_INTERPRET_CATEGORY 1

#define PQ_COLORS_PAGE 0
#define PQ_ANNOTATION_PAGE 1
#define PQ_LEGEND_PAGE 2

111
112
#define PQ_ANN_VALUE_COL 0
#define PQ_ANN_ENTRY_COL 1
113

114
115
116
117
118
119
// A simple subclass of QTreeWidgetItem that overrides the default sorting behavior.
// If both items being compared can be converted to numbers, they are compared as numbers.
// Otherwise, string comparison is used.
class pqAnnotationTreeItem : public QTreeWidgetItem
{
public:
David Thompson's avatar
David Thompson committed
120
  pqAnnotationTreeItem(QTreeWidget* parnt) : QTreeWidgetItem(parnt) { }
121
122
123
124
125
126
127
128
protected:
  virtual bool operator < ( const QTreeWidgetItem& other ) const
    {
    int column = this->treeWidget()->sortColumn();
    vtkVariant x( this->data( column, Qt::DisplayRole ).toString().toAscii().data() );
    vtkVariant y( other.data( column, Qt::DisplayRole ).toString().toAscii().data() );
    double dx, dy;
    bool vx, vy;
129
130
    dx = x.ToDouble( &vx );
    dy = y.ToDouble( &vy );
131
132
133
134
135
136
137
138
    if ( vx && vy )
      {
      return dx < dy;
      }
    return x < y;
    }
};

139
140
141
142
class pqColorScaleEditorForm : public Ui::pqColorScaleDialog
{
public:
  pqColorScaleEditorForm();
143
  ~pqColorScaleEditorForm() { }
144

145
146
  void updateInterpretation( bool indexedLookup );

147
148
  pqPropertyLinks Links; // used to link properties on the legend
  pqPropertyLinks ReprLinks; // used to link properties on the representation.
149
150
  pqSignalAdaptorColor *TitleColorAdaptor;
  pqSignalAdaptorColor *LabelColorAdaptor;
151
152
  pqStandardColorLinkAdaptor* TitleColorLink;
  pqStandardColorLinkAdaptor* LabelColorLink;
153
154
  pqSignalAdaptorComboBox *TitleFontAdaptor;
  pqSignalAdaptorComboBox *LabelFontAdaptor;
155
  vtkEventQtSlotConnect *Listener;
156
  pqColorPresetManager *Presets;
157
  QButtonGroup* Interpretation;
158
  bool InSetColors;
159
160
161
162
163
  // Is the vtkScalarsToColors SM proxy's "Annotations" property being updated via this class (the GUI)?
  // Or, is the property being changed by the server or another client?
  // If TRUE, we should not try to update the GUI with the new values. If FALSE, we should update the GUI to match.
  bool InSetAnnotation;
  bool InSetInterpretation;
164
  bool IgnoreEditor;
165
  bool MakingLegend;
166
167
  vtkSmartPointer<vtkEventQtSlotConnect> ColorFunctionConnect;
  vtkSmartPointer<vtkEventQtSlotConnect> OpacityFunctionConnect;
168
169
};

170
171
172
173
174
175
176
void pqColorScaleEditorForm::updateInterpretation( bool indexedLookup )
{
  this->Interpretation->blockSignals( true );
  this->IntervalValues->setChecked( ! indexedLookup );
  this->CategoricalValues->setChecked( indexedLookup );
  this->Interpretation->blockSignals( false );
  this->ColorTabs->setTabEnabled( PQ_COLORS_PAGE, ! indexedLookup );
177
178
179
180
  this->UseLogScaleSimple->setDisabled( indexedLookup );
  this->UseAutoRescaleSimple->setDisabled( indexedLookup );
  this->SimpleMin->setDisabled( indexedLookup );
  this->SimpleMax->setDisabled( indexedLookup );
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
  if ( indexedLookup )
    {
    if ( this->ColorTabs->currentIndex() == PQ_COLORS_PAGE )
      {
      this->ColorTabs->setCurrentIndex( PQ_ANNOTATION_PAGE );
      }
    }
  else
    {
    if ( this->ColorTabs->currentIndex() == PQ_ANNOTATION_PAGE )
      {
      this->ColorTabs->setCurrentIndex( PQ_COLORS_PAGE );
      }
    }
}

197
198
199

//----------------------------------------------------------------------------
pqColorScaleEditorForm::pqColorScaleEditorForm()
200
  : Ui::pqColorScaleDialog(), Links()
201
202
203
{
  this->TitleColorAdaptor = 0;
  this->LabelColorAdaptor = 0;
204
205
  this->TitleColorLink = 0;
  this->LabelColorLink = 0;
206
207
  this->TitleFontAdaptor = 0;
  this->LabelFontAdaptor = 0;
208
  this->Listener = 0;
209
  this->Presets = 0;
210
  this->InSetColors = false;
211
212
  this->InSetAnnotation = false;
  this->InSetInterpretation = false;
213
  this->IgnoreEditor = false;
214
  this->MakingLegend = false;
215
  this->Interpretation = new QButtonGroup;
216
217
218
219
}

//----------------------------------------------------------------------------
pqColorScaleEditor::pqColorScaleEditor(QWidget *widgetParent)
Mark Richardson's avatar
Mark Richardson committed
220
  : QDialog(widgetParent)
221
222
223
224
{
  this->Form = new pqColorScaleEditorForm();
  this->Display = 0;
  this->ColorMap = 0;
225
  this->OpacityFunction = 0;
226
  this->Legend = 0;
227
  this->ActiveUniqueValues = 0;
228
229
230

  // Set up the ui.
  this->Form->setupUi(this);
231
  this->Form->Listener = vtkEventQtSlotConnect::New();
232
233
  this->Form->Presets = new pqColorPresetManager(this);
  this->Form->Presets->restoreSettings();
234

235
  // Put the interval and catorical data interpretation buttons in the "interpretation" button group:
236
237
238
239
  this->Form->Interpretation->addButton( this->Form->IntervalValues );
  this->Form->Interpretation->addButton( this->Form->CategoricalValues );
  this->Form->Interpretation->setId(    this->Form->IntervalValues, PQ_INTERPRET_INTERVAL );
  this->Form->Interpretation->setId( this->Form->CategoricalValues, PQ_INTERPRET_CATEGORY );
240
  // Colormap domain value interpretation: interval/ratio or categorical/nominal?
241
242
  this->connect( this->Form->Interpretation, SIGNAL(buttonClicked(int)), this, SLOT(setInterpretation(int)) );

David Thompson's avatar
David Thompson committed
243
  // Annotation
244
245
246
247
  this->Form->AnnotationTree->setDragDropOverwriteMode( false );
  this->Form->AnnotationTree->setDragEnabled( true );
  this->Form->AnnotationTree->setDragDropMode( QAbstractItemView::InternalMove );
  this->Form->AnnotationTree->sortByColumn( -1, Qt::DescendingOrder );
248
  QObject::connect(
249
250
    this->Form->AnnotationTree->header(), SIGNAL(sectionClicked(int)),
    this, SLOT(updateAnnotationColors()));
251
252
  //this->Form->AnnotationTree->setSortingEnabled( false );
  //this->Form->AnnotationTree->verticalHeader()->setMovable( true );
253
254
  QObject::connect(this->Form->AnnotationTree, SIGNAL(itemSelectionChanged()),
    this, SLOT(annotationSelectionChanged()));
255
256
257
258
259
260
261
  this->Form->AnnotationTree->viewport()->installEventFilter( this );
  QObject::connect(
    this->Form->AnnotationTree->model(), SIGNAL(layoutChanged()),
    this, SLOT(annotationsChanged()) );
  QObject::connect(
    this->Form->AnnotationTree->model(), SIGNAL(rowsMoved(const QModelIndex&, int, int, const QModelIndex&, int)),
    this, SLOT(annotationsChanged()) );
David Thompson's avatar
David Thompson committed
262
263
264
  QObject::connect( this->Form->RemoveAnnotation, SIGNAL(clicked()), this, SLOT(removeAnnotation()) );
  QObject::connect( this->Form->ResetAnnotations, SIGNAL(clicked()), this, SLOT(resetAnnotations()) );
  QObject::connect( this->Form->AddActiveValues,  SIGNAL(clicked()), this, SLOT(addActiveValues()) );
265
  QObject::connect( this->Form->NewAnnotation,    SIGNAL(clicked()), this, SLOT(addAnnotationEntry()) );
266
267
268
269
270

  // Force a redraw immediately when the "Render View Immediately" button gets checked...
  // Some changes may already have been made.
  this->connect(this->Form->checkBoxImmediateRender, SIGNAL(clicked()),
    this, SLOT(renderViewOptionally()));
David Thompson's avatar
David Thompson committed
271

272
  // Color transfer function widgets
273
274
  this->restoreOptionalUserSettings();
  this->Form->ScalarColor->setVisible(0);
275
276
277
278
279
280
  this->Form->pushButtonScalarColor->setFixedHeight(40);
  this->Form->pushButtonScalarColor->setText("");
  this->Form->pushButtonScalarColor->setVisible(0);
  this->connect(this->Form->pushButtonScalarColor,SIGNAL(clicked()),
    this->Form->ScalarColor, SLOT(chooseColor()));

281
282
283
284
  this->connect(this->Form->ScalarColor,SIGNAL(chosenColorChanged(const QColor &)),
    this, SLOT(setScalarColor(const QColor &)));
  this->connect(this->Form->opacityScalar, SIGNAL(editingFinished()),
    this, SLOT(setOpacityScalarFromText()));
285
286
  this->connect(this->Form->pushButtonApply, SIGNAL(clicked()),
    this, SLOT(updateDisplay()));
287
288

  this->UseEnableOpacityCheckBox = false;
289
290
  this->connect(this->Form->EnableOpacityFunction, SIGNAL(stateChanged(int)),
    this, SLOT(setEnableOpacityMapping(int)));
291

292
293
  QLayout* tfLayout = this->Form->frameColorTF->layout();
  this->ColorMapViewer = new pqTransferFunctionChartViewWidget(this);
294
  this->ColorMapViewer->setFixedHeight(40);
295
  this->OpacityFunctionViewer = new pqTransferFunctionChartViewWidget(this);
296
297
298
  this->OpacityFunctionViewer->setSizePolicy(
    QSizePolicy::Expanding, QSizePolicy::Expanding);
  this->OpacityFunctionViewer->setMinimumHeight(60);
299
  tfLayout->addWidget(this->ColorMapViewer);
300
301
302
303
304
305

  QVBoxLayout* opacityLayout = new QVBoxLayout(this->Form->frameOpacity);
  opacityLayout->setMargin(0);
  opacityLayout->addWidget(this->OpacityFunctionViewer);
  this->Form->frameOpacity->setVisible(0);

306
307
308
309
310
311
312
  this->Form->ColorFunctionConnect = vtkSmartPointer<vtkEventQtSlotConnect>::New();
  this->Form->OpacityFunctionConnect = vtkSmartPointer<vtkEventQtSlotConnect>::New();
  double validBounds[4] = {VTK_DOUBLE_MIN, VTK_DOUBLE_MAX, 0, 1};
  this->OpacityFunctionViewer->setValidBounds(validBounds);
  this->ColorMapViewer->setValidBounds(validBounds);

  this->OpacityFunctionViewer->addCompositeFunction(0, 0, true, true);
313
  vtkCompositeControlPointsItem* composite =
314
315
316
317
318
    vtkCompositeControlPointsItem::SafeDownCast(
    this->OpacityFunctionViewer->opacityFunctionPlots()[1]);
  composite->SetColorFill(true);
  composite->SetPointsFunction(vtkCompositeControlPointsItem::OpacityPointsFunction);
  this->ColorMapViewer->addColorTransferFunction(0);
319
320

  // Initialize the state of some of the controls.
321
  this->enableRescaleControls(this->Form->UseAutoRescale->isChecked());
322
323
324
325
  this->enableResolutionControls(this->Form->UseDiscreteColors->isChecked());

  this->enableLegendControls(this->Form->ShowColorLegend->isChecked());

326
327
328
329
  // Add the color space options to the combo box.
  this->Form->ColorSpace->addItem("RGB");
  this->Form->ColorSpace->addItem("HSV");
  this->Form->ColorSpace->addItem("Wrapped HSV");
330
  this->Form->ColorSpace->addItem("CIELAB");
331
  this->Form->ColorSpace->addItem("Diverging");
332

333
  // Add the color scale presets menu.
334
335
336
  this->loadBuiltinColorPresets();

  // Make sure the line edits only allow number inputs.
337
  this->Form->ScalarValue->setValidator(new QDoubleValidator(this));
338
339
  QDoubleValidator* opacityValid = new QDoubleValidator(this);
  opacityValid->setRange(0.0, 1.0);
340
  opacityValid->setDecimals(6);
341
342
  this->Form->Opacity->setValidator(opacityValid);
  this->Form->opacityScalar->setValidator(new QDoubleValidator(this));
343
344
  this->Form->ScalarOpacityUnitDistance->setValidator(
    new QDoubleValidator(this));
Clinton Stimpson's avatar
 
Clinton Stimpson committed
345
346
347

  QIntValidator *intValidator = new QIntValidator(this);
  this->Form->TableSizeText->setValidator(intValidator);
348

349
  // Connect the color scale widgets.
350
  this->connect(this->Form->ScalarValue, SIGNAL(editingFinished()),
351
      this, SLOT(setScalarFromText()));
352
353
  this->connect(this->Form->Opacity, SIGNAL(editingFinished()),
      this, SLOT(setOpacityFromText()));
354

355
  this->connect(this->Form->ColorSpace, SIGNAL(currentIndexChanged(int)),
356
357
      this, SLOT(setColorSpace(int)));

358
359
  this->connect(this->Form->NanColor,SIGNAL(chosenColorChanged(const QColor &)),
                this, SLOT(setNanColor(const QColor &)));
360
361
  this->connect(this->Form->NanColor2,SIGNAL(chosenColorChanged(const QColor &)),
                this, SLOT(setNanColor2(const QColor &)));
362
363
  this->connect(this->Form->AnnotationSwatch,SIGNAL(chosenColorChanged(const QColor &)),
                this, SLOT(editAnnotationColor(const QColor &)));
364

365
366
367
368
369
  this->connect(this->Form->SaveButton, SIGNAL(clicked()),
      this, SLOT(savePreset()));
  this->connect(this->Form->PresetButton, SIGNAL(clicked()),
      this, SLOT(loadPreset()));

370
371
372
  this->connect(this->Form->UseLogScale, SIGNAL(toggled(bool)),
      this, SLOT(setLogScale(bool)));

373
374
375
376
377
378
  this->connect(this->Form->UseAutoRescale, SIGNAL(toggled(bool)),
      this, SLOT(setAutoRescale(bool)));
  this->connect(this->Form->RescaleButton, SIGNAL(clicked()),
      this, SLOT(rescaleToNewRange()));
  this->connect(this->Form->RescaleToDataButton, SIGNAL(clicked()),
      this, SLOT(rescaleToDataRange()));
379
380
  this->connect(this->Form->RescaleToDataOverTimeButton, SIGNAL(clicked()),
      this, SLOT(rescaleToDataRangeOverTime()));
381

382
383
384
385
  this->connect(this->Form->UseDiscreteColors, SIGNAL(toggled(bool)),
      this, SLOT(setUseDiscreteColors(bool)));
  this->connect(this->Form->TableSize, SIGNAL(valueChanged(int)),
      this, SLOT(setSizeFromSlider(int)));
386
387
  this->connect(this->Form->TableSizeText, SIGNAL(editingFinished()),
      this, SLOT(setSizeFromText()));
388
389
390
391
392
393
394
395
396
397

  // Connect the color legend widgets.
  this->connect(this->Form->ShowColorLegend, SIGNAL(toggled(bool)),
      this, SLOT(setLegendVisibility(bool)));

  this->connect(this->Form->TitleName, SIGNAL(textChanged(const QString &)),
      this, SLOT(setLegendName(const QString &)));
  this->connect(this->Form->TitleComponent, SIGNAL(textChanged(const QString &)),
      this, SLOT(setLegendComponent(const QString &)));
  this->Form->TitleColorAdaptor = new pqSignalAdaptorColor(
398
      this->Form->TitleColorButton, "chosenColor",
399
400
401
402
403
      SIGNAL(chosenColorChanged(const QColor&)), false);
  this->Form->TitleFontAdaptor = new pqSignalAdaptorComboBox(
      this->Form->TitleFont);

  this->Form->LabelColorAdaptor = new pqSignalAdaptorColor(
404
      this->Form->LabelColorButton, "chosenColor",
405
406
407
408
409
410
411
      SIGNAL(chosenColorChanged(const QColor&)), false);
  this->Form->LabelFontAdaptor = new pqSignalAdaptorComboBox(
      this->Form->LabelFont);

  // Hook the close button up to the accept action.
  this->connect(this->Form->CloseButton, SIGNAL(clicked()),
      this, SLOT(accept()));
412
413
414
415

  //Hook up the MakeDefaultButton
  this->connect(this->Form->MakeDefaultButton, SIGNAL(clicked()),
      this, SLOT(makeDefault()));
416
417
418
419
420

  // =========================
  // Simple UI add-on
  // =========================
  this->connect( this->Form->SwitchToAdvanced, SIGNAL(toggled(bool)),
421
422
                 this, SLOT(enableAdvancedPanel(bool)));
  this->enableAdvancedPanel(this->Form->SwitchToAdvanced->isChecked());
423
424
425
426
427
428
429
430
431
432
433
434
435

  this->connect( this->Form->UseLogScaleSimple, SIGNAL(toggled(bool)),
                 this, SLOT(setLogScale(bool)));

  this->connect( this->Form->UseAutoRescaleSimple, SIGNAL(toggled(bool)),
                 this, SLOT(setAutoRescale(bool)));

  this->connect( this->Form->SimpleMin, SIGNAL(editingFinished()),
                 this, SLOT(rescaleToSimpleRange()));

  this->connect( this->Form->SimpleMax, SIGNAL(editingFinished()),
                 this, SLOT(rescaleToSimpleRange()));

436
  this->connect( this->Form->AnnotationTree, SIGNAL(itemChanged(QTreeWidgetItem*,int)),
David Thompson's avatar
David Thompson committed
437
438
                 this, SLOT(annotationsChanged()) );

439
440
441
442
  // Make sure the line edits only allow number inputs.
  QDoubleValidator* validator = new QDoubleValidator(this);
  this->Form->SimpleMin->setValidator(validator);
  this->Form->SimpleMax->setValidator(validator);
443
444
445
446
}

pqColorScaleEditor::~pqColorScaleEditor()
{
447
448
  // Save the color map presets.
  this->Form->Presets->saveSettings();
449
  this->saveOptionalUserSettings();
450
451
452
453

  if ( this->ActiveUniqueValues )
    this->ActiveUniqueValues->Delete();

454
455
456
457
  delete this->Form->LabelColorAdaptor;
  delete this->Form->TitleColorAdaptor;
  delete this->Form->LabelFontAdaptor;
  delete this->Form->TitleFontAdaptor;
458
  this->Form->Listener->Delete();
459
460
461
  delete this->Form;
}

462
void pqColorScaleEditor::setRepresentation(pqDataRepresentation *display)
463
464
465
466
467
468
469
{
  if(this->Display == display)
    {
    return;
    }

  this->setLegend(0);
470
  this->Form->ShowColorLegend->setEnabled(false);
471
472
473
474
  if(this->Display)
    {
    this->disconnect(this->Display, 0, this, 0);
    this->disconnect(&this->Form->Links, 0, this->Display, 0);
475
    this->disconnect(&this->Form->ReprLinks, 0, this->Display, 0);
476
    this->Form->ReprLinks.removeAllPropertyLinks();
477
478
479
    if(this->ColorMap)
      {
      this->disconnect(this->ColorMap, 0, this, 0);
480
      this->Form->Listener->Disconnect(
481
482
483
        this->ColorMap->getProxy()->GetProperty("RGBPoints"));
      this->Form->Listener->Disconnect(
        this->ColorMap->getProxy()->GetProperty("EnableOpacityMapping"));
484
      this->Form->Listener->Disconnect(
485
        this->ColorMap->getProxy()->GetProperty( "Annotations" ) );
486
      }
487

488
    if(this->OpacityFunction)
489
490
      {
      this->Form->Listener->Disconnect(
491
          this->OpacityFunction->getProxy()->GetProperty("Points"));
492
      }
493
494
495
496
    }

  this->Display = display;
  this->ColorMap = 0;
497
  this->OpacityFunction = 0;
498
499
500
501
502
  if(this->Display)
    {
    this->connect(this->Display, SIGNAL(destroyed(QObject *)),
        this, SLOT(cleanupDisplay()));
    this->connect(&this->Form->Links, SIGNAL(qtWidgetChanged()),
503
        this, SLOT(renderViewOptionally()));
504
    this->connect(&this->Form->ReprLinks, SIGNAL(qtWidgetChanged()),
505
        this, SLOT(renderViewOptionally()));
506
507
508
509
510
511
512

    // Get the color map object for the display's lookup table.
    this->ColorMap = this->Display->getLookupTable();
    if(this->ColorMap)
      {
      this->connect(this->ColorMap, SIGNAL(destroyed(QObject *)),
          this, SLOT(cleanupDisplay()));
513
514
      this->connect(this->ColorMap, SIGNAL(scalarBarsChanged()),
          this, SLOT(checkForLegend()));
515
516
      this->Form->Listener->Connect(
          this->ColorMap->getProxy()->GetProperty("RGBPoints"),
517
          vtkCommand::ModifiedEvent, this, SLOT(handleColorPointsChanged()));
518
519
520
      this->Form->Listener->Connect(
          this->ColorMap->getProxy()->GetProperty("EnableOpacityMapping"),
          vtkCommand::ModifiedEvent, this, SLOT(handleEnableOpacityMappingChanged()));
521
522
523
524
525
526
      this->Form->Listener->Connect(
        this->ColorMap->getProxy()->GetProperty( "IndexedLookup" ),
        vtkCommand::ModifiedEvent, this, SLOT(handleInterpretationChanged()) );
      this->Form->Listener->Connect(
        this->ColorMap->getProxy()->GetProperty( "Annotations" ),
        vtkCommand::ModifiedEvent, this, SLOT(handleAnnotationsChanged()) );
527
528
      this->handleInterpretationChanged();
      this->handleAnnotationsChanged();
529
530
531
532
533
534
535
536
      //bool indexMode = this->ColorMap->getIndexedLookup();
      //this->Form->updateInterpretation( indexMode );
      }

    QString colorArrayName = display->getProxyColorArrayName();
    int acomp = ( display->getLookupTable()->getVectorMode() == pqScalarsToColors::MAGNITUDE ? -1 :
      display->getLookupTable()->getVectorComponent() );
    vtkPVArrayInformation* ainfo = display->getProxyColorArrayInfo();
537
    bool haveActiveValues = false;
538
539
540
541
542
543
544
545
546
    if ( ainfo )
      {
      if ( acomp == -1 && ainfo->GetNumberOfComponents() == 1 )
        {
        acomp = 0;
        }
      vtkAbstractArray* uniq = ainfo->GetUniqueComponentValuesIfFDiscrete( acomp );
      if ( uniq )
        {
547
        haveActiveValues = true;
548
549
        // If the lookup table doesn't have any entries and the active representation has a small set, populate the lookup table
        // with these values by default. Otherwise, let the user add any new values with the "Add ## active values" button.
David Thompson's avatar
David Thompson committed
550
        this->setActiveUniqueValues( uniq );
551
        //if ( this->ColorMap->GetNumberOfAnnotations() == 0 )
552
        if ( this->Form->AnnotationTree->topLevelItemCount() == 0 )
553
          {
David Thompson's avatar
David Thompson committed
554
          this->addActiveValues();
555
556
557
          }
        uniq->Delete();
        }
558
559
560
561
562
      }
    if ( ! haveActiveValues )
      {
      this->Form->AddActiveValues->setText( "Too Many/Few Values" );
      this->Form->AddActiveValues->setEnabled( false );
563
564
565
566
567
      }
    }

  // Disable the gui elements if the color map is null.
  this->Form->ColorTabs->setEnabled(this->ColorMap != 0);
568

569
570
  this->initColorScale();
  if(this->ColorMap)
571
    {
572
    pqRenderViewBase *renderModule = qobject_cast<pqRenderViewBase *>(
573
        this->Display->getView());
574
    this->Form->ShowColorLegend->setEnabled(renderModule != 0);
575
    this->setLegend(this->ColorMap->getScalarBar(renderModule));
576
    }
577
578
  // update opacity mapping gui elements
  this->handleEnableOpacityMappingChanged();
579
580
}

581
void pqColorScaleEditor::pushColors()
582
{
583
  if(!this->ColorMap || this->Form->InSetColors)
584
585
586
587
    {
    return;
    }

588
589
  QList<QVariant> rgbPoints;
  this->Form->InSetColors = true;
590

591
592
  foreach(vtkColorTransferControlPointsItem* plot,
    this->ColorMapViewer->plots<vtkColorTransferControlPointsItem>())
593
    {
594
    vtkColorTransferFunction* tf=plot->GetColorTransferFunction();
595
    if ( ! tf ) continue;
596
    int total = tf->GetSize();
597
    double nodeValue[6];
598
    for(int i = 0; i < total; i++)
599
      {
600
601
602
603
604
605
      tf->GetNodeValue( i, nodeValue );
      rgbPoints
        << /* x */nodeValue[0]
        << /* R */nodeValue[1]
        << /* G */nodeValue[2]
        << /* B */nodeValue[3];
606
      }
607
608
609
610
    // If there is only one control point in the transfer function originally,
    // we need to add another control point.
    if(total == 1)
      {
611
      rgbPoints << nodeValue[0] << nodeValue[1] << nodeValue[2] << nodeValue[3];
612
      }
613
    }
614

615
616
  vtkSMProxy *lookupTable = this->ColorMap->getProxy();
  pqSMAdaptor::setMultipleElementProperty(
617
    lookupTable->GetProperty("RGBPoints"), rgbPoints);
618
  this->Form->InSetColors = false;
619
  lookupTable->UpdateVTKObjects();
620
  this->renderViewOptionally();
621
622
}

623
void pqColorScaleEditor::pushOpacity()
624
{
625
  if(!this->OpacityFunction || this->Form->InSetColors)
626
    {
627
628
629
630
631
632
633
634
635
    return;
    }

  QList<QVariant> opacityPoints;
  this->Form->InSetColors = true;

  double scalar[4];//[x, value, midpoint, sharpness]
  foreach(vtkCompositeControlPointsItem* plot,
    this->OpacityFunctionViewer->plots<vtkCompositeControlPointsItem>())
636
    {
637
638
639
    vtkPiecewiseFunction* pwf=plot->GetOpacityFunction();
    int total = pwf->GetSize();
    for(int i = 0; i < total; i++)
640
      {
641
      pwf->GetNodeValue(i, scalar);
642
      opacityPoints << scalar[0] << scalar[1] << scalar[2] << scalar[3];
643
644
      }
    }
645

646
  vtkSMProxy *points = this->OpacityFunction->getProxy();
647
  vtkSMDoubleVectorProperty* smProp = vtkSMDoubleVectorProperty::SafeDownCast(
648
    points->GetProperty("Points"));
649
  pqSMAdaptor::setMultipleElementProperty(smProp, opacityPoints);
650
651
652
653
  points->UpdateVTKObjects();

  this->Form->InSetColors = false;

654
  this->renderViewOptionally();
655
656
}

657
void pqColorScaleEditor::pushAnnotations()
658
{
659
  if ( ! this->ColorMap || this->Form->InSetAnnotation )
660
    {
661
662
    return;
    }
663

David Thompson's avatar
David Thompson committed
664
665
666
667
668
  vtkColorTransferFunction* tf = this->currentColorFunction();
  if ( tf )
    {
    tf->ResetAnnotations();
    }
669
670
671

  vtkSMProxy* lookupTable = this->ColorMap->getProxy();
  QList<QVariant> categories;
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
  QTreeWidgetItem* last = this->Form->AnnotationTree->topLevelItem(0);
  QTreeWidgetItem* valItem;
  // Find top-most item in list
  while (last && (valItem = this->Form->AnnotationTree->itemAbove(last)))
    {
    last = valItem;
    }
  valItem = last;
  // Traverse list from top down
  while (valItem)
    {
    QString val( valItem->data( PQ_ANN_VALUE_COL, Qt::DisplayRole ).toString() );
    QString txt( valItem->data( PQ_ANN_ENTRY_COL, Qt::DisplayRole ).toString() );
    categories << val << txt;
    if ( tf )
      {
      tf->SetAnnotation( val.toStdString(), txt.toStdString() );
      }
    valItem = this->Form->AnnotationTree->itemBelow(valItem);
    }
692
693
694
  this->Form->InSetAnnotation = true;
  pqSMAdaptor::setMultipleElementProperty(
    lookupTable->GetProperty( "Annotations" ), categories );
695

696
697
698
  lookupTable->UpdateVTKObjects();
  this->renderViewOptionally();
  this->Form->InSetAnnotation = false;
699
}
700
701
702

void pqColorScaleEditor::handleEnableOpacityMappingChanged()
{
703
704
  if(this->UseEnableOpacityCheckBox)
    {
705
706
707
708
709
    bool enabled = pqSMAdaptor::getElementProperty(
      this->ColorMap->getProxy()->GetProperty("EnableOpacityMapping")).toBool();

    this->Form->EnableOpacityFunction->setCheckState(
      enabled ? Qt::Checked : Qt::Unchecked);
710
711

    this->Form->frameOpacity->setVisible(enabled);
712
    }
713
714
}

715
void pqColorScaleEditor::handleOpacityPointsChanged()
716
{
717
718
719
  // If the point change was not generated by setColors, update the
  // points in the editor.
  if(!this->Form->InSetColors)
720
    {
721
722
723
724
725
    // Save the current point index to use after the change.
    vtkControlPointsItem* currentItem=this->OpacityFunctionViewer->
      currentControlPointsItem();
    int index = currentItem ?
      currentItem->GetCurrentPoint() : -1;
726

727
728
729
    // Load the new points.
    this->Form->IgnoreEditor = true;
    this->loadOpacityPoints();
730

731
732
733
734
735
736
737
738
739
740
    // Set the current point on the editor.
    if(index != -1 && this->OpacityFunctionViewer->currentControlPointsItem())
      {
      this->OpacityFunctionViewer->currentControlPointsItem()->SetCurrentPoint(index);
      }

    // Update the displayed values.
    this->Form->IgnoreEditor = false;
    this->enableOpacityPointControls();
    this->updateCurrentOpacityPoint();
741
742
    }
}
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775

void pqColorScaleEditor::handleColorPointsChanged()
{
  // If the point change was not generated by setColors, update the
  // points in the editor.
  if(!this->Form->InSetColors)
    {
    // Save the index of the point currently being edited
    vtkControlPointsItem* currentItem=this->ColorMapViewer->
      currentControlPointsItem();
    int index = currentItem ?
      currentItem->GetCurrentPoint() : -1;

    // Load the new points.
    this->Form->IgnoreEditor = true;
    this->loadColorPoints();

    // Restore the current point being edited to its value before loadColorPoints() was called.
    if(index != -1 && this->ColorMapViewer->currentControlPointsItem())
      {
      this->ColorMapViewer->currentControlPointsItem()->SetCurrentPoint(index);
      }

    // Update the displayed values.
    this->Form->IgnoreEditor = false;
    this->updateCurrentColorPoint();
    }
}

/// Update the GUI radio buttons that indicate how to interpret the data when the SM proxy's IndexedLookup property changes
void pqColorScaleEditor::handleInterpretationChanged()
{
  // Only update the radio button states when the proxy change is *not* generated
776
  // by the user clicking on the radio buttons. :-)
777
778
779
780
  if ( ! this->Form->InSetInterpretation && this->ColorMap )
    {
    bool indexedLookup = this->ColorMap->getIndexedLookup();
    this->Form->updateInterpretation( indexedLookup );
781
    this->pushColors();
782
783
784
785
786
787
788
789
790
791
792
793
    }
}

/// A wrapper around loadAnnotations that saves (and restores) the selected annotations before (and after) loading.
void pqColorScaleEditor::handleAnnotationsChanged()
{
  if ( ! this->Form->InSetAnnotation )
    {
    this->loadAnnotations();
    }
}

794
void pqColorScaleEditor::setScalarFromText()
795
{
796
797
798
799
800
801
802
  vtkColorTransferFunction* colors = this->currentColorFunction();
  vtkControlPointsItem* currentItem=this->ColorMapViewer->
    currentControlPointsItem();
  int index = currentItem ?
    currentItem->GetCurrentPoint() : -1;

  if(index == -1 ||!colors)
803
804
805
806
807
808
809
810
811
812
    {
    return;
    }

  // Get the value from the line edit.
  bool ok = true;
  double value = this->Form->ScalarValue->text().toDouble(&ok);
  if(!ok)
    {
    // Reset to the previous value.
813
    this->updateCurrentColorPoint();
814
815
816
817
818
    return;
    }

  // Make sure the value is greater than the previous point and less
  // than the next point.
819
  double scalar[4];
820
821
822
823
824
825
826
  // check if the value is actually changed
  currentItem->GetControlPoint(index, scalar);
  if(scalar[0] == value)
    {
    return;
    }

827
828
  bool endpoint = index == 0;
  if(index > 0)
829
    {
830
831
832
833
    int i=index - 1;
    this->ColorMapViewer->currentControlPointsItem()->GetControlPoint(i, scalar);

    double prev = scalar[0];
834
    if(value <= prev)
835
      {
836
      // value not acceptable.
837
      this->updateCurrentColorPoint();
838
      return;
839
840
      }
    }
841

842
843
  endpoint = endpoint || index == colors->GetSize() - 1;
  if(index < colors->GetSize() - 1)
844
    {
845
846
847
    int i=index + 1;
    this->ColorMapViewer->currentControlPointsItem()->GetControlPoint(i, scalar);
    double next = scalar[0];
848
    if(value >= next)
849
      {
850
      // value not acceptable.
851
      this->updateCurrentColorPoint();
852
      return;
853
854
      }
    }
855
856
857
858

  double nodeVal[6];
  colors->GetNodeValue(index, nodeVal);
  nodeVal[0]=value;
859
860
  // Set the new value on the point in the editor.
  this->Form->IgnoreEditor = true;
861
  colors->SetNodeValue(index, nodeVal);
862
863
864
  this->Form->IgnoreEditor = false;

  // Update the colors on the proxy.
865
  this->pushColors();
866
867
868
869
870
871
872

  // Update the range if the modified point was an endpoint.
  if(endpoint)
    {
    QPair<double, double> range = this->ColorMap->getScalarRange();
    this->updateScalarRange(range.first, range.second);
    }
873

874
 // this->Viewer->Render();
875
}
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
void pqColorScaleEditor::setOpacityScalarFromText()
{
  vtkPiecewiseFunction* opacities = this->currentOpacityFunction();
  vtkControlPointsItem* currentItem=this->OpacityFunctionViewer->
    currentControlPointsItem();
  int index = currentItem ?
    currentItem->GetCurrentPoint() : -1;

  if(index == -1 ||!opacities)
    {
    return;
    }

  // Get the value from the line edit.
  bool ok = true;
  double value = this->Form->opacityScalar->text().toDouble(&ok);
  if(!ok)
    {
    // Reset to the previous value.
    this->updateCurrentOpacityPoint();
    return;
    }
  double scalar[4];
899
  // check if the value is actually changed
900
  currentItem->GetControlPoint(index, scalar);
901
902
903
904
905
  if(scalar[0] == value)
    {
    return;
    }

906
907
908
909
910
911
912
  scalar[0]=value;
  // Set the new value on the point in the editor.
  this->Form->IgnoreEditor = true;
  opacities->SetNodeValue(index, scalar);
  this->Form->IgnoreEditor = false;

  // Update the opacity on the proxy.
913
  this->pushOpacity();
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
}

void pqColorScaleEditor::setSingleOpacityFromText()
{
  if(!this->OpacityFunction)
    {
    return;
    }
  bool ok=true;
  double opacity = this->Form->Opacity->text().toDouble(&ok);
  if(!ok)
    {
    // Reset to the previous opacity.
    this->updateCurrentOpacityPoint();
    return;
    }

  QList<QVariant> opacityPoints;
  this->Form->InSetColors = true;
  vtkPiecewiseFunction* pwf=vtkPiecewiseFunction::SafeDownCast(
    this->OpacityFunction->getProxy()->GetClientSideObject());
  if(pwf)
    {
    // Make sure the opacity is valid (0.0 - 1.0).
938
939
    opacity = std::min(opacity, 1.0);
    opacity = std::max(opacity, 0.0);
940
941
942
943
944
945
946

    double scalar[4];//[x, value, midpoint, sharpness]
    int total = pwf->GetSize();
    for(int i = 0; i < total; i++)
      {
      pwf->GetNodeValue(i, scalar);
      scalar[1]=opacity;
947
      opacityPoints << scalar[0] << scalar[1] << scalar[2] << scalar[3];
948
949
      }
    vtkSMProxy *points = this->OpacityFunction->getProxy();
950
    vtkSMDoubleVectorProperty* smProp = vtkSMDoubleVectorProperty::SafeDownCast(
951
      points->GetProperty("Points"));
952
    pqSMAdaptor::setMultipleElementProperty(smProp, opacityPoints);
953
954
955
956
957
958
    points->UpdateVTKObjects();

    this->Form->InSetColors = false;

    this->renderViewOptionally();
    }
959
960
961
962
}

void pqColorScaleEditor::setOpacityFromText()
{
963
964
965
  if(this->OpacityFunction)
    {
    double range[2]={0,1};
966
    if(this->internalScalarRange(range) && range[0]==range[1])
967
968
969
970
971
972
      {
      this->setSingleOpacityFromText();
      return;
      }
    }

973
974
975
976
977
978
  vtkPiecewiseFunction *opacities = this->currentOpacityFunction();
  vtkControlPointsItem* currentItem=this->OpacityFunctionViewer->
    currentControlPointsItem();
  int index = currentItem ?
    currentItem->GetCurrentPoint() : -1;
  if(index == -1 || !this->OpacityFunction ||!opacities)
979
980
981
982
983
984
    {
    return;
    }

  // Get the opacity from the line edit.
  bool ok = true;