Skip to content
Snippets Groups Projects
MultiLayerForm.cpp 8.75 KiB
Newer Older
  • Learn to ignore specific revisions
  • //  ************************************************************************************************
    //
    //  BornAgain: simulate and fit reflection and scattering
    //
    //! @file      GUI/Views/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/Views/SampleDesigner/MultiLayerForm.h"
    
    #include "GUI/Items/MultiLayerItem.h"
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
    #include "GUI/Models/Types/VectorDescriptor.h"
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
    #include "GUI/Views/Edit/DoubleSpinBox.h"
    
    #include "GUI/Views/SampleDesigner/GroupBoxCollapser.h"
    
    #include "GUI/Views/SampleDesigner/LayerForm.h"
    #include "GUI/Views/SampleDesigner/MesoCrystalForm.h"
    #include "GUI/Views/SampleDesigner/ParticleCompositionForm.h"
    #include "GUI/Views/SampleDesigner/ParticleCoreShellForm.h"
    #include "GUI/Views/SampleDesigner/ParticleForm.h"
    #include "GUI/Views/SampleDesigner/ParticleLayoutForm.h"
    
    #include <QBoxLayout>
    #include <QLabel>
    #include <QPushButton>
    
    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("Multilayer properties");
        FormLayouter layouter(props, ec);
        layouter.setContentsMargins(6, 6, 0, 6);
        layouter.addValue(multiLayerItem->crossCorrLength());
        layouter.addVector(multiLayerItem->externalFieldVector(), false);
        GroupBoxCollapser::installIntoGroupBox(props, false);
        m_layout->addWidget(props);
    
        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)) {
                if (w->layerItem() == layerItem) {
                    layerForm = w;
                }
            }
        }
    
        if (layerForm) {
            // delete editors which are subscribed to SessionItems
            GUI::Utils::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)
        }
    
        if (addLayerWidget)
            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::nanometerPower2, Unit::angstromPower2);
                set(editor, Unit::angstromPower2, Unit::angstromPower2);
                set(editor, Unit::nanometerPowerMinus2, Unit::angstromPowerMinus2);
                set(editor, Unit::angstromPowerMinus2, Unit::angstromPowerMinus2);
            } else {
                set(editor, Unit::nanometer, Unit::nanometer);
                set(editor, Unit::angstrom, Unit::nanometer);
                set(editor, Unit::nanometerPower2, Unit::nanometerPower2);
                set(editor, Unit::angstromPower2, Unit::nanometerPower2);
                set(editor, Unit::nanometerPowerMinus2, Unit::nanometerPowerMinus2);
                set(editor, Unit::angstromPowerMinus2, Unit::nanometerPowerMinus2);
            }
    
    
                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) {
            auto index = m_layout->indexOf(w);
            if (index + 1 < m_layout->count())
                w = m_layout->itemAt(index + 1)->widget();
        }
    
        return dynamic_cast<LayerForm*>(w);
    }