Skip to content
Snippets Groups Projects
LayerStackForm.cpp 6.79 KiB
Newer Older
Mikhail Svechnikov's avatar
Mikhail Svechnikov committed
//  ************************************************************************************************
//
//  BornAgain: simulate and fit reflection and scattering
//
//! @file      GUI/View/Sample/LayerStackForm.cpp
//! @brief     Implements class LayerStackForm.
//!
//! @homepage  http://www.bornagainproject.org
//! @license   GNU General Public License v3 or higher (see COPYING)
//! @copyright Forschungszentrum Jülich GmbH 2024
//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
//
//  ************************************************************************************************

#include "GUI/View/Sample/LayerStackForm.h"
#include "Base/Util/Vec.h"
#include "GUI/Model/Sample/LayerItem.h"
#include "GUI/Model/Sample/LayerStackItem.h"
#include "GUI/Model/Sample/SampleItem.h"
#include "GUI/View/Base/LayoutUtil.h"
#include "GUI/View/Sample/HeinzFormLayout.h"
#include "GUI/View/Sample/LayerForm.h"
#include "GUI/View/Sample/SampleEditorController.h"
#include <QPushButton>
namespace {

//! Widget with a button to add a layer or stack (the "Add layer/add stack" buttons shown between
//! items)
class AddLayerContainerWidget : public QWidget {
public:
    AddLayerContainerWidget(LayerStackForm* parentStackForm, const ItemWithLayers* itemBefore,
                            SampleEditorController* ec)
        : QWidget(parentStackForm)
        , m_item(itemBefore)
    {
        auto* l = new QHBoxLayout(this);
        l->setContentsMargins(0, 0, 0, 0);
        l->addStretch();

        auto* layer_btn = new QPushButton("Add layer", this);
        l->addWidget(layer_btn);
        connect(layer_btn, &QPushButton::clicked,
                [=] { ec->addLayerItem(*parentStackForm, itemBefore); });

        l->addSpacing(10);

        auto* stack_btn = new QPushButton("Add stack", this);
        l->addWidget(stack_btn);
        connect(stack_btn, &QPushButton::clicked,
                [=] { ec->addLayerStackItem(*parentStackForm, itemBefore); });
    const ItemWithLayers* m_item;
};

} // namespace

LayerStackForm::LayerStackForm(QWidget* parent, LayerStackItem* stack, SampleEditorController* ec)
    : LayerContainerForm(parent, stack, ec, "stack")
    , m_stack_layout(new QVBoxLayout)
{
    m_layout->addRow(m_stack_layout);

    for (auto* item : stack->componentItems()) {
        m_stack_layout->addWidget(new AddLayerContainerWidget(this, item, m_ec), 0, Qt::AlignTop);
        if (auto* layer = dynamic_cast<LayerItem*>(item))
            m_stack_layout->addWidget(new LayerForm(this, layer, m_ec), 0, Qt::AlignTop);
        else if (auto* stack = dynamic_cast<LayerStackItem*>(item))
            m_stack_layout->addWidget(new LayerStackForm(this, stack, m_ec), 0, Qt::AlignTop);
        else
            ASSERT_NEVER;
    }
    m_stack_layout->addWidget(new AddLayerContainerWidget(this, nullptr, m_ec), 0, Qt::AlignTop);
    m_stack_layout->setSizeConstraint(QLayout::SetMinimumSize);

    updatePositionDependentElements();
    if (isOuterStack())
        m_title_widget->hide();
}

LayerStackItem& LayerStackForm::stackItem() const
{
    return dynamic_cast<LayerStackItem&>(*m_item);
}

void LayerStackForm::addComponentForm(ItemWithLayers* componentItem)
{
    LayerContainerForm* newForm;
    if (auto* layer = dynamic_cast<LayerItem*>(componentItem))
        newForm = new LayerForm(this, layer, m_ec);
    else if (auto* stack = dynamic_cast<LayerStackItem*>(componentItem))
        newForm = new LayerStackForm(this, stack, m_ec);
    else
        ASSERT_NEVER;

    const int row_in_layout = rowInLayout(componentItem);
    // same row => button is above!
    m_stack_layout->insertWidget(
        row_in_layout, new AddLayerContainerWidget(this, componentItem, m_ec), 0, Qt::AlignTop);
    m_stack_layout->insertWidget(row_in_layout, newForm, 0, Qt::AlignTop);
}

void LayerStackForm::onComponentMoved(const ItemWithLayers* componentItem)
{
    LayerContainerForm* wl = nullptr;
    AddLayerContainerWidget* al = nullptr;
    for (int index = 0; index < m_stack_layout->count(); index++) {
        if (auto* w =
                dynamic_cast<AddLayerContainerWidget*>(m_stack_layout->itemAt(index)->widget()))
            if (w->m_item == componentItem) {
                al = w;
                m_stack_layout->takeAt(index);
                break;
            }
    }
    for (int index = 0; index < m_stack_layout->count(); index++) {
        if (auto* w = dynamic_cast<LayerContainerForm*>(m_stack_layout->itemAt(index)->widget()))
            if (w->item() == componentItem) {
                wl = w;
                m_stack_layout->takeAt(index);
                break;
            }
    }
    const int row_in_layout = rowInLayout(componentItem);
    m_stack_layout->insertWidget(row_in_layout, wl, 0, Qt::AlignTop);
    // same row => button is above!
    m_stack_layout->insertWidget(row_in_layout, al, 0, Qt::AlignTop);
}

void LayerStackForm::removeComponentForm(ItemWithLayers* componentItem)
{
    LayerContainerForm* componentForm = nullptr;
    AddLayerContainerWidget* addLayerWidget = nullptr;
    for (auto* c : findChildren<QWidget*>()) {
        if (auto* w = dynamic_cast<AddLayerContainerWidget*>(c))
            if (w->m_item == componentItem)
                addLayerWidget = w;

        if (auto* w = dynamic_cast<LayerContainerForm*>(c)) {
            if (w->item() == componentItem)
                componentForm = w;
        }
    }
    ASSERT(componentForm);
    ASSERT(addLayerWidget);

    // delete editors which are subscribed to SessionItems
    GUI::Util::Layout::clearLayout(componentForm->layout());
    componentForm->hide();
    componentForm->setParent(nullptr); // so it is not findable in update routines
    componentForm->deleteLater();      // delete later (this is the sender)

    delete addLayerWidget;
}

void LayerStackForm::updatePositionDependentElements()
{
    LayerContainerForm::updatePositionDependentElements();
void LayerStackForm::updateTitle()
    const SampleItem* sampleItem = m_ec->sampleItem();
    ASSERT(sampleItem);

    auto unique_layers_inside = stackItem().uniqueLayerItems();
    if (!unique_layers_inside.size()) {
        setTitle("Empty stack");
        return;
    }

    LayerItem* first_layer = unique_layers_inside.front();
    LayerItem* last_layer = unique_layers_inside.back();

    auto unique_layers_global = sampleItem->uniqueLayerItems();
    int i_first = Vec::indexOfPtr(first_layer, unique_layers_global);
    int i_last = Vec::indexOfPtr(last_layer, unique_layers_global);

    setTitle("Stack of layers from " + QString::number(i_first) + " to " + QString::number(i_last));
}

bool LayerStackForm::isOuterStack() const
    return &stackItem() == &(m_ec->sampleItem()->outerStackItem());
int LayerStackForm::rowInLayout(const ItemWithLayers* componentItem) const
    return stackItem().indexOfComponent(componentItem) * 2 + 1;