// SPDX-License-Identifier: LGPL-2.1-or-later /*************************************************************************** * Copyright (c) 2002 Jürgen Riegel * * * * This file is part of the FreeCAD CAx development system. * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Library General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * * This library 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 Library General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this library; see the file COPYING.LIB. If not, * * write to the Free Software Foundation, Inc., 59 Temple Place, * * Suite 330, Boston, MA 02111-1307, USA * * * ***************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include "DlgDisplayPropertiesImp.h" #include "ui_DlgDisplayProperties.h" using namespace MatGui; using namespace std; namespace sp = std::placeholders; /* TRANSLATOR Gui::Dialog::DlgDisplayPropertiesImp */ class DlgDisplayPropertiesImp::Private { using DlgDisplayPropertiesImp_Connection = fastsignals::connection; public: Ui::DlgDisplayProperties ui; DlgDisplayPropertiesImp_Connection connectChangedObject; static void setElementColor(const std::vector& views, const char* property, Gui::ColorButton* buttonColor) { bool hasElementColor = false; for (const auto& view : views) { if (auto* prop = dynamic_cast(view->getPropertyByName(property))) { Base::Color color = prop->getValue(); QSignalBlocker block(buttonColor); buttonColor->setColor(color.asValue()); hasElementColor = true; break; } } buttonColor->setEnabled(hasElementColor); } static void setElementAppearance(const std::vector& views, const char* property, Gui::ColorButton* buttonColor) { bool hasElementColor = false; for (const auto& view : views) { if (auto* prop = dynamic_cast(view->getPropertyByName(property))) { Base::Color color = prop->getDiffuseColor(); QSignalBlocker block(buttonColor); buttonColor->setColor(color.asValue()); hasElementColor = true; break; } } buttonColor->setEnabled(hasElementColor); } static void setDrawStyle(const std::vector& views, const char* property, QSpinBox* spinbox) { bool hasDrawStyle = false; for (const auto& view : views) { if (auto* prop = dynamic_cast(view->getPropertyByName(property))) { QSignalBlocker block(spinbox); spinbox->setValue(int(prop->getValue())); hasDrawStyle = true; break; } } spinbox->setEnabled(hasDrawStyle); } static void setTransparency(const std::vector& views, const char* property, QSpinBox* spinbox, QSlider* slider) { bool hasTransparency = false; for (const auto& view : views) { if (auto* prop = dynamic_cast(view->getPropertyByName(property))) { QSignalBlocker blockSpinBox(spinbox); spinbox->setValue(prop->getValue()); QSignalBlocker blockSlider(slider); slider->setValue(prop->getValue()); hasTransparency = true; break; } } spinbox->setEnabled(hasTransparency); slider->setEnabled(hasTransparency); } }; DlgDisplayPropertiesImp::DlgDisplayPropertiesImp(QWidget* parent, Qt::WindowFlags fl) : QDialog(parent, fl) , d(new Private) { d->ui.setupUi(this); setupConnections(); d->ui.textLabel1_3->hide(); d->ui.changePlot->hide(); d->ui.buttonLineColor->setModal(false); d->ui.buttonPointColor->setModal(false); // Create a filter to only include current format materials // that contain the basic render model. setupFilters(); { QSignalBlocker block(d->ui.widgetMaterial); setPropertiesFromSelection(); } Gui::Selection().Attach(this); // NOLINTBEGIN d->connectChangedObject = Gui::Application::Instance->signalChangedObject.connect( std::bind(&DlgDisplayPropertiesImp::slotChangedObject, this, sp::_1, sp::_2)); // NOLINTEND } DlgDisplayPropertiesImp::~DlgDisplayPropertiesImp() { // no need to delete child widgets, Qt does it all for us d->connectChangedObject.disconnect(); Gui::Selection().Detach(this); } void DlgDisplayPropertiesImp::setupFilters() { // Create a filter to only include current format materials // that contain the basic render model. auto filterList = std::make_shared>>(); auto filter = std::make_shared(); filter->setName(tr("Basic appearance")); filter->addRequiredComplete(Materials::ModelUUIDs::ModelUUID_Rendering_Basic); filterList->push_back(filter); filter = std::make_shared(); filter->setName(tr("Texture appearance")); filter->addRequiredComplete(Materials::ModelUUIDs::ModelUUID_Rendering_Texture); filterList->push_back(filter); filter = std::make_shared(); filter->setName(tr("All materials")); filterList->push_back(filter); d->ui.widgetMaterial->setIncludeEmptyFolders(false); d->ui.widgetMaterial->setIncludeLegacy(false); d->ui.widgetMaterial->setFilter(filterList); } void DlgDisplayPropertiesImp::setupConnections() { connect(d->ui.changeMode, &QComboBox::textActivated, this, &DlgDisplayPropertiesImp::onChangeModeActivated); connect(d->ui.changePlot, &QComboBox::textActivated, this, &DlgDisplayPropertiesImp::onChangePlotActivated); connect(d->ui.spinTransparency, qOverload(&QSpinBox::valueChanged), this, &DlgDisplayPropertiesImp::onSpinTransparencyValueChanged); connect(d->ui.spinPointSize, qOverload(&QSpinBox::valueChanged), this, &DlgDisplayPropertiesImp::onSpinPointSizeValueChanged); connect(d->ui.buttonLineColor, &Gui::ColorButton::changed, this, &DlgDisplayPropertiesImp::onButtonLineColorChanged); connect(d->ui.buttonPointColor, &Gui::ColorButton::changed, this, &DlgDisplayPropertiesImp::onButtonPointColorChanged); connect(d->ui.spinLineWidth, qOverload(&QSpinBox::valueChanged), this, &DlgDisplayPropertiesImp::onSpinLineWidthValueChanged); connect(d->ui.spinLineTransparency, qOverload(&QSpinBox::valueChanged), this, &DlgDisplayPropertiesImp::onSpinLineTransparencyValueChanged); connect(d->ui.buttonCustomAppearance, &Gui::ColorButton::clicked, this, &DlgDisplayPropertiesImp::onButtonCustomAppearanceClicked); connect(d->ui.buttonColorPlot, &Gui::ColorButton::clicked, this, &DlgDisplayPropertiesImp::onButtonColorPlotClicked); connect(d->ui.widgetMaterial, &MaterialTreeWidget::materialSelected, this, &DlgDisplayPropertiesImp::onMaterialSelected); } void DlgDisplayPropertiesImp::changeEvent(QEvent* e) { if (e->type() == QEvent::LanguageChange) { d->ui.retranslateUi(this); } QDialog::changeEvent(e); } void DlgDisplayPropertiesImp::setPropertiesFromSelection() { std::vector views = getSelection(); setDisplayModes(views); setColorPlot(views); setShapeAppearance(views); setLineColor(views); setPointColor(views); setPointSize(views); setLineWidth(views); setTransparency(views); setLineTransparency(views); } /// @cond DOXERR void DlgDisplayPropertiesImp::OnChange(Gui::SelectionSingleton::SubjectType& rCaller, Gui::SelectionSingleton::MessageType Reason) { Q_UNUSED(rCaller); if (Reason.Type == Gui::SelectionChanges::AddSelection || Reason.Type == Gui::SelectionChanges::RmvSelection || Reason.Type == Gui::SelectionChanges::SetSelection || Reason.Type == Gui::SelectionChanges::ClrSelection) { setPropertiesFromSelection(); } } /// @endcond void DlgDisplayPropertiesImp::slotChangedObject(const Gui::ViewProvider& obj, const App::Property& prop) { // This method gets called if a property of any view provider is changed. // We pick out all the properties for which we need to update this dialog. std::vector Provider = getSelection(); auto vp = std::find_if(Provider.begin(), Provider.end(), [&obj](Gui::ViewProvider* v) { return v == &obj; }); if (vp != Provider.end()) { const char* name = obj.getPropertyName(&prop); // this is not a property of the view provider but of the document object if (!name) { return; } std::string prop_name = name; if (prop.is()) { Base::Color value = static_cast(prop).getValue(); if (prop_name == "LineColor") { bool blocked = d->ui.buttonLineColor->blockSignals(true); d->ui.buttonLineColor->setColor(value.asValue()); d->ui.buttonLineColor->blockSignals(blocked); } else if (prop_name == "PointColor") { bool blocked = d->ui.buttonPointColor->blockSignals(true); d->ui.buttonPointColor->setColor(value.asValue()); d->ui.buttonPointColor->blockSignals(blocked); } } else if (prop.isDerivedFrom()) { if (prop_name == "ShapeAppearance") { auto& values = static_cast(prop).getValues(); auto& material = values[0]; d->ui.widgetMaterial->setMaterial(QString::fromStdString(material.uuid)); } } else if (prop.isDerivedFrom()) { long value = static_cast(prop).getValue(); if (prop_name == "Transparency") { bool blocked = d->ui.spinTransparency->blockSignals(true); d->ui.spinTransparency->setValue(value); d->ui.spinTransparency->blockSignals(blocked); blocked = d->ui.horizontalSlider->blockSignals(true); d->ui.horizontalSlider->setValue(value); d->ui.horizontalSlider->blockSignals(blocked); } else if (prop_name == "LineTransparency") { bool blocked = d->ui.spinLineTransparency->blockSignals(true); d->ui.spinLineTransparency->setValue(value); d->ui.spinLineTransparency->blockSignals(blocked); blocked = d->ui.sliderLineTransparency->blockSignals(true); d->ui.sliderLineTransparency->setValue(value); d->ui.sliderLineTransparency->blockSignals(blocked); } } else if (prop.isDerivedFrom()) { double value = static_cast(prop).getValue(); if (prop_name == "PointSize") { bool blocked = d->ui.spinPointSize->blockSignals(true); d->ui.spinPointSize->setValue((int)value); d->ui.spinPointSize->blockSignals(blocked); } else if (prop_name == "LineWidth") { bool blocked = d->ui.spinLineWidth->blockSignals(true); d->ui.spinLineWidth->setValue((int)value); d->ui.spinLineWidth->blockSignals(blocked); } } } } void DlgDisplayPropertiesImp::reject() { QDialog::reject(); } /** * Opens a dialog that allows one to modify the 'ShapeMaterial' property of all selected view providers. */ void DlgDisplayPropertiesImp::onButtonCustomAppearanceClicked() { std::vector Provider = getSelection(); Gui::Dialog::DlgMaterialPropertiesImp dlg(this); if (!Provider.empty()) { if (auto vp = dynamic_cast(Provider.front())) { App::Material mat = vp->ShapeAppearance[0]; dlg.setCustomMaterial(mat); dlg.setDefaultMaterial(mat); } } dlg.exec(); App::Material mat = dlg.getCustomMaterial(); for (auto vp : Provider) { if (auto vpg = dynamic_cast(vp)) { vpg->ShapeAppearance.setValue(mat); } } } /** * Opens a dialog that allows one to modify the 'ShapeMaterial' property of all selected view providers. */ void DlgDisplayPropertiesImp::onButtonColorPlotClicked() { std::vector Provider = getSelection(); static QPointer dlg = nullptr; if (!dlg) { dlg = new Gui::Dialog::DlgMaterialPropertiesImp(this); } dlg->setModal(false); dlg->setAttribute(Qt::WA_DeleteOnClose); if (!Provider.empty()) { App::Property* prop = Provider.front()->getPropertyByName("TextureMaterial"); if (auto matProp = dynamic_cast(prop)) { App::Material mat = (*matProp)[0]; dlg->setCustomMaterial(mat); dlg->setDefaultMaterial(mat); } } dlg->show(); } /** * Sets the 'Display' property of all selected view providers. */ void DlgDisplayPropertiesImp::onChangeModeActivated(const QString& s) { Gui::WaitCursor wc; std::vector Provider = getSelection(); for (auto it : Provider) { if (auto* prop = dynamic_cast(it->getPropertyByName("DisplayMode"))) { prop->setValue(static_cast(s.toLatin1())); } } } void DlgDisplayPropertiesImp::onChangePlotActivated(const QString& s) { Base::Console().log("Plot = %s\n", (const char*)s.toLatin1()); } /** * Sets the 'Transparency' property of all selected view providers. */ void DlgDisplayPropertiesImp::onSpinTransparencyValueChanged(int transparency) { std::vector Provider = getSelection(); for (auto it : Provider) { if (auto* prop = dynamic_cast(it->getPropertyByName("Transparency"))) { prop->setValue(transparency); } } } /** * Sets the 'PointSize' property of all selected view providers. */ void DlgDisplayPropertiesImp::onSpinPointSizeValueChanged(int pointsize) { std::vector Provider = getSelection(); for (auto it : Provider) { if (auto* prop = dynamic_cast(it->getPropertyByName("PointSize"))) { prop->setValue(static_cast(pointsize)); } } } /** * Sets the 'LineWidth' property of all selected view providers. */ void DlgDisplayPropertiesImp::onSpinLineWidthValueChanged(int linewidth) { std::vector Provider = getSelection(); for (auto it : Provider) { if (auto* prop = dynamic_cast(it->getPropertyByName("LineWidth"))) { prop->setValue(static_cast(linewidth)); } } } void DlgDisplayPropertiesImp::onButtonLineColorChanged() { std::vector Provider = getSelection(); QColor s = d->ui.buttonLineColor->color(); Base::Color c {}; c.setValue(s); for (auto it : Provider) { if (auto* prop = dynamic_cast(it->getPropertyByName("LineColor"))) { prop->setValue(c); } } } void DlgDisplayPropertiesImp::onButtonPointColorChanged() { std::vector Provider = getSelection(); QColor s = d->ui.buttonPointColor->color(); Base::Color c {}; c.setValue(s); for (auto it : Provider) { if (auto* prop = dynamic_cast(it->getPropertyByName("PointColor"))) { prop->setValue(c); } } } void DlgDisplayPropertiesImp::onSpinLineTransparencyValueChanged(int transparency) { std::vector Provider = getSelection(); for (auto it : Provider) { if (auto* prop = dynamic_cast(it->getPropertyByName("LineTransparency"))) { prop->setValue(transparency); } } } void DlgDisplayPropertiesImp::setDisplayModes(const std::vector& views) { QStringList commonModes; QStringList modes; for (auto it = views.begin(); it != views.end(); ++it) { if (auto* prop = dynamic_cast((*it)->getPropertyByName("DisplayMode"))) { if (!prop->hasEnums()) { return; } std::vector value = prop->getEnumVector(); if (it == views.begin()) { for (const auto& jt : value) { commonModes << QLatin1String(jt.c_str()); } } else { for (const auto& jt : value) { if (commonModes.contains(QLatin1String(jt.c_str()))) { modes << QLatin1String(jt.c_str()); } } commonModes = modes; modes.clear(); } } } d->ui.changeMode->clear(); d->ui.changeMode->addItems(commonModes); d->ui.changeMode->setDisabled(commonModes.isEmpty()); // find the display mode to activate for (const auto& view : views) { if (auto* prop = dynamic_cast(view->getPropertyByName("DisplayMode"))) { QString activeMode = QString::fromLatin1(prop->getValueAsString()); int index = d->ui.changeMode->findText(activeMode); if (index != -1) { d->ui.changeMode->setCurrentIndex(index); break; } } } } void DlgDisplayPropertiesImp::setColorPlot(const std::vector& views) { bool material = false; for (auto view : views) { auto* prop = dynamic_cast(view->getPropertyByName("TextureMaterial")); if (prop) { material = true; break; } } d->ui.buttonColorPlot->setEnabled(material); } void DlgDisplayPropertiesImp::setShapeAppearance(const std::vector& views) { bool material = false; App::Material mat = App::Material(App::Material::DEFAULT); for (auto view : views) { if (auto* prop = dynamic_cast(view->getPropertyByName("ShapeAppearance"))) { material = true; mat = prop->getValues()[0]; d->ui.widgetMaterial->setMaterial(QString::fromStdString(mat.uuid)); break; } } d->ui.buttonCustomAppearance->setEnabled(material); } void DlgDisplayPropertiesImp::setLineColor(const std::vector& views) { Private::setElementColor(views, "LineColor", d->ui.buttonLineColor); } void DlgDisplayPropertiesImp::setPointColor(const std::vector& views) { Private::setElementColor(views, "PointColor", d->ui.buttonPointColor); } void DlgDisplayPropertiesImp::setPointSize(const std::vector& views) { Private::setDrawStyle(views, "PointSize", d->ui.spinPointSize); } void DlgDisplayPropertiesImp::setLineWidth(const std::vector& views) { Private::setDrawStyle(views, "LineWidth", d->ui.spinLineWidth); } void DlgDisplayPropertiesImp::setTransparency(const std::vector& views) { Private::setTransparency(views, "Transparency", d->ui.spinTransparency, d->ui.horizontalSlider); } void DlgDisplayPropertiesImp::setLineTransparency(const std::vector& views) { Private::setTransparency(views, "LineTransparency", d->ui.spinLineTransparency, d->ui.sliderLineTransparency); } std::vector DlgDisplayPropertiesImp::getSelection() const { std::vector views; // get the complete selection std::vector sel = Gui::Selection().getCompleteSelection(); for (const auto& it : sel) { Gui::ViewProvider* view = Gui::Application::Instance->getDocument(it.pDoc)->getViewProvider(it.pObject); views.push_back(view); } return views; } void DlgDisplayPropertiesImp::onMaterialSelected( const std::shared_ptr& material) { std::vector Provider = getSelection(); for (auto it : Provider) { if (auto* prop = dynamic_cast( it->getPropertyByName("ShapeAppearance"))) { prop->setValue(material->getMaterialAppearance()); } } } // ---------------------------------------------------------------------------- /* TRANSLATOR Gui::Dialog::TaskDisplayProperties */ TaskDisplayProperties::TaskDisplayProperties() { this->setButtonPosition(TaskDisplayProperties::North); widget = new DlgDisplayPropertiesImp(); addTaskBox(widget); } TaskDisplayProperties::~TaskDisplayProperties() = default; QDialogButtonBox::StandardButtons TaskDisplayProperties::getStandardButtons() const { return QDialogButtonBox::Close; } bool TaskDisplayProperties::reject() { widget->reject(); return (widget->result() == QDialog::Rejected); } #include "moc_DlgDisplayPropertiesImp.cpp"