Skip to content
Snippets Groups Projects
MultiLayerForm.cpp 8.89 KiB
Newer Older
//  ************************************************************************************************
//
//  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/Models/MultiLayerItem.h"
#include "GUI/Models/VectorDescriptor.h"
#include "GUI/Views/CommonWidgets/DoubleSpinBox.h"
#include "GUI/Views/CommonWidgets/GroupBoxCollapser.h"
#include "GUI/Views/SampleDesigner/LayerEditorUtils.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 "GUI/Views/SampleDesigner/SampleEditorController.h"
#include "GUI/utils/LayoutUtils.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)
{
    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));

    // #baLayerEditor create color for new layer, but only if not from undo remove layer!
    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();
}

Matthias Puchner's avatar
Matthias Puchner committed
void MultiLayerForm::ensureVisible(QWidget* /*w*/)
{
    // #baLayerEditor implement ensureVisible
}

void MultiLayerForm::useAngstrom(bool angstrom)
{
    const auto set = [](DoubleSpinBox* spinbox, Unit valueUnit, Unit displayUnit) {
        if (spinbox->baseUnit() == valueUnit)
            spinbox->setDisplayUnit(displayUnit);
    };

    for (auto* editor : findChildren<DoubleSpinBox*>()) {
        if (angstrom) {
            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);
        }
    }
    for (auto* label : findChildren<QLabel*>())
        LayerEditorUtils::updateLabelUnit(label);
}

void MultiLayerForm::useRadiant(bool radiant)
{
    const auto set = [](DoubleSpinBox* spinbox, Unit valueUnit, Unit displayUnit) {
        if (spinbox->baseUnit() == valueUnit)
            spinbox->setDisplayUnit(displayUnit);
    };

    for (auto* editor : findChildren<DoubleSpinBox*>()) {
        if (radiant) {
            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);
        }
    }
}

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);
}