Engauge Digitizer  2
DlgSettingsColorFilter.cpp
1 /******************************************************************************************************
2  * (C) 2014 markummitchell@github.com. This file is part of Engauge Digitizer, which is released *
3  * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file *
4  * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. *
5  ******************************************************************************************************/
6 
7 #include "CmdMediator.h"
8 #include "CmdSettingsColorFilter.h"
9 #include "ColorFilter.h"
10 #include "ColorFilterHistogram.h"
11 #include "ColorConstants.h"
12 #include "DlgFilterThread.h"
13 #include "DlgSettingsColorFilter.h"
14 #include "EngaugeAssert.h"
15 #include "Logger.h"
16 #include "MainWindow.h"
17 #include <QComboBox>
18 #include <QDebug>
19 #include <QGraphicsLineItem>
20 #include <QGraphicsScene>
21 #include <QGridLayout>
22 #include <QImage>
23 #include <QLabel>
24 #include <qmath.h>
25 #include <QPixmap>
26 #include <QRadioButton>
27 #include <QRgb>
28 #include "ViewPreview.h"
29 #include "ViewProfile.h"
30 #include "ViewProfileDivider.h"
31 #include "ViewProfileScale.h"
32 
33 const int MINIMUM_DIALOG_WIDTH_COLOR_FILTER = 640;
34 const int MINIMUM_HEIGHT = 500;
35 
37  DlgSettingsAbstractBase (tr ("Color Filter"),
38  "DlgSettingsColorFilter",
39  mainWindow),
40  m_scenePreview (0),
41  m_viewPreview (0),
42  m_filterThread (0),
43  m_modelColorFilterBefore (0),
44  m_modelColorFilterAfter (0)
45 {
46  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsColorFilter::DlgSettingsColorFilter";
47 
48  QWidget *subPanel = createSubPanel ();
49  finishPanel (subPanel,
50  MINIMUM_DIALOG_WIDTH_COLOR_FILTER);
51 }
52 
53 DlgSettingsColorFilter::~DlgSettingsColorFilter()
54 {
55  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsColorFilter::~DlgSettingsColorFilter";
56 }
57 
58 void DlgSettingsColorFilter::createControls (QGridLayout *layout, int &row)
59 {
60  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsColorFilter::createControls";
61 
62  QLabel *labelCurve = new QLabel (QString ("%1:").arg (tr ("Curve Name")));
63  layout->addWidget (labelCurve, row++, 1);
64 
65  m_cmbCurveName = new QComboBox ();
66  m_cmbCurveName->setWhatsThis (tr ("Name of the curve that is currently selected for editing"));
67  connect (m_cmbCurveName, SIGNAL (activated (const QString &)), this, SLOT (slotCurveName (const QString &))); // activated() ignores code changes
68  layout->addWidget (m_cmbCurveName, row++, 1);
69 
70  QLabel *labelProfile = new QLabel (QString ("%1:").arg (tr ("Filter mode")));
71  layout->addWidget (labelProfile, row++, 1);
72 
73  m_btnIntensity = new QRadioButton (colorFilterModeToString (COLOR_FILTER_MODE_INTENSITY));
74  m_btnIntensity->setWhatsThis (tr ("Filter the original image into black and white pixels using the Intensity parameter, "
75  "to hide unimportant information and emphasize important information.\n\n"
76  "The Intensity value of a pixel is computed from the red, green "
77  "and blue components as I = squareroot (R * R + G * G + B * B)"));
78  connect (m_btnIntensity, SIGNAL (released ()), this, SLOT (slotIntensity ()));
79  layout->addWidget (m_btnIntensity, row++, 1);
80 
81  m_btnForeground = new QRadioButton (colorFilterModeToString (COLOR_FILTER_MODE_FOREGROUND));
82  m_btnForeground->setWhatsThis (tr ("Filter the original image into black and white pixels by isolating the foreground from the background, "
83  "to hide unimportant information and emphasize important information.\n\n"
84  "The background color is shown on the left side of the scale bar.\n\n"
85  "The distance of any color (R, G, B) from the background color (Rb, Gb, Bb) is computed as "
86  "F = squareroot ((R - Rb) * (R - Rb) + (G - Gb) * (G - Gb) + (B - Bb)). On the left end of the "
87  "scale, the foreground distance value is zero, and it increases linearly to the maximum on the far right."));
88  connect (m_btnForeground, SIGNAL (released ()), this, SLOT (slotForeground ()));
89  layout->addWidget (m_btnForeground, row++, 1);
90 
91  m_btnHue = new QRadioButton (colorFilterModeToString (COLOR_FILTER_MODE_HUE));
92  m_btnHue->setWhatsThis (tr ("Filter the original image into black and white pixels using the Hue component of the "
93  "Hue, Saturation and Value (HSV) color components, "
94  "to hide unimportant information and emphasize important information."));
95  connect (m_btnHue, SIGNAL (released ()), this, SLOT (slotHue ()));
96  layout->addWidget (m_btnHue, row++, 1);
97 
98  m_btnSaturation = new QRadioButton (colorFilterModeToString (COLOR_FILTER_MODE_SATURATION));
99  m_btnSaturation->setWhatsThis (tr ("Filter the original image into black and white pixels using the Saturation component of the "
100  "Hue, Saturation and Value (HSV) color components, "
101  "to hide unimportant information and emphasize important information."));
102  connect (m_btnSaturation, SIGNAL (released ()), this, SLOT (slotSaturation ()));
103  layout->addWidget (m_btnSaturation, row++, 1);
104 
105  m_btnValue = new QRadioButton (colorFilterModeToString (COLOR_FILTER_MODE_VALUE));
106  m_btnValue->setWhatsThis (tr ("Filter the original image into black and white pixels using the Value component of the "
107  "Hue, Saturation and Value (HSV) color components, "
108  "to hide unimportant information and emphasize important information.\n\n"
109  "The Value component is also called the Lightness."));
110  connect (m_btnValue, SIGNAL (released ()), this, SLOT (slotValue ()));
111  layout->addWidget (m_btnValue, row++, 1);
112 }
113 
114 void DlgSettingsColorFilter::createOptionalSaveDefault (QHBoxLayout * /* layout */)
115 {
116 }
117 
118 void DlgSettingsColorFilter::createPreview (QGridLayout *layout, int &row)
119 {
120  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsColorFilter::createPreview";
121 
122  QLabel *labelPreview = new QLabel (tr ("Preview"));
123  layout->addWidget (labelPreview, row++, 0, 1, 5);
124 
125  m_scenePreview = new QGraphicsScene (this);
126  m_viewPreview = new ViewPreview (m_scenePreview,
127  ViewPreview::VIEW_ASPECT_RATIO_VARIABLE,
128  this);
129  m_viewPreview->setWhatsThis (tr ("Preview window that shows how current settings affect the filtering of the original image."));
130  m_viewPreview->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
131  m_viewPreview->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
132  m_viewPreview->setMinimumHeight (MINIMUM_PREVIEW_HEIGHT);
133  m_viewPreview->setRenderHint(QPainter::Antialiasing);
134 
135  layout->addWidget (m_viewPreview, row++, 0, 1, 5);
136 }
137 
138 void DlgSettingsColorFilter::createProfileAndScale (QGridLayout *layout, int &row)
139 {
140  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsColorFilter::createProfileAndScale";
141 
142  const int MINIMUM_VIEW_PROFILE_WIDTH = 70;
143 
144  QLabel *labelProfile = new QLabel (tr ("Filter Parameter Histogram Profile"));
145  layout->addWidget (labelProfile, row++, 3);
146 
147  m_sceneProfile = new QGraphicsScene;
148  m_sceneProfile->setSceneRect(0, 0, PROFILE_SCENE_WIDTH (), PROFILE_SCENE_HEIGHT ());
149 
150  m_viewProfile = new ViewProfile (m_sceneProfile,
151  MINIMUM_VIEW_PROFILE_WIDTH);
152  m_viewProfile->setWhatsThis (tr ("Histogram profile of the selected filter parameter. The two Dividers can be moved back and forth to adjust "
153  "the range of filter parameter values that will be included in the filtered image. The clear portion will "
154  "be included, and the shaded portion will be excluded."));
155  layout->addWidget (m_viewProfile, row, 3, PROFILE_HEIGHT_IN_ROWS (), 1);
156  row += PROFILE_HEIGHT_IN_ROWS ();
157 
158  m_scale = new ViewProfileScale (MINIMUM_VIEW_PROFILE_WIDTH);
159  m_scale->setWhatsThis (tr ("This read-only box displays a graphical representation of the horizontal axis in the histogram profile above."));
160  m_scale->setAutoFillBackground(true);
161  layout->addWidget (m_scale, row++, 3, 1, 1);
162 }
163 
165 {
166  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsColorFilter::createSubPanel";
167 
168  const int EMPTY_COLUMN_WIDTH = 40;
169 
170  QWidget *subPanel = new QWidget ();
171  QGridLayout *layout = new QGridLayout (subPanel);
172  subPanel->setLayout (layout);
173 
174  layout->setColumnStretch(0, 0); // Empty column
175  layout->setColumnMinimumWidth(0, EMPTY_COLUMN_WIDTH);
176  layout->setColumnStretch(1, 0); // Radio buttons
177  layout->setColumnMinimumWidth(1, 210);
178  layout->setColumnStretch(2, 0); // Empty column to put some space between previous and next columns, so they are not too close
179  layout->setColumnMinimumWidth(2, 15);
180  layout->setColumnStretch(3, 1); // Profile
181  layout->setColumnMinimumWidth(4, EMPTY_COLUMN_WIDTH); // Empty column
182  layout->setColumnStretch(4, 0);
183 
184  int rowLeft = 0, rowRight = 0;
185  createControls (layout, rowLeft);
186  createProfileAndScale (layout, rowRight);
187 
188  int row = qMax (rowLeft, rowRight);
189  createPreview (layout, row);
190 
191  return subPanel;
192 }
193 
194 QRgb DlgSettingsColorFilter::createThread ()
195 {
196  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsColorFilter::createThread";
197 
198  // Get background color
199  QImage image = cmdMediator().document().pixmap().toImage();
200  ColorFilter filter;
201  QRgb rgbBackground = filter.marginColor(&image);
202 
203  // Only create thread once
204  if (m_filterThread == 0) {
205 
206  m_filterThread = new DlgFilterThread (cmdMediator().document().pixmap(),
207  rgbBackground,
208  *this);
209  m_filterThread->start(); // Now that thread is started, we can use signalApplyFilter
210  }
211 
212  return rgbBackground;
213 }
214 
216 {
217  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsColorFilter::handleOk";
218 
220  cmdMediator ().document(),
221  *m_modelColorFilterBefore,
222  *m_modelColorFilterAfter);
223  cmdMediator ().push (cmd);
224 
225  hide ();
226 }
227 
229 {
230  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsColorFilter::load";
231 
233 
234  // Flush old data
235  delete m_modelColorFilterBefore;
236  delete m_modelColorFilterAfter;
237 
238  // Save new data
239  m_modelColorFilterBefore = new DocumentModelColorFilter (cmdMediator.document().modelColorFilter());
240  m_modelColorFilterAfter = new DocumentModelColorFilter (cmdMediator.document().modelColorFilter());
241 
242  // Populate controls. First load curve name combobox. The curve-specific controls get loaded in slotCurveName
243  m_cmbCurveName->clear ();
244  m_cmbCurveName->addItem (AXIS_CURVE_NAME);
245  QStringList curveNames = cmdMediator.curvesGraphsNames();
246  QStringList::const_iterator itr;
247  for (itr = curveNames.begin (); itr != curveNames.end (); itr++) {
248 
249  QString curveName = *itr;
250  m_cmbCurveName->addItem (curveName);
251  }
252 
253  // This sets the curve name
254  m_cmbCurveName->setCurrentText (mainWindow().selectedGraphCurve());
255  loadForCurveName();
256 
257  enableOk (false); // Disable Ok button since there not yet any changes
258 }
259 
260 void DlgSettingsColorFilter::loadForCurveName()
261 {
262  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsColorFilter::loadForCurveName";
263 
264  // Get curve name from control
265  QString curveName = m_cmbCurveName->currentText();
266 
267  // Skip if everything is not set up yet
268  if (!curveName.isEmpty () && m_modelColorFilterAfter != 0) {
269 
270  // Populate controls
271  ColorFilterMode colorFilterMode = m_modelColorFilterAfter->colorFilterMode(curveName);
272  m_btnIntensity->setChecked (colorFilterMode == COLOR_FILTER_MODE_INTENSITY);
273  m_btnForeground->setChecked (colorFilterMode == COLOR_FILTER_MODE_FOREGROUND);
274  m_btnHue->setChecked (colorFilterMode == COLOR_FILTER_MODE_HUE);
275  m_btnSaturation->setChecked (colorFilterMode == COLOR_FILTER_MODE_SATURATION);
276  m_btnValue->setChecked (colorFilterMode == COLOR_FILTER_MODE_VALUE);
277 
278  m_scenePreview->clear();
279  m_imagePreview = cmdMediator().document().pixmap().toImage();
280  m_scenePreview->addPixmap (QPixmap::fromImage (m_imagePreview));
281 
282  QRgb rgbBackground = createThread ();
283  m_scale->setBackgroundColor (rgbBackground);
284  createThread ();
285  updateHistogram();
286  updatePreview(); // Needs thread initialized
287  }
288 }
289 
291 {
292  if (!smallDialogs) {
293  setMinimumHeight (MINIMUM_HEIGHT);
294  }
295 }
296 
297 void DlgSettingsColorFilter::slotCurveName(const QString & /* curveName */)
298 {
299  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsColorFilter::slotCurveName";
300 
301  loadForCurveName ();
302 }
303 
304 void DlgSettingsColorFilter::slotDividerHigh (double xCenter)
305 {
306  m_modelColorFilterAfter->setHigh (m_cmbCurveName->currentText(),
307  xCenter / (double) PROFILE_SCENE_WIDTH ());
308  updatePreview();
309 }
310 
311 void DlgSettingsColorFilter::slotDividerLow (double xCenter)
312 {
313  m_modelColorFilterAfter->setLow (m_cmbCurveName->currentText(),
314  xCenter / (double) PROFILE_SCENE_WIDTH ());
315  updatePreview();
316 }
317 
318 void DlgSettingsColorFilter::slotForeground ()
319 {
320  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsColorFilter::slotForeground";
321 
322  m_modelColorFilterAfter->setColorFilterMode(m_cmbCurveName->currentText(),
323  COLOR_FILTER_MODE_FOREGROUND);
324  updateHistogram();
325  updatePreview();
326 }
327 
328 void DlgSettingsColorFilter::slotHue ()
329 {
330  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsColorFilter::slotHue";
331 
332  m_modelColorFilterAfter->setColorFilterMode(m_cmbCurveName->currentText(),
333  COLOR_FILTER_MODE_HUE);
334  updateHistogram();
335  updatePreview();
336 }
337 
338 void DlgSettingsColorFilter::slotIntensity ()
339 {
340  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsColorFilter::slotIntensity";
341 
342  m_modelColorFilterAfter->setColorFilterMode(m_cmbCurveName->currentText(),
343  COLOR_FILTER_MODE_INTENSITY);
344  updateHistogram();
345  updatePreview();
346 }
347 
348 void DlgSettingsColorFilter::slotSaturation ()
349 {
350  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsColorFilter::slotSaturation";
351 
352  m_modelColorFilterAfter->setColorFilterMode(m_cmbCurveName->currentText(),
353  COLOR_FILTER_MODE_SATURATION);
354  updateHistogram();
355  updatePreview();
356 }
357 
359  QImage image)
360 {
361  // Overwrite one piece of the processed image. This approach is a bit slow because the entire QPixmap
362  // in the QGraphicsScene gets exchanged as part of each update, but that seems to be the only possible
363  // approach when using QGraphicsScene. If not fast enough or there is ugly flicker, we may replace
364  // QGraphicsScene by a simple QWidget and override the paint function - but that approach may get
365  // complicated when resizing the QGraphicsView
366  for (int xFrom = 0, xTo = xLeft; xFrom < image.width(); xFrom++, xTo++) {
367  for (int y = 0; y < image.height (); y++) {
368 
369  QColor pixel = image.pixel (xFrom, y);
370  m_imagePreview.setPixel (xTo, y, pixel.rgb());
371  }
372  }
373 
374  // Remove old pixmap
375  QGraphicsItem *itemPixmap = m_scenePreview->items().at(0);
376  m_scenePreview->removeItem (itemPixmap);
377  delete itemPixmap;
378 
379  // Save new pixmap. Only visible change should be the area covered by the pixels in image
380  m_scenePreview->addPixmap (QPixmap::fromImage (m_imagePreview));
381 }
382 
383 void DlgSettingsColorFilter::slotValue ()
384 {
385  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsColorFilter::slotValue";
386 
387  m_modelColorFilterAfter->setColorFilterMode(m_cmbCurveName->currentText(),
388  COLOR_FILTER_MODE_VALUE);
389  updateHistogram();
390  updatePreview();
391 }
392 
393 void DlgSettingsColorFilter::updateHistogram()
394 {
395  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettingsColorFilter::updateHistogram";
396 
397  enableOk (true);
398 
399  const double PEN_WIDTH = 0.0; // Zero value gives one-pixel width at all scales
400 
401  QString curveName = m_cmbCurveName->currentText();
402 
403  m_sceneProfile->clear();
404 
405  m_scale->setColorFilterMode (m_modelColorFilterAfter->colorFilterMode(curveName));
406 
407  // Start with original image
408  QImage image = cmdMediator().document().pixmap().toImage();
409 
410  double *histogramBins = new double [ColorFilterHistogram::HISTOGRAM_BINS ()];
411 
412  ColorFilter filter;
413  ColorFilterHistogram filterHistogram;
414  int maxBinCount;
415  filterHistogram.generate (filter,
416  histogramBins,
417  m_modelColorFilterAfter->colorFilterMode (curveName),
418  image,
419  maxBinCount);
420 
421  // Draw histogram, normalizing so highest peak exactly fills the vertical range. Log scale is used
422  // so smaller peaks do not disappear
423  double logMaxBinCount = qLn (maxBinCount);
424  if (logMaxBinCount != 0) { // Will not have divide by zero from logMaxBinCount below
425  for (int bin = 1; bin < ColorFilterHistogram::HISTOGRAM_BINS (); bin++) {
426 
427  double x0 = PROFILE_SCENE_WIDTH () * (bin - 1.0) / (ColorFilterHistogram::HISTOGRAM_BINS () - 1.0);
428 
429  // Map logPixelCount through 0 to 0 through PROFILE_SCENE_HEIGHT-1, using log scale
430  double count0 = 1.0 + histogramBins [bin - 1];
431  double y0 = (PROFILE_SCENE_HEIGHT () - 1.0) * (1.0 - qLn (count0) / logMaxBinCount);
432 
433  double x1 = PROFILE_SCENE_WIDTH () * (bin - 0.0) / (ColorFilterHistogram::HISTOGRAM_BINS () - 1.0);
434 
435  // Map logPixelCount through 0 to 0 through PROFILE_SCENE_HEIGHT-1, using log scale
436  double count1 = 1.0 + histogramBins [bin];
437  double y1 = (PROFILE_SCENE_HEIGHT () - 1.0) * (1.0 - qLn (count1) / logMaxBinCount);
438 
439  QGraphicsLineItem *line = new QGraphicsLineItem (x0, y0, x1, y1);
440  line->setPen (QPen (QBrush (Qt::black), PEN_WIDTH));
441  m_sceneProfile->addItem (line);
442  }
443  }
444 
445  // Create low and high dividers
446  m_dividerLow = new ViewProfileDivider(*m_sceneProfile,
447  *m_viewProfile,
448  PROFILE_SCENE_WIDTH (),
449  PROFILE_SCENE_HEIGHT (),
450  PROFILE_SCENE_HEIGHT () * 2.0 / 3.0,
451  true);
452  m_dividerHigh = new ViewProfileDivider(*m_sceneProfile,
453  *m_viewProfile,
454  PROFILE_SCENE_HEIGHT (),
455  PROFILE_SCENE_WIDTH (),
456  PROFILE_SCENE_HEIGHT () / 3.0,
457  false);
458 
459  // Connect the dividers to each other since the shaded areas depend on both divides when low divider is
460  // moved to the right of the high divider
461  connect (m_dividerLow, SIGNAL (signalMovedLow (double)), m_dividerHigh, SLOT (slotOtherMoved(double)));
462  connect (m_dividerHigh, SIGNAL (signalMovedHigh (double)), m_dividerLow, SLOT (slotOtherMoved(double)));
463 
464  // Update preview when the dividers move
465  connect (m_dividerLow, SIGNAL (signalMovedLow (double)), this, SLOT (slotDividerLow (double)));
466  connect (m_dividerHigh, SIGNAL(signalMovedHigh (double)), this, SLOT (slotDividerHigh (double)));
467 
468  if (m_btnForeground->isChecked()) {
469 
470  // Foreground
471  m_dividerLow->setX (m_modelColorFilterAfter->foregroundLow(curveName), FOREGROUND_MIN, FOREGROUND_MAX);
472  m_dividerHigh->setX (m_modelColorFilterAfter->foregroundHigh(curveName), FOREGROUND_MIN, FOREGROUND_MAX);
473 
474  } else if (m_btnIntensity->isChecked()) {
475 
476  // Intensity
477  m_dividerLow->setX (m_modelColorFilterAfter->intensityLow(curveName), INTENSITY_MIN, INTENSITY_MAX);
478  m_dividerHigh->setX (m_modelColorFilterAfter->intensityHigh(curveName), INTENSITY_MIN, INTENSITY_MAX);
479 
480  } else if (m_btnHue->isChecked()) {
481 
482  // Hue
483  m_dividerLow->setX (m_modelColorFilterAfter->hueLow(curveName), HUE_MIN, HUE_MAX);
484  m_dividerHigh->setX (m_modelColorFilterAfter->hueHigh(curveName), HUE_MIN, HUE_MAX);
485 
486  } else if (m_btnSaturation->isChecked()) {
487 
488  // Saturation
489  m_dividerLow->setX (m_modelColorFilterAfter->saturationLow(curveName), SATURATION_MIN, SATURATION_MAX);
490  m_dividerHigh->setX (m_modelColorFilterAfter->saturationHigh(curveName), SATURATION_MIN, SATURATION_MAX);
491 
492  } else if (m_btnValue->isChecked()) {
493 
494  // Value
495  m_dividerLow->setX (m_modelColorFilterAfter->valueLow(curveName), VALUE_MIN, VALUE_MAX);
496  m_dividerHigh->setX (m_modelColorFilterAfter->valueHigh(curveName), VALUE_MIN, VALUE_MAX);
497 
498  } else {
499 
500  ENGAUGE_ASSERT (false);
501 
502  }
503 
504  free (histogramBins);
505 }
506 
507 void DlgSettingsColorFilter::updatePreview ()
508 {
509  LOG4CPP_INFO_S ((*mainCat)) << "DlgSettings::updatePreview";
510 
511  enableOk (true);
512 
513  // This (indirectly) updates the preview
514  QString curveName = m_cmbCurveName->currentText();
515  emit signalApplyFilter (m_modelColorFilterAfter->colorFilterMode(curveName),
516  m_modelColorFilterAfter->low(curveName),
517  m_modelColorFilterAfter->high(curveName));
518 }
void setBackgroundColor(QRgb rgbBackground)
Save the background color for foreground calculations.
int intensityHigh(const QString &curveName) const
Get method for intensity higher bound.
int valueHigh(const QString &curveName) const
Get method for value high.
int valueLow(const QString &curveName) const
Get method for value low.
void setColorFilterMode(const QString &curveName, ColorFilterMode colorFilterMode)
Set method for filter mode.
QRgb marginColor(const QImage *image) const
Identify the margin color of the image, which is defined as the most common color in the four margins...
Definition: ColorFilter.cpp:73
int hueHigh(const QString &curveName) const
Get method for hue higher bound.
void setX(double x, double xLow, double xHigh)
Set the position by specifying the new x coordinate.
int saturationLow(const QString &curveName) const
Get method for saturation lower bound.
int foregroundHigh(const QString &curveName) const
Get method for foreground higher bound.
void setCmdMediator(CmdMediator &cmdMediator)
Store CmdMediator for easy access by the leaf class.
DocumentModelColorFilter modelColorFilter() const
Get method for DocumentModelColorFilter.
Definition: Document.cpp:684
Document & document()
Provide the Document to commands, primarily for undo/redo processing.
Definition: CmdMediator.cpp:72
Class for filtering image to remove unimportant information.
Definition: ColorFilter.h:20
void slotTransferPiece(int xLeft, QImage image)
Receive processed piece of preview image, to be inserted at xLeft to xLeft+pixmap.width().
ColorFilterMode colorFilterMode(const QString &curveName) const
Get method for filter mode.
int hueLow(const QString &curveName) const
Get method for hue lower bound.
void finishPanel(QWidget *subPanel, int minimumWidth=MINIMUM_DIALOG_WIDTH, int minimumHeightOrZero=0)
Add Ok and Cancel buttons to subpanel to get the whole dialog.
virtual void handleOk()
Process slotOk.
int saturationHigh(const QString &curveName) const
Get method for saturation higher bound.
void generate(const ColorFilter &filter, double histogramBins [], ColorFilterMode colorFilterMode, const QImage &image, int &maxBinCount) const
Generate the histogram.
double high(const QString &curveName) const
High value of foreground, hue, intensity, saturation or value according to current filter mode...
void signalApplyFilter(ColorFilterMode colorFilterMode, double low, double high)
Send filter parameters to DlgFilterThread and DlgFilterWorker for processing.
virtual void setSmallDialogs(bool smallDialogs)
If false then dialogs have a minimum size so all controls are visible.
virtual void load(CmdMediator &cmdMediator)
Load settings from Document.
int intensityLow(const QString &curveName) const
Get method for intensity lower bound.
void setHigh(const QString &curveName, double s0To1)
Set the high value for the current filter mode.
Class that modifies QGraphicsView to automatically expand/shrink the view to fit the window...
Definition: ViewPreview.h:14
Model for DlgSettingsColorFilter and CmdSettingsColorFilter.
Linear horizontal scale, with the spectrum reflecting the active filter parameter.
void setColorFilterMode(ColorFilterMode colorFilterMode)
Change the gradient type.
Divider that can be dragged, in a dialog QGraphicsView.
Class for processing new filter settings. This is based on http://blog.debao.me/2013/08/how-to-use-qt...
int foregroundLow(const QString &curveName) const
Get method for foreground lower bound.
void setLow(const QString &curveName, double s0To1)
Set the low value for the current filter mode.
Command for DlgSettingsColorFilter.
virtual void createOptionalSaveDefault(QHBoxLayout *layout)
Let subclass define an optional Save As Default button.
virtual QWidget * createSubPanel()
Create dialog-specific panel to which base class will add Ok and Cancel buttons.
static int MINIMUM_PREVIEW_HEIGHT
Dialog layout constant that guarantees preview has sufficent room.
void enableOk(bool enable)
Let leaf subclass control the Ok button.
Command queue stack.
Definition: CmdMediator.h:23
DlgSettingsColorFilter(MainWindow &mainWindow)
Single constructor.
Abstract base class for all Settings dialogs.
QPixmap pixmap() const
Return the image that is being digitized.
Definition: Document.cpp:813
Class that generates a histogram according to the current filter.
Class that modifies QGraphicsView to present a two-dimensional profile, with movable dividers for sel...
Definition: ViewProfile.h:15
double low(const QString &curveName) const
Low value of foreground, hue, intensity, saturation or value according to current filter mode normali...
static int HISTOGRAM_BINS()
Number of histogram bins.
MainWindow & mainWindow()
Get method for MainWindow.
Main window consisting of menu, graphics scene, status bar and optional toolbars as a Single Document...
Definition: MainWindow.h:91
QStringList curvesGraphsNames() const
See CurvesGraphs::curvesGraphsNames.
Definition: CmdMediator.cpp:62
CmdMediator & cmdMediator()
Provide access to Document information wrapped inside CmdMediator.