Skip to content
Snippets Groups Projects
MultiLayerForm.cpp 9.63 KiB
Newer Older
  • Learn to ignore specific revisions
  • //  ************************************************************************************************
    //
    //  BornAgain: simulate and fit reflection and scattering
    //
    
    //! @file      GUI/View/SampleDesigner/MultiLayerForm.cpp
    
    //! @brief     Implements class MultiLayerForm
    //!
    //! @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/MultiLayerForm.h"
    
    #include "GUI/Model/Sample/MultiLayerItem.h"
    
    #include "GUI/Util/ActionFactory.h"
    
    #include "GUI/View/Common/DoubleSpinBox.h"
    
    #include "GUI/View/SampleDesigner/LayerForm.h"
    #include "GUI/View/SampleDesigner/MesoCrystalForm.h"
    #include "GUI/View/SampleDesigner/ParticleCompositionForm.h"
    #include "GUI/View/SampleDesigner/ParticleCoreShellForm.h"
    #include "GUI/View/SampleDesigner/ParticleForm.h"
    #include "GUI/View/SampleDesigner/ParticleLayoutForm.h"
    
    #include "GUI/View/Tool/GroupBoxCollapser.h"
    
    #include <QBoxLayout>
    #include <QLabel>
    
    
    namespace {
    
    //! Widget with a button to add a layer (the "add layer" buttons shown between layers)
    class AddLayerWidget : public QWidget {
    public:
        AddLayerWidget(QWidget* parent, LayerItem* layer, SampleEditorController* ec)
    
            : QWidget(parent)
            , m_layer(layer)
    
            auto* l = new QHBoxLayout(this);
    
            l->setContentsMargins(0, 0, 0, 0);
            auto* btn = new QPushButton("Add layer", this);
            l->addStretch();
            l->addWidget(btn);
            l->addStretch();
            connect(btn, &QPushButton::clicked, [=]() { ec->addLayer(layer); });
        }
    
        LayerItem* m_layer;
    };
    
    } // namespace
    
    MultiLayerForm::MultiLayerForm(QWidget* parent, MultiLayerItem* multiLayerItem,
                                   SampleEditorController* ec)
    
        : QWidget(parent)
        , m_multiLayerItem(multiLayerItem)
        , m_ec(ec)
        , m_useAngstrom(false)
        , m_useRadiant(false)
    
    {
        setObjectName("MultiLayerForm"); // important for style sheet addressing
        setAttribute(Qt::WA_StyledBackground, true);
    
        m_layout = new QVBoxLayout(this);
    
    
        auto* props = new QGroupBox(this);
    
        props->setTitle("Sample");
    
        FormLayouter layouter(props, ec);
        layouter.setContentsMargins(6, 6, 0, 6);
    
    
        auto* nameEdit = new QLineEdit(props);
        layouter.addRow("Name:", nameEdit);
        nameEdit->setText(multiLayerItem->sampleName());
        connect(nameEdit, &QLineEdit::textEdited, ec, &SampleEditorController::setSampleName);
    
        auto* descriptionEdit = new QTextEdit(props);
        descriptionEdit->setMinimumWidth(300);
        descriptionEdit->setMaximumHeight(100);
        descriptionEdit->setAcceptRichText(false);
        descriptionEdit->setTabChangesFocus(true);
        descriptionEdit->setPlainText(multiLayerItem->description());
        layouter.addRow("Description:", descriptionEdit);
        connect(descriptionEdit, &QTextEdit::textChanged,
                [=]() { m_ec->setSampleDescription(descriptionEdit->toPlainText()); });
    
    
        layouter.addValue(multiLayerItem->crossCorrLength());
        layouter.addVector(multiLayerItem->externalFieldVector(), false);
    
        auto* collapser = GroupBoxCollapser::installIntoGroupBox(props, false);
    
        auto* showInRealSpaceAction = ActionFactory::createShowInRealSpaceAction(
            this, "sample", [=] { m_ec->requestViewInRealSpace(m_multiLayerItem); });
    
        collapser->addAction(showInRealSpaceAction);
    
    
        for (auto* layer : multiLayerItem->layers()) {
    
            m_layout->addWidget(new AddLayerWidget(this, layer, m_ec));
            m_layout->addWidget(new LayerForm(this, layer, m_ec));
        }
        m_layout->addWidget(new AddLayerWidget(this, nullptr, m_ec));
        m_layout->setSizeConstraint(QLayout::SetMinimumSize);
        m_layout->addStretch(1);
    }
    
    void MultiLayerForm::showInlineEditButtons(bool b)
    {
        m_showInlineEditButtons = b;
        updateRowVisibilities();
    }
    
    void MultiLayerForm::onLayerAdded(LayerItem* layerItem)
    {
        const int rowInMultiLayer = m_multiLayerItem->layers().indexOf(layerItem);
    
        const int rowInLayout = rowInMultiLayer * 2 + 1;
    
        m_layout->insertWidget(rowInLayout, new LayerForm(this, layerItem, m_ec));
    
        // same row => button is above!
        m_layout->insertWidget(rowInLayout, new AddLayerWidget(this, layerItem, m_ec));
    
        updateRowVisibilities();
    }
    
    void MultiLayerForm::onLayerMoved(LayerItem* layerItem)
    {
        LayerForm* wl = nullptr;
        AddLayerWidget* al = nullptr;
        for (int index = 0; index < m_layout->count(); index++) {
    
            if (auto* w = dynamic_cast<AddLayerWidget*>(m_layout->itemAt(index)->widget()))
    
                if (w->m_layer == layerItem) {
                    al = w;
                    m_layout->takeAt(index);
                    break;
                }
        }
    
        for (int index = 0; index < m_layout->count(); index++) {
    
            if (auto* w = dynamic_cast<LayerForm*>(m_layout->itemAt(index)->widget()))
    
                if (w->layerItem() == layerItem) {
                    wl = w;
                    m_layout->takeAt(index);
                    break;
                }
        }
    
        const int rowInMultiLayer = m_multiLayerItem->layers().indexOf(layerItem);
        const int rowInLayout = rowInMultiLayer * 2 + 1;
    
        m_layout->insertWidget(rowInLayout, wl);
    
        // same row => button is above!
        m_layout->insertWidget(rowInLayout, al);
    
        updateRowVisibilities();
    }
    
    void MultiLayerForm::onAboutToRemoveLayer(LayerItem* layerItem)
    {
        LayerForm* layerForm = nullptr;
        AddLayerWidget* addLayerWidget = nullptr;
    
        for (auto* c : findChildren<QWidget*>()) {
            if (auto* w = dynamic_cast<AddLayerWidget*>(c))
    
                if (w->m_layer == layerItem)
                    addLayerWidget = w;
    
    
            if (auto* w = dynamic_cast<LayerForm*>(c)) {
    
                    layerForm = w;
            }
        }
    
        if (layerForm) {
            // delete editors which are subscribed to SessionItems
    
            GUI::Util::Layout::clearLayout(layerForm->layout());
    
            layerForm->hide();
            layerForm->setParent(nullptr); // so it is not findable in update routines
            layerForm->deleteLater();      // delete later (this is the sender)
        }
    
    
    
        delete addLayerWidget;
    
    }
    
    void MultiLayerForm::updateRowVisibilities()
    {
    
        for (auto* c : findChildren<QWidget*>()) {
            if (auto* w = dynamic_cast<LayerForm*>(c))
    
                w->enableStructureEditing(m_showInlineEditButtons);
    
            if (auto* w = dynamic_cast<ParticleLayoutForm*>(c))
    
                w->enableStructureEditing(m_showInlineEditButtons);
    
            if (auto* w = dynamic_cast<ParticleForm*>(c))
    
                w->enableStructureEditing(m_showInlineEditButtons);
    
            if (auto* w = dynamic_cast<ParticleCompositionForm*>(c))
    
                w->enableStructureEditing(m_showInlineEditButtons);
    
            if (auto* w = dynamic_cast<ParticleCoreShellForm*>(c))
    
                w->enableStructureEditing(m_showInlineEditButtons);
    
            if (auto* w = dynamic_cast<MesoCrystalForm*>(c))
    
                w->enableStructureEditing(m_showInlineEditButtons);
        }
    
        showAddLayerButtons(m_showInlineEditButtons);
    
    
        for (auto* c : findChildren<LayerForm*>())
    
            c->updateLayerPositionDependentElements();
    }
    
    
    
    void MultiLayerForm::updateUnits()
    
    {
        const auto set = [](DoubleSpinBox* spinbox, Unit valueUnit, Unit displayUnit) {
            if (spinbox->baseUnit() == valueUnit)
                spinbox->setDisplayUnit(displayUnit);
        };
    
        for (auto* editor : findChildren<DoubleSpinBox*>()) {
    
                set(editor, Unit::nanometer, Unit::angstrom);
                set(editor, Unit::angstrom, Unit::angstrom);
    
                set(editor, Unit::nanometer2, Unit::angstrom2);
                set(editor, Unit::angstrom2, Unit::angstrom2);
                set(editor, Unit::nanometerMinus2, Unit::angstromMinus2);
                set(editor, Unit::angstromMinus2, Unit::angstromMinus2);
    
            } else {
                set(editor, Unit::nanometer, Unit::nanometer);
                set(editor, Unit::angstrom, Unit::nanometer);
    
                set(editor, Unit::nanometer2, Unit::nanometer2);
                set(editor, Unit::angstrom2, Unit::nanometer2);
                set(editor, Unit::nanometerMinus2, Unit::nanometerMinus2);
                set(editor, Unit::angstromMinus2, Unit::nanometerMinus2);
    
                set(editor, Unit::degree, Unit::radiant);
                set(editor, Unit::radiant, Unit::radiant);
            } else {
                set(editor, Unit::degree, Unit::degree);
                set(editor, Unit::radiant, Unit::degree);
            }
        }
    
        for (auto* label : findChildren<QLabel*>())
            LayerEditorUtils::updateLabelUnit(label);
    }
    
    void MultiLayerForm::ensureVisible(QWidget* /*w*/)
    {
        // #baLayerEditor implement ensureVisible
    }
    
    void MultiLayerForm::setUseAngstrom(bool angstrom)
    {
        m_useAngstrom = angstrom;
        updateUnits();
    }
    
    bool MultiLayerForm::useAngstrom() const
    {
        return m_useAngstrom;
    }
    
    void MultiLayerForm::setUseRadiant(bool radiant)
    {
        m_useRadiant = radiant;
        updateUnits();
    }
    
    bool MultiLayerForm::useRadiant() const
    {
        return m_useRadiant;
    
    }
    
    void MultiLayerForm::showAddLayerButtons(bool show)
    {
    
        for (auto* c : findChildren<QWidget*>())
    
            if (dynamic_cast<AddLayerWidget*>(c))
                c->setVisible(show);
    }
    
    LayerForm* MultiLayerForm::findNextLayerForm(QWidget* w)
    {
        while (w != nullptr && dynamic_cast<LayerForm*>(w) == nullptr) {
    
            const auto index = m_layout->indexOf(w);
    
            if (index + 1 < m_layout->count())
                w = m_layout->itemAt(index + 1)->widget();
    
            else
                return nullptr;