Refactor colors.cpp/.h

Wed, 08 Jun 2022 20:41:21 +0300

author
Teemu Piippo <teemu@hecknology.net>
date
Wed, 08 Jun 2022 20:41:21 +0300
changeset 205
1a4342d80de7
parent 204
52e10e8d88cc
child 206
654661eab7f3

Refactor colors.cpp/.h

src/colors.cpp file | annotate | diff | comparison | revisions
src/colors.h file | annotate | diff | comparison | revisions
src/document.cpp file | annotate | diff | comparison | revisions
src/document.h file | annotate | diff | comparison | revisions
src/gl/compiler.cpp file | annotate | diff | comparison | revisions
src/gl/compiler.h file | annotate | diff | comparison | revisions
src/gl/partrenderer.cpp file | annotate | diff | comparison | revisions
src/gl/partrenderer.h file | annotate | diff | comparison | revisions
src/libraries.cpp file | annotate | diff | comparison | revisions
src/libraries.h file | annotate | diff | comparison | revisions
src/main.cpp file | annotate | diff | comparison | revisions
src/main.h file | annotate | diff | comparison | revisions
src/polygoncache.cpp file | annotate | diff | comparison | revisions
src/ui/canvas.cpp file | annotate | diff | comparison | revisions
src/ui/canvas.h file | annotate | diff | comparison | revisions
src/widgets/colorindexinput.cpp file | annotate | diff | comparison | revisions
src/widgets/colorindexinput.h file | annotate | diff | comparison | revisions
src/widgets/colorselectdialog.cpp file | annotate | diff | comparison | revisions
src/widgets/colorselectdialog.h file | annotate | diff | comparison | revisions
--- a/src/colors.cpp	Wed Jun 08 19:33:00 2022 +0300
+++ b/src/colors.cpp	Wed Jun 08 20:41:21 2022 +0300
@@ -1,115 +1,72 @@
-/*
- *  LDForge: LDraw parts authoring CAD
- *  Copyright (C) 2013 - 2020 Teemu Piippo
- *
- *  This program is free software: you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation, either version 3 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
 #include "colors.h"
 
-const ldraw::ColorDefinition ldraw::ColorTable::unknownColor{{}, {}, "Unknown", "???"};
+const ColorDefinition unknownColor{{}, {}, "Unknown", "???"};
 
-/**
- * @brief Clears the color table
- */
-void ldraw::ColorTable::clear()
-{
-	this->definitions = {};
-}
-
-/**
- * @brief Loads colors from LDConfig.ldr
- * @param device Opened LDConfig.ldr I/O device
- * @param errors Where to write any errors into
- * @returns whether or not it succeeded.
- */
-Result ldraw::ColorTable::load(QIODevice& device, QTextStream& errors)
+template<typename... Args>
+static QString replaced(QString text, Args&&... args)
 {
-	this->clear();
-	if (device.isReadable())
-	{
-		QTextStream stream{&device};
-		QString line;
-		while (stream.readLineInto(&line))
-		{
-			this->loadColorFromString(line);
-		}
-		return Success;
-	}
-	else
-	{
-		errors << "could not read colors";
-		return Failure;
-	}
-}
-
-/**
- * @brief Gets color information by color index.
- * @param color
- * @returns color table information
- */
-const ldraw::ColorDefinition& ldraw::ColorTable::operator[](Color color) const
-{
-	auto it = this->definitions.find(color.index);
-	if (it != this->definitions.end())
-	{
-		return it->second;
-	}
-	else
-	{
-		return unknownColor;
-	}
-}
-
-/**
- * @brief Gets the amount of elements in the color table
- * @returns int
- */
-int ldraw::ColorTable::size() const
-{
-	return this->definitions.size();
+	text.replace(args...);
+	return text;
 }
 
 /**
  * @brief Parses an LDConfig.ldr line from a string
  * @param string LDConfig.ldr line to parse
  */
