pqAnimationTimeWidget.cxx 13.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
/*=========================================================================

   Program: ParaView
   Module:  pqAnimationTimeWidget.cxx

   Copyright (c) 2005,2006 Sandia Corporation, Kitware Inc.
   All rights reserved.

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

   See License_v1.2.txt for the full ParaView license.
   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.

========================================================================*/
#include "pqAnimationTimeWidget.h"
#include "ui_pqAnimationTimeWidget.h"

#include "pqPropertyLinks.h"
36
#include "pqPropertyLinksConnection.h"
37
#include "pqTimer.h"
38 39 40 41 42 43 44 45 46 47 48 49 50 51
#include "vtkSMPropertyHelper.h"
#include "vtkSMTimeKeeperProxy.h"
#include "vtkWeakPointer.h"

#include <QDoubleValidator>

class pqAnimationTimeWidget::pqInternals
{
public:
  Ui::AnimationTimeWidget Ui;
  vtkWeakPointer<vtkSMProxy> AnimationScene;
  void* AnimationSceneVoidPtr;
  pqPropertyLinks Links;
  int CachedTimestepCount;
52
  int Precision;
53
  QChar TimeNotation;
54

Kitware Robot's avatar
Kitware Robot committed
55 56 57
  pqInternals(pqAnimationTimeWidget* self)
    : AnimationSceneVoidPtr(NULL)
    , CachedTimestepCount(-1)
58 59
    , Precision(6)
    , TimeNotation('g')
Kitware Robot's avatar
Kitware Robot committed
60
  {
61 62
    this->Ui.setupUi(self);
    this->Ui.timeValue->setValidator(new QDoubleValidator(self));
Kitware Robot's avatar
Kitware Robot committed
63
  }
64 65 66 67
};

namespace
{
Kitware Robot's avatar
Kitware Robot committed
68 69 70
/// Used to link the number of elements in a sm-property to the qt widget.
class pqAnimationTimeWidgetLinks : public pqPropertyLinksConnection
{
71
  typedef pqPropertyLinksConnection Superclass;
Kitware Robot's avatar
Kitware Robot committed
72

73
public:
Kitware Robot's avatar
Kitware Robot committed
74 75 76 77 78 79 80
  pqAnimationTimeWidgetLinks(QObject* qobject, const char* qproperty, const char* qsignal,
    vtkSMProxy* smproxy, vtkSMProperty* smproperty, int smindex, bool use_unchecked_modified_event,
    QObject* parentObject = 0)
    : Superclass(qobject, qproperty, qsignal, smproxy, smproperty, smindex,
        use_unchecked_modified_event, parentObject)
  {
  }
Ben Boeckel's avatar
Ben Boeckel committed
81
  ~pqAnimationTimeWidgetLinks() override {}
82 83

protected:
Ben Boeckel's avatar
Ben Boeckel committed
84
  QVariant currentServerManagerValue(bool use_unchecked) const override
Kitware Robot's avatar
Kitware Robot committed
85
  {
86
    Q_ASSERT(use_unchecked == false);
87
    Q_UNUSED(use_unchecked);
88 89
    unsigned int count = vtkSMPropertyHelper(this->propertySM()).GetNumberOfElements();
    return QVariant(static_cast<int>(count));
Kitware Robot's avatar
Kitware Robot committed
90
  }
91 92

private:
93
  Q_DISABLE_COPY(pqAnimationTimeWidgetLinks)
Kitware Robot's avatar
Kitware Robot committed
94
};
95 96 97 98
}

//-----------------------------------------------------------------------------
pqAnimationTimeWidget::pqAnimationTimeWidget(QWidget* parentObject)
Kitware Robot's avatar
Kitware Robot committed
99 100
  : Superclass(parentObject)
  , Internals(new pqAnimationTimeWidget::pqInternals(this))
101 102 103
{
  this->setEnabled(false);

Kitware Robot's avatar
Kitware Robot committed
104
  Ui::AnimationTimeWidget& ui = this->Internals->Ui;
105
  ui.timeValueComboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents);
106
  this->connect(ui.timeValue, SIGNAL(textChangedAndEditingFinished()), SLOT(timeLineEditChanged()));
Kitware Robot's avatar
Kitware Robot committed
107
  this->connect(
108 109 110
    ui.timeValueComboBox, SIGNAL(currentTextChanged(QString)), SLOT(timeComboBoxChanged()));
  ui.timeValueComboBox->setVisible(false);
  this->connect(ui.radioButtonValue, SIGNAL(toggled(bool)), SLOT(timeRadioButtonToggled()));
