Download src/Mod/Material/Gui/MaterialDelegate.cpp from AbdulElahGwaith/FreeCAD: direct link, hf CLI and curl.
- Browser
- Download file 17.7 kB
-
https://huggingface.co/AbdulElahGwaith/FreeCAD/resolve/main/src/Mod/Material/Gui/MaterialDelegate.cpp
- Command line
-
hf download hf://AbdulElahGwaith/FreeCAD/src/Mod/Material/Gui/MaterialDelegate.cpp
-
curl -L -o MaterialDelegate.cpp https://huggingface.co/AbdulElahGwaith/FreeCAD/resolve/main/src/Mod/Material/Gui/MaterialDelegate.cpp
17.7 kB
| // SPDX-License-Identifier: LGPL-2.1-or-later | |
| /*************************************************************************** | |
| * Copyright (c) 2023 David Carter <dcarter@david.carter.ca> * | |
| * * | |
| * This file is part of FreeCAD. * | |
| * * | |
| * FreeCAD is free software: you can redistribute it and/or modify it * | |
| * under the terms of the GNU Lesser General Public License as * | |
| * published by the Free Software Foundation, either version 2.1 of the * | |
| * License, or (at your option) any later version. * | |
| * * | |
| * FreeCAD 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 * | |
| * Lesser General Public License for more details. * | |
| * * | |
| * You should have received a copy of the GNU Lesser General Public * | |
| * License along with FreeCAD. If not, see * | |
| * <https://www.gnu.org/licenses/>. * | |
| * * | |
| **************************************************************************/ | |
| using namespace MatGui; | |
| MaterialDelegate::MaterialDelegate(QObject* parent) | |
| : BaseDelegate(parent) | |
| {} | |
| bool MaterialDelegate::newRow(const QAbstractItemModel* model, const QModelIndex& index) const | |
| { | |
| Q_UNUSED(model) | |
| Q_UNUSED(index) | |
| // New rows are for lists and arrays | |
| return false; | |
| } | |
| Materials::MaterialValue::ValueType MaterialDelegate::getType(const QModelIndex& index) const | |
| { | |
| auto treeModel = dynamic_cast<const QStandardItemModel*>(index.model()); | |
| auto item = treeModel->itemFromIndex(index); | |
| auto group = item->parent(); | |
| if (!group) { | |
| return {}; | |
| } | |
| int row = index.row(); | |
| QString propertyType; | |
| if (group->child(row, 1)) { | |
| propertyType = group->child(row, 2)->text(); | |
| } | |
| return Materials::MaterialValue::mapType(propertyType); | |
| } | |
| QString MaterialDelegate::getUnits(const QModelIndex& index) const | |
| { | |
| auto treeModel = dynamic_cast<const QStandardItemModel*>(index.model()); | |
| auto item = treeModel->itemFromIndex(index); | |
| auto group = item->parent(); | |
| if (!group) { | |
| return {}; | |
| } | |
| int row = index.row(); | |
| QString propertyUnits; | |
| if (group->child(row, 1)) { | |
| propertyUnits = group->child(row, 3)->text(); | |
| } | |
| return propertyUnits; | |
| } | |
| QVariant MaterialDelegate::getValue(const QModelIndex& index) const | |
| { | |
| auto treeModel = dynamic_cast<const QStandardItemModel*>(index.model()); | |
| auto item = treeModel->itemFromIndex(index); | |
| auto group = item->parent(); | |
| if (!group) { | |
| return {}; | |
| } | |
| int row = index.row(); | |
| QVariant propertyValue; | |
| if (group->child(row, 1)) { | |
| auto material = group->child(row, 1)->data().value<std::shared_ptr<Materials::Material>>(); | |
| // auto propertyName = group->child(row, 0)->text(); | |
| auto propertyName = group->child(row, 0)->data().toString(); | |
| propertyValue = material->getProperty(propertyName)->getValue(); | |
| } | |
| return propertyValue; | |
| } | |
| void MaterialDelegate::setValue(QAbstractItemModel* model, | |
| const QModelIndex& index, | |
| const QVariant& value) const | |
| { | |
| auto matModel = dynamic_cast<const QStandardItemModel*>(model); | |
| auto item = matModel->itemFromIndex(index); | |
| auto group = item->parent(); | |
| if (!group) { | |
| return; | |
| } | |
| int row = index.row(); | |
| if (group->child(row, 1)) { | |
| auto material = group->child(row, 1)->data().value<std::shared_ptr<Materials::Material>>(); | |
| auto propertyName = group->child(row, 0)->data().toString(); | |
| std::string _name = propertyName.toStdString(); | |
| auto property = material->getProperty(propertyName); | |
| try { | |
| property->setValue(value); | |
| } | |
| catch (const Base::ValueError&) { | |
| // Units mismatch | |
| auto quantity = value.value<Base::Quantity>(); | |
| Base::Console().log("Units mismatch '%s' = '%s', " | |
| "setting to default property units '%s'\n", | |
| propertyName.toStdString().c_str(), | |
| quantity.getUserString().c_str(), | |
| property->getUnits().toStdString().c_str()); | |
| QMessageBox msgBox; | |
| msgBox.setWindowTitle(QStringLiteral("Property Units Mismatch")); | |
| msgBox.setText(QStringLiteral("Units mismatch '%1' = '%2', " | |
| "setting to default property units '%3'\n") | |
| .arg(propertyName) | |
| .arg(QString::fromStdString(quantity.getUserString())) | |
| .arg(property->getUnits())); | |
| msgBox.exec(); | |
| property->setQuantity( | |
| Base::Quantity(quantity.getValue(), property->getUnits().toStdString())); | |
| } | |
| group->child(row, 1)->setText(property->getString()); | |
| } | |
| notifyChanged(model, index); | |
| } | |
| void MaterialDelegate::notifyChanged(const QAbstractItemModel* model, | |
| const QModelIndex& index) const | |
| { | |
| auto treeModel = dynamic_cast<const QStandardItemModel*>(model); | |
| auto item = treeModel->itemFromIndex(index); | |
| auto group = item->parent(); | |
| if (!group) { | |
| return; | |
| } | |
| int row = index.row(); | |
| if (group->child(row, 1)) { | |
| auto material = group->child(row, 1)->data().value<std::shared_ptr<Materials::Material>>(); | |
| // auto propertyName = group->child(row, 0)->text(); | |
| auto propertyName = group->child(row, 0)->data().toString(); | |
| auto propertyValue = material->getProperty(propertyName)->getValue(); | |
| material->setEditStateAlter(); | |
| Q_EMIT const_cast<MaterialDelegate*>(this)->propertyChange(propertyName, propertyValue); | |
| } | |
| } | |
| bool MaterialDelegate::editorEvent(QEvent* event, | |
| QAbstractItemModel* model, | |
| const QStyleOptionViewItem& option, | |
| const QModelIndex& index) | |
| { | |
| if (index.column() == 1) { | |
| if (event->type() == QEvent::MouseButtonDblClick) { | |
| auto treeModel = dynamic_cast<const QStandardItemModel*>(index.model()); | |
| // Check we're not the material model root. This is also used to access the entry | |
| // columns | |
| auto item = treeModel->itemFromIndex(index); | |
| auto group = item->parent(); | |
| if (!group) { | |
| return QStyledItemDelegate::editorEvent(event, model, option, index); | |
| } | |
| int row = index.row(); | |
| // QString propertyName = group->child(row, 0)->text(); | |
| QString propertyName = group->child(row, 0)->data().toString(); | |
| auto type = getType(index); | |
| if (type == Materials::MaterialValue::Color) { | |
| showColorModal(propertyName, item); | |
| // Mark as handled | |
| return true; | |
| } | |
| if (type == Materials::MaterialValue::MultiLineString) { | |
| showMultiLineStringModal(propertyName, item); | |
| // Mark as handled | |
| return true; | |
| } | |
| if (type == Materials::MaterialValue::List || type == Materials::MaterialValue::FileList | |
| || type == Materials::MaterialValue::ImageList) { | |
| showListModal(propertyName, item); | |
| // Mark as handled | |
| return true; | |
| } | |
| if (type == Materials::MaterialValue::Array2D) { | |
| showArray2DModal(propertyName, item); | |
| // Mark as handled | |
| return true; | |
| } | |
| if (type == Materials::MaterialValue::Array3D) { | |
| showArray3DModal(propertyName, item); | |
| // Mark as handled | |
| return true; | |
| } | |
| if (type == Materials::MaterialValue::Image || type == Materials::MaterialValue::SVG) { | |
| showImageModal(propertyName, item); | |
| // Mark as handled | |
| return true; | |
| } | |
| } | |
| } | |
| return QStyledItemDelegate::editorEvent(event, model, option, index); | |
| } | |
| void MaterialDelegate::showColorModal(const QString& propertyName, QStandardItem* item) | |
| { | |
| auto currentColor = parseColor(item->text()).asValue<QColor>(); | |
| auto dlg = new QColorDialog(currentColor); | |
| dlg->setAttribute(Qt::WA_DeleteOnClose); | |
| if (Gui::DialogOptions::dontUseNativeColorDialog()) { | |
| dlg->setOptions(QColorDialog::DontUseNativeDialog); | |
| } | |
| dlg->setOption(QColorDialog::ColorDialogOption::ShowAlphaChannel, false); | |
| dlg->setCurrentColor(currentColor); | |
| dlg->adjustSize(); | |
| connect(dlg, &QColorDialog::finished, this, [&](int result) { | |
| if (result == QDialog::Accepted) { | |
| QColor color = dlg->selectedColor(); | |
| if (color.isValid()) { | |
| QString colorText = QString(QStringLiteral("(%1,%2,%3,%4)")) | |
| .arg(color.red() / 255.0) | |
| .arg(color.green() / 255.0) | |
| .arg(color.blue() / 255.0) | |
| .arg(color.alpha() / 255.0); | |
| item->setText(colorText); | |
| Q_EMIT const_cast<MaterialDelegate*>(this)->propertyChange(propertyName, | |
| item->text()); | |
| } | |
| } | |
| }); | |
| dlg->exec(); | |
| } | |
| void MaterialDelegate::showImageModal(const QString& propertyName, QStandardItem* item) | |
| { | |
| auto material = item->data().value<std::shared_ptr<Materials::Material>>(); | |
| auto dlg = new ImageEdit(propertyName, material); | |
| dlg->setAttribute(Qt::WA_DeleteOnClose); | |
| dlg->adjustSize(); | |
| // connect(dlg, &QDialog::finished, this, [&](int result) {}); | |
| dlg->exec(); | |
| } | |
| void MaterialDelegate::showListModal(const QString& propertyName, QStandardItem* item) | |
| { | |
| auto material = item->data().value<std::shared_ptr<Materials::Material>>(); | |
| auto dlg = new ListEdit(propertyName, material); | |
| dlg->setAttribute(Qt::WA_DeleteOnClose); | |
| dlg->adjustSize(); | |
| // connect(dlg, &QDialog::finished, this, [&](int result) {}); | |
| dlg->exec(); | |
| } | |
| void MaterialDelegate::showMultiLineStringModal(const QString& propertyName, QStandardItem* item) | |
| { | |
| auto material = item->data().value<std::shared_ptr<Materials::Material>>(); | |
| auto dlg = new TextEdit(propertyName, material); | |
| dlg->setAttribute(Qt::WA_DeleteOnClose); | |
| dlg->adjustSize(); | |
| // connect(dlg, &QDialog::finished, this, [&](int result) {}); | |
| dlg->exec(); | |
| } | |
| void MaterialDelegate::showArray2DModal(const QString& propertyName, QStandardItem* item) | |
| { | |
| auto material = item->data().value<std::shared_ptr<Materials::Material>>(); | |
| auto dlg = new Array2D(propertyName, material); | |
| dlg->setAttribute(Qt::WA_DeleteOnClose); | |
| dlg->adjustSize(); | |
| // connect(dlg, &QDialog::finished, this, [&](int result) {}); | |
| dlg->exec(); | |
| } | |
| void MaterialDelegate::showArray3DModal(const QString& propertyName, QStandardItem* item) | |
| { | |
| auto material = item->data().value<std::shared_ptr<Materials::Material>>(); | |
| auto dlg = new Array3D(propertyName, material); | |
| dlg->setAttribute(Qt::WA_DeleteOnClose); | |
| dlg->adjustSize(); | |
| // connect(dlg, &QDialog::finished, this, [&](int result) {}); | |
| dlg->exec(); | |
| } | |
| void MaterialDelegate::paint(QPainter* painter, | |
| const QStyleOptionViewItem& option, | |
| const QModelIndex& index) const | |
| { | |
| if (index.column() != 1) { | |
| QStyledItemDelegate::paint(painter, option, index); | |
| return; | |
| } | |
| auto treeModel = dynamic_cast<const QStandardItemModel*>(index.model()); | |
| // Check we're not the material model root. This is also used to access the entry columns | |
| auto item = treeModel->itemFromIndex(index); | |
| auto group = item->parent(); | |
| if (!group) { | |
| QStyledItemDelegate::paint(painter, option, index); | |
| return; | |
| } | |
| auto type = getType(index); | |
| if (type == Materials::MaterialValue::Quantity) { | |
| paintQuantity(painter, option, index); | |
| return; | |
| } | |
| if (type == Materials::MaterialValue::Image) { | |
| paintImage(painter, option, index); | |
| return; | |
| } | |
| if (type == Materials::MaterialValue::SVG) { | |
| paintSVG(painter, option, index); | |
| return; | |
| } | |
| if (type == Materials::MaterialValue::Color) { | |
| paintColor(painter, option, index); | |
| return; | |
| } | |
| if (type == Materials::MaterialValue::List || type == Materials::MaterialValue::FileList | |
| || type == Materials::MaterialValue::ImageList) { | |
| paintList(painter, option, index); | |
| return; | |
| } | |
| if (type == Materials::MaterialValue::MultiLineString) { | |
| paintMultiLineString(painter, option, index); | |
| return; | |
| } | |
| if (type == Materials::MaterialValue::Array2D || type == Materials::MaterialValue::Array3D) { | |
| paintArray(painter, option, index); | |
| return; | |
| } | |
| QStyledItemDelegate::paint(painter, option, index); | |
| } | |
| QWidget* MaterialDelegate::createEditor(QWidget* parent, | |
| const QStyleOptionViewItem& styleOption, | |
| const QModelIndex& index) const | |
| { | |
| Q_UNUSED(styleOption) | |
| if (index.column() != 1) { | |
| return nullptr; | |
| } | |
| auto treeModel = dynamic_cast<const QStandardItemModel*>(index.model()); | |
| // Check we're not the material model root. This is also used to access the entry columns | |
| auto item = treeModel->itemFromIndex(index); | |
| auto group = item->parent(); | |
| if (!group) { | |
| return nullptr; | |
| } | |
| QVariant value = treeModel->data(index); | |
| QWidget* editor = createWidget(parent, value, index); | |
| return editor; | |
| } | |
| QWidget* MaterialDelegate::createWidget(QWidget* parent, | |
| const QVariant& item, | |
| const QModelIndex& index) const | |
| { | |
| QWidget* widget = nullptr; | |
| auto type = getType(index); | |
| if (type == Materials::MaterialValue::Integer) { | |
| auto spinner = new Gui::IntSpinBox(parent); | |
| spinner->setMinimum(0); | |
| spinner->setMaximum(std::numeric_limits<int>::max()); | |
| spinner->setValue(item.toInt()); | |
| widget = spinner; | |
| } | |
| else if (type == Materials::MaterialValue::Float) { | |
| auto spinner = new Gui::DoubleSpinBox(parent); | |
| // the magnetic permeability is the parameter for which many decimals matter | |
| // the most however, even for this, 6 digits are sufficient | |
| spinner->setDecimals(6); | |
| // for almost all Float parameters of materials a step of 1 would be too large | |
| spinner->setSingleStep(0.1); | |
| spinner->setMinimum(std::numeric_limits<double>::min()); | |
| spinner->setMaximum(std::numeric_limits<double>::max()); | |
| spinner->setValue(item.toDouble()); | |
| widget = spinner; | |
| } | |
| else if (type == Materials::MaterialValue::Boolean) { | |
| auto combo = new Gui::PrefComboBox(parent); | |
| combo->insertItem(0, QStringLiteral("")); | |
| combo->insertItem(1, tr("False")); | |
| combo->insertItem(2, tr("True")); | |
| combo->setCurrentText(item.toString()); | |
| widget = combo; | |
| } | |
| else if (type == Materials::MaterialValue::Quantity) { | |
| // auto input = new Gui::InputField(parent); | |
| auto input = new Gui::QuantitySpinBox(parent); | |
| input->setMinimum(std::numeric_limits<double>::min()); | |
| input->setMaximum(std::numeric_limits<double>::max()); | |
| input->setUnitText(getUnits(index)); | |
| // input->setPrecision(6); | |
| input->setValue(item.value<Base::Quantity>()); | |
| widget = input; | |
| } | |
| else if (type == Materials::MaterialValue::File) { | |
| auto chooser = new Gui::FileChooser(parent); | |
| if (!item.toString().isEmpty()) { | |
| chooser->setFileName(item.toString()); | |
| } | |
| widget = chooser; | |
| } | |
| else { | |
| // Default editor | |
| auto lineEdit = new Gui::PrefLineEdit(parent); | |
| lineEdit->setText(item.toString()); | |
| widget = lineEdit; | |
| } | |
| return widget; | |
| } | |