// ************************************************************************************************ // // BornAgain: simulate and fit reflection and scattering // //! @file GUI/View/SampleDesigner/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/SampleDesigner/LayerForm.h" #include "Base/Util/Assert.h" #include "GUI/Model/Sample/LayerItem.h" #include "GUI/Model/Sample/MaterialItem.h" #include "GUI/Model/Sample/MaterialModel.h" #include "GUI/Model/Sample/SampleItem.h" #include "GUI/Support/Util/ActionFactory.h" #include "GUI/Support/Util/WidgetMoverButton.h" #include "GUI/View/Numeric/NumWidgetUtil.h" #include "GUI/View/SampleDesigner/HeinzFormLayout.h" #include "GUI/View/SampleDesigner/MaterialInplaceForm.h" #include "GUI/View/SampleDesigner/ParticleLayoutForm.h" #include <QLineEdit> #include <QMenu> #include <QPushButton> #include <memory> LayerForm::LayerForm(QWidget* parent, LayerItem* layerItem, SampleEditorController* ec) : CollapsibleGroupBox(layerItem->layerName(), parent, layerItem->expandLayer) , m_layer(layerItem) , m_ec(ec) { m_layout = new HeinzFormLayout(ec); 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 : LayerEditorUtil::predefinedLayerColors()) { QPixmap p(64, 64); p.fill(col); auto* ca = menu->addAction(QIcon(p), ""); connect(ca, &QAction::triggered, [this, layerItem, col]() { layerItem->setColor(col); updateColor(); }); } } // move { m_moveButton = new WidgetMoverButton(this, this, 1); m_moveButton->setToolTip("Move layer up/down"); connect(m_moveButton, &WidgetMoverButton::finishedMoving, ec, &SampleEditorController::onStoppedToMoveLayer); addTitleWidget(m_moveButton); m_structureEditingWidgets << m_moveButton; } // show in real space { auto* showInRealspaceAction = ActionFactory::createShowInRealspaceAction( this, "layer", [ec, layerItem] { ec->requestViewInRealspace(layerItem); }); addTitleAction(showInRealspaceAction); } // duplicate { m_duplicateAction = ActionFactory::createDuplicateAction( this, "layer", [ec, layerItem] { ec->duplicateLayerItem(layerItem); }); addTitleAction(m_duplicateAction); } // remove { m_removeAction = ActionFactory::createRemoveAction( this, "layer", [ec, layerItem] { ec->removeLayerItem(layerItem); }); addTitleAction(m_removeAction); } QColor bckgroundCol = m_layer->color(); setStyleSheet("CollapsibleGroupBox {background-color: " + bckgroundCol.name(QColor::HexRgb) + "}"); m_layout->addBoldRow("Material:", new MaterialInplaceForm(this, layerItem, ec)); m_layout->addValue(m_layer->thickness()); m_thicknessRow = m_layout->rowCount() - 1; m_layout->addBoldRow("Number of slices:", GUI::Util::createIntSpinbox( [this] { return m_layer->numSlices(); }, [this](int v) { m_layer->setNumSlices(v); emit m_ec->modified(); }, RealLimits::lowerLimited(1), "Number of horizontal slices.\n" "Used for Average Layer Material calculations \n" "when corresponding simulation option is set.")); m_layout->addSelection(m_layer->roughnessSelection()); m_roughnessRow = m_layout->rowCount() - 1; // -- layouts for (auto* layout : layerItem->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_structureEditingWidgets << 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(), &MaterialModel::materialChanged, this, &LayerForm::updateTitle); updateLayerPositionDependentElements(); } void LayerForm::enableStructureEditing(bool b) { m_removeAction->setVisible(b); m_duplicateAction->setVisible(b); for (auto* w : m_structureEditingWidgets) w->setVisible(b); if (b && m_ec->sampleItem()->layerItems().size() < 2) m_moveButton->setVisible(false); } void LayerForm::updateColor() { QColor bckgroundCol = m_layer->color(); setStyleSheet("LayerForm {background-color: " + bckgroundCol.name(QColor::HexRgb) + "}"); } void LayerForm::updateTitle() { const SampleItem* sampleItem = m_ec->sampleItem(); ASSERT(sampleItem); int i = sampleItem->layerItems().indexOf(m_layer); setTitle("Layer " + QString::number(i) + " Material: " + m_layer->materialName()); } void LayerForm::expand() { setExpanded(true); } void LayerForm::updateLayerPositionDependentElements() { if (m_roughnessRow == -1) return; updateTitle(); const auto* sample = m_ec->sampleItem(); const bool isFirstLayer = sample->layerItems().first() == m_layer; const bool isLastLayer = sample->layerItems().last() == m_layer; const bool thicknessIsSemiInfinite = (isFirstLayer || isLastLayer) && (sample->layerItems().size() != 1); const bool thicknessIsInfinite = sample->layerItems().size() == 1; m_layout->setRowVisible(m_roughnessRow, !isFirstLayer); if (m_thicknessRow == -1) return; QWidget* w = m_layout->itemAt(m_thicknessRow, QFormLayout::FieldRole)->widget(); if (thicknessIsSemiInfinite || thicknessIsInfinite) { auto* info = qobject_cast<QLineEdit*>(w); if (info == nullptr) { m_layout->removeRow(m_thicknessRow); info = new QLineEdit(this); info->setEnabled(false); info->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); m_layout->insertRow(m_thicknessRow, m_layer->thickness().label(), info); } info->setText(thicknessIsSemiInfinite ? "Semi-infinite" : "Infinite"); } else if (!thicknessIsSemiInfinite && !thicknessIsInfinite && (qobject_cast<QLineEdit*>(w) != nullptr)) { m_layout->removeRow(m_thicknessRow); m_layout->insertValue(m_thicknessRow, m_layer->thickness()); } if (m_ec->sampleItem()->layerItems().size() < 2) m_moveButton->setVisible(false); } void LayerForm::onLayoutAdded(ParticleLayoutItem* newLayoutItem) { int index = m_layer->layoutItems().indexOf(newLayoutItem); const int rowInLayout = m_layout->rowCount() - m_layer->layoutItems().size() + index; QWidget* w = new ParticleLayoutForm(this, newLayoutItem, m_ec); m_layout->insertRow(rowInLayout, w); } void LayerForm::onAboutToRemoveLayout(ParticleLayoutItem* layoutItem) { int index = m_layer->layoutItems().indexOf(layoutItem); const int rowInLayout = m_layout->rowCount() - m_layer->layoutItems().size() - 1 + index; // -1: btn m_layout->removeRow(rowInLayout); } LayerItem* LayerForm::layerItem() const { return m_layer; }