111 112 113 114 115 116 117 118 119

  // the idiosyncrasies of QSpinBox make it so that we have to delay when we
  // respond to the "go-to-next" event (see paraview/paraview#18204).
  auto timer = new pqTimer(this);
  timer->setInterval(100);
  timer->setSingleShot(true);
  this->connect(timer, SIGNAL(timeout()), SLOT(timeSpinBoxChanged()));
  QObject::connect(
    ui.timestepValue, SIGNAL(valueChangedAndEditingFinished()), timer, SLOT(start()));
120 121 122 123 124 125 126 127
}

//-----------------------------------------------------------------------------
pqAnimationTimeWidget::~pqAnimationTimeWidget()
{
}

//-----------------------------------------------------------------------------
Utkarsh Ayachit's avatar
Utkarsh Ayachit committed
128
void pqAnimationTimeWidget::setAnimationScene(vtkSMProxy* ascene)
129 130
{
  pqInternals& internals = *this->Internals;
Utkarsh Ayachit's avatar
Utkarsh Ayachit committed
131
  if (internals.AnimationSceneVoidPtr == ascene)
Kitware Robot's avatar
Kitware Robot committed
132
  {
133
    return;
Kitware Robot's avatar
Kitware Robot committed
134
  }
135 136

  internals.Links.clear();
Utkarsh Ayachit's avatar
Utkarsh Ayachit committed
137 138 139 140
  internals.AnimationScene = ascene;
  internals.AnimationSceneVoidPtr = ascene;
  this->setEnabled(ascene != NULL);
  if (!ascene)
Kitware Robot's avatar
Kitware Robot committed
141
  {
142
    return;
Kitware Robot's avatar
Kitware Robot committed
143
  }
144 145

  internals.Links.addPropertyLink(
Kitware Robot's avatar
Kitware Robot committed
146 147 148
    this, "timeValue", SIGNAL(timeValueChanged()), ascene, ascene->GetProperty("AnimationTime"));
  internals.Links.addPropertyLink(
    this, "playMode", SIGNAL(playModeChanged()), ascene, ascene->GetProperty("PlayMode"));
149 150 151

  // In a ParaView application, it's safe to assume that the timekeeper an
  // animation scene is using doesn't change in the life span of the scene.
Utkarsh Ayachit's avatar
Utkarsh Ayachit committed
152 153
  vtkSMProxy* atimekeeper = vtkSMPropertyHelper(ascene, "TimeKeeper").GetAsProxy();
  Q_ASSERT(atimekeeper != NULL);
154

Kitware Robot's avatar
Kitware Robot committed
155 156
  internals.Links.addPropertyLink<pqAnimationTimeWidgetLinks>(this, "timeStepCount",
    SIGNAL(dummySignal()), atimekeeper, atimekeeper->GetProperty("TimestepValues"));
157
  internals.Links.addPropertyLink(
Kitware Robot's avatar
Kitware Robot committed
158
    this, "timeLabel", SIGNAL(dummySignal()), atimekeeper, atimekeeper->GetProperty("TimeLabel"));
159 160 161 162 163 164 165 166 167 168 169 170 171
}

//-----------------------------------------------------------------------------
vtkSMProxy* pqAnimationTimeWidget::animationScene() const
{
  pqInternals& internals = *this->Internals;
  return internals.AnimationScene;
}

//-----------------------------------------------------------------------------
vtkSMProxy* pqAnimationTimeWidget::timeKeeper() const
{
  pqInternals& internals = *this->Internals;
Kitware Robot's avatar
Kitware Robot committed
172 173 174
  return internals.AnimationScene
    ? vtkSMPropertyHelper(internals.AnimationScene, "TimeKeeper").GetAsProxy()
    : NULL;
175 176 177 178 179
}

//-----------------------------------------------------------------------------
void pqAnimationTimeWidget::setTimeValue(double time)
{
Kitware Robot's avatar
Kitware Robot committed
180
  Ui::AnimationTimeWidget& ui = this->Internals->Ui;
181
  ui.timeValue->setProperty("PQ_DOUBLE_VALUE", QVariant(time));
182 183 184 185 186 187 188 189 190 191 192 193 194
  QString textValue =
    QString::number(time, this->Internals->TimeNotation.toLatin1(), this->Internals->Precision);
  ui.timeValue->setTextAndResetCursor(textValue);

  for (int index = 0; index < ui.timeValueComboBox->count(); index++)
  {
    if (ui.timeValueComboBox->itemData(index).toDouble() == time)
    {
      ui.timeValueComboBox->setCurrentIndex(index);
      break;
    }
  }

195
  bool prev = ui.timestepValue->blockSignals(true);
196 197
  int index = vtkSMTimeKeeperProxy::GetLowerBoundTimeStepIndex(this->timeKeeper(), time);
  ui.timestepValue->setValue(index);
198 199 200 201 202 203
  ui.timestepValue->blockSignals(prev);
}

