Changeset View
Changeset View
Standalone View
Standalone View
libs/widgets/kis_int_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_int_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 | KisIntParseSpinBox::KisIntParseSpinBox(QWidget *parent) : | ||||
30 | QSpinBox(parent), | ||||
31 | boolLastValid(true) | ||||
32 | { | ||||
33 | lastExprParsed = new QString("0"); | ||||
34 | | ||||
35 | connect(this, SIGNAL(noMoreParsingError()), | ||||
36 | this, SLOT(clearErrorStyle())); | ||||
37 | | ||||
38 | //hack to let the clearError be called, even if the value changed method is the one from QSpinBox. | ||||
39 | connect(this, SIGNAL(valueChanged(int)), | ||||
40 | this, SLOT(clearError())); | ||||
41 | | ||||
42 | connect(this, SIGNAL(errorWhileParsing(QString)), | ||||
43 | this, SLOT(setErrorStyle())); | ||||
44 | | ||||
45 | oldVal = value(); | ||||
46 | | ||||
47 | warningIcon = new QLabel(this); | ||||
48 | | ||||
49 | if (QFile(":/./16_light_warning.svg").exists()) { | ||||
50 | warningIcon->setPixmap(QIcon(":/./16_light_warning.svg").pixmap(16, 16)); | ||||
51 | } else { | ||||
52 | warningIcon->setText("!"); | ||||
53 | } | ||||
54 | | ||||
55 | warningIcon->setStyleSheet("background:transparent;"); | ||||
56 | warningIcon->move(1, 1); | ||||
57 | warningIcon->setVisible(false); | ||||
58 | | ||||
59 | isOldPaletteSaved = false; | ||||
60 | areOldMarginsSaved = false; | ||||
61 | | ||||
62 | } | ||||
63 | | ||||
64 | KisIntParseSpinBox::~KisIntParseSpinBox() | ||||
65 | { | ||||
66 | | ||||
67 | //needed to avoid a segfault during destruction. | ||||
68 | delete lastExprParsed; | ||||
69 | | ||||
70 | } | ||||
71 | | ||||
72 | int KisIntParseSpinBox::valueFromText(const QString & text) const | ||||
73 | { | ||||
74 | | ||||
75 | *lastExprParsed = text; | ||||
76 | | ||||
77 | bool ok; | ||||
78 | | ||||
79 | int val; | ||||
80 | | ||||
81 | if ( (suffix().isEmpty() || !text.endsWith(suffix())) && | ||||
82 | (prefix().isEmpty() || !text.startsWith(prefix())) ) { | ||||
83 | | ||||
84 | val = KisNumericParser::parseIntegerMathExpr(text, &ok); | ||||
85 | | ||||
86 | } else { | ||||
87 | | ||||
88 | QString expr = text; | ||||
89 | | ||||
90 | if (text.endsWith(suffix())) { | ||||
91 | expr.remove(text.size()-suffix().size(), suffix().size()); | ||||
92 | } | ||||
93 | | ||||
94 | if(text.startsWith(prefix())){ | ||||
95 | expr.remove(0, prefix().size()); | ||||
96 | } | ||||
97 | | ||||
98 | *lastExprParsed = expr; | ||||
99 | | ||||
100 | val = KisNumericParser::parseIntegerMathExpr(expr, &ok); | ||||
101 | | ||||
102 | } | ||||
103 | | ||||
104 | if (text.trimmed().isEmpty()) { //an empty text is considered valid in this case. | ||||
105 | ok = true; | ||||
106 | } | ||||
107 | | ||||
108 | if (!ok) { | ||||
109 | | ||||
110 | if (boolLastValid == true) { | ||||
111 | oldVal = value(); | ||||
112 | } | ||||
113 | | ||||
114 | boolLastValid = false; | ||||
115 | //emit errorWhileParsing(text); //if uncommented become red everytime the string is wrong. | ||||
116 | val = oldVal; | ||||
117 | } else { | ||||
118 | | ||||
119 | if (boolLastValid == false) { | ||||
120 | oldVal = val; | ||||
121 | } | ||||
122 | | ||||
123 | boolLastValid = true; | ||||
124 | //emit noMoreParsingError(); | ||||
125 | } | ||||
126 | | ||||
127 | return val; | ||||
128 | | ||||
129 | } | ||||
130 | | ||||
131 | QString KisIntParseSpinBox::textFromValue(int val) const | ||||
132 | { | ||||
133 | | ||||
134 | if (!boolLastValid) { | ||||
135 | emit errorWhileParsing(*lastExprParsed); | ||||
136 | return *lastExprParsed; | ||||
137 | } | ||||
138 | | ||||
139 | emit noMoreParsingError(); | ||||
140 | | ||||
141 | int v = KisNumericParser::parseIntegerMathExpr(cleanText()); | ||||
142 | 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. | ||||
143 | return cleanText(); | ||||
144 | } | ||||
145 | | ||||
146 | return QSpinBox::textFromValue(val); | ||||
147 | | ||||
148 | } | ||||
149 | | ||||
150 | QValidator::State KisIntParseSpinBox::validate ( QString & input, int & pos ) const | ||||
151 | { | ||||
152 | | ||||
153 | Q_UNUSED(input); | ||||
154 | Q_UNUSED(pos); | ||||
155 | | ||||
156 | //this simple definition is sufficient for the moment | ||||
157 | //TODO: see if needed to get something more complex. | ||||
158 | return QValidator::Acceptable; | ||||
159 | | ||||
160 | } | ||||
161 | | ||||
162 | void KisIntParseSpinBox::stepBy(int steps) | ||||
163 | { | ||||
164 | | ||||
165 | boolLastValid = true; | ||||
166 | emit noMoreParsingError(); | ||||
167 | | ||||
168 | QSpinBox::stepBy(steps); | ||||
169 | | ||||
170 | } | ||||
171 | | ||||
172 | void KisIntParseSpinBox::setValue(int val) | ||||
173 | { | ||||
174 | | ||||
175 | if(val == oldVal && hasFocus()){ //avoid to reset the button when it set the value of something that will recall this slot. | ||||
176 | return; | ||||
177 | } | ||||
178 | | ||||
179 | if (!hasFocus()) { | ||||
180 | clearError(); | ||||
181 | } | ||||
182 | | ||||
183 | QSpinBox::setValue(val); | ||||
184 | } | ||||
185 | | ||||
186 | void KisIntParseSpinBox::setErrorStyle() | ||||
187 | { | ||||
188 | | ||||
189 | if (!boolLastValid) { | ||||
190 | //setStyleSheet(_oldStyleSheet + "Background: red; color: white; padding-left: 18px;"); | ||||
191 | | ||||
192 | if (!isOldPaletteSaved) { | ||||
193 | oldPalette = palette(); | ||||
194 | } | ||||
195 | isOldPaletteSaved = true; | ||||
196 | | ||||
197 | QPalette nP = oldPalette; | ||||
198 | nP.setColor(QPalette::Background, Qt::red); | ||||
199 | nP.setColor(QPalette::Base, Qt::red); | ||||
200 | nP.setColor(QPalette::Text, Qt::white); | ||||
201 | setPalette(nP); | ||||
202 | | ||||
203 | if (!areOldMarginsSaved) { | ||||
204 | oldMargins = lineEdit()->textMargins(); | ||||
205 | } | ||||
206 | areOldMarginsSaved = true; | ||||
207 | | ||||
208 | if (width() - height() >= 3*height()) { //if we have twice as much place as needed by the warning icon then display it. | ||||
209 | QMargins newMargins = oldMargins; | ||||
210 | newMargins.setLeft( newMargins.left() + height() - 4 ); | ||||
211 | lineEdit()->setTextMargins(newMargins); | ||||
212 | | ||||
213 | int h = warningIcon->height(); | ||||
214 | int hp = height()-2; | ||||
215 | | ||||
216 | if (h != hp) { | ||||
217 | warningIcon->resize(hp, hp); | ||||
218 | | ||||
219 | if (QFile(":/./16_light_warning.svg").exists()) { | ||||
220 | warningIcon->setPixmap(QIcon(":/./16_light_warning.svg").pixmap(hp-7, hp-7)); | ||||
221 | } | ||||
222 | } | ||||
223 | | ||||
224 | warningIcon->move(oldMargins.left()+4, 1); | ||||
225 | warningIcon->setVisible(true); | ||||
226 | } | ||||
227 | } | ||||
228 | } | ||||
229 | | ||||
230 | void KisIntParseSpinBox::clearErrorStyle() | ||||
231 | { | ||||
232 | if (boolLastValid) { | ||||
233 | warningIcon->setVisible(false); | ||||
234 | | ||||
235 | //setStyleSheet(""); | ||||
236 | | ||||
237 | setPalette(oldPalette); | ||||
238 | isOldPaletteSaved = false; | ||||
239 | | ||||
240 | lineEdit()->setTextMargins(oldMargins); | ||||
241 | areOldMarginsSaved = false; | ||||
242 | } | ||||
243 | } | ||||
244 | | ||||
245 | | ||||
246 | void KisIntParseSpinBox::clearError() | ||||
247 | { | ||||
248 | boolLastValid = true; | ||||
249 | emit noMoreParsingError(); | ||||
250 | oldVal = value(); | ||||
251 | clearErrorStyle(); | ||||
252 | } |