Main color is now configurable

Sat, 01 Feb 2020 17:10:11 +0200

author
Teemu Piippo <teemu@hecknology.net>
date
Sat, 01 Feb 2020 17:10:11 +0200
changeset 39
caac957e9834
parent 38
bb60dda3093f
child 40
30cb5e836736

Main color is now configurable

CMakeLists.txt file | annotate | diff | comparison | revisions
locale/fi.ts file | annotate | diff | comparison | revisions
locale/sv.ts file | annotate | diff | comparison | revisions
src/document.cpp file | annotate | diff | comparison | revisions
src/document.h file | annotate | diff | comparison | revisions
src/gl/common.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/mainwindow.cpp file | annotate | diff | comparison | revisions
src/mainwindow.h file | annotate | diff | comparison | revisions
src/settingseditor/settingseditor.cpp file | annotate | diff | comparison | revisions
src/settingseditor/settingseditor.ui file | annotate | diff | comparison | revisions
src/widgets/colorbutton.cpp file | annotate | diff | comparison | revisions
src/widgets/colorbutton.h file | annotate | diff | comparison | revisions
--- a/CMakeLists.txt	Sat Feb 01 15:49:28 2020 +0200
+++ b/CMakeLists.txt	Sat Feb 01 17:10:11 2020 +0200
@@ -49,6 +49,7 @@
 	src/settingseditor/librarieseditor.cpp
 	src/settingseditor/settingseditor.cpp
 	src/types/boundingbox.cpp
+	src/widgets/colorbutton.cpp
 )
 set (LDFORGE_HEADERS
 	src/basics.h
@@ -84,6 +85,7 @@
 	src/settingseditor/librarieseditor.h
 	src/settingseditor/settingseditor.h
 	src/types/boundingbox.h
+	src/widgets/colorbutton.h
 )
 set (LDFORGE_FORMS
 	src/document.ui
@@ -98,18 +100,18 @@
 )
 
 set(LDFORGE_RESOURCES ldforge.qrc)
+set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+set(CMAKE_CXX_EXTENSIONS OFF)
+include_directories("${PROJECT_BINARY_DIR}")
+include_directories("${PROJECT_BINARY_DIR}/src")
+include_directories("${PROJECT_SOURCE_DIR}/src")
 
 # Translations
 qt5_create_translation(QM_FILES ${LDFORGE_SOURCES} ${LDFORGE_HEADERS} ${LDFORGE_FORMS} ${LDFORGE_LOCALES})
 add_custom_target(translations ALL DEPENDS ${QM_FILES})
 add_custom_target(resources ALL DEPENDS ${LDFORGE_RESOURCES})
 
-set(CMAKE_CXX_STANDARD 17)
-set(CMAKE_CXX_STANDARD_REQUIRED ON)
-set(CMAKE_CXX_EXTENSIONS OFF)
-include_directories("${PROJECT_BINARY_DIR}")
-include_directories("${PROJECT_BINARY_DIR}/src")
-include_directories("${PROJECT_SOURCE_DIR}/src")
 if (NOT MSVC)
 	if ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug" OR "${CMAKE_BUILD_TYPE}" STREQUAL "RelWithDebInfo")
 		set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDEBUG")
--- a/locale/fi.ts	Sat Feb 01 15:49:28 2020 +0200
+++ b/locale/fi.ts	Sat Feb 01 17:10:11 2020 +0200
@@ -181,27 +181,27 @@
         <translation type="unfinished">Satunnaiset värit</translation>
     </message>
     <message>
-        <location filename="../src/mainwindow.cpp" line="88"/>
+        <location filename="../src/mainwindow.cpp" line="91"/>
         <source>Open model</source>
         <translation>Avaa malli</translation>
     </message>
     <message>
-        <location filename="../src/mainwindow.cpp" line="90"/>
+        <location filename="../src/mainwindow.cpp" line="93"/>
         <source>LDraw models (*.ldr *.dat)</source>
         <translation>LDraw-mallit (*.ldr *.dat)</translation>
     </message>
     <message>
-        <location filename="../src/mainwindow.cpp" line="109"/>
+        <location filename="../src/mainwindow.cpp" line="112"/>
         <source>Problem loading references</source>
         <translation type="unfinished">Ongelma viitteiden lataamisessa</translation>
     </message>
     <message>