-void ldraw::ColorTable::loadColorFromString(const QString& string)
+static auto loadColorFromString(const QString& string)
 {
-	const QRegExp pattern{
-		R"(^\s*0 \!COLOUR\s+([^\s]+)\s+)"_q +
-		R"(CODE\s+(\d+)\s+)"_q +
-		R"(VALUE\s+(\#[0-9a-fA-F]{3,6})\s+)"_q +
-		R"(EDGE\s+(\#[0-9a-fA-F]{3,6}))"_q +
-		R"((?:\s+ALPHA\s+(\d+))?)"_q
-	};
+	std::optional<std::pair<ColorIndex, ColorDefinition>> result;
+	static const QRegExp pattern{QStringLiteral(
+		R"(^\s*0 \!COLOUR\s+([^\s]+)\s+)"
+		R"(CODE\s+(\d+)\s+)"
+		R"(VALUE\s+(\#[0-9a-fA-F]{3,6})\s+)"
+		R"(EDGE\s+(\#[0-9a-fA-F]{3,6}))"
+		R"((?:\s+ALPHA\s+(\d+))?)"
+	)};
 	if (pattern.indexIn(string) != -1)
 	{
 		const int code = pattern.cap(2).toInt();
-		ColorDefinition& definition = this->definitions[code];
-		definition = {}; // in case there's an existing definition
-		definition.name = pattern.cap(1);
-		definition.displayName = definition.name;
-		definition.displayName.replace("_", " ");
-		definition.faceColor = pattern.cap(3);
-		definition.edgeColor = pattern.cap(4);
+		const QString name = pattern.cap(1);
+		ColorDefinition definition = {
+			.faceColor = pattern.cap(3),
+			.edgeColor = pattern.cap(4),
+			.name = name,
+			.displayName = replaced(name, "_", " "),
+		};
 		if (not pattern.cap(5).isEmpty())
 		{
 			const int alpha = pattern.cap(5).toInt();
 			definition.faceColor.setAlpha(alpha);
 		}
+		result = std::make_pair(ColorIndex{code}, definition);
 	}
+	return result;
+}
+
+/**
+ * @brief Loads colors from LDConfig.ldr
+ */
+std::optional<ColorTable> loadColorTable(QIODevice &device, QTextStream &errors)
+{
+	std::optional<ColorTable> result;
+	if (device.isReadable())
+	{
+		result.emplace();
+		QTextStream stream{&device};
+		QString line;
+		while (stream.readLineInto(&line))
+		{
+			const auto pair = loadColorFromString(line);
+			if (pair.has_value()) {
+				(*result)[pair->first] = pair->second;
+			}
+		}
+	}
+	else
+	{
+		errors << "could not read colors";
+	}
+	return result;
 }
 
 /**
@@ -118,109 +75,67 @@
  * @param color
  * @returns luma value [0, 1]
  */
-double luma(const QColor& color)
+qreal luma(const QColor& color)
 {
-	return 0.2126 * color.redF() + 0.7152 * color.greenF() + 0.0722 * color.blueF();
+	return luma(color.redF(), color.greenF(), color.blueF());
 }
 
-/**
- * @brief Returns a direct color index that codes the specified color value
- * @param color
- * @returns direct color index
- */
-ldraw::Color ldraw::directColor(const QColor& color)
+//! @brief Returns a direct color index that codes the specified color value
+ColorIndex directColor(const QColor& color)
 {
-	return ldraw::Color{0x2000000 | (color.red() << 16) | (color.green() << 8) | color.blue()};
+	return directColor(color.red(), color.green(), color.blue());
 }
 
-/**
- * @brief Checks whether or not the specified color index is a direct color
- * @param color Color to check
- * @returns bool
- */
-bool ldraw::isDirectColor(ldraw::Color color)
+//! @brief Returns a face color for @param color, taking direct colors into account
+std::optional<QColor> colorFace(ColorIndex color, const ColorTable& colorTable)
 {
-	return color.index >= 0x2000000;
+	std::optional<QColor> result;
+	if (isDirectColor(color)) {
+		const std::array<int, 3> rgb = directColorRgb(color);
+		result = QColor{rgb[0], rgb[1], rgb[2]};
+	}
+	else {
+		const ColorDefinition* def = findInMap(colorTable, color);
+		if (def != nullptr) {
+			result = def->faceColor;
+		}
+	}
+	return result;
 }
 
