src/dialogs/subfilereferenceeditor.cpp

Wed, 30 May 2018 22:31:06 +0300

author
Teemu Piippo <teemu@hecknology.net>
date
Wed, 30 May 2018 22:31:06 +0300
changeset 1390
3eace926af7f
parent 1389
3fb8ad4d27b1
child 1391
5fa4bf1fc781
permissions
-rw-r--r--

added draw plane feature (doesn't work with circle draw quite right yet)

/*
 *  LDForge: LDraw parts authoring CAD
 *  Copyright (C) 2013 - 2018 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 "subfilereferenceeditor.h"
#include "ui_subfilereferenceeditor.h"
#include "../linetypes/modelobject.h"
#include "../primitives.h"
#include "../guiutilities.h"
#include "../dialogs/colorselector.h"

SubfileReferenceEditor::SubfileReferenceEditor(LDSubfileReference* reference, QWidget* parent) :
	QDialog {parent},
	reference {reference},
	ui {*new Ui::SubfileReferenceEditor}
{
	this->ui.setupUi(this);
	this->ui.referenceName->setText(reference->referenceName());
	this->color = reference->color();
	::setColorButton(this->ui.colorButton, this->color);
	this->ui.positionX->setValue(reference->position().x);
	this->ui.positionY->setValue(reference->position().y);
	this->ui.positionZ->setValue(reference->position().z);
	connect(
		this->ui.colorButton,
		&QPushButton::clicked,
		[&]()
		{
			if (ColorSelector::selectColor(this, this->color, this->color))
				::setColorButton(this->ui.colorButton, this->color);
		}
	);
	for (int i : {0, 1, 2})
	for (int j : {0, 1, 2})
	{
		QLayoutItem* item = this->ui.matrixLayout->itemAtPosition(i, j);
		QDoubleSpinBox* spinbox = item ? qobject_cast<QDoubleSpinBox*>(item->widget()) : nullptr;
		withSignalsBlocked(spinbox, [&]()
		{
			spinbox->setValue(reference->transformationMatrix()(i, j));
		});
		connect(
			spinbox,
			qOverload<double>(&QDoubleSpinBox::valueChanged),
			this,
			&SubfileReferenceEditor::matrixChanged
		);
	}
	connect(
		this->ui.primitivesTreeView,
		&QTreeView::clicked,
		[&](const QModelIndex& index)
		{
			QAbstractItemModel* model = this->ui.primitivesTreeView->model();
			QVariant primitiveName = model->data(index, PrimitiveManager::PrimitiveNameRole);

			if (primitiveName.isValid())
				this->ui.referenceName->setText(primitiveName.toString());
		}
	);

	for (QDoubleSpinBox* spinbox : {this->ui.scalingX, this->ui.scalingY, this->ui.scalingZ})
	{
		connect(
			spinbox,
			qOverload<double>(&QDoubleSpinBox::valueChanged),
			this,
			&SubfileReferenceEditor::scalingChanged
		);
	}

	// Fill in the initial scaling values
	for (int column : {0, 1, 2})
	{
		QDoubleSpinBox* spinbox = this->vectorElement(column);
		withSignalsBlocked(spinbox, [&]()
		{
			spinbox->setValue(this->matrixScaling(column));
		});
	}
}

SubfileReferenceEditor::~SubfileReferenceEditor()
{
	delete &this->ui;
}

/*
 * Returns a spinbox from the matrix grid at position (row, column).
 * Row and column must be within [0, 2].
 */
QDoubleSpinBox* SubfileReferenceEditor::matrixCell(int row, int column) const
{
	if (qBound(0, row, 2) != row or qBound(0, column, 2) != column)
	{
		throw std::out_of_range {"bad row and column values"};
	}
	else
	{
		QLayoutItem* item = this->ui.matrixLayout->itemAtPosition(row, column);
		return item ? qobject_cast<QDoubleSpinBox*>(item->widget()) : nullptr;
	}
}

/*
 * Returns a spinbox for the vector element at the given position
 * Index must be within [0, 2]
 */
QDoubleSpinBox* SubfileReferenceEditor::vectorElement(int index)
{
	switch (index)
	{
	case 0:
		return this->ui.scalingX;

	case 1:
		return this->ui.scalingY;

	case 2:
		return this->ui.scalingZ;

	default:
		throw std::out_of_range {"bad index"};
	}
}

void SubfileReferenceEditor::accept()
{
	this->reference->setReferenceName(this->ui.referenceName->text());
	Matrix transformationMatrix;
	for (int i : {0, 1, 2})
	for (int j : {0, 1, 2})
	{
		transformationMatrix(i, j) = this->matrixCell(i, j)->value();
	}
	this->reference->setTransformationMatrix(transformationMatrix);
	this->reference->setPosition({
		this->ui.positionX->value(),
		this->ui.positionY->value(),
		this->ui.positionZ->value()
	});
	this->reference->setColor(this->color);
	QDialog::accept();
}

void SubfileReferenceEditor::setPrimitivesTree(PrimitiveManager* primitives)
{
	this->ui.primitivesTreeView->setModel(primitives);
}

double SubfileReferenceEditor::matrixScaling(int column) const
{
	return sqrt(
		pow(this->matrixCell(0, column)->value(), 2) +
		pow(this->matrixCell(1, column)->value(), 2) +
		pow(this->matrixCell(2, column)->value(), 2)
	);
}

/*
 * Updates the appropriate matrix column when a scaling vector element is changed.
 */
void SubfileReferenceEditor::scalingChanged()
{
	for (int column : {0, 1, 2})
	{
		if (this->sender() == this->vectorElement(column))
		{
			double oldScaling = this->matrixScaling(column);
			double newScaling = static_cast<QDoubleSpinBox*>(this->sender())->value();

			if (not qFuzzyCompare(newScaling, 0.0))
			{
				for (int row : {0, 1, 2})
				{
					double cellValue = this->matrixCell(row, column)->value();
					cellValue *= newScaling / oldScaling;
					QDoubleSpinBox* cellWidget = this->matrixCell(row, column);
					withSignalsBlocked(cellWidget, [&]()
					{
						cellWidget->setValue(cellValue);
					});
				}
			}

			break;
		}
	}
}

/*
 * Finds the position for the given cell widget.
 */
QPair<int, int> SubfileReferenceEditor::cellPosition(QDoubleSpinBox* cellWidget)
{
	for (int row : {0, 1, 2})
	for (int column : {0, 1, 2})
	{
		if (this->matrixCell(row, column) == cellWidget)
			return {row, column};
	}

	throw std::out_of_range {"widget is not in the matrix"};
}

/*
 * Updates the appropriate scaling vector element when a matrix cell is changed.
 */
void SubfileReferenceEditor::matrixChanged()
{
	QDoubleSpinBox* cellWidget = static_cast<QDoubleSpinBox*>(this->sender());

	try
	{
		int column = this->cellPosition(cellWidget).second;
		QDoubleSpinBox* spinbox = this->vectorElement(column);
		withSignalsBlocked(spinbox, [&]()
		{
			spinbox->setValue(this->matrixScaling(column));
		});
	}
	catch (const std::out_of_range&) {}
}

mercurial