-        <location filename="../src/mainwindow.cpp" line="119"/>
+        <location filename="../src/mainwindow.cpp" line="122"/>
         <source>Problem opening file</source>
         <translation>Ongelma tiedoston avaamisessa</translation>
     </message>
     <message>
-        <location filename="../src/mainwindow.cpp" line="121"/>
+        <location filename="../src/mainwindow.cpp" line="124"/>
         <source>Could not open %1: %2</source>
         <translation>Ei voitu avata %1: %2</translation>
     </message>
@@ -228,27 +228,42 @@
     </message>
     <message>
         <location filename="../src/settingseditor/settingseditor.ui" line="30"/>
+        <source>Interface</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../src/settingseditor/settingseditor.ui" line="36"/>
         <source>Language:</source>
         <translation>Kieli:</translation>
     </message>
     <message>
-        <location filename="../src/settingseditor/settingseditor.ui" line="38"/>
-        <location filename="../src/settingseditor/settingseditor.cpp" line="54"/>
+        <location filename="../src/settingseditor/settingseditor.ui" line="46"/>
+        <location filename="../src/settingseditor/settingseditor.cpp" line="55"/>
         <source>System language</source>
         <translation>Järjestelmän kieli</translation>
     </message>
     <message>
-        <location filename="../src/settingseditor/settingseditor.ui" line="43"/>
+        <location filename="../src/settingseditor/settingseditor.ui" line="51"/>
         <source>English</source>
         <translation>Englanti</translation>
     </message>
     <message>
-        <location filename="../src/settingseditor/settingseditor.ui" line="52"/>
+        <location filename="../src/settingseditor/settingseditor.ui" line="77"/>
+        <source>Rendering</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../src/settingseditor/settingseditor.ui" line="83"/>
+        <source>Main color:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../src/settingseditor/settingseditor.ui" line="131"/>
         <source>LDraw parts libraries</source>
         <translation>LDraw-osakirjastot</translation>
     </message>
     <message>
-        <location filename="../src/settingseditor/settingseditor.ui" line="57"/>
+        <location filename="../src/settingseditor/settingseditor.ui" line="136"/>
         <source>Keyboard shortcuts</source>
         <translation>Näppäinyhdistelmät</translation>
     </message>
--- a/locale/sv.ts	Sat Feb 01 15:49:28 2020 +0200
+++ b/locale/sv.ts	Sat Feb 01 17:10:11 2020 +0200
@@ -266,6 +266,18 @@
         <source>Keyboard shortcuts</source>
         <translation>Tangentbordsgenvägar</translation>
     </message>
+    <message>
+        <source>Interface</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Rendering</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Main color:</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>gl::Compiler</name>
--- a/src/document.cpp	Sat Feb 01 15:49:28 2020 +0200
+++ b/src/document.cpp	Sat Feb 01 17:10:11 2020 +0200
@@ -55,7 +55,7 @@
 	this->ui.splitter->restoreState(state);
 }
 
-void Document::setRenderStyle(gl::RenderStyle newRenderStyle)
+void Document::setRenderPreferences(const gl::RenderPreferences& newPreferences)
 {
-	this->renderer->setRenderStyle(newRenderStyle);
+	this->renderer->setRenderPreferences(newPreferences);
 }
--- a/src/document.h	Sat Feb 01 15:49:28 2020 +0200
+++ b/src/document.h	Sat Feb 01 17:10:11 2020 +0200
@@ -40,7 +40,7 @@
 	~Document();
 	QByteArray saveSplitterState() const;
 	void restoreSplitterState(const QByteArray& state);
-	void setRenderStyle(gl::RenderStyle newRenderStyle);
+	void setRenderPreferences(const gl::RenderPreferences& newPreferences);
 signals:
 	void splitterChanged();
 private:
--- a/src/gl/common.h	Sat Feb 01 15:49:28 2020 +0200
+++ b/src/gl/common.h	Sat Feb 01 17:10:11 2020 +0200
@@ -150,4 +150,12 @@
 		BfcRed = 2,
 		RandomColors = 3,
 	};
+
+	// User options for rendering
+	struct RenderPreferences
+	{
+		gl::RenderStyle style = gl::RenderStyle::Normal;
+		QColor mainColor{255, 255, 64};
+		float lineThickness = 2.0f;
+	};
 }
--- a/src/gl/compiler.cpp	Sat Feb 01 15:49:28 2020 +0200
+++ b/src/gl/compiler.cpp	Sat Feb 01 17:10:11 2020 +0200
@@ -143,14 +143,14 @@
 	}
 }
 
