void DlgSettingsExportFormat::updatePreview()
{
  // Save the scroll position for continuity before and after the preview update
  int scrollPosition = m_editPreview->verticalScrollBar()->value();

  QString exportedText;
  QTextStream str (&exportedText);

  if (mainWindow().transformation().transformIsDefined()) {

    // Transformaiton is defined so we can create a preview
    if (m_tabWidget->currentIndex() == TAB_WIDGET_INDEX_FUNCTIONS) {

      ExportFileFunctions exportStrategy;
      exportStrategy.exportToFile (*m_modelExportAfter,
                                   cmdMediator().document(),
                                   mainWindow().modelMainWindow(),
                                   mainWindow().transformation(),
                                   str);

    } else {

      ExportFileRelations exportStrategy;
      exportStrategy.exportToFile (*m_modelExportAfter,
                                   cmdMediator().document(),
                                   mainWindow().modelMainWindow(),
                                   mainWindow().transformation(),
                                   str);

    }
  } else {

    str << "Preview is unavailable until axis points are defined.";
  }

  m_editPreview->setText (exportedText);

  // Restore scroll position
  m_editPreview->verticalScrollBar()->setValue (scrollPosition);
}
void DlgSettingsExportFormat::updateControlsUponLoad ()
{
  CurveStyles curveStyles = cmdMediator().document().modelCurveStyles();

  m_haveFunction = false;
  m_haveRelation = false;

  QStringList curveNames = curveStyles.curveNames();

  QStringList::const_iterator itr;
  for (itr = curveNames.begin(); itr != curveNames.end (); itr++) {
    QString curveName = *itr;
    CurveStyle curveStyle = curveStyles.curveStyle (curveName);
    CurveConnectAs curveConnectAs = curveStyle.lineStyle().curveConnectAs();
    if (curveConnectAs == CONNECT_AS_FUNCTION_SMOOTH || curveConnectAs == CONNECT_AS_FUNCTION_STRAIGHT) {
      m_haveFunction = true;
    } else if (curveConnectAs == CONNECT_AS_RELATION_SMOOTH || curveConnectAs == CONNECT_AS_RELATION_STRAIGHT) {
      m_haveRelation = true;
    }
  }

  // Enable function-specific widgets if appropriate
  m_btnFunctionsPointsAllCurves->setEnabled (m_haveFunction);
  m_btnFunctionsPointsFirstCurve->setEnabled (m_haveFunction);
  m_btnFunctionsPointsEvenlySpaced->setEnabled (m_haveFunction);
  m_editFunctionsPointsEvenlySpacing->setEnabled (m_haveFunction);
  m_cmbFunctionsPointsEvenlySpacingUnits->setEnabled (m_haveFunction);
  m_btnFunctionsPointsRaw->setEnabled (m_haveFunction);

  // Enable relation-specific widgets if appropriate
  m_btnRelationsPointsEvenlySpaced->setEnabled (m_haveRelation);
  m_editRelationsPointsEvenlySpacing->setEnabled (m_haveRelation);
  m_cmbRelationsPointsEvenlySpacingUnits->setEnabled (m_haveRelation);
  m_btnRelationsPointsRaw->setEnabled (m_haveRelation);

  // Do not start with a tab that does not apply to the current set of functions/relations
  if (!m_haveRelation) {
    m_tabWidget->setCurrentIndex (TAB_WIDGET_INDEX_FUNCTIONS);
  } else if (!m_haveFunction) {
    m_tabWidget->setCurrentIndex (TAB_WIDGET_INDEX_RELATIONS);
  }
}
void DlgSettingsExportFormat::initializeIntervalConstraints ()
{
  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsExportFormat::initializeIntervalConstraints";

  const int MAX_POINTS_ACROSS_RANGE = 1000;

  // Get min and max of graph and screen coordinates
  CallbackBoundingRects ftor (mainWindow().transformation());

  Functor2wRet<const QString &, const Point &, CallbackSearchReturn> ftorWithCallback = functor_ret (ftor,
                                                                                                     &CallbackBoundingRects::callback);
  cmdMediator().iterateThroughCurvesPointsGraphs (ftorWithCallback);

  // If there are no points, then interval will be zero. That special case must be handled downstream to prevent infinite loops
  bool isEmpty;
  double maxSizeGraph = qMax (ftor.boundingRectGraph(isEmpty).width(),
                              ftor.boundingRectGraph(isEmpty).height());
  double maxSizeScreen = qMax (ftor.boundingRectScreen(isEmpty).width(),
                               ftor.boundingRectScreen(isEmpty).height());
  m_minIntervalGraph = maxSizeGraph / MAX_POINTS_ACROSS_RANGE;
  m_minIntervalScreen = maxSizeScreen / MAX_POINTS_ACROSS_RANGE;
}
void DlgSettingsColorFilter::updateHistogram()
{
  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsColorFilter::updateHistogram";

  enableOk (true);

  const double PEN_WIDTH = 0.0; // Zero value gives one-pixel width at all scales

  QString curveName = m_cmbCurveName->currentText();

  m_sceneProfile->clear();

  m_scale->setColorFilterMode (m_modelColorFilterAfter->colorFilterMode(curveName));

  // Start with original image
  QImage image = cmdMediator().document().pixmap().toImage();

  double *histogramBins = new double [ColorFilterHistogram::HISTOGRAM_BINS ()];

  ColorFilter filter;
  ColorFilterHistogram filterHistogram;
  int maxBinCount;
  filterHistogram.generate (filter,
                            histogramBins,
                            m_modelColorFilterAfter->colorFilterMode (curveName),
                            image,
                            maxBinCount);

  // Draw histogram, normalizing so highest peak exactly fills the vertical range. Log scale is used
  // so smaller peaks do not disappear
  double logMaxBinCount = qLn (maxBinCount);
  for (int bin = 1; bin < ColorFilterHistogram::HISTOGRAM_BINS (); bin++) {

    double x0 = PROFILE_SCENE_WIDTH () * (bin - 1.0) / (ColorFilterHistogram::HISTOGRAM_BINS () - 1.0);

    // Map logPixelCount through 0 to 0 through PROFILE_SCENE_HEIGHT-1, using log scale
    double count0 = 1.0 + histogramBins [bin - 1];
    double y0 = (PROFILE_SCENE_HEIGHT () - 1.0) * (1.0 - qLn (count0) / logMaxBinCount);

    double x1 = PROFILE_SCENE_WIDTH () * (bin - 0.0) / (ColorFilterHistogram::HISTOGRAM_BINS () - 1.0);

    // Map logPixelCount through 0 to 0 through PROFILE_SCENE_HEIGHT-1, using log scale
    double count1 = 1.0 + histogramBins [bin];
    double y1 = (PROFILE_SCENE_HEIGHT () - 1.0) * (1.0 - qLn (count1) / logMaxBinCount);

    QGraphicsLineItem *line = new QGraphicsLineItem (x0, y0, x1, y1);
    line->setPen (QPen (QBrush (Qt::black), PEN_WIDTH));
    m_sceneProfile->addItem (line);
  }

  // Create low and high dividers
  m_dividerLow = new ViewProfileDivider(*m_sceneProfile,
                                        *m_viewProfile,
                                        PROFILE_SCENE_WIDTH (),
                                        PROFILE_SCENE_HEIGHT (),
                                        PROFILE_SCENE_HEIGHT () * 2.0 / 3.0,
                                        true);
  m_dividerHigh = new ViewProfileDivider(*m_sceneProfile,
                                         *m_viewProfile,
                                         PROFILE_SCENE_HEIGHT (),
                                         PROFILE_SCENE_WIDTH (),
                                         PROFILE_SCENE_HEIGHT () / 3.0,
                                         false);

  // Connect the dividers to each other since the shaded areas depend on both divides when low divider is
  // moved to the right of the high divider
  connect (m_dividerLow, SIGNAL (signalMovedLow (double)), m_dividerHigh, SLOT (slotOtherMoved(double)));
  connect (m_dividerHigh, SIGNAL (signalMovedHigh (double)), m_dividerLow, SLOT (slotOtherMoved(double)));

  // Update preview when the dividers move
  connect (m_dividerLow, SIGNAL (signalMovedLow (double)), this, SLOT (slotDividerLow (double)));
  connect (m_dividerHigh, SIGNAL(signalMovedHigh (double)), this, SLOT (slotDividerHigh (double)));

  if (m_btnForeground->isChecked()) {

    // Foreground
    m_dividerLow->setX (m_modelColorFilterAfter->foregroundLow(curveName), FOREGROUND_MIN, FOREGROUND_MAX);
    m_dividerHigh->setX (m_modelColorFilterAfter->foregroundHigh(curveName), FOREGROUND_MIN, FOREGROUND_MAX);

  } else if (m_btnIntensity->isChecked()) {

    // Intensity
    m_dividerLow->setX (m_modelColorFilterAfter->intensityLow(curveName), INTENSITY_MIN, INTENSITY_MAX);
    m_dividerHigh->setX (m_modelColorFilterAfter->intensityHigh(curveName), INTENSITY_MIN, INTENSITY_MAX);

  } else if (m_btnHue->isChecked()) {

    // Hue
    m_dividerLow->setX (m_modelColorFilterAfter->hueLow(curveName), HUE_MIN, HUE_MAX);
    m_dividerHigh->setX (m_modelColorFilterAfter->hueHigh(curveName), HUE_MIN, HUE_MAX);

  } else if (m_btnSaturation->isChecked()) {

    // Saturation
    m_dividerLow->setX (m_modelColorFilterAfter->saturationLow(curveName), SATURATION_MIN, SATURATION_MAX);
    m_dividerHigh->setX (m_modelColorFilterAfter->saturationHigh(curveName), SATURATION_MIN, SATURATION_MAX);

  } else if (m_btnValue->isChecked()) {

    // Value
    m_dividerLow->setX (m_modelColorFilterAfter->valueLow(curveName), VALUE_MIN, VALUE_MAX);
    m_dividerHigh->setX (m_modelColorFilterAfter->valueHigh(curveName), VALUE_MIN, VALUE_MAX);

  } else {

    ENGAUGE_ASSERT (false);

  }

  free (histogramBins);
}