-/**
- * @brief Extracts the color value from a direct color index
- * @param color Direct color index
- * @returns color value. Returns a default-constructed QColor in case a non-direct color is given.
- */
-QColor ldraw::directColorFace(ldraw::Color color)
+//! @brief Returns an edge color for @param color, taking direct colors into account
+std::optional<QColor> colorEdge(ColorIndex color, const ColorTable& colorTable)
 {
-	if (isDirectColor(color))
-	{
-		return {(color.index >> 16) & 0xff, (color.index >> 8) & 0xff, color.index & 0xff};
+	if (isDirectColor(color)) {
+		const std::array<int, 3> rgb = directColorRgb(color);
+		return (luma(rgb[0], rgb[1], rgb[2]) < 0.4) ? Qt::white : Qt::black;
 	}
-	else
-	{
-		return {};
+	else {
+		return colorFace(color, colorTable);
 	}
 }
 
-/**
- * @brief Gets the face color for the specified color index
- * @param color Color index to get face color for
- * @param colorTable Color table to use for lookup
- * @returns QColor
- */
-QColor ldraw::colorFace(ldraw::Color color, const ldraw::ColorTable& colorTable)
-{
-	if (isDirectColor(color))
-	{
-		return directColorFace(color);
-	}
-	else
-	{
-		return colorTable[color].faceColor;
-	}
-}
-
-QColor ldraw::colorEdge(ldraw::Color color, const ldraw::ColorTable& colorTable)
-{
-	if (isDirectColor(color))
-	{
-		QColor const faceColor = directColorFace(color);
-		return (luma(faceColor) < 0.4) ? Qt::white : Qt::black;
-	}
-	else
-	{
-		return colorTable[color].faceColor;
-	}
-}
-
-/**
- * @brief Writes a color index into a @c QDataStream
- * @param stream
- * @param color
- * @returns stream
- */
-QDataStream& operator<<(QDataStream& stream, ldraw::Color color)
+QDataStream& operator<<(QDataStream& stream, ColorIndex color)
 {
 	return stream << color.index;
 }
 
-/**
- * @brief Reads a color index from a @c QDataStream
- * @param stream
- * @param color
- * @returns stream
- */
-QDataStream& operator>>(QDataStream& stream, ldraw::Color& color)
+QDataStream& operator>>(QDataStream& stream, ColorIndex& color)
 {
 	return stream >> color.index;
 }
 
-QString ldraw::colorDisplayName(ldraw::Color color, const ldraw::ColorTable &colorTable)
+std::optional<QString> colorDisplayName(ColorIndex color, const ColorTable &colorTable)
 {
-	if (isDirectColor(color))
-	{
-		return directColorFace(color).name();
+	std::optional<QString> result;
+	if (isDirectColor(color)) {
+		result = colorFace(color, colorTable).value_or(QColor{}).name();
 	}
-	else
-	{
-		return colorTable[color].displayName;
+	else {
+		const ColorDefinition* def = findInMap(colorTable, color);
+		if (def != nullptr) {
+			result = def->displayName;
+		}
 	}
+	return result;
 }
--- a/src/colors.h	Wed Jun 08 19:33:00 2022 +0300
+++ b/src/colors.h	Wed Jun 08 20:41:21 2022 +0300
@@ -20,19 +20,6 @@
 #include <QColor>
 #include "main.h"
 
-namespace ldraw
-{
-	struct Color;
-	struct ColorDefinition;
-	class ColorTable;
-	Color directColor(const QColor& color);
-	bool isDirectColor(Color color);
-	QColor directColorFace(Color color);
-	QColor colorFace(Color color, const ColorTable& colorTable);
-	QColor colorEdge(Color color, const ColorTable& colorTable);
-	QString colorDisplayName(Color color, const ColorTable& colorTable);
-}
-
 /**
  * @brief Represents an LDraw color index (e.g 16, 24, ...)
  * 
@@ -52,64 +39,77 @@
  * LDConfig.ldr). Since this structure only contains an integer, it should be
  * passed by value to functions instead of l-value reference.
  */
-struct ldraw::Color
+struct ColorIndex
 {
 	qint32 index = 0;
-	constexpr auto operator<=>(const Color&) const = default;
+	constexpr auto operator<=>(const ColorIndex&) const = default;
 };
 
-Q_DECLARE_METATYPE(ldraw::Color)
-QDataStream& operator<<(QDataStream&, ldraw::Color);
-QDataStream& operator>>(QDataStream&, ldraw::Color&);
-
-namespace ldraw
-{
-	static constexpr Color MAIN_COLOR {16};
-	static constexpr Color EDGE_COLOR {24};
-}
+Q_DECLARE_METATYPE(ColorIndex)
+static constexpr ColorIndex MAIN_COLOR {16};
+static constexpr ColorIndex EDGE_COLOR {24};
 
 /**
  * @brief Contains the information about a specific color
  */
-struct ldraw::ColorDefinition
+struct ColorDefinition
 {
-	/**
-	 * @brief The face color. This is the color used for most objects.
-	 * This is also used for the polygons of a subfile reference.
-	 */
+	//! @brief The face color. This is the color used for most objects.
 	QColor faceColor;
-	/**
-	 * @brief The edge color, used for the edge lines of a subfile reference.
-	 * Note that edges using a color actually use the face color. LDraw standards
-	 * require edges to use color 24, however.
-	 */
+	//! @brief The edge color, used for the edge lines of a subfile reference.
+	//! Note that edges using a color actually use the face color. LDraw standards
+	//! require edges to use color 24, however.
 	QColor edgeColor;
-	/**
-	 * @brief Name of the color
-	 */
+	//! @brief Name of the color
 	QString name;
-	/**
-	 * @brief A version of the name that can be shown to the user.
-	 */
+	//! @brief A version of the name that can be shown to the user.
 	QString displayName;
 };
 
-/**
- * @brief Reads LDConfig.ldr and contains color table information for lookup purposes.
- */
-class ldraw::ColorTable
+//extern const ColorDefinition unknownColor;
+using ColorTable = std::map<ColorIndex, ColorDefinition>;
+std::optional<ColorTable> loadColorTable(QIODevice& device, QTextStream& errors);
+qreal luma(const QColor& color);
+ColorIndex directColor(const QColor& color);
+std::optional<QColor> colorFace(ColorIndex color, const ColorTable& colorTable);
+std::optional<QColor> colorEdge(ColorIndex color, const ColorTable& colorTable);
+std::optional<QString> colorDisplayName(ColorIndex color, const ColorTable& colorTable);
+QDataStream& operator<<(QDataStream&, ColorIndex);
+QDataStream& operator>>(QDataStream&, ColorIndex&);
+
+//! @brief Calculates the luma-value for the given color.
+//! @details c.f. https://en.wikipedia.org/wiki/Luma_(video)
+template<typename T>
+constexpr T luma(T r, T g, T b)
+{
+	return 0.2126 * r + 0.7152 * g + 0.0722 * b;
+}
+
+//! @brief Checks whether or not the specified color index is a direct color
+constexpr bool isDirectColor(ColorIndex color)
 {
-public:
-	void clear();
-	Result load(QIODevice& device, QTextStream& errors);
-	const ColorDefinition& operator[](Color index) const;
-	static const ColorDefinition unknownColor;
-	auto begin() const { return this->definitions.begin(); }
-	auto end() const { return this->definitions.end(); }
-	int size() const;
-private:
-	void loadColorFromString(const QString& string);
-	std::map<qint32, ColorDefinition> definitions;
-};
+	return color.index >= 0x2000000;
+}
+
+//! @brief Returns a direct color index that codes the specified color value
+constexpr ColorIndex directColor(int r, int g, int b)
+{
+	return ColorIndex{0x2000000 | (r << 16) | (g << 8) | b};
+}
 
-double luma(const QColor& color);
+//! @brief Extracts the r, g and b color channel values from a direct color
+//! index. Returns a default-constructed QColor in case a non-direct color is
+//! given.
+constexpr std::array<int, 3> directColorRgb(ColorIndex color)
+{
+	return {
+		(color.index >> 16) & 0xff,
+		(color.index >> 8) & 0xff,
+		color.index & 0xff
+	};
+}
+
+namespace ldraw
+{
+	using Color = ColorIndex;
+}
--- a/src/document.cpp	Wed Jun 08 19:33:00 2022 +0300
+++ b/src/document.cpp	Wed Jun 08 20:41:21 2022 +0300
@@ -26,7 +26,7 @@
 EditorTabWidget::EditorTabWidget(
 	Model* model,
 	DocumentManager* documents,
-	const ldraw::ColorTable& colorTable,
+	const ColorTable& colorTable,
 	QWidget* parent) :
 	QWidget{parent},
 	colorTable{colorTable},
@@ -188,7 +188,7 @@
 						.p1 = this->drawState.polygon[0],
 						.p2 = this->drawState.polygon[1],
 					},
-					ldraw::EDGE_COLOR,
+					EDGE_COLOR,
 				}
 			});
 			break;