-void gl::Compiler::build(Model* model, DocumentManager* context)
+void gl::Compiler::build(Model* model, DocumentManager* context, const gl::RenderPreferences& preferences)
 {
 	this->boundingBox = {};
 	std::vector<gl::Vertex> vboData[gl::NUM_ARRAY_CLASSES];
 	const std::vector<gl::Polygon> polygons = model->getPolygons(context);
 	for (const gl::Polygon& polygon : polygons)
 	{
-		this->buildPolygon(polygon, vboData);
+		this->buildPolygon(polygon, vboData, preferences);
 	}
 	for (int arrayId = 0; arrayId < gl::NUM_ARRAY_CLASSES; arrayId += 1)
 	{
@@ -190,13 +190,16 @@
 	return {r, g, b};
 }
 
-void gl::Compiler::buildPolygon(gl::Polygon polygon, std::vector<gl::Vertex>* vboData)
+void gl::Compiler::buildPolygon(
+	gl::Polygon polygon,
+	std::vector<gl::Vertex>* vboData,
+	const gl::RenderPreferences& preferences)
 {
 	const gl::ArrayClass vboClass = classifyPolygon(polygon);
 	std::vector<gl::Vertex>& vertexBuffer = vboData[static_cast<int>(vboClass)];
 	auto vertexRing = iter::ring(polygon.vertices, polygon.numPolygonVertices());
 	reserveMore(vertexBuffer, polygon.numPolygonVertices());
-	const QColor color = this->getColorForPolygon(polygon);
+	const QColor color = this->getColorForPolygon(polygon, preferences);
 	for (unsigned int i = 0; i < polygon.numPolygonVertices(); i += 1)
 	{
 		const glm::vec3& v1 = vertexRing[i - 1];
@@ -210,13 +213,13 @@
 	}
 }
 
-QColor gl::Compiler::getColorForPolygon(const gl::Polygon& polygon)
+QColor gl::Compiler::getColorForPolygon(const gl::Polygon& polygon, const gl::RenderPreferences& preferences)
 {
 	QColor color;
 	// For normal colors, use the polygon's color.
 	if (polygon.color == ldraw::mainColor)
 	{
-		color = {255, 255, 64}; // mainColorRepresentation();
+		color = preferences.mainColor;
 	}
 	else if (polygon.color == ldraw::edgeColor)
 	{
--- a/src/gl/compiler.h	Sat Feb 01 15:49:28 2020 +0200
+++ b/src/gl/compiler.h	Sat Feb 01 17:10:11 2020 +0200
@@ -48,10 +48,10 @@
 public:
 	Compiler(const ldraw::ColorTable& colorTable, QObject* parent);
 	~Compiler();
-	void build(Model* model, DocumentManager* context);
-	void buildPolygon(Polygon polygon, std::vector<Vertex>* vboData);
+	void build(Model* model, DocumentManager* context, const RenderPreferences& preferences);
+	void buildPolygon(Polygon polygon, std::vector<Vertex>* vboData, const gl::RenderPreferences& preferences);
 	std::size_t vertexCount(gl::ArrayClass arrayClass) const;
-	QColor getColorForPolygon(const gl::Polygon& polygon);
+	QColor getColorForPolygon(const gl::Polygon& polygon, const RenderPreferences& preferences);
 	glm::vec3 modelCenter() const;
 	double modelDistance() const;
 	void initialize();
--- a/src/gl/partrenderer.cpp	Sat Feb 01 15:49:28 2020 +0200
+++ b/src/gl/partrenderer.cpp	Sat Feb 01 17:10:11 2020 +0200
@@ -49,7 +49,7 @@
 		abort();
 	}
 	this->compiler->initialize();
-	this->compiler->build(this->model, this->documents);
+	this->compiler->build(this->model, this->documents, this->renderPreferences);
 	this->initialized = true;
 	this->modelQuaternion = glm::angleAxis(glm::radians(30.0f), glm::vec3{-1, 0, 0});
 	this->modelQuaternion *= glm::angleAxis(glm::radians(225.0f), glm::vec3{-0, 1, 0});
@@ -105,7 +105,7 @@
 	glEnable(GL_DEPTH_TEST);
 	glEnable(GL_POLYGON_OFFSET_FILL);
 	glPolygonOffset(1.0f, 1.0f);
-	switch (this->renderStyle)
+	switch (this->renderPreferences.style)
 	{
 	case gl::RenderStyle::Normal:
 		this->setFragmentStyle(gl::FragmentStyle::Normal);
@@ -224,9 +224,14 @@
  * @brief Changes the way the scene is rendered
  * @param newStyle new render style to use
  */
-void PartRenderer::setRenderStyle(const gl::RenderStyle newStyle)
+void PartRenderer::setRenderPreferences(const gl::RenderPreferences& newPreferences)
 {
-	this->renderStyle = newStyle;
+	bool mainColorChanged = this->renderPreferences.mainColor != newPreferences.mainColor;
+	this->renderPreferences = newPreferences;
+	if (mainColorChanged)
+	{
+		this->compiler->build(this->model, this->documents, this->renderPreferences);
+	}
 	this->update();
 }
 
--- a/src/gl/partrenderer.h	Sat Feb 01 15:49:28 2020 +0200
+++ b/src/gl/partrenderer.h	Sat Feb 01 17:10:11 2020 +0200
@@ -21,7 +21,7 @@
 		const ldraw::ColorTable& colorTable,
 		QWidget* parent = nullptr);
 	~PartRenderer() override;
-	void setRenderStyle(const gl::RenderStyle newStyle);
+	void setRenderPreferences(const gl::RenderPreferences& newPreferences);
 protected:
 	void initializeGL() override;
 	void resizeGL(int width, int height) override;
@@ -38,7 +38,7 @@
 	const ldraw::ColorTable& colorTable;
 	QPointF lastMousePosition;
 	gl::Compiler* compiler;
-	gl::RenderStyle renderStyle = gl::RenderStyle::Normal;
+	gl::RenderPreferences renderPreferences;
 	glm::mat4 projectionMatrix;
 	glm::mat4 viewMatrix;
 	glm::quat modelQuaternion;
--- a/src/mainwindow.cpp	Sat Feb 01 15:49:28 2020 +0200
+++ b/src/mainwindow.cpp	Sat Feb 01 17:10:11 2020 +0200
@@ -68,10 +68,13 @@
 	}
 	this->updateTitle();
 	this->restoreSettings();
-	this->updateRenderStyles();
+	this->updateRenderPreferences();
 	this->newModel();
 }
 
