Thu, 23 Feb 2017 19:32:36 +0200
Some cleanup in mainwindow.cpp, use QSet<QString> for the 'ignore' variable.
655
b376645315ab
- renamed files to camelCase
Santeri Piippo <crimsondusk64@gmail.com>
parents:
diff
changeset
|
1 | /* |
b376645315ab
- renamed files to camelCase
Santeri Piippo <crimsondusk64@gmail.com>
parents:
diff
changeset
|
2 | * LDForge: LDraw parts authoring CAD |
1072 | 3 | * Copyright (C) 2013 - 2017 Teemu Piippo |
655
b376645315ab
- renamed files to camelCase
Santeri Piippo <crimsondusk64@gmail.com>
parents:
diff
changeset
|
4 | * |
b376645315ab
- renamed files to camelCase
Santeri Piippo <crimsondusk64@gmail.com>
parents:
diff
changeset
|
5 | * This program is free software: you can redistribute it and/or modify |
b376645315ab
- renamed files to camelCase
Santeri Piippo <crimsondusk64@gmail.com>
parents:
diff
changeset
|
6 | * it under the terms of the GNU General Public License as published by |
b376645315ab
- renamed files to camelCase
Santeri Piippo <crimsondusk64@gmail.com>
parents:
diff
changeset
|
7 | * the Free Software Foundation, either version 3 of the License, or |
b376645315ab
- renamed files to camelCase
Santeri Piippo <crimsondusk64@gmail.com>
parents:
diff
changeset
|
8 | * (at your option) any later version. |
b376645315ab
- renamed files to camelCase
Santeri Piippo <crimsondusk64@gmail.com>
parents:
diff
changeset
|
9 | * |
b376645315ab
- renamed files to camelCase
Santeri Piippo <crimsondusk64@gmail.com>
parents:
diff
changeset
|
10 | * This program is distributed in the hope that it will be useful, |
b376645315ab
- renamed files to camelCase
Santeri Piippo <crimsondusk64@gmail.com>
parents:
diff
changeset
|
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
b376645315ab
- renamed files to camelCase
Santeri Piippo <crimsondusk64@gmail.com>
parents:
diff
changeset
|
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
b376645315ab
- renamed files to camelCase
Santeri Piippo <crimsondusk64@gmail.com>
parents:
diff
changeset
|
13 | * GNU General Public License for more details. |
b376645315ab
- renamed files to camelCase
Santeri Piippo <crimsondusk64@gmail.com>
parents:
diff
changeset
|
14 | * |
b376645315ab
- renamed files to camelCase
Santeri Piippo <crimsondusk64@gmail.com>
parents:
diff
changeset
|
15 | * You should have received a copy of the GNU General Public License |
b376645315ab
- renamed files to camelCase
Santeri Piippo <crimsondusk64@gmail.com>
parents:
diff
changeset
|
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
b376645315ab
- renamed files to camelCase
Santeri Piippo <crimsondusk64@gmail.com>
parents:
diff
changeset
|
17 | */ |
b376645315ab
- renamed files to camelCase
Santeri Piippo <crimsondusk64@gmail.com>
parents:
diff
changeset
|
18 | |
998 | 19 | #include <QMessageBox> |
655
b376645315ab
- renamed files to camelCase
Santeri Piippo <crimsondusk64@gmail.com>
parents:
diff
changeset
|
20 | #include "colors.h" |
1012 | 21 | #include "ldpaths.h" |
655
b376645315ab
- renamed files to camelCase
Santeri Piippo <crimsondusk64@gmail.com>
parents:
diff
changeset
|
22 | |
1114
ffd49a28f49e
Moved some global constants into appropriate namespaces.
Teemu Piippo <teemu@hecknology.net>
parents:
1086
diff
changeset
|
23 | ColorData* LDColor::colorData = nullptr; |
1153 | 24 | const LDColor LDColor::nullColor = -1; |
946 | 25 | |
1044 | 26 | /* |
27 | * Initializes the color information module. | |
28 | */ | |
1114
ffd49a28f49e
Moved some global constants into appropriate namespaces.
Teemu Piippo <teemu@hecknology.net>
parents:
1086
diff
changeset
|
29 | void LDColor::initColors() |
655
b376645315ab
- renamed files to camelCase
Santeri Piippo <crimsondusk64@gmail.com>
parents:
diff
changeset
|
30 | { |
1153 | 31 | print("Initializing color information.\n"); |
998 | 32 | static ColorData colors; |
1114
ffd49a28f49e
Moved some global constants into appropriate namespaces.
Teemu Piippo <teemu@hecknology.net>
parents:
1086
diff
changeset
|
33 | LDColor::colorData = &colors; |
946 | 34 | } |
655
b376645315ab
- renamed files to camelCase
Santeri Piippo <crimsondusk64@gmail.com>
parents:
diff
changeset
|
35 | |
1044 | 36 | /* |
1153 | 37 | * Default-constructs an LDColor to 0(black). |
1044 | 38 | */ |
39 | LDColor::LDColor() : | |
1153 | 40 | m_index {0} {} |
1044 | 41 | |
42 | /* | |
43 | * Constructs an LDColor by index. | |
44 | */ | |
1153 | 45 | LDColor::LDColor(qint32 index) : |
46 | m_index {index} {} | |
1044 | 47 | |
48 | /* | |
49 | * Returns whether or not the color is valid. | |
50 | */ | |
946 | 51 | bool LDColor::isValid() const |
52 | { | |
998 | 53 | if (isLDConfigColor() and data().name.isEmpty()) |
946 | 54 | return false; // Unknown LDConfig color |
1044 | 55 | else |
56 | return m_index != -1; | |
795
195fa1fff9c3
- changed all color usage to use LDColor classes instead of color indices. Added support for direct colors.
Santeri Piippo <crimsondusk64@gmail.com>
parents:
706
diff
changeset
|
57 | } |
655
b376645315ab
- renamed files to camelCase
Santeri Piippo <crimsondusk64@gmail.com>
parents:
diff
changeset
|
58 | |
1044 | 59 | /* |
60 | * Returns whether or not this color is defined in LDConfig.ldr. | |
61 | * This is false for e.g. direct colors. | |
62 | */ | |
946 | 63 | bool LDColor::isLDConfigColor() const |
795
195fa1fff9c3
- changed all color usage to use LDColor classes instead of color indices. Added support for direct colors.
Santeri Piippo <crimsondusk64@gmail.com>
parents:
706
diff
changeset
|
64 | { |
1044 | 65 | return colorData->contains(index()); |
998 | 66 | } |
67 | ||
1044 | 68 | /* |
69 | * Returns the ColorData entry for this color. | |
70 | */ | |
998 | 71 | const ColorData::Entry& LDColor::data() const |
72 | { | |
1044 | 73 | return colorData->get(index()); |
795
195fa1fff9c3
- changed all color usage to use LDColor classes instead of color indices. Added support for direct colors.
Santeri Piippo <crimsondusk64@gmail.com>
parents:
706
diff
changeset
|
74 | } |
195fa1fff9c3
- changed all color usage to use LDColor classes instead of color indices. Added support for direct colors.
Santeri Piippo <crimsondusk64@gmail.com>
parents:
706
diff
changeset
|
75 | |
1044 | 76 | /* |
77 | * Returns the name of this color. | |
78 | */ | |
946 | 79 | QString LDColor::name() const |
795
195fa1fff9c3
- changed all color usage to use LDColor classes instead of color indices. Added support for direct colors.
Santeri Piippo <crimsondusk64@gmail.com>
parents:
706
diff
changeset
|
80 | { |
946 | 81 | if (isDirect()) |
1153 | 82 | return "0x" + QString::number(index(), 16).toUpper(); |
946 | 83 | else if (isLDConfigColor()) |
998 | 84 | return data().name; |
946 | 85 | else if (index() == -1) |
86 | return "null color"; | |
87 | else | |
1044 | 88 | return "unknown"; |
946 | 89 | } |
90 | ||
1044 | 91 | /* |
92 | * Returns the hexadecimal code of this color. | |
93 | */ | |
946 | 94 | QString LDColor::hexcode() const |
95 | { | |
96 | return faceColor().name(); | |
655
b376645315ab
- renamed files to camelCase
Santeri Piippo <crimsondusk64@gmail.com>
parents:
diff
changeset
|
97 | } |
b376645315ab
- renamed files to camelCase
Santeri Piippo <crimsondusk64@gmail.com>
parents:
diff
changeset
|
98 | |
1044 | 99 | /* |
100 | * Returns the color used for surfaces. | |
101 | */ | |
946 | 102 | QColor LDColor::faceColor() const |
655
b376645315ab
- renamed files to camelCase
Santeri Piippo <crimsondusk64@gmail.com>
parents:
diff
changeset
|
103 | { |
946 | 104 | if (isDirect()) |
105 | { | |
1044 | 106 | // Direct color -- compute from the index. |
946 | 107 | QColor color; |
1044 | 108 | color.setRed((index() & 0x0FF0000) >> 16); |
109 | color.setGreen((index() & 0x000FF00) >> 8); | |
110 | color.setBlue(index() & 0x00000FF); | |
946 | 111 | |
112 | if (index() >= 0x3000000) | |
1044 | 113 | color.setAlpha(128); |
946 | 114 | |
115 | return color; | |
116 | } | |
117 | else if (isLDConfigColor()) | |
118 | { | |
998 | 119 | return data().faceColor; |
946 | 120 | } |
121 | else | |
122 | { | |
123 | return Qt::black; | |
124 | } | |
655
b376645315ab
- renamed files to camelCase
Santeri Piippo <crimsondusk64@gmail.com>
parents:
diff
changeset
|
125 | } |
b376645315ab
- renamed files to camelCase
Santeri Piippo <crimsondusk64@gmail.com>
parents:
diff
changeset
|
126 | |
1044 | 127 | /* |
128 | * Returns the color used for edge lines. | |
129 | */ | |
946 | 130 | QColor LDColor::edgeColor() const |
655
b376645315ab
- renamed files to camelCase
Santeri Piippo <crimsondusk64@gmail.com>
parents:
diff
changeset
|
131 | { |
946 | 132 | if (isDirect()) |
1044 | 133 | return luma(faceColor()) < 48 ? Qt::white : Qt::black; |
946 | 134 | else if (isLDConfigColor()) |
998 | 135 | return data().edgeColor; |
946 | 136 | else |
137 | return Qt::black; | |
138 | } | |
655
b376645315ab
- renamed files to camelCase
Santeri Piippo <crimsondusk64@gmail.com>
parents:
diff
changeset
|
139 | |
1044 | 140 | /* |
141 | * Returns the index number of this color. | |
142 | */ | |
946 | 143 | qint32 LDColor::index() const |
144 | { | |
145 | return m_index; | |
655
b376645315ab
- renamed files to camelCase
Santeri Piippo <crimsondusk64@gmail.com>
parents:
diff
changeset
|
146 | } |
b376645315ab
- renamed files to camelCase
Santeri Piippo <crimsondusk64@gmail.com>
parents:
diff
changeset
|
147 | |
1044 | 148 | /* |
149 | * Returns a string containing the preferred representation of the index. | |
150 | */ | |
806
4240f47aa2d4
- moved most of LDColorData API into LDColor
Santeri Piippo <crimsondusk64@gmail.com>
parents:
797
diff
changeset
|
151 | QString LDColor::indexString() const |
4240f47aa2d4
- moved most of LDColorData API into LDColor
Santeri Piippo <crimsondusk64@gmail.com>
parents:
797
diff
changeset
|
152 | { |
4240f47aa2d4
- moved most of LDColorData API into LDColor
Santeri Piippo <crimsondusk64@gmail.com>
parents:
797
diff
changeset
|
153 | if (isDirect()) |
1044 | 154 | { |
155 | // Use hexadecimal notation for direct colors. | |
156 | return "0x" + QString::number(index(), 16).toUpper(); | |
157 | } | |
158 | else | |
159 | { | |
160 | return QString::number(index()); | |
161 | } | |
806
4240f47aa2d4
- moved most of LDColorData API into LDColor
Santeri Piippo <crimsondusk64@gmail.com>
parents:
797
diff
changeset
|
162 | } |
4240f47aa2d4
- moved most of LDColorData API into LDColor
Santeri Piippo <crimsondusk64@gmail.com>
parents:
797
diff
changeset
|
163 | |
1044 | 164 | /* |
165 | * Returns whether or not this color is a direct color. | |
166 | * Direct colors are picked by RGB value and are not defined in LDConfig.ldr. | |
167 | */ | |
806
4240f47aa2d4
- moved most of LDColorData API into LDColor
Santeri Piippo <crimsondusk64@gmail.com>
parents:
797
diff
changeset
|
168 | bool LDColor::isDirect() const |
4240f47aa2d4
- moved most of LDColorData API into LDColor
Santeri Piippo <crimsondusk64@gmail.com>
parents:
797
diff
changeset
|
169 | { |
4240f47aa2d4
- moved most of LDColorData API into LDColor
Santeri Piippo <crimsondusk64@gmail.com>
parents:
797
diff
changeset
|
170 | return index() >= 0x02000000; |
4240f47aa2d4
- moved most of LDColorData API into LDColor
Santeri Piippo <crimsondusk64@gmail.com>
parents:
797
diff
changeset
|
171 | } |
4240f47aa2d4
- moved most of LDColorData API into LDColor
Santeri Piippo <crimsondusk64@gmail.com>
parents:
797
diff
changeset
|
172 | |
1044 | 173 | /* |
174 | * LDColors are hashed by their index. | |
175 | */ | |
1031
55c0d3beea0d
removed removeDuplicates in favor of QSet, and the unused ObjectList class
Teemu Piippo <crimsondusk64@gmail.com>
parents:
1014
diff
changeset
|
176 | uint qHash(LDColor color) |
55c0d3beea0d
removed removeDuplicates in favor of QSet, and the unused ObjectList class
Teemu Piippo <crimsondusk64@gmail.com>
parents:
1014
diff
changeset
|
177 | { |
55c0d3beea0d
removed removeDuplicates in favor of QSet, and the unused ObjectList class
Teemu Piippo <crimsondusk64@gmail.com>
parents:
1014
diff
changeset
|
178 | return color.index(); |
55c0d3beea0d
removed removeDuplicates in favor of QSet, and the unused ObjectList class
Teemu Piippo <crimsondusk64@gmail.com>
parents:
1014
diff
changeset
|
179 | } |
55c0d3beea0d
removed removeDuplicates in favor of QSet, and the unused ObjectList class
Teemu Piippo <crimsondusk64@gmail.com>
parents:
1014
diff
changeset
|
180 | |
1044 | 181 | /* |
182 | * Calculates the luma-value for the given color. | |
183 | * c.f. https://en.wikipedia.org/wiki/Luma_(video) | |
184 | */ | |
1153 | 185 | int luma(const QColor& color) |
655
b376645315ab
- renamed files to camelCase
Santeri Piippo <crimsondusk64@gmail.com>
parents:
diff
changeset
|
186 | { |
1153 | 187 | return static_cast<int>(round(0.2126 * color.red() + 0.7152 * color.green() + 0.0722 * color.blue())); |
655
b376645315ab
- renamed files to camelCase
Santeri Piippo <crimsondusk64@gmail.com>
parents:
diff
changeset
|
188 | } |
795
195fa1fff9c3
- changed all color usage to use LDColor classes instead of color indices. Added support for direct colors.
Santeri Piippo <crimsondusk64@gmail.com>
parents:
706
diff
changeset
|
189 | |
1044 | 190 | /* |
191 | * Constructs the color data array. | |
192 | */ | |
998 | 193 | ColorData::ColorData() |
795
195fa1fff9c3
- changed all color usage to use LDColor classes instead of color indices. Added support for direct colors.
Santeri Piippo <crimsondusk64@gmail.com>
parents:
706
diff
changeset
|
194 | { |
998 | 195 | // Initialize main and edge colors, they're special like that. |
1044 | 196 | m_data[MainColor].faceColor = "#AAAAAA"; |
998 | 197 | m_data[MainColor].edgeColor = Qt::black; |
198 | m_data[MainColor].name = "Main color"; | |
1153 | 199 | m_data[EdgeColor].faceColor = Qt::black; |
200 | m_data[EdgeColor].edgeColor = Qt::black; | |
998 | 201 | m_data[EdgeColor].name = "Edge color"; |
1044 | 202 | |
203 | // Load the rest from LDConfig.ldr. | |
998 | 204 | loadFromLdconfig(); |
205 | } | |
206 | ||
1044 | 207 | /* |
208 | * ColorData :: contains | |
209 | * | |
210 | * Returns whether or not the given color index is present in the array. | |
211 | */ | |
212 | bool ColorData::contains(int code) const | |
946 | 213 | { |
1065
c8ecddbd99e9
Actually, let's call it countof(). Makes more sense.
Teemu Piippo <teemu@hecknology.net>
parents:
1063
diff
changeset
|
214 | return code >= 0 and code < countof(m_data); |
998 | 215 | } |
216 | ||
1044 | 217 | /* |
218 | * Returns an entry in the color array. | |
219 | */ | |
220 | const ColorData::Entry& ColorData::get(int code) const | |
998 | 221 | { |
1044 | 222 | if (not contains(code)) |
223 | throw std::runtime_error {"Attempted to get non-existant color information"}; | |
946 | 224 | |
998 | 225 | return m_data[code]; |
226 | } | |
227 | ||
1044 | 228 | /* |
229 | * Loads color information from LDConfig.ldr. | |
230 | */ | |
998 | 231 | void ColorData::loadFromLdconfig() |
232 | { | |
1012 | 233 | QString path = LDPaths::ldConfigPath(); |
1044 | 234 | QFile file {path}; |
998 | 235 | |
1153 | 236 | if (not file.open(QIODevice::ReadOnly)) |
946 | 237 | { |
1044 | 238 | QMessageBox::critical(nullptr, "Error", "Unable to open LDConfig.ldr for parsing: " + file.errorString()); |
946 | 239 | return; |
240 | } | |
241 | ||
998 | 242 | // TODO: maybe LDConfig can be loaded as a Document? Or would that be overkill? |
1044 | 243 | while (not file.atEnd()) |
946 | 244 | { |
1153 | 245 | QString line = QString::fromUtf8(file.readLine()); |
946 | 246 | |
247 | if (line.isEmpty() or line[0] != '0') | |
248 | continue; // empty or illogical | |
249 | ||
1044 | 250 | line.remove('\r'); |
251 | line.remove('\n'); | |
946 | 252 | |
253 | // Parse the line | |
1044 | 254 | LDConfigParser parser = {line}; |
998 | 255 | QString name; |
256 | QString facename; | |
257 | QString edgename; | |
258 | QString codestring; | |
946 | 259 | |
260 | // Check 0 !COLOUR, parse the name | |
1044 | 261 | if (not parser.compareToken(0, "0") or not parser.compareToken(1, "!COLOUR") or not parser.getToken(name, 2)) |
946 | 262 | continue; |
263 | ||
264 | // Replace underscores in the name with spaces for readability | |
1044 | 265 | name.replace("_", " "); |
946 | 266 | |
1153 | 267 | if (not parser.parseTag("CODE", codestring)) |
946 | 268 | continue; |
269 | ||
270 | bool ok; | |
1044 | 271 | int code = codestring.toShort(&ok); |
946 | 272 | |
1044 | 273 | if (not ok or not contains(code)) |
946 | 274 | continue; |
275 | ||
1044 | 276 | if (not parser.parseTag("VALUE", facename) or not parser.parseTag("EDGE", edgename)) |
946 | 277 | continue; |
278 | ||
279 | // Ensure that our colors are correct | |
1044 | 280 | QColor faceColor = {facename}; |
281 | QColor edgeColor = {edgename}; | |
946 | 282 | |
283 | if (not faceColor.isValid() or not edgeColor.isValid()) | |
284 | continue; | |
285 | ||
1044 | 286 | // Fill in the entry now. |
998 | 287 | Entry& entry = m_data[code]; |
946 | 288 | entry.name = name; |
289 | entry.faceColor = faceColor; | |
290 | entry.edgeColor = edgeColor; | |
998 | 291 | |
1044 | 292 | // If the alpha tag is present, fill in that too. |
293 | if (parser.parseTag("ALPHA", codestring)) | |
294 | entry.faceColor.setAlpha(qBound(0, codestring.toInt(), 255)); | |
946 | 295 | } |
296 | } | |
297 | ||
1044 | 298 | /* |
299 | * Constructs the LDConfig.ldr parser. | |
300 | */ | |
301 | LDConfigParser::LDConfigParser(QString inputText) | |
946 | 302 | { |
1153 | 303 | m_tokens = inputText.split(' ', QString::SkipEmptyParts); |
946 | 304 | } |
305 | ||
1044 | 306 | /* |
307 | * Returns whether or not there is a token at the given position. | |
308 | * If there is, fills in the value parameter with it. | |
309 | */ | |
310 | bool LDConfigParser::getToken(QString& tokenText, int position) | |
946 | 311 | { |
1065
c8ecddbd99e9
Actually, let's call it countof(). Makes more sense.
Teemu Piippo <teemu@hecknology.net>
parents:
1063
diff
changeset
|
312 | if (position >= countof(m_tokens)) |
1044 | 313 | { |
946 | 314 | return false; |
1044 | 315 | } |
316 | else | |
317 | { | |
318 | tokenText = m_tokens[position]; | |
319 | return true; | |
320 | } | |
946 | 321 | } |
322 | ||
1044 | 323 | /* |
324 | * Attempts to find the provided token in the parsed LDConfig.ldr line. | |
325 | * If found, fills in the first parameter with the position of the token. | |
326 | * | |
327 | * The args parameter specifies how many arguments (i.e. following tokens) the token needs to have. | |
328 | */ | |
329 | bool LDConfigParser::findToken(int& tokenPosition, QString needle, int args) | |
946 | 330 | { |
1065
c8ecddbd99e9
Actually, let's call it countof(). Makes more sense.
Teemu Piippo <teemu@hecknology.net>
parents:
1063
diff
changeset
|
331 | for (int i = 0; i < (countof(m_tokens) - args); ++i) |
946 | 332 | { |
333 | if (m_tokens[i] == needle) | |
334 | { | |
1044 | 335 | tokenPosition = i; |
946 | 336 | return true; |
337 | } | |
338 | } | |
339 | ||
340 | return false; | |
341 | } | |
342 | ||
1044 | 343 | /* |
344 | * Returns whether or not the token at the given position has the given text value. | |
345 | */ | |
1153 | 346 | bool LDConfigParser::compareToken(int position, QString text) |
946 | 347 | { |
1044 | 348 | QString token; |
1153 | 349 | return getToken(token, position) and (token == text); |
946 | 350 | } |
351 | ||
1044 | 352 | /* |
353 | * Finds an attribute in the line, and fills in its value. | |
354 | * For instance, if the line contains "ALPHA 128", this function can find the "128" for "ALPHA". | |
355 | * Returns whether or not the attribute was found. | |
356 | */ | |
1153 | 357 | bool LDConfigParser::parseTag(QString key, QString& value) |
946 | 358 | { |
1044 | 359 | int position; |
946 | 360 | |
361 | // Try find the token and get its position | |
1153 | 362 | if (not findToken(position, key, 1)) |
1044 | 363 | { |
946 | 364 | return false; |
1044 | 365 | } |
366 | else | |
367 | { | |
368 | // Get the token after it and store it in. | |
1153 | 369 | return getToken(value, position + 1); |
1044 | 370 | } |
371 | } |