Changeset View
Changeset View
Standalone View
Standalone View
libs/widgets/kis_double_parse_spin_box.cpp
- This file was added.
1 | /* | ||||
---|---|---|---|---|---|
2 | * Copyright (c) 2016 Laurent Valentin Jospin <laurent.valentin@famillejospin.ch> | ||||
3 | * | ||||
4 | * This program is free software; you can redistribute it and/or modify | ||||
5 | * it under the terms of the GNU General Public License as published by | ||||
6 | * the Free Software Foundation; either version 2 of the License, or | ||||
7 | * (at your option) any later version. | ||||
8 | * | ||||
9 | * This program is distributed in the hope that it will be useful, | ||||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
12 | * GNU General Public License for more details. | ||||
13 | * | ||||
14 | * You should have received a copy of the GNU General Public License | ||||
15 | * along with this program; if not, write to the Free Software | ||||
16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||||
17 | */ | ||||
18 | | ||||
19 | #include "kis_double_parse_spin_box.h" | ||||
20 | | ||||
21 | #include "kis_num_parser.h" | ||||
22 | | ||||
23 | #include <QLabel> | ||||
24 | #include <QPixmap> | ||||
25 | #include <QIcon> | ||||
26 | #include <QFile> | ||||
27 | #include <QLineEdit> | ||||
28 | | ||||
29 | KisDoubleParseSpinBox::KisDoubleParseSpinBox(QWidget *parent) : | ||||
30 | QDoubleSpinBox(parent), | ||||
31 | boolLastValid(true) | ||||
32 | { | ||||
33 | | ||||
34 | lastExprParsed = new QString("0.0"); | ||||
35 | | ||||
36 | connect(this, SIGNAL(noMoreParsingError()), | ||||
37 | this, SLOT(clearErrorStyle())); | ||||
38 | | ||||
39 | //hack to let the clearError be called, even if the value changed method is the one from QDoubleSpinBox. | ||||
40 | connect(this, SIGNAL(valueChanged(double)), | ||||
41 | this, SLOT(clearError())); | ||||
42 | | ||||
43 | connect(this, SIGNAL(errorWhileParsing(QString)), | ||||
44 | this, SLOT(setErrorStyle())); | ||||
45 | | ||||
46 | oldValue = value(); | ||||
47 | | ||||
48 | warningIcon = new QLabel(this); | ||||
49 | | ||||
50 | if (QFile(":/./16_light_warning.svg").exists()) { | ||||
51 | warningIcon->setPixmap(QIcon(":/./16_light_warning.svg").pixmap(16, 16)); | ||||
52 | } else { | ||||
53 | warningIcon->setText("!"); | ||||
54 | } | ||||
55 | | ||||
56 | warningIcon->setStyleSheet("background:transparent;"); | ||||
57 | warningIcon->move(1, 1); | ||||
58 | warningIcon->setVisible(false); | ||||
59 | | ||||
60 | isOldPaletteSaved = false; | ||||
61 | areOldMarginsSaved = false; | ||||
62 | | ||||
63 | } | ||||
64 | | ||||
65 | KisDoubleParseSpinBox::~KisDoubleParseSpinBox() | ||||
66 | { | ||||
67 | | ||||
68 | //needed to avoid a segfault during destruction. | ||||
69 | delete lastExprParsed; | ||||
70 | | ||||
71 | } | ||||
72 | | ||||
73 | double KisDoubleParseSpinBox::valueFromText(const QString & text) const | ||||
74 | { | ||||
75 | | ||||
76 | *lastExprParsed = text; | ||||
77 | | ||||
78 | bool ok; | ||||
79 | | ||||
80 | double ret; | ||||
81 | | ||||
82 | if ( (suffix().isEmpty() || !text.endsWith(suffix())) && | ||||
83 | (prefix().isEmpty() || !text.startsWith(prefix())) ) { | ||||
84 | | ||||
85 | ret = KisNumericParser::parseSimpleMathExpr(text, &ok); | ||||
86 | | ||||
87 | } else { | ||||
88 | | ||||
89 | QString expr = text; | ||||
90 | | ||||
91 | if (text.endsWith(suffix())) { | ||||
92 | expr.remove(text.size()-suffix().size(), suffix().size()); | ||||
93 | } | ||||
94 | | ||||
95 | if(text.startsWith(prefix())){ | ||||
96 | expr.remove(0, prefix().size()); | ||||
97 | } | ||||
98 | | ||||
99 | *lastExprParsed = expr; | ||||
100 | | ||||
101 | ret = KisNumericParser::parseSimpleMathExpr(expr, &ok); | ||||
102 | | ||||
103 | } | ||||
104 | | ||||
105 | if(std::isnan(ret) || std::isinf(ret)){ | ||||
106 | ok = false; | ||||
107 | } | ||||
108 | | ||||
109 | if (!ok) { | ||||
110 | if (boolLastValid) { | ||||
111 | oldValue = value(); | ||||
112 | } | ||||
113 | | ||||
114 | boolLastValid = false; | ||||
115 | ret = oldValue; //in case of error set to minimum. | ||||
116 | } else { | ||||
117 | | ||||
118 | if (!boolLastValid) { | ||||
119 | oldValue = ret; | ||||
120 | } | ||||
121 | | ||||
122 | boolLastValid = true; | ||||
123 | } | ||||
124 | | ||||
125 | return ret; | ||||
126 | | ||||
127 | } | ||||
128 | QString KisDoubleParseSpinBox::textFromValue(double val) const | ||||
129 | { | ||||
130 | | ||||
131 | if (!boolLastValid) { | ||||
132 | emit errorWhileParsing(*lastExprParsed); | ||||
133 | return *lastExprParsed; | ||||
134 | } | ||||
135 | | ||||
136 | emit noMoreParsingError(); | ||||
137 | | ||||
138 | double v = KisNumericParser::parseSimpleMathExpr(cleanText()); | ||||
139 | v = QString("%1").arg(v, 0, 'f', decimals()).toDouble(); | ||||
140 | if (hasFocus() && (v == value() || (v >= maximum() && value() == maximum()) || (v <= minimum() && value() == minimum())) ) { //solve a very annoying bug where the formula can collapse while editing. With this trick the formula is not lost until focus is lost. | ||||
141 | return cleanText(); | ||||
142 | } | ||||
143 | | ||||
144 | return QDoubleSpinBox::textFromValue(val); | ||||
145 | } | ||||
146 | | ||||
147 | QValidator::State KisDoubleParseSpinBox::validate ( QString & input, int & pos ) const | ||||
148 | { | ||||
149 | | ||||
150 | Q_UNUSED(input); | ||||
151 | Q_UNUSED(pos); | ||||
152 | | ||||
153 | return QValidator::Acceptable; | ||||
154 | | ||||
155 | } | ||||
156 | | ||||
157 | void KisDoubleParseSpinBox::stepBy(int steps) | ||||
158 | { | ||||
159 | | ||||
160 | boolLastValid = true; //reset to valid state so we can use the up and down buttons. | ||||
161 | emit noMoreParsingError(); | ||||
162 | | ||||
163 | QDoubleSpinBox::stepBy(steps); | ||||
164 | | ||||
165 | } | ||||
166 | | ||||
167 | void KisDoubleParseSpinBox::setValue(double value) | ||||
168 | { | ||||
169 | if(value == oldValue && hasFocus()){ //avoid to reset the button when it set the value of something that will recall this slot. | ||||
170 | return; | ||||
171 | } | ||||
172 | | ||||
173 | if (!hasFocus()) { | ||||
174 | clearError(); | ||||
175 | } | ||||
176 | | ||||
177 | QDoubleSpinBox::setValue(value); | ||||
178 | } | ||||
179 | | ||||
180 | void KisDoubleParseSpinBox::setErrorStyle() | ||||
181 | { | ||||
182 | | ||||
183 | if (!boolLastValid) { | ||||
184 | //setStyleSheet(_oldStyleSheet + "Background: red; color: white; padding-left: 18px;"); | ||||
185 | | ||||
186 | if (!isOldPaletteSaved) { | ||||
187 | oldPalette = palette(); | ||||
188 | } | ||||
189 | isOldPaletteSaved = true; | ||||
190 | | ||||
191 | QPalette nP = oldPalette; | ||||
192 | nP.setColor(QPalette::Background, Qt::red); | ||||
193 | nP.setColor(QPalette::Base, Qt::red); | ||||
194 | nP.setColor(QPalette::Text, Qt::white); | ||||
195 | setPalette(nP); | ||||
196 | | ||||
197 | if (!areOldMarginsSaved) { | ||||
198 | oldMargins = lineEdit()->textMargins(); | ||||
199 | } | ||||
200 | areOldMarginsSaved = true; | ||||
201 | | ||||
202 | if (width() - height() >= 3*height()) { //if we have twice as much place as needed by the warning icon then display it. | ||||
203 | QMargins newMargins = oldMargins; | ||||
204 | newMargins.setLeft( newMargins.left() + height() - 4 ); | ||||
205 | lineEdit()->setTextMargins(newMargins); | ||||
206 | | ||||
207 | int h = warningIcon->height(); | ||||
208 | int hp = height()-2; | ||||
209 | | ||||
210 | if (h != hp) { | ||||
211 | warningIcon->resize(hp, hp); | ||||
212 | | ||||
213 | if (QFile(":/./16_light_warning.svg").exists()) { | ||||
214 | warningIcon->setPixmap(QIcon(":/./16_light_warning.svg").pixmap(hp-7, hp-7)); | ||||
215 | } | ||||
216 | } | ||||
217 | | ||||
218 | warningIcon->move(oldMargins.left()+4, 1); | ||||
219 | warningIcon->setVisible(true); | ||||
220 | } | ||||
221 | } | ||||
222 | } | ||||
223 | | ||||
224 | void KisDoubleParseSpinBox::clearErrorStyle() | ||||
225 | { | ||||
226 | if (boolLastValid) { | ||||
227 | warningIcon->setVisible(false); | ||||
228 | | ||||
229 | //setStyleSheet(""); | ||||
230 | | ||||
231 | setPalette(oldPalette); | ||||
232 | isOldPaletteSaved = false; | ||||
233 | | ||||
234 | lineEdit()->setTextMargins(oldMargins); | ||||
235 | areOldMarginsSaved = false; | ||||
236 | } | ||||
237 | } | ||||
238 | void KisDoubleParseSpinBox::clearError() | ||||
239 | { | ||||
240 | boolLastValid = true; | ||||
241 | emit noMoreParsingError(); | ||||
242 | oldValue = value(); | ||||
243 | clearErrorStyle(); | ||||
244 | } |