+// MainWindow needs a destructor even if it is empty because otherwise the destructor of the
+// std::unique_ptr is resolved in the header file, where it will complain about Ui_MainWindow
+// being incomplete.
 MainWindow::~MainWindow()
 {
 }
@@ -162,7 +165,7 @@
 void MainWindow::openModelForEditing(const QString& modelName)
 {
 	Document* document = new Document{this->documents.findModelByName(modelName), &this->documents, this->colorTable};
-	document->setRenderStyle(this->renderStyle);
+	document->setRenderPreferences(this->renderPreferences);
 	this->ui->tabs->addTab(document, modelName);
 	this->ui->tabs->setCurrentWidget(document);
 	document->restoreSplitterState(this->documentSplitterState);
@@ -221,9 +224,9 @@
 
 void MainWindow::setRenderStyle(gl::RenderStyle renderStyle)
 {
-	this->renderStyle = renderStyle;
+	this->renderPreferences.style = renderStyle;
 	this->saveSettings();
-	this->updateRenderStyles();
+	this->updateRenderPreferences();
 }
 
 void MainWindow::changeEvent(QEvent* event)
@@ -264,20 +267,20 @@
 	setWindowTitle(title);
 }
 
-void MainWindow::updateRenderStyles()
+void MainWindow::updateRenderPreferences()
 {
 	for (int i = 0; i < this->ui->tabs->count(); i += 1)
 	{
 		Document* document = qobject_cast<Document*>(this->ui->tabs->widget(i));
 		if (document != nullptr)
 		{
-			document->setRenderStyle(renderStyle);
+			document->setRenderPreferences(this->renderPreferences);
 		}
 	}
 	for (auto data : ::renderStyleButtons)
 	{
 		QAction* action = data.memberInstance(this->ui.get());
-		action->setChecked(this->renderStyle == data.payload);
+		action->setChecked(this->renderPreferences.style == data.payload);
 	}
 }
 
@@ -289,7 +292,7 @@
 	this->settings.setValue("MainWindow/Geometry", this->saveGeometry());
 	this->settings.setValue("MainWindow/RecentlyOpened", this->recentlyOpenedFiles);
 	this->settings.setValue("MainWindow/DocumentSplitterState", this->documentSplitterState);