//-----------------------------------------------------------------------------
double pqAnimationTimeWidget::timeValue() const
{
Kitware Robot's avatar
Kitware Robot committed
204
  Ui::AnimationTimeWidget& ui = this->Internals->Ui;
205 206 207 208 209 210 211 212 213
  auto doubleValue = ui.timeValue->property("PQ_DOUBLE_VALUE");
  return doubleValue.isValid() ? doubleValue.toDouble() : ui.timeValue->text().toDouble();
}

//-----------------------------------------------------------------------------
void pqAnimationTimeWidget::timeLineEditChanged()
{
  auto& ui = this->Internals->Ui;
  const auto currentValue = ui.timeValue->text().toDouble();
214 215 216 217 218 219 220 221 222 223
  this->setTimeValue(currentValue);
  emit this->timeValueChanged();
}

//-----------------------------------------------------------------------------
void pqAnimationTimeWidget::timeComboBoxChanged()
{
  auto& ui = this->Internals->Ui;
  const auto currentValue = ui.timeValueComboBox->currentData().toDouble();
  this->setTimeValue(currentValue);
224
  emit this->timeValueChanged();
225 226
}

227 228 229 230
//-----------------------------------------------------------------------------
void pqAnimationTimeWidget::setTimePrecision(int val)
{
  this->Internals->Precision = val;
231 232
  this->setTimeValue(this->timeValue());
  this->repopulateTimeComboBox();
233 234 235 236 237 238 239 240
}

//-----------------------------------------------------------------------------
int pqAnimationTimeWidget::timePrecision() const
{
  return this->Internals->Precision;
}

241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
//-----------------------------------------------------------------------------
void pqAnimationTimeWidget::setTimeNotation(const QChar& notation)
{
  QString possibilities = QString("eEfgG");
  if (possibilities.contains(notation) && this->Internals->TimeNotation != notation)
  {
    this->Internals->TimeNotation = notation;
    this->setTimeValue(this->timeValue());
    this->repopulateTimeComboBox();
  }
}

//-----------------------------------------------------------------------------
QChar pqAnimationTimeWidget::timeNotation() const
{
  return this->Internals->TimeNotation;
}

259 260 261 262 263 264
//-----------------------------------------------------------------------------
void pqAnimationTimeWidget::setTimeStepCount(int value)
{
  pqInternals& internals = *this->Internals;
  internals.CachedTimestepCount = value;

Kitware Robot's avatar
Kitware Robot committed
265 266 267 268
  Ui::AnimationTimeWidget& ui = this->Internals->Ui;
  ui.timestepValue->setMaximum(value > 0 ? value - 1 : 0);
  ui.timestepCountLabel->setText(QString("(max is %1)").arg(value > 0 ? value - 1 : 0));
  ui.timestepCountLabel->setVisible((value > 0) && (this->playMode() == "Snap To TimeSteps"));
269 270 271 272 273 274

  bool prev = ui.timestepValue->blockSignals(true);
  ui.timestepValue->setValue(
    vtkSMTimeKeeperProxy::GetLowerBoundTimeStepIndex(this->timeKeeper(), this->timeValue()));
  ui.timestepValue->blockSignals(prev);

275
  this->repopulateTimeComboBox();
276 277 278 279 280 281 282 283 284 285 286 287 288
  this->updateTimestepCountLabelVisibility();
}

//-----------------------------------------------------------------------------
int pqAnimationTimeWidget::timeStepCount() const
{
  pqInternals& internals = *this->Internals;
  return internals.CachedTimestepCount;
}

//-----------------------------------------------------------------------------
void pqAnimationTimeWidget::setPlayMode(const QString& value)
{
Kitware Robot's avatar
Kitware Robot committed
289
  Ui::AnimationTimeWidget& ui = this->Internals->Ui;
290
  if (value == "Sequence" || value == "Real Time")
Kitware Robot's avatar
Kitware Robot committed
291
  {
292
    ui.radioButtonValue->setChecked(true);
293 294
    ui.timeValueComboBox->setVisible(false);
    ui.timeValue->setVisible(true);
Kitware Robot's avatar
Kitware Robot committed
295
  }
296
  else if (value == "Snap To TimeSteps")
Kitware Robot's avatar
Kitware Robot committed
297
  {
298
    ui.radioButtonStep->setChecked(true);
299 300
    ui.timeValueComboBox->setVisible(true);
    ui.timeValue->setVisible(false);
Kitware Robot's avatar
Kitware Robot committed
301
  }
302 303 304 305 306 307
  this->updateTimestepCountLabelVisibility();
}

