Skip to content
Snippets Groups Projects
LayerStackForm.cpp 6.93 KiB
Newer Older
  • Learn to ignore specific revisions
  • 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)
    {
        ASSERT(stack);
        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);
    
        if (isOuterStack()) {
            setStyleSheet("LayerStackForm {background-color: light grey}");
            m_title_widget->hide();
        } else {
            // Unlike layers, all stacks have fixed color
            setStyleSheet("LayerStackForm {background-color: grey}");
        }
    
    }
    
    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()
    {
        updateTitle();
    }
    
    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;