pqColorScaleEditor.cxx 73.2 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 "pqChartValue.h"
41
42
#include "pqColorMapModel.h"
#include "pqColorPresetManager.h"
43
#include "pqColorPresetModel.h"
44
#include "pqCoreUtilities.h"
45
#include "pqDataRepresentation.h"
46
#include "pqLookupTableManager.h"
47
#include "pqOutputPort.h"
48
#include "pqPipelineRepresentation.h"
49
#include "pqPropertyLinks.h"
50
#include "pqRenderViewBase.h"
51
#include "pqRescaleRange.h"
52
#include "pqScalarBarRepresentation.h"
53
#include "pqScalarOpacityFunction.h"
54
#include "pqScalarsToColors.h"
55
#include "pqSettings.h"
56
57
#include "pqSignalAdaptors.h"
#include "pqSMAdaptor.h"
58
#include "pqStandardColorLinkAdaptor.h"
59
#include "pqTransferFunctionChartViewWidget.h"
60
61
#include "vtkAxis.h"
#include "vtkChartXY.h"
62
63
64
65
#include "vtkColorTransferControlPointsItem.h"
#include "vtkCompositeControlPointsItem.h"
#include "vtkPiecewiseControlPointsItem.h"
#include "vtkTransferFunctionViewer.h"
66
67
68
69
#include "vtkColorTransferFunction.h"
#include "vtkEventQtSlotConnect.h"
#include "vtkPiecewiseFunction.h"
#include "vtkPVTemporalDataInformation.h"
70
#include "vtkSMDoubleVectorProperty.h"
71
72
73
74
#include "vtkSMProperty.h"
#include "vtkSMProxy.h"
#include "vtkSMPVRepresentationProxy.h"
#include "vtkType.h"
75
#include "vtkSmartPointer.h"
76
77

#include <QCloseEvent>
78
79
#include <QColor>
#include <QColorDialog>
80
#include <QDoubleValidator>
81
#include <QGridLayout>
82
#include <QIntValidator>
83
#include <QItemSelectionModel>
84
85
#include <QList>
#include <QMenu>
86
#include <QMessageBox>
87
#include <QPointer>
88
89
90
91
#include <QSpacerItem>
#include <QString>
#include <QtDebug>
#include <QVariant>
92
#include "QVTKWidget.h"
93
94
95
96
97

class pqColorScaleEditorForm : public Ui::pqColorScaleDialog
{
public:
  pqColorScaleEditorForm();
98
  ~pqColorScaleEditorForm() { }
99

100
101
  pqPropertyLinks Links; // used to link properties on the legend
  pqPropertyLinks ReprLinks; // used to link properties on the representation.
102
103
  pqSignalAdaptorColor *TitleColorAdaptor;
  pqSignalAdaptorColor *LabelColorAdaptor;
104
105
  pqStandardColorLinkAdaptor* TitleColorLink;
  pqStandardColorLinkAdaptor* LabelColorLink;
106
107
  pqSignalAdaptorComboBox *TitleFontAdaptor;
  pqSignalAdaptorComboBox *LabelFontAdaptor;
108
  vtkEventQtSlotConnect *Listener;
109
  pqColorPresetManager *Presets;
110
111
  bool InSetColors;
  bool IgnoreEditor;
112
  bool MakingLegend;
113
114
  vtkSmartPointer<vtkEventQtSlotConnect> ColorFunctionConnect;
  vtkSmartPointer<vtkEventQtSlotConnect> OpacityFunctionConnect;
115
116
117
118
119
};


//----------------------------------------------------------------------------
pqColorScaleEditorForm::pqColorScaleEditorForm()
120
  : Ui::pqColorScaleDialog(), Links()
121
122
123
{
  this->TitleColorAdaptor = 0;
  this->LabelColorAdaptor = 0;
124
125
  this->TitleColorLink = 0;
  this->LabelColorLink = 0;
126
127
  this->TitleFontAdaptor = 0;
  this->LabelFontAdaptor = 0;
128
  this->Listener = 0;
129
  this->Presets = 0;
130
131
  this->InSetColors = false;
  this->IgnoreEditor = false;
132
  this->MakingLegend = false;
133
134
135
136
}

//----------------------------------------------------------------------------
pqColorScaleEditor::pqColorScaleEditor(QWidget *widgetParent)
Mark Richardson's avatar
Mark Richardson committed
137
  : QDialog(widgetParent)
