Newer
Older
// ************************************************************************************************
//
// 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"
namespace {
//! Widget with a button to add a layer or stack (the "Add layer/add stack" buttons shown between
//! items)
public:
AddButtonsWidget(LayerStackForm* parentStackForm, const ItemWithLayers* itemBefore,
SampleEditorController* ec)
, 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); });
l->addStretch();
}
};
} // namespace
LayerStackForm::LayerStackForm(QWidget* parent, LayerStackItem* stack, SampleEditorController* ec)
: LayerContainerForm(parent, stack, ec, "stack")
// if outer stack
if (&stackItem() == &(m_ec->sampleItem()->outerStackItem()))
m_title_widget->hide();
else
m_layout->addBoldRow(
"Number of periods:",
GUI::Util::createIntSpinBox([this] { return stackItem().numberOfPeriods(); },
[this](int v) {
stackItem().setNumberOfPeriods(v);
emit gDoc->sampleChanged();
},
RealLimits::lowerLimited(0),
"Number of periods.\n"
"The content of the stack will be repeated\n"
"exactly that number of times."));
auto* components_widget = new QWidget;
components_widget->setLayout(m_components_layout);
m_layout->addRow(components_widget);
m_components_layout->addWidget(new AddButtonsWidget(this, nullptr, m_ec), 0, Qt::AlignTop);
for (auto* component : stack->componentItems())
addComponentForm(component);
m_components_layout->setSizeConstraint(QLayout::SetMinimumSize);
}
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;
auto* buttons = new AddButtonsWidget(this, componentItem, m_ec);
const int row_in_layout = rowInLayout(componentItem);
// same row => button is above!
m_components_layout->insertWidget(row_in_layout, buttons, 0, Qt::AlignTop);
m_components_layout->insertWidget(row_in_layout, newForm, 0, Qt::AlignTop);
}
void LayerStackForm::onComponentMoved(const ItemWithLayers* componentItem)
{
LayerContainerForm* wl = nullptr;
AddButtonsWidget* al = nullptr;
for (int index = 0; index < m_components_layout->count(); index++) {
if (auto* w = dynamic_cast<AddButtonsWidget*>(m_components_layout->itemAt(index)->widget()))
if (w->m_item == componentItem) {
al = w;
for (int index = 0; index < m_components_layout->count(); index++) {
if (auto* w =
dynamic_cast<LayerContainerForm*>(m_components_layout->itemAt(index)->widget()))
if (w->item() == componentItem) {
wl = w;
break;
}
}
const int row_in_layout = rowInLayout(componentItem);
// same row => button is above!
m_components_layout->insertWidget(row_in_layout, al, 0, Qt::AlignTop);
m_components_layout->insertWidget(row_in_layout, wl, 0, Qt::AlignTop);
void LayerStackForm::removeComponentForm(ItemWithLayers* componentItem)
{
LayerContainerForm* componentForm = nullptr;
for (auto* c : findChildren<QWidget*>()) {
if (w->m_item == componentItem)
addLayerWidget = w;
if (auto* w = dynamic_cast<LayerContainerForm*>(c)) {
if (w->item() == componentItem)
componentForm = w;
}
}
ASSERT(componentForm);
ASSERT(addLayerWidget);
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)
LayerContainerForm* LayerStackForm::findNextComponentForm(QWidget* w)
{
while (w != nullptr && dynamic_cast<LayerContainerForm*>(w) == nullptr) {
const auto index = m_components_layout->indexOf(w);
if (index + 1 < m_components_layout->count())
w = m_components_layout->itemAt(index + 1)->widget();
else
return nullptr;
}
return dynamic_cast<LayerContainerForm*>(w);
}
void LayerStackForm::updatePositionDependentElements()
{
LayerContainerForm::updatePositionDependentElements();
void LayerStackForm::updateTitle()
auto layers_inside = stackItem().uniqueLayerItems();
if (!layers_inside.size()) {
setTitle("Empty stack");
return;
}
auto unique_layers_global = m_ec->sampleItem()->uniqueLayerItems();
int i_first = Vec::indexOfPtr(layers_inside.front(), unique_layers_global);
int i_last = Vec::indexOfPtr(layers_inside.back(), unique_layers_global);
setTitle("Stack of layers from " + QString::number(i_first) + " to " + QString::number(i_last));
}
int LayerStackForm::rowInLayout(const ItemWithLayers* componentItem) const
return stackItem().indexOfComponent(componentItem) * 2 + 1;