added a color select dialog

Mon, 21 Sep 2020 19:48:18 +0300

author
Teemu Piippo <teemu@hecknology.net>
date
Mon, 21 Sep 2020 19:48:18 +0300
changeset 94
164f53fb5921
parent 93
6fe24fd945c0
child 95
06a1aef170aa

added a color select dialog

CMakeLists.txt file | annotate | diff | comparison | revisions
src/colors.cpp file | annotate | diff | comparison | revisions
src/colors.h file | annotate | diff | comparison | revisions
src/document.ui file | annotate | diff | comparison | revisions
src/mainwindow.cpp file | annotate | diff | comparison | revisions
src/widgets/colorselectdialog.cpp file | annotate | diff | comparison | revisions
--- a/CMakeLists.txt	Mon Aug 24 23:02:30 2020 +0300
+++ b/CMakeLists.txt	Mon Sep 21 19:48:18 2020 +0300
@@ -18,13 +18,13 @@
 find_package(OpenGL REQUIRED)
 include_directories(${QT_INCLUDES} ${CMAKE_CURRENT_BINARY_DIR})
 include_directories(${GLM_INCLUDE_DIR})
-source_group("1 Foundation code" REGULAR_EXPRESSION "src/.+\\.(cpp|h)")
-source_group("4 OpenGL renderer" REGULAR_EXPRESSION "src/gl/.+\\.(cpp|h)")
-source_group("5 LDraw line types" REGULAR_EXPRESSION "src/linetypes/.+\\.(cpp|h)")
-source_group("3 UI and widgets" REGULAR_EXPRESSION "src/(ui|widgets)/.+\\.(cpp|h)")
-source_group("3.1 Settings editor" REGULAR_EXPRESSION "src/settingseditor/.+\\.(cpp|h)")
-source_group("3.2 Main UI" REGULAR_EXPRESSION "src/(mainwindow|document|documentmanager|uiutilities)\\.(cpp|h)")
-source_group("2 Model handling" REGULAR_EXPRESSION "src/(model|modeleditcontext|libraries|colors|parser)\\.(cpp|h)")
+source_group("1 Foundation code" REGULAR_EXPRESSION "src/.+\\.(cpp|h|ui)")
+source_group("4 OpenGL renderer" REGULAR_EXPRESSION "src/gl/.+\\.(cpp|h|ui)")
+source_group("5 LDraw line types" REGULAR_EXPRESSION "src/linetypes/.+\\.(cpp|h|ui)")
+source_group("3.2 Widgets" REGULAR_EXPRESSION "src/(ui|widgets)/.+\\.(cpp|h|ui)")
+source_group("3.1 Settings editor" REGULAR_EXPRESSION "src/settingseditor/.+\\.(cpp|h|ui)")
+source_group("3 User interface" REGULAR_EXPRESSION "src/(mainwindow|document|documentmanager|uiutilities)\\.(cpp|h|ui)")
+source_group("2 Model handling" REGULAR_EXPRESSION "src/(model|modeleditcontext|libraries|colors|parser)\\.(cpp|h|ui)")
 
 set (LDFORGE_SOURCES
 	src/colors.cpp
@@ -63,6 +63,7 @@
 	src/ui/objecteditor.cpp
 	src/ui/polygonobjecteditor.cpp
 	src/widgets/colorbutton.cpp
+	src/widgets/colorselectdialog.cpp
 	src/widgets/doublespinbox.cpp
 	src/widgets/matrixeditor.cpp
 	src/widgets/vec3editor.cpp
@@ -113,6 +114,7 @@
 	src/ui/objecteditor.h
 	src/ui/polygonobjecteditor.h
 	src/widgets/colorbutton.h
+	src/widgets/colorselectdialog.h
 	src/widgets/doublespinbox.h
 	src/widgets/matrixeditor.h
 	src/widgets/vec3editor.h
@@ -123,6 +125,7 @@
 	src/settingseditor/librarieseditor.ui
 	src/settingseditor/settingseditor.ui
 	src/ui/multiplyfactordialog.ui
+	src/widgets/colorselectdialog.ui
 	src/widgets/matrixeditor.ui
 	src/widgets/vec3editor.ui
 )
--- a/src/colors.cpp	Mon Aug 24 23:02:30 2020 +0300
+++ b/src/colors.cpp	Mon Sep 21 19:48:18 2020 +0300
@@ -18,7 +18,7 @@
 
 #include "colors.h"
 
