19 #include <QMessageBox> |
19 #include <QMessageBox> |
20 #include "colors.h" |
20 #include "colors.h" |
21 #include "ldpaths.h" |
21 #include "ldpaths.h" |
22 |
22 |
23 ColorData* LDColor::colorData = nullptr; |
23 ColorData* LDColor::colorData = nullptr; |
24 const LDColor LDColor::nullColor {-1}; |
24 const LDColor LDColor::nullColor = -1; |
25 |
25 |
26 /* |
26 /* |
27 * initColors |
|
28 * |
|
29 * Initializes the color information module. |
27 * Initializes the color information module. |
30 */ |
28 */ |
31 void LDColor::initColors() |
29 void LDColor::initColors() |
32 { |
30 { |
33 print ("Initializing color information.\n"); |
31 print("Initializing color information.\n"); |
34 static ColorData colors; |
32 static ColorData colors; |
35 LDColor::colorData = &colors; |
33 LDColor::colorData = &colors; |
36 } |
34 } |
37 |
35 |
38 /* |
36 /* |
39 * LDColor :: LDColor |
37 * Default-constructs an LDColor to 0(black). |
40 * |
|
41 * Default-constructs an LDColor to 0 (black). |
|
42 */ |
38 */ |
43 LDColor::LDColor() : |
39 LDColor::LDColor() : |
44 m_index (0) {} |
40 m_index {0} {} |
45 |
41 |
46 /* |
42 /* |
47 * LDColor :: LDColor |
|
48 * |
|
49 * Constructs an LDColor by index. |
43 * Constructs an LDColor by index. |
50 */ |
44 */ |
51 LDColor::LDColor (qint32 index) |
45 LDColor::LDColor(qint32 index) : |
52 : m_index (index) {} |
46 m_index {index} {} |
53 |
47 |
54 /* |
48 /* |
55 * LDColor :: isValid |
|
56 * |
|
57 * Returns whether or not the color is valid. |
49 * Returns whether or not the color is valid. |
58 */ |
50 */ |
59 bool LDColor::isValid() const |
51 bool LDColor::isValid() const |
60 { |
52 { |
61 if (isLDConfigColor() and data().name.isEmpty()) |
53 if (isLDConfigColor() and data().name.isEmpty()) |
63 else |
55 else |
64 return m_index != -1; |
56 return m_index != -1; |
65 } |
57 } |
66 |
58 |
67 /* |
59 /* |
68 * LDColor :: isLDConfigColor |
|
69 * |
|
70 * Returns whether or not this color is defined in LDConfig.ldr. |
60 * Returns whether or not this color is defined in LDConfig.ldr. |
71 * This is false for e.g. direct colors. |
61 * This is false for e.g. direct colors. |
72 */ |
62 */ |
73 bool LDColor::isLDConfigColor() const |
63 bool LDColor::isLDConfigColor() const |
74 { |
64 { |
75 return colorData->contains(index()); |
65 return colorData->contains(index()); |
76 } |
66 } |
77 |
67 |
78 /* |
68 /* |
79 * LDColor :: data |
|
80 * |
|
81 * Returns the ColorData entry for this color. |
69 * Returns the ColorData entry for this color. |
82 */ |
70 */ |
83 const ColorData::Entry& LDColor::data() const |
71 const ColorData::Entry& LDColor::data() const |
84 { |
72 { |
85 return colorData->get(index()); |
73 return colorData->get(index()); |
86 } |
74 } |
87 |
75 |
88 /* |
76 /* |
89 * LDColor :: name |
|
90 * |
|
91 * Returns the name of this color. |
77 * Returns the name of this color. |
92 */ |
78 */ |
93 QString LDColor::name() const |
79 QString LDColor::name() const |
94 { |
80 { |
95 if (isDirect()) |
81 if (isDirect()) |
96 return "0x" + QString::number (index(), 16).toUpper(); |
82 return "0x" + QString::number(index(), 16).toUpper(); |
97 else if (isLDConfigColor()) |
83 else if (isLDConfigColor()) |
98 return data().name; |
84 return data().name; |
99 else if (index() == -1) |
85 else if (index() == -1) |
100 return "null color"; |
86 return "null color"; |
101 else |
87 else |
102 return "unknown"; |
88 return "unknown"; |
103 } |
89 } |
104 |
90 |
105 /* |
91 /* |
106 * LDColor :: hexcode |
|
107 * |
|
108 * Returns the hexadecimal code of this color. |
92 * Returns the hexadecimal code of this color. |
109 */ |
93 */ |
110 QString LDColor::hexcode() const |
94 QString LDColor::hexcode() const |
111 { |
95 { |
112 return faceColor().name(); |
96 return faceColor().name(); |
113 } |
97 } |
114 |
98 |
115 /* |
99 /* |
116 * LDColor :: faceColor |
|
117 * |
|
118 * Returns the color used for surfaces. |
100 * Returns the color used for surfaces. |
119 */ |
101 */ |
120 QColor LDColor::faceColor() const |
102 QColor LDColor::faceColor() const |
121 { |
103 { |
122 if (isDirect()) |
104 if (isDirect()) |
184 return QString::number(index()); |
160 return QString::number(index()); |
185 } |
161 } |
186 } |
162 } |
187 |
163 |
188 /* |
164 /* |
189 * LDColor :: isDirect |
|
190 * |
|
191 * Returns whether or not this color is a direct color. |
165 * Returns whether or not this color is a direct color. |
192 * Direct colors are picked by RGB value and are not defined in LDConfig.ldr. |
166 * Direct colors are picked by RGB value and are not defined in LDConfig.ldr. |
193 */ |
167 */ |
194 bool LDColor::isDirect() const |
168 bool LDColor::isDirect() const |
195 { |
169 { |
196 return index() >= 0x02000000; |
170 return index() >= 0x02000000; |
197 } |
171 } |
198 |
172 |
199 /* |
173 /* |
200 * qHash |
|
201 * |
|
202 * LDColors are hashed by their index. |
174 * LDColors are hashed by their index. |
203 */ |
175 */ |
204 uint qHash(LDColor color) |
176 uint qHash(LDColor color) |
205 { |
177 { |
206 return color.index(); |
178 return color.index(); |
207 } |
179 } |
208 |
180 |
209 /* |
181 /* |
210 * luma |
|
211 * |
|
212 * Calculates the luma-value for the given color. |
182 * Calculates the luma-value for the given color. |
213 * c.f. https://en.wikipedia.org/wiki/Luma_(video) |
183 * c.f. https://en.wikipedia.org/wiki/Luma_(video) |
214 */ |
184 */ |
215 int luma (const QColor& color) |
185 int luma(const QColor& color) |
216 { |
186 { |
217 return round((0.2126 * color.red()) + (0.7152 * color.green()) + (0.0722 * color.blue())); |
187 return static_cast<int>(round(0.2126 * color.red() + 0.7152 * color.green() + 0.0722 * color.blue())); |
218 } |
188 } |
219 |
189 |
220 /* |
190 /* |
221 * ColorData :: ColorData |
|
222 * |
|
223 * Constructs the color data array. |
191 * Constructs the color data array. |
224 */ |
192 */ |
225 ColorData::ColorData() |
193 ColorData::ColorData() |
226 { |
194 { |
227 // Initialize main and edge colors, they're special like that. |
195 // Initialize main and edge colors, they're special like that. |
228 m_data[MainColor].faceColor = "#AAAAAA"; |
196 m_data[MainColor].faceColor = "#AAAAAA"; |
229 m_data[MainColor].edgeColor = Qt::black; |
197 m_data[MainColor].edgeColor = Qt::black; |
230 m_data[MainColor].name = "Main color"; |
198 m_data[MainColor].name = "Main color"; |
231 m_data[EdgeColor].faceColor = |
199 m_data[EdgeColor].faceColor = Qt::black; |
232 m_data[EdgeColor].edgeColor = "#000000"; |
200 m_data[EdgeColor].edgeColor = Qt::black; |
233 m_data[EdgeColor].name = "Edge color"; |
201 m_data[EdgeColor].name = "Edge color"; |
234 |
202 |
235 // Load the rest from LDConfig.ldr. |
203 // Load the rest from LDConfig.ldr. |
236 loadFromLdconfig(); |
204 loadFromLdconfig(); |
237 } |
205 } |
258 |
224 |
259 return m_data[code]; |
225 return m_data[code]; |
260 } |
226 } |
261 |
227 |
262 /* |
228 /* |
263 * ColorData :: loadFromLdconfig |
|
264 * |
|
265 * Loads color information from LDConfig.ldr. |
229 * Loads color information from LDConfig.ldr. |
266 */ |
230 */ |
267 void ColorData::loadFromLdconfig() |
231 void ColorData::loadFromLdconfig() |
268 { |
232 { |
269 QString path = LDPaths::ldConfigPath(); |
233 QString path = LDPaths::ldConfigPath(); |
270 QFile file {path}; |
234 QFile file {path}; |
271 |
235 |
272 if (not file.open (QIODevice::ReadOnly)) |
236 if (not file.open(QIODevice::ReadOnly)) |
273 { |
237 { |
274 QMessageBox::critical(nullptr, "Error", "Unable to open LDConfig.ldr for parsing: " + file.errorString()); |
238 QMessageBox::critical(nullptr, "Error", "Unable to open LDConfig.ldr for parsing: " + file.errorString()); |
275 return; |
239 return; |
276 } |
240 } |
277 |
241 |
278 // TODO: maybe LDConfig can be loaded as a Document? Or would that be overkill? |
242 // TODO: maybe LDConfig can be loaded as a Document? Or would that be overkill? |
279 while (not file.atEnd()) |
243 while (not file.atEnd()) |
280 { |
244 { |
281 QString line = QString::fromUtf8 (file.readLine()); |
245 QString line = QString::fromUtf8(file.readLine()); |
282 |
246 |
283 if (line.isEmpty() or line[0] != '0') |
247 if (line.isEmpty() or line[0] != '0') |
284 continue; // empty or illogical |
248 continue; // empty or illogical |
285 |
249 |
286 line.remove('\r'); |
250 line.remove('\r'); |
298 continue; |
262 continue; |
299 |
263 |
300 // Replace underscores in the name with spaces for readability |
264 // Replace underscores in the name with spaces for readability |
301 name.replace("_", " "); |
265 name.replace("_", " "); |
302 |
266 |
303 if (not parser.parseTag ("CODE", codestring)) |
267 if (not parser.parseTag("CODE", codestring)) |
304 continue; |
268 continue; |
305 |
269 |
306 bool ok; |
270 bool ok; |
307 int code = codestring.toShort(&ok); |
271 int code = codestring.toShort(&ok); |
308 |
272 |
330 entry.faceColor.setAlpha(qBound(0, codestring.toInt(), 255)); |
294 entry.faceColor.setAlpha(qBound(0, codestring.toInt(), 255)); |
331 } |
295 } |
332 } |
296 } |
333 |
297 |
334 /* |
298 /* |
335 * LDConfigParser :: LDConfigParser |
|
336 * |
|
337 * Constructs the LDConfig.ldr parser. |
299 * Constructs the LDConfig.ldr parser. |
338 */ |
300 */ |
339 LDConfigParser::LDConfigParser(QString inputText) |
301 LDConfigParser::LDConfigParser(QString inputText) |
340 { |
302 { |
341 m_tokens = inputText.split (' ', QString::SkipEmptyParts); |
303 m_tokens = inputText.split(' ', QString::SkipEmptyParts); |
342 } |
304 } |
343 |
305 |
344 /* |
306 /* |
345 * LDConfigParser :: getToken |
|
346 * |
|
347 * Returns whether or not there is a token at the given position. |
307 * Returns whether or not there is a token at the given position. |
348 * If there is, fills in the value parameter with it. |
308 * If there is, fills in the value parameter with it. |
349 */ |
309 */ |
350 bool LDConfigParser::getToken(QString& tokenText, int position) |
310 bool LDConfigParser::getToken(QString& tokenText, int position) |
351 { |
311 { |
381 |
339 |
382 return false; |
340 return false; |
383 } |
341 } |
384 |
342 |
385 /* |
343 /* |
386 * LDConfigParser :: compareToken |
|
387 * |
|
388 * Returns whether or not the token at the given position has the given text value. |
344 * Returns whether or not the token at the given position has the given text value. |
389 */ |
345 */ |
390 bool LDConfigParser::compareToken (int position, QString text) |
346 bool LDConfigParser::compareToken(int position, QString text) |
391 { |
347 { |
392 QString token; |
348 QString token; |
393 |
349 return getToken(token, position) and (token == text); |
394 if (not getToken(token, position)) |
350 } |
395 return false; |
351 |
396 else |
352 /* |
397 return (token == text); |
|
398 } |
|
399 |
|
400 /* |
|
401 * LDConfig :: parseTag |
|
402 * |
|
403 * Finds an attribute in the line, and fills in its value. |
353 * Finds an attribute in the line, and fills in its value. |
404 * For instance, if the line contains "ALPHA 128", this function can find the "128" for "ALPHA". |
354 * For instance, if the line contains "ALPHA 128", this function can find the "128" for "ALPHA". |
405 * Returns whether or not the attribute was found. |
355 * Returns whether or not the attribute was found. |
406 */ |
356 */ |
407 bool LDConfigParser::parseTag (QString key, QString& value) |
357 bool LDConfigParser::parseTag(QString key, QString& value) |
408 { |
358 { |
409 int position; |
359 int position; |
410 |
360 |
411 // Try find the token and get its position |
361 // Try find the token and get its position |
412 if (not findToken (position, key, 1)) |
362 if (not findToken(position, key, 1)) |
413 { |
363 { |
414 return false; |
364 return false; |
415 } |
365 } |
416 else |
366 else |
417 { |
367 { |
418 // Get the token after it and store it in. |
368 // Get the token after it and store it in. |
419 return getToken (value, position + 1); |
369 return getToken(value, position + 1); |
420 } |
370 } |
421 } |
371 } |