138
139
140
141
{
  this->Form = new pqColorScaleEditorForm();
  this->Display = 0;
  this->ColorMap = 0;
142
  this->OpacityFunction = 0;
143
144
145
146
  this->Legend = 0;

  // Set up the ui.
  this->Form->setupUi(this);
147
  this->Form->Listener = vtkEventQtSlotConnect::New();
148
149
  this->Form->Presets = new pqColorPresetManager(this);
  this->Form->Presets->restoreSettings();
150
151

  // Color transfer function widgets
152
153
154
155
156
157
  this->restoreOptionalUserSettings();
  this->Form->ScalarColor->setVisible(0);
  this->connect(this->Form->ScalarColor,SIGNAL(chosenColorChanged(const QColor &)),
    this, SLOT(setScalarColor(const QColor &)));
  this->connect(this->Form->opacityScalar, SIGNAL(editingFinished()),
    this, SLOT(setOpacityScalarFromText()));
158
159
  this->connect(this->Form->pushButtonApply, SIGNAL(clicked()),
    this, SLOT(updateDisplay()));
160
161

  QVBoxLayout* tfLayout = new QVBoxLayout(this->Form->frameColorTF);
162
163
  this->ColorMapViewer = new pqTransferFunctionChartViewWidget(
    this);
164
  this->ColorMapViewer->setFixedHeight(40);
165
166
  this->OpacityFunctionViewer = new pqTransferFunctionChartViewWidget(
    this);
167
168
169
170
  this->OpacityFunctionViewer->setSizePolicy(
    QSizePolicy::Expanding, QSizePolicy::Expanding);
  this->OpacityFunctionViewer->setMinimumHeight(60);
  tfLayout->setMargin(0);
171
  tfLayout->addWidget(this->ColorMapViewer);
172
173
174
175
176
177

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

178
179
180
181
182
183
184
185
186
187
188
189
190
  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);
  vtkCompositeControlPointsItem* composite = 
    vtkCompositeControlPointsItem::SafeDownCast(
    this->OpacityFunctionViewer->opacityFunctionPlots()[1]);
  composite->SetColorFill(true);
  composite->SetPointsFunction(vtkCompositeControlPointsItem::OpacityPointsFunction);
  this->ColorMapViewer->addColorTransferFunction(0);
191
192

  // Initialize the state of some of the controls.
193
  this->enableRescaleControls(this->Form->UseAutoRescale->isChecked());
194
195
196
197
  this->enableResolutionControls(this->Form->UseDiscreteColors->isChecked());

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

198
199
200
201
  // 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");
202
  this->Form->ColorSpace->addItem("CIELAB");
203
  this->Form->ColorSpace->addItem("Diverging");
204

205
  // Add the color scale presets menu.
206
207
208
  this->loadBuiltinColorPresets();

  // Make sure the line edits only allow number inputs.
209
  this->Form->ScalarValue->setValidator(new QDoubleValidator(this));
210
211
  QDoubleValidator* opacityValid = new QDoubleValidator(this);
  opacityValid->setRange(0.0, 1.0);
212
  opacityValid->setDecimals(6);
213
214
  this->Form->Opacity->setValidator(opacityValid);
  this->Form->opacityScalar->setValidator(new QDoubleValidator(this));
215
216
  this->Form->ScalarOpacityUnitDistance->setValidator(
    new QDoubleValidator(this));
Clinton Stimpson's avatar
   
Clinton Stimpson committed
217
218
219

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

221
  // Connect the color scale widgets.
222
  this->connect(this->Form->ScalarValue, SIGNAL(editingFinished()),
223
      this, SLOT(setScalarFromText()));
224
225
  this->connect(this->Form->Opacity, SIGNAL(editingFinished()),
      this, SLOT(setOpacityFromText()));
226

227
  this->connect(this->Form->ColorSpace, SIGNAL(currentIndexChanged(int)),
228
229
      this, SLOT(setColorSpace(int)));

230
231
232
  this->connect(this->Form->NanColor,SIGNAL(chosenColorChanged(const QColor &)),
                this, SLOT(setNanColor(const QColor &)));

233
234
235
236
237
  this->connect(this->Form->SaveButton, SIGNAL(clicked()),
      this, SLOT(savePreset()));
  this->connect(this->Form->PresetButton, SIGNAL(clicked()),
      this, SLOT(loadPreset()));

238
239
240
  this->connect(this->Form->UseLogScale, SIGNAL(toggled(bool)),
      this, SLOT(setLogScale(bool)));

241
242
243
244
245
246
  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()));
247
248
  this->connect(this->Form->RescaleToDataOverTimeButton, SIGNAL(clicked()),
      this, SLOT(rescaleToDataRangeOverTime()));
249

250
251
252
253
  this->connect(this->Form->UseDiscreteColors, SIGNAL(toggled(bool)),
      this, SLOT(setUseDiscreteColors(bool)));
  this->connect(this->Form->TableSize, SIGNAL(valueChanged(int)),
      this, SLOT(setSizeFromSlider(int)));
