Wed, 22 Jun 2022 20:27:53 +0300
Move some widgets into a static library
--- a/CMakeLists.txt Wed Jun 22 20:10:57 2022 +0300 +++ b/CMakeLists.txt Wed Jun 22 20:27:53 2022 +0300 @@ -21,6 +21,22 @@ add_definitions(-DQT_NO_KEYWORDS) source_group("LDForge" REGULAR_EXPRESSION "src/.+\\.(cpp|h|ui)") +qt5_wrap_ui(LDFORGEWIDGETS_FORMS + widgets/vec3editor.ui + widgets/multiplyfactordialog.ui + widgets/matrixeditor.ui +) +add_library(ldforgewidgets STATIC + widgets/matrixeditor.cpp + widgets/matrixeditor.h + widgets/vec3editor.cpp + widgets/vec3editor.h + widgets/multiplyfactordialog.cpp + widgets/multiplyfactordialog.h + ${LDFORGEWIDGETS_FORMS} +) +target_link_libraries(ldforgewidgets Qt5::Widgets) + set (LDFORGE_SOURCES src/colors.cpp src/document.cpp @@ -49,14 +65,11 @@ src/settingseditor/settingseditor.cpp src/types/boundingbox.cpp src/ui/circletooloptionswidget.cpp - src/ui/multiplyfactordialog.cpp src/ui/objecteditor.cpp src/widgets/colorbutton.cpp src/widgets/colorindexinput.cpp src/widgets/colorselectdialog.cpp src/widgets/doublespinbox.cpp - src/widgets/matrixeditor.cpp - src/widgets/vec3editor.cpp ) set (LDFORGE_HEADERS src/basics.h @@ -93,26 +106,20 @@ src/settingseditor/settingseditor.h src/types/boundingbox.h src/ui/circletooloptionswidget.h - src/ui/multiplyfactordialog.h src/ui/objecteditor.h src/widgets/colorbutton.h src/widgets/colorindexinput.h src/widgets/colorselectdialog.h src/widgets/doublespinbox.h - src/widgets/matrixeditor.h - src/widgets/vec3editor.h ) set (LDFORGE_FORMS src/mainwindow.ui src/settingseditor/librarieseditor.ui src/settingseditor/settingseditor.ui src/ui/circletool.ui - src/ui/multiplyfactordialog.ui src/ui/objecteditor.ui src/widgets/colorselectdialog.ui src/widgets/colorindexinput.ui - src/widgets/matrixeditor.ui - src/widgets/vec3editor.ui ) set(LDFORGE_LOCALES @@ -130,6 +137,7 @@ set(CMAKE_CXX_EXTENSIONS OFF) include_directories("${PROJECT_BINARY_DIR}") include_directories("${PROJECT_BINARY_DIR}/src") +include_directories("${PROJECT_SOURCE_DIR}") include_directories("${PROJECT_SOURCE_DIR}/src") # Translations @@ -184,6 +192,7 @@ set_source_files_properties(${LDFORGE_OTHER_FILES} PROPERTIES HEADER_FILE_ONLY TRUE) set_target_properties(ldforge PROPERTIES AUTOMOC 1) target_link_libraries(ldforge Qt5::Widgets Qt5::Network Qt5::OpenGL ${OPENGL_LIBRARIES}) +target_link_libraries(ldforge ldforgewidgets) add_dependencies(ldforge resources) #cotire(ldforge)
--- a/src/ui/multiplyfactordialog.cpp Wed Jun 22 20:10:57 2022 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,102 +0,0 @@ -#include "multiplyfactordialog.h" -#include "ui_multiplyfactordialog.h" - -MultiplyFactorDialog::MultiplyFactorDialog(const glm::vec3& baseVector, QWidget* parent) : - QDialog{parent}, - baseVector{baseVector}, - preview{baseVector, parent, Vec3Editor::NoMultiplyButton} -{ - ui = std::make_unique<Ui::MultiplyFactorDialog>(); - ui->setupUi(this); - this->preview.setEnabled(false); - this->ui->previewGroupBox->setLayout(new QVBoxLayout{parent}); - this->ui->previewGroupBox->layout()->addWidget(&this->preview); - connect( - this->ui->invert, - &QCheckBox::clicked, - this, - &MultiplyFactorDialog::updatePreview); - connect( - this->ui->factor, - qOverload<double>(&DoubleSpinBox::valueChanged), - this, - &MultiplyFactorDialog::updatePreview); -} - -/** - * @brief empty destructor, necessary because std::unique_ptr is used with a forward declaration - */ -MultiplyFactorDialog::~MultiplyFactorDialog() -{ -} - -/** - * @brief Computes the resulting vector - * @return the input vector multiplied by the specified vector - */ -glm::vec3 MultiplyFactorDialog::value() const -{ - glm::vec3 result = baseVector; - if (this->ui->invert->isChecked()) - { - if (qFuzzyIsNull(this->ui->factor->value())) - { - constexpr double infinity = std::numeric_limits<double>::quiet_NaN(); - result = {infinity, infinity, infinity}; - } - else - { - result /= this->ui->factor->value(); - } - } - else - { - result *= this->ui->factor->value(); - } - return result; -} - -/** - * @brief Makes a string that is prefixed to the factor input. - * @param ui - * @return prefix string - */ -QString prefixForFactorInput(const Ui::MultiplyFactorDialog& ui) -{ - if (ui.invert->isChecked()) - { - return "1 : "; - } - else - { - return ""; - } -} - -/** - * @brief Makes a string that is suffixed to the factor input. - * @param ui - * @return prefix string - */ -QString suffixForFactorInput(const Ui::MultiplyFactorDialog& ui) -{ - if (ui.invert->isChecked()) - { - // render the actual factor that stuff gets effectively multiplied by - return " = " + QString::number(1.0 / (ui.factor->value())); - } - else - { - return ""; - } -} - -/** - * @brief Responds to changes in the value and updates previews accordingly - */ -void MultiplyFactorDialog::updatePreview() -{ - this->ui->factor->setPrefix(::prefixForFactorInput(*this->ui)); - this->ui->factor->setSuffix(::suffixForFactorInput(*this->ui)); - this->preview.setValue(this->value()); -}
--- a/src/ui/multiplyfactordialog.h Wed Jun 22 20:10:57 2022 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,23 +0,0 @@ -#pragma once -#include <QDialog> -#include "../basics.h" -#include "../widgets/vec3editor.h" - -namespace Ui -{ - class MultiplyFactorDialog; -} - -class MultiplyFactorDialog : public QDialog -{ - Q_OBJECT -public: - explicit MultiplyFactorDialog(const glm::vec3& baseVector = glm::vec3{}, QWidget *parent = nullptr); - ~MultiplyFactorDialog(); - glm::vec3 value() const; -private: - Q_SLOT void updatePreview(); - std::unique_ptr<Ui::MultiplyFactorDialog> ui; - const glm::vec3 baseVector; - Vec3Editor preview; -};
--- a/src/ui/multiplyfactordialog.ui Wed Jun 22 20:10:57 2022 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,103 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>MultiplyFactorDialog</class> - <widget class="QDialog" name="MultiplyFactorDialog"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>286</width> - <height>169</height> - </rect> - </property> - <property name="windowTitle"> - <string>Multiply with a scalar</string> - </property> - <layout class="QVBoxLayout" name="verticalLayout"> - <item> - <layout class="QFormLayout" name="formLayout"> - <item row="0" column="0"> - <widget class="QLabel" name="label"> - <property name="text"> - <string>Factor:</string> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="DoubleSpinBox" name="factor"> - <property name="value"> - <double>1.000000000000000</double> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="QCheckBox" name="invert"> - <property name="text"> - <string>Invert</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <widget class="QGroupBox" name="previewGroupBox"> - <property name="title"> - <string>Preview</string> - </property> - </widget> - </item> - <item> - <widget class="QDialogButtonBox" name="buttonBox"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="standardButtons"> - <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> - </property> - </widget> - </item> - </layout> - </widget> - <customwidgets> - <customwidget> - <class>DoubleSpinBox</class> - <extends>QDoubleSpinBox</extends> - <header>widgets/doublespinbox.h</header> - </customwidget> - </customwidgets> - <resources/> - <connections> - <connection> - <sender>buttonBox</sender> - <signal>accepted()</signal> - <receiver>MultiplyFactorDialog</receiver> - <slot>accept()</slot> - <hints> - <hint type="sourcelabel"> - <x>248</x> - <y>254</y> - </hint> - <hint type="destinationlabel"> - <x>157</x> - <y>274</y> - </hint> - </hints> - </connection> - <connection> - <sender>buttonBox</sender> - <signal>rejected()</signal> - <receiver>MultiplyFactorDialog</receiver> - <slot>reject()</slot> - <hints> - <hint type="sourcelabel"> - <x>316</x> - <y>260</y> - </hint> - <hint type="destinationlabel"> - <x>286</x> - <y>274</y> - </hint> - </hints> - </connection> - </connections> -</ui>
--- a/src/ui/objecteditor.cpp Wed Jun 22 20:10:57 2022 +0300 +++ b/src/ui/objecteditor.cpp Wed Jun 22 20:27:53 2022 +0300 @@ -1,11 +1,11 @@ #include <QCheckBox> #include <QLineEdit> #include <QFormLayout> +#include <widgets/vec3editor.h> #include "objecteditor.h" #include "document.h" #include "widgets/colorbutton.h" #include "widgets/colorindexinput.h" -#include "widgets/vec3editor.h" #include "ui_objecteditor.h" using PropertyPointer = std::variant<
--- a/src/widgets/matrixeditor.cpp Wed Jun 22 20:10:57 2022 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,90 +0,0 @@ -#include "basics.h" -#include "matrixeditor.h" -#include "ui_matrixeditor.h" -#include "../ui/multiplyfactordialog.h" - -constexpr char BUTTON_COLUMN_PROPERTY[] = "_ldforge_column"; - -MatrixEditor::MatrixEditor(const glm::mat4 value, QWidget* parent) : - QWidget(parent), - ui(new Ui::MatrixEditor) -{ - ui->setupUi(this); - for (int column = 0; column < countof(this->spinboxes); column += 1) - { - for (int row = 0; row < countof(this->spinboxes[0]); row += 1) - { - const QString name = QStringLiteral("cell%1%2").arg(column).arg(row); - QDoubleSpinBox** spinbox = &this->spinboxes[column][row]; - *spinbox = this->findChild<QDoubleSpinBox*>(name); - connect(*spinbox, qOverload<double>(&QDoubleSpinBox::valueChanged), [&]() - { - Q_EMIT this->valueChanged(this->value()); - }); - Q_ASSERT(*spinbox != nullptr); - } - const QString multiplyButtonName = QStringLiteral("multiply%1").arg(column); - QAbstractButton* button = this->findChild<QAbstractButton*>(multiplyButtonName); - button->setProperty(BUTTON_COLUMN_PROPERTY, column); - connect(button, &QAbstractButton::clicked, this, &MatrixEditor::multiplyButtonPressed); - } - this->setValue(value); -} - -MatrixEditor::MatrixEditor(QWidget *parent) : - MatrixEditor{glm::mat4{1}, parent} -{ -} - -MatrixEditor::~MatrixEditor() -{ - delete ui; -} - -glm::mat4 MatrixEditor::value() const -{ - glm::mat4 result{1}; - for (int column = 0; column < countof(this->spinboxes); column += 1) - { - for (int row = 0; row < countof(this->spinboxes[0]); row += 1) - { - result[column][row] = narrow<float>(this->spinboxes[column][row]->value()); - } - } - return result; -} - -void MatrixEditor::setValue(const glm::mat4& value) -{ - for (int column = 0; column < countof(this->spinboxes); column += 1) - { - for (int row = 0; row < countof(this->spinboxes[0]); row += 1) - { - QDoubleSpinBox* spinbox = this->spinboxes[column][row]; - QSignalBlocker blocker{spinbox}; - spinbox->setValue(value[column][row]); - } - } -} - -void MatrixEditor::multiplyButtonPressed() -{ - QAbstractButton* button = qobject_cast<QAbstractButton*>(this->sender()); - if (button != nullptr) - { - bool ok; - const int column = button->property(BUTTON_COLUMN_PROPERTY).toInt(&ok); - if (ok and column >= 0 and column < this->matrixSize()) - { - glm::mat4 newValue = this->value(); - MultiplyFactorDialog dialog{newValue[column], this}; - const int result = dialog.exec(); - if (result == QDialog::Accepted) - { - newValue[column] = glm::vec4{dialog.value(), (column == 3) ? 1 : 0}; - this->setValue(newValue); - Q_EMIT valueChanged(newValue); - } - } - } -}
--- a/src/widgets/matrixeditor.h Wed Jun 22 20:10:57 2022 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -#pragma once -#include <QWidget> -#include "basics.h" - -namespace Ui { -class MatrixEditor; -} - -class MatrixEditor : public QWidget -{ - Q_OBJECT -public: - explicit MatrixEditor(QWidget *parent = nullptr); - explicit MatrixEditor(const glm::mat4 value, QWidget* parent = nullptr); - ~MatrixEditor(); - glm::mat4 value() const; - void setValue(const glm::mat4& value); -Q_SIGNALS: - void valueChanged(const glm::mat4& value); -private: - constexpr int matrixSize() const; - Q_SLOT void multiplyButtonPressed(); - class QDoubleSpinBox* spinboxes[4][3]; - Ui::MatrixEditor *ui; -}; - -constexpr int MatrixEditor::matrixSize() const -{ - return 4; -}
--- a/src/widgets/matrixeditor.ui Wed Jun 22 20:10:57 2022 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,123 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>MatrixEditor</class> - <widget class="QWidget" name="MatrixEditor"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>356</width> - <height>172</height> - </rect> - </property> - <property name="windowTitle"> - <string>Form</string> - </property> - <layout class="QGridLayout" name="gridLayout"> - <item row="0" column="0"> - <widget class="DoubleSpinBox" name="cell00"/> - </item> - <item row="0" column="1"> - <widget class="DoubleSpinBox" name="cell10"/> - </item> - <item row="0" column="2"> - <widget class="DoubleSpinBox" name="cell20"/> - </item> - <item row="0" column="3"> - <widget class="DoubleSpinBox" name="cell30"/> - </item> - <item row="1" column="0"> - <widget class="DoubleSpinBox" name="cell01"/> - </item> - <item row="1" column="1"> - <widget class="DoubleSpinBox" name="cell11"/> - </item> - <item row="1" column="2"> - <widget class="DoubleSpinBox" name="cell21"/> - </item> - <item row="1" column="3"> - <widget class="DoubleSpinBox" name="cell31"/> - </item> - <item row="2" column="0"> - <widget class="DoubleSpinBox" name="cell02"/> - </item> - <item row="2" column="1"> - <widget class="DoubleSpinBox" name="cell12"/> - </item> - <item row="2" column="2"> - <widget class="DoubleSpinBox" name="cell22"/> - </item> - <item row="2" column="3"> - <widget class="DoubleSpinBox" name="cell32"/> - </item> - <item row="3" column="0"> - <widget class="DoubleSpinBox" name="doubleSpinBox"> - <property name="enabled"> - <bool>false</bool> - </property> - </widget> - </item> - <item row="3" column="1"> - <widget class="DoubleSpinBox" name="doubleSpinBox_2"> - <property name="enabled"> - <bool>false</bool> - </property> - </widget> - </item> - <item row="3" column="2"> - <widget class="DoubleSpinBox" name="doubleSpinBox_3"> - <property name="enabled"> - <bool>false</bool> - </property> - </widget> - </item> - <item row="3" column="3"> - <widget class="DoubleSpinBox" name="doubleSpinBox_4"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="value"> - <double>1.000000000000000</double> - </property> - </widget> - </item> - <item row="4" column="0"> - <widget class="QPushButton" name="multiply0"> - <property name="text"> - <string>×</string> - </property> - </widget> - </item> - <item row="4" column="1"> - <widget class="QPushButton" name="multiply1"> - <property name="text"> - <string>×</string> - </property> - </widget> - </item> - <item row="4" column="2"> - <widget class="QPushButton" name="multiply2"> - <property name="text"> - <string>×</string> - </property> - </widget> - </item> - <item row="4" column="3"> - <widget class="QPushButton" name="multiply3"> - <property name="text"> - <string>×</string> - </property> - </widget> - </item> - </layout> - </widget> - <customwidgets> - <customwidget> - <class>DoubleSpinBox</class> - <extends>QDoubleSpinBox</extends> - <header>widgets/doublespinbox.h</header> - </customwidget> - </customwidgets> - <resources/> - <connections/> -</ui>
--- a/src/widgets/vec3editor.cpp Wed Jun 22 20:10:57 2022 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -#include <QDialog> -#include <QCheckBox> -#include <QSignalBlocker> -#include "vec3editor.h" -#include "ui_vec3editor.h" -#include "../ui/multiplyfactordialog.h" - -Vec3Editor::Vec3Editor(const glm::vec3& value, QWidget *parent, QFlags<Flag> flags) : - QWidget{parent}, - ui{new Ui::Vec3Editor} -{ - this->ui->setupUi(this); - this->setValue(value); - if (flags.testFlag(NoMultiplyButton)) - { - this->ui->multiply->setVisible(false); - } - else - { - connect(this->ui->multiply, &QPushButton::clicked, this, &Vec3Editor::multiplyPressed); - } - for (QDoubleSpinBox* spinbox : this->spinboxes()) - { - connect(spinbox, qOverload<double>(&QDoubleSpinBox::valueChanged), [&](double) - { - Q_EMIT this->valueChanged(this->value()); - }); - } -} - -Vec3Editor::~Vec3Editor() -{ -} - -glm::vec3 Vec3Editor::value() const -{ - auto get = [](DoubleSpinBox* spinbox){ return float_cast(spinbox->value()); }; - return {get(this->ui->x), get(this->ui->y), get(this->ui->z)}; -} - -void Vec3Editor::setValue(const glm::vec3& value) -{ - auto set = [](DoubleSpinBox* spinbox, float value) - { - QSignalBlocker blocker{spinbox}; - spinbox->setValue(qreal_cast(value)); - }; - set(this->ui->x, value.x); - set(this->ui->y, value.y); - set(this->ui->z, value.z); - Q_EMIT this->valueChanged(value); -} - -std::array<DoubleSpinBox*, 3> Vec3Editor::spinboxes() -{ - return {this->ui->x, this->ui->y, this->ui->z}; -} - -void Vec3Editor::multiplyPressed() -{ - MultiplyFactorDialog dialog{this->value(), this}; - const int dialogResult = dialog.exec(); - if (dialogResult == QDialog::Accepted) - { - this->setValue(dialog.value()); - } -}
--- a/src/widgets/vec3editor.h Wed Jun 22 20:10:57 2022 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -#pragma once -#include <QWidget> -#include "basics.h" - -namespace Ui -{ - class Vec3Editor; -} - -class Vec3Editor : public QWidget -{ - Q_OBJECT -public: - enum Flag - { - NoMultiplyButton = 0x1 - }; - explicit Vec3Editor(const glm::vec3& value, QWidget* parent = nullptr, QFlags<Flag> flags = {}); - ~Vec3Editor(); - glm::vec3 value() const; - void setValue(const glm::vec3& value); -Q_SIGNALS: - void valueChanged(const glm::vec3& value); -private: - std::array<class DoubleSpinBox*, 3> spinboxes(); - Q_SLOT void multiplyPressed(); - std::unique_ptr<Ui::Vec3Editor> ui; -}; - -Q_DECLARE_OPERATORS_FOR_FLAGS(QFlags<Vec3Editor::Flag>)
--- a/src/widgets/vec3editor.ui Wed Jun 22 20:10:57 2022 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,83 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>Vec3Editor</class> - <widget class="QWidget" name="Vec3Editor"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>613</width> - <height>46</height> - </rect> - </property> - <property name="windowTitle"> - <string>Form</string> - </property> - <layout class="QHBoxLayout" name="horizontalLayout" stretch="1,1,1,0"> - <item> - <widget class="DoubleSpinBox" name="x"> - <property name="prefix"> - <string>x = </string> - </property> - <property name="decimals"> - <number>4</number> - </property> - <property name="minimum"> - <double>-1000000.000000000000000</double> - </property> - <property name="maximum"> - <double>1000000.000000000000000</double> - </property> - </widget> - </item> - <item> - <widget class="DoubleSpinBox" name="y"> - <property name="prefix"> - <string>y = </string> - </property> - <property name="decimals"> - <number>4</number> - </property> - <property name="minimum"> - <double>-1000000.000000000000000</double> - </property> - <property name="maximum"> - <double>1000000.000000000000000</double> - </property> - </widget> - </item> - <item> - <widget class="DoubleSpinBox" name="z"> - <property name="prefix"> - <string>z = </string> - </property> - <property name="decimals"> - <number>4</number> - </property> - <property name="minimum"> - <double>-1000000.000000000000000</double> - </property> - <property name="maximum"> - <double>1000000.000000000000000</double> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="multiply"> - <property name="text"> - <string>×</string> - </property> - </widget> - </item> - </layout> - </widget> - <customwidgets> - <customwidget> - <class>DoubleSpinBox</class> - <extends>QDoubleSpinBox</extends> - <header>widgets/doublespinbox.h</header> - </customwidget> - </customwidgets> - <resources/> - <connections/> -</ui>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/widgets/matrixeditor.cpp Wed Jun 22 20:27:53 2022 +0300 @@ -0,0 +1,89 @@ +#include "matrixeditor.h" +#include "ui_matrixeditor.h" +#include "multiplyfactordialog.h" + +constexpr char BUTTON_COLUMN_PROPERTY[] = "_ldforge_column"; + +MatrixEditor::MatrixEditor(const glm::mat4 value, QWidget* parent) : + QWidget(parent), + ui(new Ui::MatrixEditor) +{ + ui->setupUi(this); + for (int column = 0; column < (int)glm::countof(this->spinboxes); column += 1) + { + for (int row = 0; row < (int)glm::countof(this->spinboxes[0]); row += 1) + { + const QString name = QStringLiteral("cell%1%2").arg(column).arg(row); + QDoubleSpinBox** spinbox = &this->spinboxes[column][row]; + *spinbox = this->findChild<QDoubleSpinBox*>(name); + connect(*spinbox, qOverload<double>(&QDoubleSpinBox::valueChanged), [&]() + { + Q_EMIT this->valueChanged(this->value()); + }); + Q_ASSERT(*spinbox != nullptr); + } + const QString multiplyButtonName = QStringLiteral("multiply%1").arg(column); + QAbstractButton* button = this->findChild<QAbstractButton*>(multiplyButtonName); + button->setProperty(BUTTON_COLUMN_PROPERTY, column); + connect(button, &QAbstractButton::clicked, this, &MatrixEditor::multiplyButtonPressed); + } + this->setValue(value); +} + +MatrixEditor::MatrixEditor(QWidget *parent) : + MatrixEditor{glm::mat4{1}, parent} +{ +} + +MatrixEditor::~MatrixEditor() +{ + delete ui; +} + +glm::mat4 MatrixEditor::value() const +{ + glm::mat4 result{1}; + for (int column = 0; column < (int)glm::countof(this->spinboxes); column += 1) + { + for (int row = 0; row < (int)glm::countof(this->spinboxes[0]); row += 1) + { + result[column][row] = static_cast<float>(this->spinboxes[column][row]->value()); + } + } + return result; +} + +void MatrixEditor::setValue(const glm::mat4& value) +{ + for (int column = 0; column < (int)glm::countof(this->spinboxes); column += 1) + { + for (int row = 0; row < (int)glm::countof(this->spinboxes[0]); row += 1) + { + QDoubleSpinBox* spinbox = this->spinboxes[column][row]; + QSignalBlocker blocker{spinbox}; + spinbox->setValue(value[column][row]); + } + } +} + +void MatrixEditor::multiplyButtonPressed() +{ + QAbstractButton* button = qobject_cast<QAbstractButton*>(this->sender()); + if (button != nullptr) + { + bool ok; + const int column = button->property(BUTTON_COLUMN_PROPERTY).toInt(&ok); + if (ok and column >= 0 and column < this->matrixSize()) + { + glm::mat4 newValue = this->value(); + MultiplyFactorDialog dialog{newValue[column], this}; + const int result = dialog.exec(); + if (result == QDialog::Accepted) + { + newValue[column] = glm::vec4{dialog.value(), (column == 3) ? 1 : 0}; + this->setValue(newValue); + Q_EMIT valueChanged(newValue); + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/widgets/matrixeditor.h Wed Jun 22 20:27:53 2022 +0300 @@ -0,0 +1,30 @@ +#pragma once +#include <QWidget> +#include <glm/glm.hpp> + +namespace Ui { +class MatrixEditor; +} + +class MatrixEditor : public QWidget +{ + Q_OBJECT +public: + explicit MatrixEditor(QWidget *parent = nullptr); + explicit MatrixEditor(const glm::mat4 value, QWidget* parent = nullptr); + ~MatrixEditor(); + glm::mat4 value() const; + void setValue(const glm::mat4& value); +Q_SIGNALS: + void valueChanged(const glm::mat4& value); +private: + constexpr int matrixSize() const; + Q_SLOT void multiplyButtonPressed(); + class QDoubleSpinBox* spinboxes[4][3]; + Ui::MatrixEditor *ui; +}; + +constexpr int MatrixEditor::matrixSize() const +{ + return 4; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/widgets/matrixeditor.ui Wed Jun 22 20:27:53 2022 +0300 @@ -0,0 +1,123 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>MatrixEditor</class> + <widget class="QWidget" name="MatrixEditor"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>356</width> + <height>172</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> + <widget class="DoubleSpinBox" name="cell00"/> + </item> + <item row="0" column="1"> + <widget class="DoubleSpinBox" name="cell10"/> + </item> + <item row="0" column="2"> + <widget class="DoubleSpinBox" name="cell20"/> + </item> + <item row="0" column="3"> + <widget class="DoubleSpinBox" name="cell30"/> + </item> + <item row="1" column="0"> + <widget class="DoubleSpinBox" name="cell01"/> + </item> + <item row="1" column="1"> + <widget class="DoubleSpinBox" name="cell11"/> + </item> + <item row="1" column="2"> + <widget class="DoubleSpinBox" name="cell21"/> + </item> + <item row="1" column="3"> + <widget class="DoubleSpinBox" name="cell31"/> + </item> + <item row="2" column="0"> + <widget class="DoubleSpinBox" name="cell02"/> + </item> + <item row="2" column="1"> + <widget class="DoubleSpinBox" name="cell12"/> + </item> + <item row="2" column="2"> + <widget class="DoubleSpinBox" name="cell22"/> + </item> + <item row="2" column="3"> + <widget class="DoubleSpinBox" name="cell32"/> + </item> + <item row="3" column="0"> + <widget class="DoubleSpinBox" name="doubleSpinBox"> + <property name="enabled"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="DoubleSpinBox" name="doubleSpinBox_2"> + <property name="enabled"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="3" column="2"> + <widget class="DoubleSpinBox" name="doubleSpinBox_3"> + <property name="enabled"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="3" column="3"> + <widget class="DoubleSpinBox" name="doubleSpinBox_4"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="value"> + <double>1.000000000000000</double> + </property> + </widget> + </item> + <item row="4" column="0"> + <widget class="QPushButton" name="multiply0"> + <property name="text"> + <string>×</string> + </property> + </widget> + </item> + <item row="4" column="1"> + <widget class="QPushButton" name="multiply1"> + <property name="text"> + <string>×</string> + </property> + </widget> + </item> + <item row="4" column="2"> + <widget class="QPushButton" name="multiply2"> + <property name="text"> + <string>×</string> + </property> + </widget> + </item> + <item row="4" column="3"> + <widget class="QPushButton" name="multiply3"> + <property name="text"> + <string>×</string> + </property> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>DoubleSpinBox</class> + <extends>QDoubleSpinBox</extends> + <header>widgets/doublespinbox.h</header> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/widgets/multiplyfactordialog.cpp Wed Jun 22 20:27:53 2022 +0300 @@ -0,0 +1,102 @@ +#include "multiplyfactordialog.h" +#include "ui_multiplyfactordialog.h" + +MultiplyFactorDialog::MultiplyFactorDialog(const glm::vec3& baseVector, QWidget* parent) : + QDialog{parent}, + baseVector{baseVector}, + preview{baseVector, parent, Vec3Editor::NoMultiplyButton} +{ + ui = std::make_unique<Ui::MultiplyFactorDialog>(); + ui->setupUi(this); + this->preview.setEnabled(false); + this->ui->previewGroupBox->setLayout(new QVBoxLayout{parent}); + this->ui->previewGroupBox->layout()->addWidget(&this->preview); + connect( + this->ui->invert, + &QCheckBox::clicked, + this, + &MultiplyFactorDialog::updatePreview); + connect( + this->ui->factor, + qOverload<double>(&DoubleSpinBox::valueChanged), + this, + &MultiplyFactorDialog::updatePreview); +} + +/** + * @brief empty destructor, necessary because std::unique_ptr is used with a forward declaration + */ +MultiplyFactorDialog::~MultiplyFactorDialog() +{ +} + +/** + * @brief Computes the resulting vector + * @return the input vector multiplied by the specified vector + */ +glm::vec3 MultiplyFactorDialog::value() const +{ + glm::vec3 result = baseVector; + if (this->ui->invert->isChecked()) + { + if (qFuzzyIsNull(this->ui->factor->value())) + { + constexpr double infinity = std::numeric_limits<double>::quiet_NaN(); + result = {infinity, infinity, infinity}; + } + else + { + result /= this->ui->factor->value(); + } + } + else + { + result *= this->ui->factor->value(); + } + return result; +} + +/** + * @brief Makes a string that is prefixed to the factor input. + * @param ui + * @return prefix string + */ +QString prefixForFactorInput(const Ui::MultiplyFactorDialog& ui) +{ + if (ui.invert->isChecked()) + { + return "1 : "; + } + else + { + return ""; + } +} + +/** + * @brief Makes a string that is suffixed to the factor input. + * @param ui + * @return prefix string + */ +QString suffixForFactorInput(const Ui::MultiplyFactorDialog& ui) +{ + if (ui.invert->isChecked()) + { + // render the actual factor that stuff gets effectively multiplied by + return " = " + QString::number(1.0 / (ui.factor->value())); + } + else + { + return ""; + } +} + +/** + * @brief Responds to changes in the value and updates previews accordingly + */ +void MultiplyFactorDialog::updatePreview() +{ + this->ui->factor->setPrefix(::prefixForFactorInput(*this->ui)); + this->ui->factor->setSuffix(::suffixForFactorInput(*this->ui)); + this->preview.setValue(this->value()); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/widgets/multiplyfactordialog.h Wed Jun 22 20:27:53 2022 +0300 @@ -0,0 +1,22 @@ +#pragma once +#include <QDialog> +#include "vec3editor.h" + +namespace Ui +{ + class MultiplyFactorDialog; +} + +class MultiplyFactorDialog : public QDialog +{ + Q_OBJECT +public: + explicit MultiplyFactorDialog(const glm::vec3& baseVector = glm::vec3{}, QWidget *parent = nullptr); + ~MultiplyFactorDialog(); + glm::vec3 value() const; +private: + Q_SLOT void updatePreview(); + std::unique_ptr<Ui::MultiplyFactorDialog> ui; + const glm::vec3 baseVector; + Vec3Editor preview; +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/widgets/multiplyfactordialog.ui Wed Jun 22 20:27:53 2022 +0300 @@ -0,0 +1,103 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>MultiplyFactorDialog</class> + <widget class="QDialog" name="MultiplyFactorDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>286</width> + <height>169</height> + </rect> + </property> + <property name="windowTitle"> + <string>Multiply with a scalar</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QFormLayout" name="formLayout"> + <item row="0" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Factor:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="DoubleSpinBox" name="factor"> + <property name="value"> + <double>1.000000000000000</double> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QCheckBox" name="invert"> + <property name="text"> + <string>Invert</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QGroupBox" name="previewGroupBox"> + <property name="title"> + <string>Preview</string> + </property> + </widget> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>DoubleSpinBox</class> + <extends>QDoubleSpinBox</extends> + <header>widgets/doublespinbox.h</header> + </customwidget> + </customwidgets> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>MultiplyFactorDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>MultiplyFactorDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/widgets/vec3editor.cpp Wed Jun 22 20:27:53 2022 +0300 @@ -0,0 +1,67 @@ +#include <QDialog> +#include <QCheckBox> +#include <QSignalBlocker> +#include "vec3editor.h" +#include "ui_vec3editor.h" +#include "multiplyfactordialog.h" + +Vec3Editor::Vec3Editor(const glm::vec3& value, QWidget *parent, QFlags<Flag> flags) : + QWidget{parent}, + ui{new Ui::Vec3Editor} +{ + this->ui->setupUi(this); + this->setValue(value); + if (flags.testFlag(NoMultiplyButton)) + { + this->ui->multiply->setVisible(false); + } + else + { + connect(this->ui->multiply, &QPushButton::clicked, this, &Vec3Editor::multiplyPressed); + } + for (QDoubleSpinBox* spinbox : this->spinboxes()) + { + connect(spinbox, qOverload<double>(&QDoubleSpinBox::valueChanged), [&](double) + { + Q_EMIT this->valueChanged(this->value()); + }); + } +} + +Vec3Editor::~Vec3Editor() +{ +} + +glm::vec3 Vec3Editor::value() const +{ + auto get = [](DoubleSpinBox* spinbox){ return static_cast<float>(spinbox->value()); }; + return {get(this->ui->x), get(this->ui->y), get(this->ui->z)}; +} + +void Vec3Editor::setValue(const glm::vec3& value) +{ + auto set = [](DoubleSpinBox* spinbox, float value) + { + QSignalBlocker blocker{spinbox}; + spinbox->setValue(static_cast<qreal>(value)); + }; + set(this->ui->x, value.x); + set(this->ui->y, value.y); + set(this->ui->z, value.z); + Q_EMIT this->valueChanged(value); +} + +std::array<DoubleSpinBox*, 3> Vec3Editor::spinboxes() +{ + return {this->ui->x, this->ui->y, this->ui->z}; +} + +void Vec3Editor::multiplyPressed() +{ + MultiplyFactorDialog dialog{this->value(), this}; + const int dialogResult = dialog.exec(); + if (dialogResult == QDialog::Accepted) + { + this->setValue(dialog.value()); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/widgets/vec3editor.h Wed Jun 22 20:27:53 2022 +0300 @@ -0,0 +1,30 @@ +#pragma once +#include <QWidget> +#include <glm/glm.hpp> + +namespace Ui +{ + class Vec3Editor; +} + +class Vec3Editor : public QWidget +{ + Q_OBJECT +public: + enum Flag + { + NoMultiplyButton = 0x1 + }; + explicit Vec3Editor(const glm::vec3& value, QWidget* parent = nullptr, QFlags<Flag> flags = {}); + ~Vec3Editor(); + glm::vec3 value() const; + void setValue(const glm::vec3& value); +Q_SIGNALS: + void valueChanged(const glm::vec3& value); +private: + std::array<class DoubleSpinBox*, 3> spinboxes(); + Q_SLOT void multiplyPressed(); + std::unique_ptr<Ui::Vec3Editor> ui; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QFlags<Vec3Editor::Flag>)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/widgets/vec3editor.ui Wed Jun 22 20:27:53 2022 +0300 @@ -0,0 +1,83 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>Vec3Editor</class> + <widget class="QWidget" name="Vec3Editor"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>613</width> + <height>46</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QHBoxLayout" name="horizontalLayout" stretch="1,1,1,0"> + <item> + <widget class="DoubleSpinBox" name="x"> + <property name="prefix"> + <string>x = </string> + </property> + <property name="decimals"> + <number>4</number> + </property> + <property name="minimum"> + <double>-1000000.000000000000000</double> + </property> + <property name="maximum"> + <double>1000000.000000000000000</double> + </property> + </widget> + </item> + <item> + <widget class="DoubleSpinBox" name="y"> + <property name="prefix"> + <string>y = </string> + </property> + <property name="decimals"> + <number>4</number> + </property> + <property name="minimum"> + <double>-1000000.000000000000000</double> + </property> + <property name="maximum"> + <double>1000000.000000000000000</double> + </property> + </widget> + </item> + <item> + <widget class="DoubleSpinBox" name="z"> + <property name="prefix"> + <string>z = </string> + </property> + <property name="decimals"> + <number>4</number> + </property> + <property name="minimum"> + <double>-1000000.000000000000000</double> + </property> + <property name="maximum"> + <double>1000000.000000000000000</double> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="multiply"> + <property name="text"> + <string>×</string> + </property> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>DoubleSpinBox</class> + <extends>QDoubleSpinBox</extends> + <header>widgets/doublespinbox.h</header> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui>