1 /** -*- mode: c++ ; c-basic-offset: 2 -*-
2  *
3  *  @file IntParameter.cpp
4  *
5  *  Copyright 2017 Sebastien Fourey
6  *
7  *  This file is part of G'MIC-Qt, a generic plug-in for raster graphics
8  *  editors, offering hundreds of filters thanks to the underlying G'MIC
9  *  image processing framework.
10  *
11  *  gmic_qt is free software: you can redistribute it and/or modify
12  *  it under the terms of the GNU General Public License as published by
13  *  the Free Software Foundation, either version 3 of the License, or
14  *  (at your option) any later version.
15  *
16  *  gmic_qt is distributed in the hope that it will be useful,
17  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  *  GNU General Public License for more details.
20  *
21  *  You should have received a copy of the GNU General Public License
22  *  along with gmic_qt.  If not, see <http://www.gnu.org/licenses/>.
23  *
24  */
25 #include "FilterParameters/IntParameter.h"
26 #include <QGridLayout>
27 #include <QLabel>
28 #include <QPalette>
29 #include <QSlider>
30 #include <QTimerEvent>
31 #include <QWidget>
32 #include "DialogSettings.h"
33 #include "FilterParameters/CustomSpinBox.h"
34 #include "FilterTextTranslator.h"
35 #include "Globals.h"
36 #include "HtmlTranslator.h"
37 #include "Logger.h"
38 
39 namespace GmicQt
40 {
41 
IntParameter(QObject * parent)42 IntParameter::IntParameter(QObject * parent) : AbstractParameter(parent), _min(0), _max(0), _default(0), _value(0), _label(nullptr), _slider(nullptr), _spinBox(nullptr)
43 {
44   _timerId = 0;
45   _connected = false;
46 }
47 
~IntParameter()48 IntParameter::~IntParameter()
49 {
50   delete _spinBox;
51   delete _slider;
52   delete _label;
53 }
54 
size() const55 int IntParameter::size() const
56 {
57   return 1;
58 }
59 
addTo(QWidget * widget,int row)60 bool IntParameter::addTo(QWidget * widget, int row)
61 {
62   _grid = dynamic_cast<QGridLayout *>(widget->layout());
63   Q_ASSERT_X(_grid, __PRETTY_FUNCTION__, "No grid layout in widget");
64   _row = row;
65   delete _spinBox;
66   delete _slider;
67   delete _label;
68   _slider = new QSlider(Qt::Horizontal, widget);
69   _slider->setMinimumWidth(SLIDER_MIN_WIDTH);
70   _slider->setRange(_min, _max);
71   _slider->setValue(_value);
72 
73   const int delta = 1 + _max - _min;
74   if (delta < 20) {
75     _slider->setPageStep(1);
76   } else {
77     const int fact = delta < 100 ? 10 : delta < 1000 ? 100 : delta < 10000 ? 1000 : 10000;
78     _slider->setPageStep(fact * (delta / fact) / 10);
79   }
80 
81   _spinBox = new CustomSpinBox(widget, _min, _max);
82   _spinBox->setValue(_value);
83   if (DialogSettings::darkThemeEnabled()) {
84     QPalette p = _slider->palette();
85     p.setColor(QPalette::Button, QColor(100, 100, 100));
86     p.setColor(QPalette::Highlight, QColor(130, 130, 130));
87     _slider->setPalette(p);
88   }
89   _grid->addWidget(_label = new QLabel(_name, widget), row, 0, 1, 1);
90   _grid->addWidget(_slider, row, 1, 1, 1);
91   _grid->addWidget(_spinBox, row, 2, 1, 1);
92   connectSliderSpinBox();
93 
94   connect(_spinBox, &CustomSpinBox::editingFinished, [this]() { notifyIfRelevant(); });
95 
96   return true;
97 }
98 
value() const99 QString IntParameter::value() const
100 {
101   return _spinBox->text();
102 }
103 
defaultValue() const104 QString IntParameter::defaultValue() const
105 {
106   return QString::number(_default);
107 }
108 
setValue(const QString & value)109 void IntParameter::setValue(const QString & value)
110 {
111   bool ok = true;
112   const int k = value.toInt(&ok);
113   if (!ok) {
114     Logger::warning(QString("IntParameter::setValue(\"%1\"): bad value").arg(value));
115     return;
116   }
117   _value = k;
118   if (_spinBox) {
119     disconnectSliderSpinBox();
120     _spinBox->setValue(_value);
121     _slider->setValue(_value);
122     connectSliderSpinBox();
123   }
124 }
125 
reset()126 void IntParameter::reset()
127 {
128   disconnectSliderSpinBox();
129   _slider->setValue(_default);
130   _spinBox->setValue(_default);
131   _value = _default;
132   connectSliderSpinBox();
133 }
134 
initFromText(const char * text,int & textLength)135 bool IntParameter::initFromText(const char * text, int & textLength)
136 {
137   QList<QString> list = parseText("int", text, textLength);
138   if (list.isEmpty()) {
139     return false;
140   }
141   _name = HtmlTranslator::html2txt(FilterTextTranslator::translate(list[0]));
142 
143   QList<QString> values = list[1].split(QChar(','));
144   if (values.size() != 3) {
145     return false;
146   }
147   bool ok1, ok2, ok3;
148   _default = values[0].toInt(&ok1);
149   _min = values[1].toInt(&ok2);
150   _max = values[2].toInt(&ok3);
151   _value = _default;
152   return ok1 && ok2 && ok3;
153 }
154 
timerEvent(QTimerEvent * e)155 void IntParameter::timerEvent(QTimerEvent * e)
156 {
157   killTimer(e->timerId());
158   _timerId = 0;
159   if (not _spinBox->unfinishedKeyboardEditing()) {
160     notifyIfRelevant();
161   }
162 }
163 
onSliderMoved(int value)164 void IntParameter::onSliderMoved(int value)
165 {
166   if (value != _value) {
167     _spinBox->setValue(_value = value);
168   }
169 }
170 
onSliderValueChanged(int value)171 void IntParameter::onSliderValueChanged(int value)
172 {
173   if (value != _value) {
174     _spinBox->setValue(_value = value);
175   }
176 }
177 
onSpinBoxChanged(int i)178 void IntParameter::onSpinBoxChanged(int i)
179 {
180   _value = i;
181   _slider->setValue(i);
182   if (_timerId) {
183     killTimer(_timerId);
184   }
185   if (_spinBox->unfinishedKeyboardEditing()) {
186     _timerId = 0;
187   } else {
188     _timerId = startTimer(UPDATE_DELAY);
189   }
190 }
191 
connectSliderSpinBox()192 void IntParameter::connectSliderSpinBox()
193 {
194   if (_connected) {
195     return;
196   }
197   connect(_slider, SIGNAL(sliderMoved(int)), this, SLOT(onSliderMoved(int)));
198   connect(_slider, SIGNAL(valueChanged(int)), this, SLOT(onSliderValueChanged(int)));
199   connect(_spinBox, SIGNAL(valueChanged(int)), this, SLOT(onSpinBoxChanged(int)));
200   _connected = true;
201 }
202 
disconnectSliderSpinBox()203 void IntParameter::disconnectSliderSpinBox()
204 {
205   if (!_connected) {
206     return;
207   }
208   _slider->disconnect(this);
209   _spinBox->disconnect(this);
210   _connected = false;
211 }
212 
213 } // namespace GmicQt
214