@@ -200,7 +200,7 @@
 						.p2 = this->drawState.polygon[1],
 						.p3 = this->drawState.polygon[2],
 					},
-					ldraw::MAIN_COLOR,
+					MAIN_COLOR,
 				}
 			});
 			break;
@@ -213,7 +213,7 @@
 						.p3 = this->drawState.polygon[2],
 						.p4 = this->drawState.polygon[3],
 					},
-					ldraw::MAIN_COLOR,
+					MAIN_COLOR,
 				}
 			});
 			break;
--- a/src/document.h	Wed Jun 08 19:33:00 2022 +0300
+++ b/src/document.h	Wed Jun 08 20:41:21 2022 +0300
@@ -45,12 +45,12 @@
 	explicit EditorTabWidget(
 		Model* model,
 		DocumentManager* documents,
-		const ldraw::ColorTable& colorTable,
+		const ColorTable& colorTable,
 		QWidget *parent = nullptr);
 	~EditorTabWidget() override;
 	void applyToVertices(VertexMap::ApplyFunction fn) const;
 	const QSet<ModelId> selectedObjects() const;
-	const ldraw::ColorTable& colorTable;
+	const ColorTable& colorTable;
 	Canvas* const canvas;
 	Model* const model;
 	EditingMode currentEditingMode() const;