//-----------------------------------------------------------------------------
QString pqAnimationTimeWidget::playMode() const
{
Kitware Robot's avatar
Kitware Robot committed
308 309
  Ui::AnimationTimeWidget& ui = this->Internals->Ui;
  return ui.radioButtonValue->isChecked() ? "Sequence" : "Snap To TimeSteps";
310 311 312 313 314
}

//-----------------------------------------------------------------------------
void pqAnimationTimeWidget::updateTimestepCountLabelVisibility()
{
Kitware Robot's avatar
Kitware Robot committed
315
  Ui::AnimationTimeWidget& ui = this->Internals->Ui;
316 317 318 319 320
  ui.timestepCountLabel->setVisible(
    (this->timeStepCount() > 0) && (this->playMode() == "Snap To TimeSteps"));
}

//-----------------------------------------------------------------------------
321
void pqAnimationTimeWidget::timeSpinBoxChanged()
322
{
Kitware Robot's avatar
Kitware Robot committed
323
  Ui::AnimationTimeWidget& ui = this->Internals->Ui;
324 325
  int index = ui.timestepValue->value();
  vtkSMPropertyHelper helper(this->timeKeeper(), "TimestepValues");
Kitware Robot's avatar
Kitware Robot committed
326 327
  if (index >= 0 && static_cast<unsigned int>(index) < helper.GetNumberOfElements())
  {
328 329
    this->setTimeValue(helper.GetAsDouble(index));
    emit this->timeValueChanged();
Kitware Robot's avatar
Kitware Robot committed
330
  }
331
}
332 333 334
//-----------------------------------------------------------------------------
void pqAnimationTimeWidget::setTimeLabel(const QString& val)
{
Kitware Robot's avatar
Kitware Robot committed
335
  Ui::AnimationTimeWidget& ui = this->Internals->Ui;
336 337 338 339 340 341
  ui.timeLabel->setText(val + ":");
}

//-----------------------------------------------------------------------------
QString pqAnimationTimeWidget::timeLabel() const
{
Kitware Robot's avatar
Kitware Robot committed
342
  Ui::AnimationTimeWidget& ui = this->Internals->Ui;
343
  QString txt = ui.timeLabel->text();
Kitware Robot's avatar
Kitware Robot committed
344
  return txt.left(txt.length() - 1);
345
}
346 347 348 349

//-----------------------------------------------------------------------------
void pqAnimationTimeWidget::setPlayModeReadOnly(bool val)
{
Kitware Robot's avatar
Kitware Robot committed
350
  Ui::AnimationTimeWidget& ui = this->Internals->Ui;
351 352 353 354 355 356 357
  ui.radioButtonValue->setVisible(!val);
  ui.radioButtonStep->setVisible(!val);
}

//-----------------------------------------------------------------------------
bool pqAnimationTimeWidget::playModeReadOnly() const
{
Kitware Robot's avatar
Kitware Robot committed
358
  Ui::AnimationTimeWidget& ui = this->Internals->Ui;
359 360
  return !ui.radioButtonStep->isVisible();
}
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392

//-----------------------------------------------------------------------------
void pqAnimationTimeWidget::repopulateTimeComboBox()
{
  if (this->timeKeeper() == nullptr)
  {
    return;
  }

  double currentTimeValue = this->timeValue();
  Ui::AnimationTimeWidget& ui = this->Internals->Ui;

  vtkSMPropertyHelper helper(this->timeKeeper(), "TimestepValues");
  bool prev = ui.timeValueComboBox->blockSignals(true);
  ui.timeValueComboBox->clear();
  for (unsigned int index = 0; index < helper.GetNumberOfElements(); index++)
  {
    QString textValue = QString::number(helper.GetAsDouble(index),
      this->Internals->TimeNotation.toLatin1(), this->Internals->Precision);
    ui.timeValueComboBox->addItem(textValue, helper.GetAsDouble(index));
  }
  ui.timeValueComboBox->blockSignals(prev);

  this->setTimeValue(currentTimeValue);
}

//-----------------------------------------------------------------------------
void pqAnimationTimeWidget::timeRadioButtonToggled()
{
  this->setPlayMode(this->playMode());
  emit this->playModeChanged();
}