-	this->settings.setValue("MainWindow/RenderStyle", static_cast<int>(this->renderStyle));
+	this->settings.setValue("MainWindow/RenderStyle", static_cast<int>(this->renderPreferences.style));
 	this->libraries.storeToSettings(&this->settings);
 }
 
@@ -301,13 +304,15 @@
 	this->restoreGeometry(this->settings.value("MainWindow/Geometry").toByteArray());
 	this->recentlyOpenedFiles = this->settings.value("MainWindow/RecentlyOpened").toStringList();
 	this->documentSplitterState = this->settings.value("MainWindow/DocumentSplitterState").toByteArray();
-	this->renderStyle = static_cast<gl::RenderStyle>(this->settings.value("MainWindow/RenderStyle").toInt());
+	this->renderPreferences.style = static_cast<gl::RenderStyle>(this->settings.value("Render/Style").toInt());
+	this->renderPreferences.mainColor = this->settings.value("Render/MainColor").toString();
 	const QString systemLocale = QLocale::system().name();
 	const QVariant defaultLocale = this->settings.value("locale", systemLocale);
 	changeLanguage(defaultLocale.toString());
 	this->libraries.restoreFromSettings(&this->settings);
 	this->updateRecentlyOpenedDocumentsMenu();
 	this->loadColors();
+	this->updateRenderPreferences();
 }
 
 QString MainWindow::pathToTranslation(const QString& localeCode)
--- a/src/mainwindow.h	Sat Feb 01 15:49:28 2020 +0200
+++ b/src/mainwindow.h	Sat Feb 01 17:10:11 2020 +0200
@@ -30,7 +30,7 @@
 	Q_OBJECT
 public:
 	MainWindow(QWidget *parent = nullptr);
-	~MainWindow();
+	~MainWindow() override;
 private slots:
 	void newModel();
 	void openModel();
@@ -56,9 +56,9 @@
 	static constexpr int maxRecentlyOpenedFiles = 10;
 	QStringList recentlyOpenedFiles;
 	ldraw::ColorTable colorTable;
-	gl::RenderStyle renderStyle;
+	gl::RenderPreferences renderPreferences;
 	void updateTitle();
-	void updateRenderStyles();
+	void updateRenderPreferences();
 	void saveSettings();
 	void restoreSettings();
 	void changeLanguage(QString localeCode);
--- a/src/settingseditor/settingseditor.cpp	Sat Feb 01 15:49:28 2020 +0200
+++ b/src/settingseditor/settingseditor.cpp	Sat Feb 01 17:10:11 2020 +0200
@@ -37,6 +37,7 @@
 void SettingsEditor::handleAccepted()
 {
 	this->settings->setValue("locale", this->ui.language->currentData().toString());
+	this->settings->setValue("Render/MainColor", this->ui.mainColorButton->selectedColor().name());
 	this->librariesEditor.saveSettings(this->settings);
 }
 
@@ -65,6 +66,7 @@
 void SettingsEditor::setDefaults()
 {
 	this->setCurrentLanguage(this->settings->value("locale", QLocale::system().name()).toString());
+	this->ui.mainColorButton->setSelectedColor(this->settings->value("Render/MainColor").toString());
 }
 
 void SettingsEditor::setCurrentLanguage(const QString& localeCode)
--- a/src/settingseditor/settingseditor.ui	Sat Feb 01 15:49:28 2020 +0200
+++ b/src/settingseditor/settingseditor.ui	Sat Feb 01 17:10:11 2020 +0200
@@ -17,34 +17,113 @@
    <item>
     <widget class="QTabWidget" name="tabWidget">
      <property name="currentIndex">
-      <number>2</number>
+      <number>0</number>
      </property>
      <widget class="QWidget" name="tabGeneral">
       <attribute name="title">
        <string>General</string>
       </attribute>
-      <layout class="QFormLayout" name="formLayout">
-       <item row="0" column="0">
-        <widget class="QLabel" name="label">
-         <property name="text">
-          <string>Language:</string>
+      <layout class="QVBoxLayout" name="verticalLayout_3">
+       <item>
+        <widget class="QGroupBox" name="groupBox">
+         <property name="title">
+          <string>Interface</string>
          </property>