254
255
  this->connect(this->Form->TableSizeText, SIGNAL(editingFinished()),
      this, SLOT(setSizeFromText()));
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279

  // 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(
      this->Form->TitleColorButton, "chosenColor", 
      SIGNAL(chosenColorChanged(const QColor&)), false);
  this->Form->TitleFontAdaptor = new pqSignalAdaptorComboBox(
      this->Form->TitleFont);

  this->Form->LabelColorAdaptor = new pqSignalAdaptorColor(
      this->Form->LabelColorButton, "chosenColor", 
      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()));
280
281
282
283

  //Hook up the MakeDefaultButton
  this->connect(this->Form->MakeDefaultButton, SIGNAL(clicked()),
      this, SLOT(makeDefault()));
284
285
286
287
}

pqColorScaleEditor::~pqColorScaleEditor()
{
288
289
  // Save the color map presets.
  this->Form->Presets->saveSettings();
290
  this->saveOptionalUserSettings();
291
292
293
294
  delete this->Form->LabelColorAdaptor;
  delete this->Form->TitleColorAdaptor;
  delete this->Form->LabelFontAdaptor;
  delete this->Form->TitleFontAdaptor;
295
  this->Form->Listener->Delete();
296
297
298
  delete this->Form;
}

299
void pqColorScaleEditor::setRepresentation(pqDataRepresentation *display)
300
301
302
303
304
305
306
{
  if(this->Display == display)
    {
    return;
    }

  this->setLegend(0);
307
  this->Form->ShowColorLegend->setEnabled(false);
308
309
310
311
  if(this->Display)
    {
    this->disconnect(this->Display, 0, this, 0);
    this->disconnect(&this->Form->Links, 0, this->Display, 0);
312
    this->disconnect(&this->Form->ReprLinks, 0, this->Display, 0);
313
    this->Form->ReprLinks.removeAllPropertyLinks();
314
315
316
    if(this->ColorMap)
      {
      this->disconnect(this->ColorMap, 0, this, 0);
317
318
      this->Form->Listener->Disconnect(
          this->ColorMap->getProxy()->GetProperty("RGBPoints"));
319
      }
320

321
    if(this->OpacityFunction)
322
323
      {
      this->Form->Listener->Disconnect(
324
          this->OpacityFunction->getProxy()->GetProperty("Points"));
325
      }
326
327
328
329
    }

  this->Display = display;
  this->ColorMap = 0;
330
  this->OpacityFunction = 0;
331
332
333
334
335
  if(this->Display)
    {
    this->connect(this->Display, SIGNAL(destroyed(QObject *)),
        this, SLOT(cleanupDisplay()));
    this->connect(&this->Form->Links, SIGNAL(qtWidgetChanged()),
336
        this, SLOT(renderViewOptionally()));
337
    this->connect(&this->Form->ReprLinks, SIGNAL(qtWidgetChanged()),
338
        this, SLOT(renderViewOptionally()));
339
340
341
342
343
344
345

    // 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()));
346
347
      this->connect(this->ColorMap, SIGNAL(scalarBarsChanged()),
          this, SLOT(checkForLegend()));
348
349
      this->Form->Listener->Connect(
          this->ColorMap->getProxy()->GetProperty("RGBPoints"),
350
          vtkCommand::ModifiedEvent, this, SLOT(handleColorPointsChanged()));
351
352
353
354
355
      }
    }

  // Disable the gui elements if the color map is null.
  this->Form->ColorTabs->setEnabled(this->ColorMap != 0);
356
357
  this->initColorScale();
  if(this->ColorMap)
358
    {
359
    pqRenderViewBase *renderModule = qobject_cast<pqRenderViewBase *>(
360
        this->Display->getView());
361
    this->Form->ShowColorLegend->setEnabled(renderModule != 0);
362
    this->setLegend(this->ColorMap->getScalarBar(renderModule));
363
364
365
    }
}