--- a/src/gl/compiler.cpp	Wed Jun 08 19:33:00 2022 +0300
+++ b/src/gl/compiler.cpp	Wed Jun 08 20:41:21 2022 +0300
@@ -232,15 +232,15 @@
 static QColor getColorForPolygon(
 	const gl::Polygon& polygon,
 	const gl::RenderPreferences& preferences,
-	const ldraw::ColorTable& colorTable)
+	const ColorTable& colorTable)
 {
 	QColor color;
 	// For normal colors, use the polygon's color.
-	if (polygon.color == ldraw::MAIN_COLOR)
+	if (polygon.color == MAIN_COLOR)
 	{
 		color = preferences.mainColor;
 	}
-	else if (polygon.color == ldraw::EDGE_COLOR)
+	else if (polygon.color == EDGE_COLOR)
 	{
 		// Edge color is black, unless we have a dark background, in which case lines need to be bright.
 		color = luma(preferences.backgroundColor) > (40.0 / 256.0) ? Qt::black : Qt::white;
@@ -248,7 +248,7 @@
 	else
 	{
 		// Not main or edge color, use the polygon's color as is.
-		color = colorTable[polygon.color].faceColor;
+		color = colorFace(polygon.color, colorTable).value_or(Qt::black);
 	}
 	return color;
 }
@@ -275,7 +275,7 @@
 void gl::build(
 	gl::ModelShaders* shaders,
 	Model* model,
-	const ldraw::ColorTable& colorTable,
+	const ColorTable& colorTable,
 	DocumentManager* context,
 	const gl::RenderPreferences& preferences)
 {
--- a/src/gl/compiler.h	Wed Jun 08 19:33:00 2022 +0300
+++ b/src/gl/compiler.h	Wed Jun 08 20:41:21 2022 +0300
@@ -59,7 +59,7 @@
 	void build(
 		ModelShaders* shaders,
 		Model *model,
-		const ldraw::ColorTable& colorTable,
+		const ColorTable& colorTable,
 		DocumentManager* context,
 		const RenderPreferences& preferences);
 	void initializeModelShaders(ModelShaders* modelShaders);
--- a/src/gl/partrenderer.cpp	Wed Jun 08 19:33:00 2022 +0300
+++ b/src/gl/partrenderer.cpp	Wed Jun 08 20:41:21 2022 +0300
@@ -34,7 +34,7 @@
 PartRenderer::PartRenderer(
 	Model* model,
 	DocumentManager* documents,
-	const ldraw::ColorTable& colorTable,
+	const ColorTable& colorTable,
 	QWidget* parent) :
 	QOpenGLWidget{parent},
 	model{model},
--- a/src/gl/partrenderer.h	Wed Jun 08 19:33:00 2022 +0300
+++ b/src/gl/partrenderer.h	Wed Jun 08 20:41:21 2022 +0300
@@ -13,7 +13,7 @@
 	PartRenderer(
 		Model* model,
 		DocumentManager* documents,
-		const ldraw::ColorTable& colorTable,
+		const ColorTable& colorTable,
 		QWidget* parent = nullptr);
 	~PartRenderer() override;
 	void setRenderPreferences(const gl::RenderPreferences& newPreferences);
@@ -27,7 +27,7 @@
 	void wheelEvent(QWheelEvent* event) override;
 	Model* const model;
 	DocumentManager* const documents;
-	const ldraw::ColorTable& colorTable;
+	const ColorTable& colorTable;
 	BoundingBox boundingBox;
 	gl::ModelShaders shaders;
 	ModelId highlighted = {0};
--- a/src/libraries.cpp	Wed Jun 08 19:33:00 2022 +0300
+++ b/src/libraries.cpp	Wed Jun 08 20:41:21 2022 +0300
@@ -220,16 +220,20 @@
  * @param errors Where to stream any encountered errors
  * @return color table
  */
-ldraw::ColorTable LibraryManager::loadColorTable(QTextStream& errors) const
+ColorTable LibraryManager::loadColorTable(QTextStream& errors) const
 {
-	ldraw::ColorTable result;
+	ColorTable result;
 	for (const Library& library : this->libraries)
 	{
 		const QString path = library.path.filePath("LDConfig.ldr");
 		QFile file{path};
 		if (file.open(QIODevice::ReadOnly | QIODevice::Text))
 		{
-			(void) result.load(file, errors);
+			const auto loadedTable = ::loadColorTable(file, errors);
+			if (loadedTable) {
+				result = std::move(*loadedTable);
+			}
+			break;
 		}
 	}
 	return result;
--- a/src/libraries.h	Wed Jun 08 19:33:00 2022 +0300
+++ b/src/libraries.h	Wed Jun 08 20:41:21 2022 +0300
@@ -78,7 +78,7 @@
 	int rowCount(const QModelIndex&) const override;
 	int columnCount(const QModelIndex&) const override;
 	bool isValidIndex(const int libraryIndex) const;
-	ldraw::ColorTable loadColorTable(QTextStream& errors) const;
+	ColorTable loadColorTable(QTextStream& errors) const;
 private:
 	enum Column
 	{
--- a/src/main.cpp	Wed Jun 08 19:33:00 2022 +0300
+++ b/src/main.cpp	Wed Jun 08 20:41:21 2022 +0300
@@ -170,7 +170,7 @@
 	return title;
 }
 
-static ldraw::ColorTable loadColors(const LibraryManager* libraries)
+static ColorTable loadColors(const LibraryManager* libraries)
 {
 	QTextStream errors;
 	return libraries->loadColorTable(errors);
@@ -292,7 +292,7 @@
 	LibraryManager libraries{&mainWindow};
 	QByteArray documentSplitterState;
 	QStringList recentlyOpenedFiles;
-	ldraw::ColorTable colorTable;
+	ColorTable colorTable;
 	gl::RenderPreferences renderPreferences;
 	QMap<Model*, QItemSelectionModel*> itemSelectionModels;
 	ui.setupUi(&mainWindow);
--- a/src/main.h	Wed Jun 08 19:33:00 2022 +0300
+++ b/src/main.h	Wed Jun 08 20:41:21 2022 +0300
@@ -265,6 +265,9 @@
 	}
 }
 
+template<typename T>
+using opt = std::optional<T>;
+
 // some magic code from https://en.cppreference.com/w/cpp/utility/variant/visit
 // for use with std::visit
 template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
--- a/src/polygoncache.cpp	Wed Jun 08 19:33:00 2022 +0300
+++ b/src/polygoncache.cpp	Wed Jun 08 20:41:21 2022 +0300
@@ -61,7 +61,7 @@
 						{
 							gl::invert(polygon);
 						}
-						if (polygon.color == ldraw::MAIN_COLOR)
+						if (polygon.color == MAIN_COLOR)
 						{
 							polygon.color = ref.color;
 						}
--- a/src/ui/canvas.cpp	Wed Jun 08 19:33:00 2022 +0300
+++ b/src/ui/canvas.cpp	Wed Jun 08 20:41:21 2022 +0300
@@ -7,7 +7,7 @@
 	Model* model,
 	EditorTabWidget *document,
 	DocumentManager* documents,
-	const ldraw::ColorTable& colorTable,
+	const ColorTable& colorTable,
 	QWidget* parent) :
 	PartRenderer{model, documents, colorTable, parent},
 	document{document}
--- a/src/ui/canvas.h	Wed Jun 08 19:33:00 2022 +0300
+++ b/src/ui/canvas.h	Wed Jun 08 20:41:21 2022 +0300
@@ -32,7 +32,7 @@
 		Model* model,
 		EditorTabWidget* document,
 		DocumentManager* documents,
-		const ldraw::ColorTable& colorTable,
+		const ColorTable& colorTable,
 		QWidget* parent = nullptr);
 	void setOverpaintCallback(OverpaintCallback fn);
 	void drawWorldPoint(QPainter* painter, const glm::vec3& worldPoint) const;