+         <layout class="QFormLayout" name="formLayout">
+          <item row="0" column="0">
+           <widget class="QLabel" name="label">
+            <property name="text">
+             <string>Language:</string>
+            </property>
+           </widget>
+          </item>
+          <item row="0" column="1">
+           <layout class="QHBoxLayout" name="horizontalLayout_2">
+            <item>
+             <widget class="QComboBox" name="language">
+              <item>
+               <property name="text">
+                <string>System language</string>
+               </property>
+              </item>
+              <item>
+               <property name="text">
+                <string>English</string>
+               </property>
+              </item>
+             </widget>
+            </item>
+            <item>
+             <spacer name="horizontalSpacer_2">
+              <property name="orientation">
+               <enum>Qt::Horizontal</enum>
+              </property>
+              <property name="sizeHint" stdset="0">
+               <size>
+                <width>40</width>
+                <height>20</height>
+               </size>
+              </property>
+             </spacer>
+            </item>
+           </layout>
+          </item>
+         </layout>
         </widget>
        </item>
-       <item row="0" column="1">
-        <widget class="QComboBox" name="language">
-         <item>
-          <property name="text">
-           <string>System language</string>
-          </property>
-         </item>
-         <item>
-          <property name="text">
-           <string>English</string>
-          </property>
-         </item>
+       <item>
+        <widget class="QGroupBox" name="groupBox_2">
+         <property name="title">
+          <string>Rendering</string>
+         </property>
+         <layout class="QFormLayout" name="formLayout_2">
+          <item row="0" column="0">
+           <widget class="QLabel" name="label_2">
+            <property name="text">
+             <string>Main color:</string>
+            </property>
+           </widget>
+          </item>
+          <item row="0" column="1">
+           <layout class="QHBoxLayout" name="horizontalLayout">
+            <item>
+             <widget class="ColorButton" name="mainColorButton">
+              <property name="text">
+               <string/>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <spacer name="horizontalSpacer">
+              <property name="orientation">
+               <enum>Qt::Horizontal</enum>
+              </property>
+              <property name="sizeHint" stdset="0">
+               <size>
+                <width>40</width>
+                <height>20</height>
+               </size>
+              </property>
+             </spacer>
+            </item>
+           </layout>
+          </item>
+         </layout>
         </widget>
        </item>
+       <item>
+        <spacer name="verticalSpacer">
+         <property name="orientation">
+          <enum>Qt::Vertical</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>20</width>
+           <height>40</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
       </layout>
      </widget>
      <widget class="QWidget" name="tabLdrawLibraries">
@@ -76,6 +155,13 @@
    </item>
   </layout>
  </widget>
+ <customwidgets>
+  <customwidget>
+   <class>ColorButton</class>
+   <extends>QPushButton</extends>
+   <header>widgets/colorbutton.h</header>
+  </customwidget>
+ </customwidgets>
  <resources/>
  <connections>
   <connection>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/widgets/colorbutton.cpp	Sat Feb 01 17:10:11 2020 +0200
@@ -0,0 +1,34 @@
+#include <QColorDialog>
+#include "colorbutton.h"
+
+ColorButton::ColorButton(const QColor& color, QWidget* parent) :
+	ColorButton{parent}
+{
+	this->setSelectedColor(color);
+}
+
+ColorButton::ColorButton(QWidget* parent) :
+	QPushButton{parent}
+{
+	connect(this, &QPushButton::clicked, [&]()
+	{
+		const QColor color = QColorDialog::getColor(this->storedSelectedColor, this->parentWidget());
+		if (color.isValid())
+		{
+			this->setSelectedColor(color);
+		}
+	});
+}
+
+QColor ColorButton::selectedColor() const
+{
+	return this->storedSelectedColor;
+}
+
+void ColorButton::setSelectedColor(const QColor& newSelectedColor)
+{
+	this->storedSelectedColor = newSelectedColor;
+	this->setStyleSheet(QString{"background-color: %1"}.arg(newSelectedColor.name()));
+	this->setText(newSelectedColor.name());
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/widgets/colorbutton.h	Sat Feb 01 17:10:11 2020 +0200
@@ -0,0 +1,16 @@
+#pragma once
+#include <QPushButton>
+
+/**
+ * @brief A button that can be used to select a color
+ */
+class ColorButton : public QPushButton
+{
+public:
+	ColorButton(const QColor& color = {}, QWidget* parent = nullptr);
+	ColorButton(QWidget* parent = nullptr);
+	QColor selectedColor() const;
+	void setSelectedColor(const QColor& newSelectedColor);
+private:
+	QColor storedSelectedColor;
+};

mercurial