366
void pqColorScaleEditor::pushColors()
367
{
368
  if(!this->ColorMap || this->Form->InSetColors)
369
370
371
372
    {
    return;
    }

373
374
  QList<QVariant> rgbPoints;
  this->Form->InSetColors = true;
375

376
  double rgb[3];
377
  double scalar[4];//[x, r, g, b]
378
379
  foreach(vtkColorTransferControlPointsItem* plot,
    this->ColorMapViewer->plots<vtkColorTransferControlPointsItem>())
380
    {
381
382
383
    vtkColorTransferFunction* tf=plot->GetColorTransferFunction();
    int total = tf->GetSize();
    for(int i = 0; i < total; i++)
384
      {
385
386
387
      plot->GetControlPoint(i, scalar);
      tf->GetColor(scalar[0], rgb);
      rgbPoints << scalar[0] << rgb[0] << rgb[1] << rgb[2];
388
      }
389
390
391
392
393
394
    // If there is only one control point in the transfer function originally,
    // we need to add another control point.
    if(total == 1)
      {
      rgbPoints << scalar[0] << rgb[0] << rgb[1] << rgb[2];
      }
395
    }
396
    
397
398
399
400
  vtkSMProxy *lookupTable = this->ColorMap->getProxy();
  pqSMAdaptor::setMultipleElementProperty(
      lookupTable->GetProperty("RGBPoints"), rgbPoints);
  this->Form->InSetColors = false;
401
  lookupTable->UpdateVTKObjects();
402
  this->renderViewOptionally();
403
404
}

405
void pqColorScaleEditor::pushOpacity()
406
{
407
  if(!this->OpacityFunction || this->Form->InSetColors)
408
    {
409
410
411
412
413
414
415
416
417
    return;
    }

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

  double scalar[4];//[x, value, midpoint, sharpness]
  foreach(vtkCompositeControlPointsItem* plot,
    this->OpacityFunctionViewer->plots<vtkCompositeControlPointsItem>())
418
    {
419
420
421
    vtkPiecewiseFunction* pwf=plot->GetOpacityFunction();
    int total = pwf->GetSize();
    for(int i = 0; i < total; i++)
422
      {
423
      pwf->GetNodeValue(i, scalar);
424
      opacityPoints << scalar[0] << scalar[1] << scalar[2] << scalar[3];
425
426
      }
    }
427
428
    
  vtkSMProxy *points = this->OpacityFunction->getProxy();
429
  vtkSMDoubleVectorProperty* smProp = vtkSMDoubleVectorProperty::SafeDownCast(
430
    points->GetProperty("Points"));
431
  pqSMAdaptor::setMultipleElementProperty(smProp, opacityPoints);
432
433
434
435
  points->UpdateVTKObjects();

  this->Form->InSetColors = false;

436
  this->renderViewOptionally();
437
438
}

439
void pqColorScaleEditor::handleColorPointsChanged()
440
441
442
443
444
{
  // If the point change was not generated by setColors, update the
  // points in the editor.
  if(!this->Form->InSetColors)
    {
445
446
447
448
    vtkControlPointsItem* currentItem=this->ColorMapViewer->
      currentControlPointsItem();
    int index = currentItem ?
      currentItem->GetCurrentPoint() : -1;
449
450
451
452
453

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

454
    // Set the current point on the editor.
455
    if(index != -1 && this->ColorMapViewer->currentControlPointsItem())
456
      {
457
      this->ColorMapViewer->currentControlPointsItem()->SetCurrentPoint(index);
458
459
460
461
      }

    // Update the displayed values.
    this->Form->IgnoreEditor = false;
462
    this->updateCurrentColorPoint();
463
464
    }
}
465
void pqColorScaleEditor::handleOpacityPointsChanged()
466
{
467
468
469
  // If the point change was not generated by setColors, update the
  // points in the editor.
  if(!this->Form->InSetColors)
470
    {
471
472
473
474
475
    // Save the current point index to use after the change.
    vtkControlPointsItem* currentItem=this->OpacityFunctionViewer->
      currentControlPointsItem();
    int index = currentItem ?
      currentItem->GetCurrentPoint() : -1;
476

477
478
479
    // Load the new points.
    this->Form->IgnoreEditor = true;
    this->loadOpacityPoints();
480

481
482
483
484
485
486
487
488
489
490
    // 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();
491
492
    }
}
493
void pqColorScaleEditor::setScalarFromText()
494
{
495
496
497
498
499
500
501
  vtkColorTransferFunction* colors = this->currentColorFunction();
  vtkControlPointsItem* currentItem=this->ColorMapViewer->
    currentControlPointsItem();
  int index = currentItem ?
    currentItem->GetCurrentPoint() : -1;

  if(index == -1 ||!colors)
502
503
504
505
506
507
508
509
510
511
    {
    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.
512
    this->updateCurrentColorPoint();
513
514
515
516
517
    return;
    }

  // Make sure the value is greater than the previous point and less
  // than the next point.
518
519
520
  double scalar[4];
  bool endpoint = index == 0;
  if(index > 0)
521
    {
522
523
524
525
    int i=index - 1;
    this->ColorMapViewer->currentControlPointsItem()->GetControlPoint(i, scalar);

    double prev = scalar[0];
526
    if(value <= prev)
527
      {
528
      // value not acceptable.
529
      this->updateCurrentOpacityPoint();
530
      return;
531
532
      }
    }
533

534
535
  endpoint = endpoint || index == colors->GetSize() - 1;
  if(index < colors->GetSize() - 1)
536
    {
537
538
539
    int i=index + 1;
    this->ColorMapViewer->currentControlPointsItem()->GetControlPoint(i, scalar);
    double next = scalar[0];
540
    if(value >= next)
541
      {
542
      // value not acceptable.
543
      this->updateCurrentOpacityPoint();
544
      return;
545
546
      }
    }
547
  currentItem->GetControlPoint(index, scalar);
548
  scalar[0]=value;
549
550
  // Set the new value on the point in the editor.
  this->Form->IgnoreEditor = true;
551
  colors->SetNodeValue(index, scalar);
552
553
554
  this->Form->IgnoreEditor = false;

  // Update the colors on the proxy.
555
  this->pushColors();
556
557
558
559
560
561
562

  // 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);
    }