-const ldraw::ColorTable::ColorDefinition ldraw::ColorTable::unknownColor{{}, {}, "Unknown"};
+const ldraw::ColorTable::ColorDefinition ldraw::ColorTable::unknownColor{{}, {}, "Unknown", "???"};
 
 void ldraw::ColorTable::clear()
 {
@@ -50,7 +50,7 @@
 	auto it = this->definitions.find(color.index);
 	if (it != this->definitions.end())
 	{
-		return *it;
+		return it->second;
 	}
 	else
 	{
@@ -73,6 +73,8 @@
 		ColorDefinition& definition = 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);
 		if (not pattern.cap(5).isEmpty())
@@ -91,3 +93,37 @@
 {
 	return 0.2126 * color.redF() + 0.7152 * color.greenF() + 0.0722 * color.blueF();
 }
+
+ldraw::Color ldraw::directColor(const QColor& color)
+{
+	return ldraw::Color{0x2000000 | (color.red() << 16) | (color.green() << 8) | color.blue()};
+}
+
+bool ldraw::isDirectColor(ldraw::Color color)
+{
+	return color.index >= 0x2000000;
+}
+
+QColor ldraw::directColorFace(ldraw::Color color)
+{
+	if (isDirectColor(color))
+	{
+		return {(color.index >> 16) & 0xff, (color.index >> 8) & 0xff, color.index & 0xff};
+	}
+	else
+	{
+		return {};
+	}
+}
+
+QColor ldraw::colorFace(ldraw::Color color, const ldraw::ColorTable& colorTable)
+{
+	if (isDirectColor(color))
+	{
+		return directColorFace(color);
+	}
+	else
+	{
+		return colorTable[color].faceColor;
+	}
+}
--- a/src/colors.h	Mon Aug 24 23:02:30 2020 +0300
+++ b/src/colors.h	Mon Sep 21 19:48:18 2020 +0300
@@ -24,6 +24,10 @@
 {
 	struct Color;
 	class ColorTable;
+	Color directColor(const QColor& color);
+	bool isDirectColor(Color color);
+	QColor directColorFace(Color color);
+	QColor colorFace(Color color, const ColorTable& colorTable);
 }
 
 struct ldraw::Color
@@ -41,14 +45,18 @@
 		QColor faceColor;
 		QColor edgeColor;
 		QString name;
+		QString displayName;
 	};
 	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 { return this->definitions.size(); }
 private:
 	void loadColorFromString(const QString& string);
-	QMap<qint32, ColorDefinition> definitions;
+	std::map<qint32, ColorDefinition> definitions;
 };
 
 namespace ldraw
--- a/src/document.ui	Mon Aug 24 23:02:30 2020 +0300
+++ b/src/document.ui	Mon Sep 21 19:48:18 2020 +0300
@@ -15,28 +15,33 @@
   </property>
   <layout class="QVBoxLayout" name="verticalLayout">
    <item>
-    <widget class="QSplitter" name="splitter">
+    <widget class="QSplitter" name="splitter_2">
      <property name="orientation">
-      <enum>Qt::Horizontal</enum>
+      <enum>Qt::Vertical</enum>
      </property>
-     <widget class="QFrame" name="viewportFrame">
-      <property name="frameShape">
-       <enum>QFrame::StyledPanel</enum>
-      </property>
-      <property name="frameShadow">
-       <enum>QFrame::Raised</enum>
+     <widget class="QSplitter" name="splitter">
+      <property name="orientation">
+       <enum>Qt::Horizontal</enum>
       </property>
-     </widget>
-     <widget class="QListView" name="listView">
-      <property name="alternatingRowColors">
-       <bool>true</bool>
-      </property>
-      <property name="selectionMode">
-       <enum>QAbstractItemView::ExtendedSelection</enum>
-      </property>
-      <property name="selectionBehavior">
-       <enum>QAbstractItemView::SelectRows</enum>
-      </property>
+      <widget class="QFrame" name="viewportFrame">
+       <property name="frameShape">
+        <enum>QFrame::StyledPanel</enum>
+       </property>
+       <property name="frameShadow">
+        <enum>QFrame::Raised</enum>
+       </property>
+      </widget>
+      <widget class="QListView" name="listView">
+       <property name="alternatingRowColors">
+        <bool>true</bool>
+       </property>
+       <property name="selectionMode">
+        <enum>QAbstractItemView::ExtendedSelection</enum>
+       </property>
+       <property name="selectionBehavior">
+        <enum>QAbstractItemView::SelectRows</enum>
+       </property>
+      </widget>
      </widget>
      <widget class="QFrame" name="objectEditorFrame">
       <property name="frameShape">
--- a/src/mainwindow.cpp	Mon Aug 24 23:02:30 2020 +0300
+++ b/src/mainwindow.cpp	Mon Sep 21 19:48:18 2020 +0300
@@ -27,6 +27,7 @@
 #include "version.h"
 #include "document.h"
 #include "uiutilities.h"