--- a/src/widgets/colorindexinput.cpp	Wed Jun 08 19:33:00 2022 +0300
+++ b/src/widgets/colorindexinput.cpp	Wed Jun 08 20:41:21 2022 +0300
@@ -3,7 +3,7 @@
 #include "colorselectdialog.h"
 #include "uiutilities.h"
 
-ColorIndexInput::ColorIndexInput(EditorTabWidget *document, ldraw::Color color, QWidget *parent) :
+ColorIndexInput::ColorIndexInput(EditorTabWidget *document, ColorIndex color, QWidget *parent) :
 	QWidget{parent},
 	document{document},
 	ui{*new Ui_ColorIndexInput}
@@ -20,8 +20,11 @@
 	});
 	connect(this->ui.index, qOverload<int>(&QSpinBox::valueChanged), [this](int value)
 	{
-		this->ui.button->setText(ldraw::colorDisplayName({value}, this->document->colorTable));
-		uiutilities::colorizeWidget(this->ui.button, ldraw::colorFace({value}, this->document->colorTable));
+		this->ui.button->setText(colorDisplayName({value}, this->document->colorTable).value_or("???"));
+		const opt<QColor> face = colorFace({value}, this->document->colorTable);
+		if (face.has_value()) {
+			uiutilities::colorizeWidget(this->ui.button, *face);
+		}
 		Q_EMIT this->colorChanged({value});
 	});
 	this->ui.index->setValue(color.index);