563

564
 // this->Viewer->Render();
565
}
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
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];
  currentItem->GetControlPoint(index, scalar);
  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.
597
  this->pushOpacity();
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
}

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).
622
623
    opacity = std::min(opacity, 1.0);
    opacity = std::max(opacity, 0.0);
624
625
626
627
628
629
630

    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;
631
      opacityPoints << scalar[0] << scalar[1] << scalar[2] << scalar[3];
632
633
      }
    vtkSMProxy *points = this->OpacityFunction->getProxy();
634
    vtkSMDoubleVectorProperty* smProp = vtkSMDoubleVectorProperty::SafeDownCast(
635
      points->GetProperty("Points"));
636
    pqSMAdaptor::setMultipleElementProperty(smProp, opacityPoints);
637
638
639
640
641
642
    points->UpdateVTKObjects();

    this->Form->InSetColors = false;

    this->renderViewOptionally();
    }
643
644
645
646
}

void pqColorScaleEditor::setOpacityFromText()
{
647
648
649
  if(this->OpacityFunction)
    {
    double range[2]={0,1};
650
    if(this->internalScalarRange(range) && range[0]==range[1])
651
652
653
654
655
656
      {
      this->setSingleOpacityFromText();
      return;
      }
    }

657
658
659
660
661
662
  vtkPiecewiseFunction *opacities = this->currentOpacityFunction();
  vtkControlPointsItem* currentItem=this->OpacityFunctionViewer->
    currentControlPointsItem();
  int index = currentItem ?
    currentItem->GetCurrentPoint() : -1;
  if(index == -1 || !this->OpacityFunction ||!opacities)
663
664
665
666
667
668
    {
    return;
    }

  // Get the opacity from the line edit.
  bool ok = true;
669
  double opacity = this->Form->Opacity->text().toDouble(&ok);
670
671
672
  if(!ok)
    {
    // Reset to the previous opacity.
673
    this->updateCurrentOpacityPoint();
674
675
676
677
678
679
680
681
682
683
684
685
686
    return;
    }

  // Make sure the opacity is valid (0.0 - 1.0).
  if(opacity < 0.0)
    {
    opacity = 0.0;
    }
  else if(opacity > 1.0)
    {
    opacity = 1.0;
    }

687
  // Set the new opacity on the point in the editor.
688
  this->Form->IgnoreEditor = true;
689
690
691
692
693
694

  double scalar[4];
  this->OpacityFunctionViewer->currentControlPointsItem()->GetControlPoint(
    index, scalar);
  scalar[1]=opacity;
  opacities->SetNodeValue(index, scalar);
695
696
697
  this->Form->IgnoreEditor = false;

  // Update the colors on the proxy.
698
  this->pushOpacity();
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
}
void pqColorScaleEditor::internalSetColorSpace(int index,
  vtkColorTransferFunction* colors)
{
  if(!colors)
    {
    return;
    }
  switch (index)
    {
    case 0:
      colors->SetColorSpaceToRGB();
      break;
    case 1:
      colors->SetColorSpaceToHSV();
      colors->HSVWrapOff();
      break;
    case 2:
      colors->SetColorSpaceToHSV();
      colors->HSVWrapOn();
      break;
    case 3:
      colors->SetColorSpaceToLab();
      break;
    case 4:
      colors->SetColorSpaceToDiverging();
      break;
    }
727
}
728
729
void pqColorScaleEditor::setColorSpace(int index)
{
730
731
  vtkColorTransferFunction* colors =this->currentColorFunction();
  if(this->ColorMap && colors)
732
    {
733
    this->internalSetColorSpace(index, colors);
734
    this->renderTransferFunctionViews();
735

736
737
    // Set the property on the lookup table.
    int wrap = index == 2 ? 1 : 0;
738
    if(index >= 2)
739
      {
740
      index--;
741
742
      }

743
    this->Form->InSetColors = true;
744
745
746
747
748
    vtkSMProxy *lookupTable = this->ColorMap->getProxy();
    pqSMAdaptor::setElementProperty(
        lookupTable->GetProperty("ColorSpace"), index);
    pqSMAdaptor::setElementProperty(
        lookupTable->GetProperty("HSVWrap"), wrap);
749
    this->Form->InSetColors = false;
750
    lookupTable->UpdateVTKObjects();
751
    this->renderViewOptionally();
752
753
754
    }
}

