// ************************************************************************************************ // // BornAgain: simulate and fit reflection and scattering // //! @file GUI/View/Sample/LayerForm.cpp //! @brief Implements class LayerForm. //! //! @homepage http://www.bornagainproject.org //! @license GNU General Public License v3 or higher (see COPYING) //! @copyright Forschungszentrum Jülich GmbH 2021 //! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS) // // ************************************************************************************************ #include "GUI/View/Sample/LayerForm.h" #include "Base/Util/Assert.h" #include "Base/Util/Vec.h" #include "GUI/Model/Material/MaterialItem.h" #include "GUI/Model/Material/MaterialsSet.h" #include "GUI/Model/Project/ProjectDocument.h" #include "GUI/Model/Sample/LayerItem.h" #include "GUI/Model/Sample/RoughnessItems.h" #include "GUI/Model/Sample/SampleItem.h" #include "GUI/Model/Type/PredefinedColors.h" #include "GUI/View/Base/ActionFactory.h" #include "GUI/View/Numeric/NumWidgetUtil.h" #include "GUI/View/Sample/HeinzFormLayout.h" #include "GUI/View/Sample/MaterialInplaceForm.h" #include "GUI/View/Sample/ParticleLayoutForm.h" #include "GUI/View/Sample/RoughnessForm.h" #include "GUI/View/Widget/WidgetMoverButton.h" #include <QLineEdit> #include <QMenu> #include <QPushButton> LayerForm::LayerForm(QWidget* parent, LayerItem* layer, SampleEditorController* ec) : LayerContainerForm(parent, layer, ec) { setContentsMargins(5, 5, 5, 5); body()->setLayout(m_layout); //... top right corner actions // choose color { auto* chooseColorAction = new QAction(this); chooseColorAction->setText("Choose color"); chooseColorAction->setIcon(QIcon(":/images/palette.svg")); chooseColorAction->setIconText("Choose color"); chooseColorAction->setToolTip("Choose a color for this layer"); auto* menu = new QMenu(this); chooseColorAction->setMenu(menu); addTitleAction(chooseColorAction); for (const auto& col : GUI::Colors::layerDefaults()) { QPixmap p(64, 64); p.fill(col); auto* ca = menu->addAction(QIcon(p), ""); connect(ca, &QAction::triggered, [this, layer, col] { layer->setColor(col); updateColor(); }); } } // move { m_move_button = new WidgetMoverButton(this, this, 1); m_move_button->setToolTip("Move layer up/down"); connect(m_move_button, &WidgetMoverButton::finishedMoving, ec, &SampleEditorController::onStoppedToMoveLayer); addTitleWidget(m_move_button); m_structure_editing_widgets << m_move_button; } // show in real space { auto* showInRealspaceAction = ActionFactory::createShowInRealspaceAction( this, "layer", [ec, layer] { ec->requestViewInRealspace(layer); }); addTitleAction(showInRealspaceAction); } // duplicate { m_duplicate_action = ActionFactory::createDuplicateAction( this, "layer", [ec, layer] { ec->duplicateLayerItem(layer); }); addTitleAction(m_duplicate_action); } // remove { m_remove_action = ActionFactory::createRemoveAction( this, "layer", [ec, layer] { ec->removeLayerItem(layer); }); addTitleAction(m_remove_action); } QColor bckgroundCol = layer->color(); setStyleSheet("LayerForm {background-color: " + bckgroundCol.name(QColor::HexRgb) + "}"); m_layout->addBoldRow("Material:", new MaterialInplaceForm(layer, ec)); m_layout->addValue(layer->thickness()); m_thickness_row = m_layout->rowCount() - 1; m_layout->addBoldRow("Number of slices:", GUI::Util::createIntSpinBox( [this] { return layerItem()->numSlices(); }, [this](int v) { layerItem()->setNumSlices(v); emit gDoc->sampleChanged(); }, RealLimits::lowerLimited(1), "Number of horizontal slices.\n" "Used for Average Layer Material calculations \n" "when corresponding simulation option is set.")); m_roughnessForm = new RoughnessForm(this, layer->roughnessSelection(), layer->expandRoughness, m_ec); m_layout->addRow(m_roughnessForm); m_roughness_row = m_layout->rowCount() - 1; // -- layouts for (auto* layout : layer->layoutItems()) m_layout->addRow(new ParticleLayoutForm(this, layout, ec)); // -- Button for adding a new layout auto* btn = new QPushButton("Add particle layout", this); connect(btn, &QPushButton::clicked, [this, ec] { ec->addLayoutItem(this); }); m_structure_editing_widgets << btn; m_layout->addStructureEditingRow(btn); // listen to changes in materials to update the title (contains the material name). Necessary // to reflect e.g. a name change done in the material editor. connect(ec->materialModel(), &MaterialsSet::materialChanged, this, &LayerForm::updateTitle); updateLayerPositionDependentElements(); } LayerItem* LayerForm::layerItem() const { return dynamic_cast<LayerItem*>(m_item); } void LayerForm::updateColor() { QColor bckgroundCol = layerItem()->color(); setStyleSheet("LayerForm {background-color: " + bckgroundCol.name(QColor::HexRgb) + "}"); } void LayerForm::updateTitle() { const SampleItem* sampleItem = m_ec->sampleItem(); ASSERT(sampleItem); int i = Vec::indexOfPtr(layerItem(), sampleItem->uniqueLayerItems()); setTitle("Layer " + QString::number(i) + " Material: " + layerItem()->materialName()); } void LayerForm::updateLayerPositionDependentElements() { if (m_roughness_row == -1) return; updateTitle(); const auto* sample = m_ec->sampleItem(); const bool isFirstLayer = sample->uniqueLayerItems().front() == layerItem(); const bool isLastLayer = sample->uniqueLayerItems().back() == layerItem(); const bool thicknessIsSemiInfinite = (isFirstLayer || isLastLayer) && (sample->uniqueLayerItems().size() != 1); const bool thicknessIsInfinite = sample->uniqueLayerItems().size() == 1; m_roughnessForm->setVisible(!isFirstLayer); if (m_thickness_row == -1) return; m_roughnessForm->markLayerAsBottom(isLastLayer); QWidget* w = m_layout->itemAt(m_thickness_row, QFormLayout::FieldRole)->widget(); if (thicknessIsSemiInfinite || thicknessIsInfinite) { auto* info = qobject_cast<QLineEdit*>(w); if (info == nullptr) { m_layout->removeRow(m_thickness_row); info = new QLineEdit(this); info->setEnabled(false); info->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); m_layout->insertRow(m_thickness_row, layerItem()->thickness().label(), info); } info->setText(thicknessIsSemiInfinite ? "Semi-infinite" : "Infinite"); } else if (!thicknessIsSemiInfinite && !thicknessIsInfinite && (qobject_cast<QLineEdit*>(w) != nullptr)) { m_layout->removeRow(m_thickness_row); m_layout->insertValue(m_thickness_row, layerItem()->thickness()); } m_move_button->setVisible(m_ec->sampleItem()->uniqueLayerItems().size() > 1); } void LayerForm::onLayoutAdded(ParticleLayoutItem* t) { int index = Vec::indexOfPtr(t, layerItem()->layoutItems()); const int rowInLayout = m_layout->rowCount() - layerItem()->layoutItems().size() + index; QWidget* w = new ParticleLayoutForm(this, t, m_ec); m_layout->insertRow(rowInLayout, w); } void LayerForm::onAboutToRemoveLayout(ParticleLayoutItem* t) { int index = Vec::indexOfPtr(t, layerItem()->layoutItems()); const int rowInLayout = m_layout->rowCount() - layerItem()->layoutItems().size() - 1 + index; // -1: btn m_layout->removeRow(rowInLayout); }