--- a/src/widgets/colorindexinput.h	Wed Jun 08 19:33:00 2022 +0300
+++ b/src/widgets/colorindexinput.h	Wed Jun 08 20:41:21 2022 +0300
@@ -5,7 +5,7 @@
 {
 	Q_OBJECT
 public:
-	ColorIndexInput(EditorTabWidget *document, ldraw::Color color = ldraw::MAIN_COLOR, QWidget *parent = nullptr);
+	ColorIndexInput(EditorTabWidget *document, ColorIndex color = MAIN_COLOR, QWidget *parent = nullptr);
 	~ColorIndexInput();
 	ldraw::Color selectedColor() const;
 	void setSelectedColor(ldraw::Color color);
--- a/src/widgets/colorselectdialog.cpp	Wed Jun 08 19:33:00 2022 +0300
+++ b/src/widgets/colorselectdialog.cpp	Wed Jun 08 20:41:21 2022 +0300
@@ -5,7 +5,7 @@
 #include "ui_colorselectdialog.h"
 #include "uiutilities.h"
 
-ColorSelectDialog::ColorSelectDialog(const ldraw::ColorTable& colorTable, QWidget *parent) :
+ColorSelectDialog::ColorSelectDialog(const ColorTable& colorTable, QWidget *parent) :
 	QDialog{parent},
 	ui{*new Ui_ColorSelectDialog},
 	colorTable{colorTable}
@@ -39,12 +39,13 @@
 		iterator != std::end(this->colorTable);
 		++iterator
 	) {
-		const qint32 index = iterator->first;
-		const ldraw::ColorDefinition& colordef = iterator->second;
+		const qint32 index = iterator->first.index;
+		const ColorDefinition& colordef = iterator->second;
 		QPushButton* const button = new QPushButton{QString::number(index), this};
 		button->setMinimumSize({40, 40});
 		button->setToolTip(colordef.displayName);
-		uiutilities::colorizeWidget(button, ldraw::colorFace({index}, colorTable));
+		const QColor face = colorFace({index}, colorTable).value_or(QColor{});
+		uiutilities::colorizeWidget(button, face);
 		button->setProperty("_colorIndex", index);
 		button->setCheckable(true);
 		connect(button, &QAbstractButton::clicked, this, &ColorSelectDialog::handleButtonClick);
@@ -90,8 +91,10 @@
 
 void ColorSelectDialog::updateSelectedColorTexts()
 {
-	this->ui.selectedColorName->setText(ldraw::colorDisplayName(this->selectedColor, this->colorTable));
-	uiutilities::colorizeWidget(this->ui.selectedColorName, ldraw::colorFace(this->selectedColor, colorTable));
+	const QString displayName = colorDisplayName(this->selectedColor, this->colorTable).value_or(QStringLiteral("???"));
+	this->ui.selectedColorName->setText(displayName);
+	const QColor face = colorFace(this->selectedColor, colorTable).value_or(QColor{});
+	uiutilities::colorizeWidget(this->ui.selectedColorName, face);
 	this->ui.colorIndex->setValue(this->selectedColor.index);
 	for (QPushButton* button : this->buttons)
 	{
@@ -117,10 +120,13 @@
 void ColorSelectDialog::chooseDirectColor()
 {
 	QColorDialog dialog;
-	dialog.setCurrentColor(ldraw::colorFace(this->selectedColor, this->colorTable));
+	const std::optional<QColor> face = colorFace(this->selectedColor, this->colorTable);
+	if (face.has_value()) {
+		dialog.setCurrentColor(*face);
+	}
 	if (dialog.exec())
 	{
-		this->setCurrentColor(ldraw::directColor(dialog.selectedColor()));
+		this->setCurrentColor(directColor(dialog.selectedColor()));
 	}
 }
 
@@ -133,12 +139,12 @@
 	}
 	else
 	{
-		const ldraw::ColorDefinition& colordef = this->colorTable[color];
-		return colordef.displayName.contains(filterText, Qt::CaseInsensitive);
+		const std::optional<QString> name = colorDisplayName(color, colorTable);
+		return name.value_or(QString{}).contains(filterText, Qt::CaseInsensitive);
 	}
 }
 
-void ColorSelectDialog::setCurrentColor(ldraw::Color color)
+void ColorSelectDialog::setCurrentColor(ColorIndex color)
 {
 	this->selectedColor = color;
 	this->updateSelectedColorTexts();
--- a/src/widgets/colorselectdialog.h	Wed Jun 08 19:33:00 2022 +0300
+++ b/src/widgets/colorselectdialog.h	Wed Jun 08 20:41:21 2022 +0300
@@ -10,9 +10,9 @@
 {
 	Q_OBJECT
 public:
-	explicit ColorSelectDialog(const ldraw::ColorTable& colorTable, QWidget* parent = nullptr);
+	explicit ColorSelectDialog(const ColorTable& colorTable, QWidget* parent = nullptr);
 	~ColorSelectDialog();
-	void setCurrentColor(ldraw::Color color);
+	void setCurrentColor(ColorIndex color);
 	ldraw::Color currentColor() const;
 private Q_SLOTS:
 	void populateColors();
@@ -24,7 +24,7 @@
 	void makeColorButtons();
 	bool filterColor(ldraw::Color color) const;
 	class Ui_ColorSelectDialog& ui;
-	const ldraw::ColorTable& colorTable;
+	const ColorTable& colorTable;
 	std::vector<QPushButton*> buttons;
-	ldraw::Color selectedColor = ldraw::MAIN_COLOR;
+	ColorIndex selectedColor = MAIN_COLOR;
 };

mercurial