755
756
757
758
759
760
761
762
763
764
765
766
void pqColorScaleEditor::setNanColor(const QColor &color)
{
  if (this->ColorMap)
    {
    this->Form->InSetColors = true;
    vtkSMProxy *lookupTable = this->ColorMap->getProxy();
    QList<QVariant> values;
    values << color.redF() << color.greenF() << color.blueF();
    pqSMAdaptor::setMultipleElementProperty(
                                  lookupTable->GetProperty("NanColor"), values);
    this->Form->InSetColors = false;
    lookupTable->UpdateVTKObjects();
767
768
769
770
771
772
    this->renderViewOptionally();
    this->renderTransferFunctionViews();
    }
}
void pqColorScaleEditor::setScalarColor(const QColor &color)
{
773
  if (!this->Form->InSetColors && this->ColorMap)
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
    {
    this->Form->InSetColors = true;
    vtkColorTransferFunction* clientTF=vtkColorTransferFunction::SafeDownCast(
      this->ColorMap->getProxy()->GetClientSideObject());
    if(!clientTF)
      {
      return;
      }
    int total = clientTF->GetSize();
    double nodeVal[6];
    QList<QVariant> rgbPoints;
    for(int i = 0; i < total; i++)
      {
      clientTF->GetNodeValue(i, nodeVal);
      nodeVal[1]=color.redF();
      nodeVal[2]=color.greenF();
      nodeVal[3]=color.blueF();
      clientTF->SetNodeValue(i, nodeVal);
      rgbPoints << nodeVal[0] << nodeVal[1] << nodeVal[2] <<nodeVal[3];
      }
794
795
796
797
798
799
800
801
    //// SHOULD NEVER GET HERE
    // If there is only one control point in the transfer function originally,
    // we need to add another control point.
    if(total == 1)
      {
      rgbPoints << nodeVal[0] << nodeVal[1] << nodeVal[2] <<nodeVal[3];
      }

802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
    vtkSMProxy *lookupTable = this->ColorMap->getProxy();
    pqSMAdaptor::setMultipleElementProperty(
      lookupTable->GetProperty("RGBPoints"), rgbPoints);
    lookupTable->UpdateVTKObjects();
    this->Form->InSetColors = false;
    this->renderViewOptionally();
    }
}

void pqColorScaleEditor::renderTransferFunctionViews()
{
  this->ColorMapViewer->renderView();
  if(this->OpacityFunction)
    {
    this->OpacityFunctionViewer->renderView();
817
818
819
    }
}

820
821
void pqColorScaleEditor::savePreset()
{
822
  // Get the color preset model from the manager.
823
  pqColorPresetModel *model = this->Form->Presets->getModel();
824
825
826

  // Save the current color scale settings as a preset.
  double rgb[3];
827
  double scalar = 0.0;
828
829
  pqColorMapModel colorMap;
  colorMap.setColorSpaceFromInt(this->Form->ColorSpace->currentIndex());
830
831
832
833
834
835
  vtkColorTransferFunction* tf = this->currentColorFunction();
  vtkControlPointsItem* plot=this->ColorMapViewer->currentControlPointsItem();
  int total = tf->GetSize();
  double scalars[4];//[x, y, midpoint, sharpness]
  vtkPiecewiseFunction* pwf=this->currentOpacityFunction();

836
837
  for(int i = 0; i < total; i++)
    {
838
839
840
841
    plot->GetControlPoint(i, scalars);
    scalar = scalars[0];
    tf->GetColor(scalar, rgb);
    if(this->OpacityFunction && pwf)
842
      {
843
844
845
846
847
848
849
850
      double opacity = pwf->GetValue(scalar);
      colorMap.addPoint(pqChartValue(scalar),
          QColor::fromRgbF(rgb[0], rgb[1], rgb[2]), pqChartValue(opacity));
      }
    else
      {
      colorMap.addPoint(pqChartValue(scalar),
          QColor::fromRgbF(rgb[0], rgb[1], rgb[2]));
851
      }
852
    }
853
  colorMap.setNanColor(this->Form->NanColor->chosenColor());
854
855
856
857

  model->addColorMap(colorMap, "New Color Preset");

  // Select the newly added item (the last in the list).
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
  QItemSelectionModel *selection = this->Form->Presets->getSelectionModel();
  selection->setCurrentIndex(model->index(model->rowCount() - 1, 0),
      QItemSelectionModel::ClearAndSelect);

  // Set up the dialog and open it.
  this->Form->Presets->setUsingCloseButton(true);
  this->Form->Presets->exec();
}