+#include "widgets/colorselectdialog.h"
 
 template<typename BaseType, typename MemberType, typename DataType>
 struct MemberData
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/widgets/colorselectdialog.cpp	Mon Sep 21 19:48:18 2020 +0300
@@ -0,0 +1,158 @@
+#include <QColorDialog>
+#include <QTableView>
+#include "colorselectdialog.h"
+#include "ui_colorselectdialog.h"
+
+ColorSelectDialog::ColorSelectDialog(const ldraw::ColorTable& colorTable, QWidget *parent) :
+	QDialog{parent},
+	ui{*new Ui_ColorSelectDialog},
+	colorTable{colorTable}
+{
+	this->ui.setupUi(this);
+	this->makeColorButtons();
+	connect(this->ui.filter, &QLineEdit::textEdited, this, &ColorSelectDialog::populateColors);
+	this->updateSelectedColorTexts();
+	connect(this->ui.colorIndex, qOverload<int>(&QSpinBox::valueChanged), this, &ColorSelectDialog::spinboxEdited);
+	connect(this->ui.directColorButton, &QPushButton::clicked, this, &ColorSelectDialog::chooseDirectColor);
+	connect(this->ui.buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
+	connect(this->ui.buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
+	this->populateColors();
+}
+
+ColorSelectDialog::~ColorSelectDialog()
+{
+	delete &this->ui;
+}
+
+ldraw::Color colorFromButton(QAbstractButton* button)
+{
+	return {button->property("_colorIndex").value<qint32>()};
+}
+
+QString styleSheetForColor(const QColor& color)
+{
+	QColor const textColor = (luma(color) < 0.4) ? Qt::white : Qt::black;
+	return QString{"background-color: %1; color: %2;"}
+		.arg(color.name())
+		.arg(textColor.name());
+}
+
+void ColorSelectDialog::makeColorButtons()
+{
+	this->buttons.reserve(this->colorTable.size());
+	for (
+		auto iterator = std::begin(this->colorTable);
+		iterator != std::end(this->colorTable);
+		++iterator
+	) {
+		const qint32 index = iterator->first;
+		const ldraw::ColorTable::ColorDefinition& colordef = iterator->second;
+		QPushButton* const button = new QPushButton{QString::number(index), this};
+		button->setToolTip(colordef.displayName);
+		button->setStyleSheet(styleSheetForColor(colordef.faceColor));
+		button->setProperty("_colorIndex", index);
+		button->setCheckable(true);
+		connect(button, &QAbstractButton::clicked, this, &ColorSelectDialog::handleButtonClick);
+		this->buttons.push_back(button);
+	}
+	std::sort(
+		std::begin(this->buttons),
+		std::end(this->buttons),
+		[](QAbstractButton* button_1, QAbstractButton* button_2)
+		{
+			return colorFromButton(button_1) < colorFromButton(button_2);
+		}
+	);
+}
+
+void ColorSelectDialog::populateColors()
+{
+	delete this->ui.colorFrame->layout();
+	if (this->buttons.size() > 0)
+	{
+		QGridLayout* gridLayout = new QGridLayout{};
+		this->ui.colorFrame->setLayout(gridLayout);
+		const int columnsPerRow = 8;
+		int i = 0;
+		for (
+			auto iterator = std::begin(this->buttons);
+			iterator != std::end(this->buttons);
+			++iterator
+		) {
+			QPushButton* const button = *iterator;
+			const bool filtered = this->filterColor(colorFromButton(button));
+			button->setVisible(filtered);
+			if (filtered)
+			{
+				const int row = i / columnsPerRow;
+				const int column = i % columnsPerRow;
+				gridLayout->addWidget(button, row, column);
+				i += 1;
+			}
+		}
+	}
+}
+
+void ColorSelectDialog::updateSelectedColorTexts()
+{
+	if (ldraw::isDirectColor(this->selectedColor))
+	{
+		this->ui.selectedColorName->setText(ldraw::directColorFace(this->selectedColor).name());
+	}
+	else
+	{
+		const ldraw::ColorTable::ColorDefinition& colordef = this->colorTable[this->selectedColor];
+		this->ui.selectedColorName->setText(colordef.displayName);
+	}
+	this->ui.selectedColorName->setStyleSheet(styleSheetForColor(ldraw::colorFace(this->selectedColor, this->colorTable)));
+	this->ui.colorIndex->setValue(this->selectedColor.index);
+	for (QPushButton* button : this->buttons)
+	{
+		ldraw::Color buttonColor = colorFromButton(button);
+		button->setChecked(buttonColor == this->selectedColor);
+	}
+}
+
+void ColorSelectDialog::handleButtonClick()
+{
+	QAbstractButton* button = qobject_cast<QAbstractButton*>(this->sender());
+	if (button != nullptr)
+	{
+		this->setCurrentColor(colorFromButton(button));
+	}
+}
+
+void ColorSelectDialog::spinboxEdited()
+{
+	this->setCurrentColor(ldraw::Color{this->ui.colorIndex->value()});
+}
+
+void ColorSelectDialog::chooseDirectColor()
+{
+	QColorDialog dialog;
+	dialog.setCurrentColor(ldraw::colorFace(this->selectedColor, this->colorTable));
+	if (dialog.exec())
+	{
+		this->setCurrentColor(ldraw::directColor(dialog.selectedColor()));
+	}
+}
+
+bool ColorSelectDialog::filterColor(ldraw::Color color) const
+{
+	const QString& filterText = this->ui.filter->text();
+	if (filterText.isEmpty())
+	{
+		return true;
+	}
+	else
+	{
+		const ldraw::ColorTable::ColorDefinition& colordef = this->colorTable[color];
+		return colordef.displayName.contains(filterText, Qt::CaseInsensitive);
+	}
+}
+
+void ColorSelectDialog::setCurrentColor(ldraw::Color color)
+{
+	this->selectedColor = color;
+	this->updateSelectedColorTexts();
+}

mercurial