Skip to content
Snippets Groups Projects
LayerForm.cpp 8.15 KiB
Newer Older
  • Learn to ignore specific revisions
  • //  ************************************************************************************************
    //
    //  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"
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
    #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"
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
    #include "GUI/Support/Util/ActionFactory.h"
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
    #include "GUI/Support/Util/WidgetMoverButton.h"
    
    #include "GUI/View/Numeric/NumWidgetUtil.h"
    
    #include "GUI/View/SampleDesigner/MaterialInplaceForm.h"
    #include "GUI/View/SampleDesigner/ParticleLayoutForm.h"
    
    #include <QLineEdit>
    #include <QMenu>
    #include <QPushButton>
    
    Mikhail Svechnikov's avatar
    Mikhail Svechnikov committed
    LayerForm::LayerForm(QWidget* parent, LayerItem* layerItem, SampleEditorController* ec)
    
        : CollapsibleGroupBox(layerItem->layerName(), parent, layerItem->expandLayer)
    
    Mikhail Svechnikov's avatar
    Mikhail Svechnikov committed
        , m_layer(layerItem)
    
        m_layouter = std::make_unique<FormLayouter>(this, ec);
    
        body()->setLayout(m_layouter->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), "");
    
    Mikhail Svechnikov's avatar
    Mikhail Svechnikov committed
                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(
    
    Mikhail Svechnikov's avatar
    Mikhail Svechnikov committed
                this, "layer", [ec, layerItem] { ec->requestViewInRealspace(layerItem); });
    
            addTitleAction(showInRealspaceAction);
    
        }
        // duplicate
        {
    
            m_duplicateAction = ActionFactory::createDuplicateAction(
    
    Mikhail Svechnikov's avatar
    Mikhail Svechnikov committed
                this, "layer", [ec, layerItem] { ec->duplicateLayerItem(layerItem); });
    
            addTitleAction(m_duplicateAction);
    
        }
        // remove
        {
            m_removeAction = ActionFactory::createRemoveAction(
    
    Mikhail Svechnikov's avatar
    Mikhail Svechnikov committed
                this, "layer", [ec, layerItem] { ec->removeLayerItem(layerItem); });
    
            addTitleAction(m_removeAction);
    
        QColor bckgroundCol = m_layer->color();
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
        setStyleSheet("CollapsibleGroupBox {background-color: " + bckgroundCol.name(QColor::HexRgb)
                      + "}");
    
    Mikhail Svechnikov's avatar
    Mikhail Svechnikov committed
        m_layouter->addRow("Material:", new MaterialInplaceForm(this, layerItem, ec));
    
        m_thicknessRow = m_layouter->addValue(m_layer->thickness());
    
    
        m_layouter->addRow("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_roughnessRow = m_layouter->addSelection(m_layer->roughnessSelection());
    
    Mikhail Svechnikov's avatar
    Mikhail Svechnikov committed
        for (auto* layout : layerItem->layoutItems())
    
            m_layouter->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_layouter->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.
    
    Mikhail Svechnikov's avatar
    Mikhail Svechnikov committed
        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)
    
        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) + "}");
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
        const SampleItem* sampleItem = m_ec->sampleItem();
        ASSERT(sampleItem);
        int i = sampleItem->layerItems().indexOf(m_layer);
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
        setTitle("Layer " + QString::number(i) + "     Material: " + m_layer->materialName());
    
        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_layouter->setRowVisible(m_roughnessRow, !isFirstLayer);
    
        if (m_thicknessRow == -1)
            return;
        QWidget* w = m_layouter->layout()->itemAt(m_thicknessRow, QFormLayout::FieldRole)->widget();
    
        if (thicknessIsSemiInfinite || thicknessIsInfinite) {
    
            if (info == nullptr) {
                m_layouter->removeRow(m_thicknessRow);
                info = new QLineEdit(this);
                info->setEnabled(false);
                info->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
    
                m_layouter->insertRow(m_thicknessRow, m_layer->thickness().label(), info);
    
            }
            info->setText(thicknessIsSemiInfinite ? "Semi-infinite" : "Infinite");
        } else if (!thicknessIsSemiInfinite && !thicknessIsInfinite
                   && (qobject_cast<QLineEdit*>(w) != nullptr)) {
    
            m_layouter->removeRow(m_thicknessRow);
            m_layouter->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);
    
    Mikhail Svechnikov's avatar
    Mikhail Svechnikov committed
        const int rowInLayout =
            m_layouter->layout()->rowCount() - m_layer->layoutItems().size() + index;
    
    
        m_layouter->insertRow(rowInLayout, new ParticleLayoutForm(this, newLayoutItem, m_ec));
    }
    
    void LayerForm::onAboutToRemoveLayout(ParticleLayoutItem* layoutItem)
    {
    
        int index = m_layer->layoutItems().indexOf(layoutItem);
    
            m_layouter->layout()->rowCount() - m_layer->layoutItems().size() - 1 + index; // -1: btn
    
    
        m_layouter->removeRow(rowInLayout);
    }
    
    LayerItem* LayerForm::layerItem() const
    {
        return m_layer;
    }