void pqColorScaleEditor::loadPreset()
{
  this->Form->Presets->setUsingCloseButton(false);
  if(this->Form->Presets->exec() == QDialog::Accepted)
    {
    // Get the color map from the selection.
    QItemSelectionModel *selection = this->Form->Presets->getSelectionModel();
    QModelIndex index = selection->currentIndex();
    const pqColorMapModel *colorMap =
        this->Form->Presets->getModel()->getColorMap(index.row());
    if(colorMap)
      {
879
880
881
882
      this->Form->IgnoreEditor = true;
      int colorSpace = colorMap->getColorSpaceAsInt();

      QColor color;
883
      pqChartValue value, opacity;
884
885
886
887
888
889
890
891
      pqColorMapModel temp(*colorMap);
      if(this->Form->UseAutoRescale->isChecked() ||
          colorMap->isRangeNormalized())
        {
        QPair<double, double> range = this->ColorMap->getScalarRange();
        temp.setValueRange(range.first, range.second);
        }

892
893
      vtkPiecewiseFunction *opacities = NULL;
      vtkColorTransferFunction* colors = this->currentColorFunction();
894
      this->ColorMapViewer->currentControlPointsItem()->SetCurrentPoint(-1);
895
      colors->RemoveAllPoints();
896
      if(this->OpacityFunction)
897
        {
898
        opacities = this->currentOpacityFunction();
899
900
        this->OpacityFunctionViewer->currentControlPointsItem()->
          SetCurrentPoint(-1);
901
902
903
        opacities->RemoveAllPoints();
        }

904
905
906
907
      // Update the displayed range.
      temp.getValueRange(value, opacity);
      this->updateScalarRange(value.getDoubleValue(), opacity.getDoubleValue());

908
909
910
911
912
913
      for(int i = 0; i < colorMap->getNumberOfPoints(); i++)
        {
        temp.getPointColor(i, color);
        temp.getPointValue(i, value);
        colors->AddRGBPoint(value.getDoubleValue(), color.redF(),
            color.greenF(), color.blueF());
914
        if(this->OpacityFunction)
915
916
917
918
919
          {
          temp.getPointOpacity(i, opacity);
          opacities->AddPoint(value.getDoubleValue(),
              opacity.getDoubleValue());
          }
920
921
922
        }

      // Update the color space.
923
      this->internalSetColorSpace(colorSpace, colors);
924

925
      // Update the color space chooser.
926
      this->Form->ColorSpace->blockSignals(true);
927
      this->Form->ColorSpace->setCurrentIndex(colorSpace);
928
      this->Form->ColorSpace->blockSignals(false);
929
930
931
932
      if(this->ColorMap)
        {
        // Set the property on the lookup table.
        int wrap = colorSpace == 2 ? 1 : 0;
933
        if(colorSpace >= 2)
934
          {
935
          colorSpace--;
936
          }
937

938
        this->Form->InSetColors = true;
939
940
941
942
943
        vtkSMProxy *lookupTable = this->ColorMap->getProxy();
        pqSMAdaptor::setElementProperty(
            lookupTable->GetProperty("ColorSpace"), colorSpace);
        pqSMAdaptor::setElementProperty(
            lookupTable->GetProperty("HSVWrap"), wrap);
944
        this->Form->InSetColors = false;
945
946
        }

947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
      // Update the NaN color.
      QColor nanColor;
      colorMap->getNanColor(nanColor);
      this->Form->NanColor->blockSignals(true);
      this->Form->NanColor->setChosenColor(nanColor);
      this->Form->NanColor->blockSignals(false);

      if (this->ColorMap)
        {
        // Set the property on the lookup table.
        this->Form->InSetColors = true;
        vtkSMProxy *lookupTable = this->ColorMap->getProxy();
        QList<QVariant> values;
        values << nanColor.redF() << nanColor.greenF() << nanColor.blueF();
        pqSMAdaptor::setMultipleElementProperty(
                                  lookupTable->GetProperty("NanColor"), values);
        this->Form->InSetColors = false;
        }

966
      // Update the actual color map.
967
      this->Form->IgnoreEditor = false;
968
      this->pushColors();
969

970
      this->updatePointValues();
971
972
973
974
      }
    }
}

975
976
void pqColorScaleEditor::setLogScale(bool on)
{
977
978
  this->renderTransferFunctionViews();

979
980
981
982
  vtkSMProxy *lookupTable = this->ColorMap->getProxy();
  pqSMAdaptor::setElementProperty(
      lookupTable->GetProperty("UseLogScale"), on ? 1 : 0);

983
  // Set the log scale flag on the editor.
984
985
  this->currentColorFunction()->SetScale(
    on ? VTK_CTF_LOG10 : VTK_CTF_LINEAR);
986

987
  lookupTable->UpdateVTKObjects();
988
  this->renderViewOptionally();
989
990
}

991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
void pqColorScaleEditor::setAutoRescale(bool on)
{
  this->enableRescaleControls(!on);
  this->ColorMap->setScalarRangeLock(!on);
  this->enablePointControls();
  if(on)
    {
    // Reset the range to the current.
    this->rescaleToDataRange();
    }
}

void pqColorScaleEditor::rescaleToNewRange()
{
  // Launch the rescale range dialog to get the new range.
  pqRescaleRange rescaleDialog(this);
  QPair<double, double> range = this->ColorMap->getScalarRange();
  rescaleDialog.setRange(range.first, range.second);
  if(rescaleDialog.exec() == QDialog::Accepted)
    {
1011
1012
    this->Form->InSetColors = true;
    this->unsetCurrentPoints();
1013
1014
    this->setScalarRange(rescaleDialog.getMinimum(),
        rescaleDialog.getMaximum());
1015
1016
1017
    this->Form->InSetColors = false;
    range = this->ColorMap->getScalarRange();
    this->updateScalarRange(range.first, range.second);
1018
    this->updateCurrentColorPoint();
1019
1020
1021
    }
}

1022
1023
1024
//-----------------------------------------------------------------------------
void pqColorScaleEditor::rescaleToDataRangeOverTime()
{
1025
  this->Form->InSetColors = true;
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
  if (QMessageBox::warning(
      pqCoreUtilities::mainWidget(),
      "Potentially slow operation",
      "This can potentially take a long time to complete. \n"
      "Are you sure you want to continue?",
      QMessageBox::Yes |QMessageBox::No, QMessageBox::No) ==
    QMessageBox::Yes)
    {
    pqPipelineRepresentation *pipeline =
      qobject_cast<pqPipelineRepresentation *>(this->Display);
    if(pipeline)
      {
1038
      this->unsetCurrentPoints();
1039
1040
      pipeline->resetLookupTableScalarRangeOverTime();
      pipeline->renderViewEventually();
1041
1042
1043
1044
      if(this->ColorMap)
        {
        QPair<double, double> range = this->ColorMap->getScalarRange();
        this->updateScalarRange(range.first, range.second);
1045
        this->updateCurrentColorPoint();
1046
        }
1047
1048
      }
    }
1049
  this->Form->InSetColors = false;
1050
1051
1052
1053
  // TODO: Handle all the other representation types!
}

//-----------------------------------------------------------------------------
1054
1055
void pqColorScaleEditor::rescaleToDataRange()
{
1056
1057
  this->Form->InSetColors = true;
  this->unsetCurrentPoints();
1058
1059
1060
1061
1062
1063
  pqPipelineRepresentation *pipeline =
      qobject_cast<pqPipelineRepresentation *>(this->Display);
  if(pipeline)
    {
    pipeline->resetLookupTableScalarRange();
    pipeline->renderViewEventually();
1064
1065
1066
1067
    if(this->ColorMap)
      {
      QPair<double, double> range = this->ColorMap->getScalarRange();
      this->updateScalarRange(range.first, range.second);
1068
      this->updateCurrentColorPoint();
1069
      }
1070
    }
1071
  this->Form->InSetColors = false;
1072
1073
}

1074
//-----------------------------------------------------------------------------
1075
1076
1077
1078
void pqColorScaleEditor::setUseDiscreteColors(bool on)
{
  // Update the color scale widget and gui controls.
  this->enableResolutionControls(on);
1079

1080
1081
1082
1083
1084
1085
1086
  if(this->ColorMap)
    {
    // Set the property on the lookup table.
    vtkSMProxy *lookupTable = this->ColorMap->getProxy();
    pqSMAdaptor::setElementProperty(
        lookupTable->GetProperty("Discretize"), (on ? 1 : 0));
    lookupTable->UpdateVTKObjects();
1087
    this->renderViewOptionally();
1088
1089
1090
    }
}