Skip to content
Snippets Groups Projects
LayerForm.cpp 6.94 KiB
Newer Older
//  ************************************************************************************************
//
//  BornAgain: simulate and fit reflection and scattering
//
//! @file      GUI/View/SampleDesigner/LayerForm.cpp
//! @brief     Implements class LayerForm
//!
//! @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/View/SampleDesigner/LayerForm.h"
#include "GUI/Model/Sample/LayerItem.h"
#include "GUI/Model/Sample/MaterialItem.h"
#include "GUI/Model/Sample/MaterialItems.h"
Wuttke, Joachim's avatar
Wuttke, Joachim committed
#include "GUI/Model/Sample/MultiLayerItem.h"
#include "GUI/Util/ActionFactory.h"
#include "GUI/View/SampleDesigner/MaterialInplaceForm.h"
#include "GUI/View/SampleDesigner/ParticleLayoutForm.h"
#include "GUI/View/SampleDesigner/WidgetMoverButton.h"
#include "GUI/View/Tool/GroupBoxCollapser.h"

#include <QLineEdit>
#include <QMenu>
#include <QPushButton>

LayerForm::LayerForm(QWidget* parent, LayerItem* layer, SampleEditorController* ec)
    : QGroupBox(parent)
    , m_layer(layer)
    , m_ec(ec)
    setTitle(m_layer->layerName());
    m_layouter = std::make_unique<FormLayouter>(this, ec);
    m_layouter->setContentsMargins(6, 6, 0, 6);
    m_collapser = GroupBoxCollapser::installIntoGroupBox(this, false);

    m_removeAction =
        ActionFactory::createRemoveAction(this, "layer", [=] { ec->removeLayer(layer); });

    auto* chooseColorAction = new QAction(this);
    chooseColorAction->setText("Choose color");
    chooseColorAction->setIcon(QIcon(":/images/palette.svg"));
    chooseColorAction->setIconText("Choose color");
    chooseColorAction->setToolTip("Choose a color for this layer");
    auto* menu = new QMenu(this);
    chooseColorAction->setMenu(menu);

    for (const auto& col : LayerEditorUtils::predefinedLayerColors()) {
        auto* ca = menu->addAction(QIcon(p), "");
        connect(ca, &QAction::triggered, [=]() {
            layer->setColor(col);
            updateColor();
        });
    }

    m_moveButton = new WidgetMoverButton(this, this, 1);
    m_moveButton->setToolTip("Move layer up/down");
    connect(m_moveButton, &WidgetMoverButton::startingToMove, ec,
            &SampleEditorController::onStartingToMoveLayer);
    connect(m_moveButton, &WidgetMoverButton::finishedMoving, ec,
            &SampleEditorController::onStoppedToMoveLayer);

    auto* showInRealSpaceAction = ActionFactory::createShowInRealSpaceAction(
        this, "layer", [=] { m_ec->requestViewInRealSpace(layer); });

    m_collapser->addAction(showInRealSpaceAction);
    m_collapser->addAction(chooseColorAction);
    m_collapser->addAction(m_removeAction);
    m_collapser->addWidget(m_moveButton);
    m_structureEditingWidgets << m_moveButton;

    QColor bckgroundCol = m_layer->color();
    setStyleSheet("QGroupBox {background-color: " + bckgroundCol.name(QColor::HexRgb) + "}");

    m_layouter->addRow("Material:", new MaterialInplaceForm(this, layer, ec));
    m_thicknessRow = m_layouter->addValue(m_layer->thickness());
    m_layouter->addValue(m_layer->numSlices());
    m_roughnessRow = m_layouter->addSelection(m_layer->roughness());

    // -- layouts
    for (auto* layout : layer->layouts())
        m_layouter->addRow(new ParticleLayoutForm(this, layout, ec));

    // -- Button for adding a new layout
    auto* btn = new QPushButton("Add particle layout", this);
    connect(btn, &QPushButton::clicked, [=] { ec->addLayout(this); });
    m_structureEditingWidgets << btn;
    m_layouter->addStructureEditingRow(btn);

    // listen to changes in materials to update the title (contains the material name). Necessary
    // to reflect e.g. a name change done in the material editor.
Matthias Puchner's avatar
Matthias Puchner committed
    connect(ec->materialItems(), &MaterialItems::materialChanged, this, &LayerForm::updateTitle);
    updateLayerPositionDependentElements();
}

void LayerForm::enableStructureEditing(bool b)
{
    m_removeAction->setVisible(b);

    for (auto* w : m_structureEditingWidgets)

    if (b && m_ec->multiLayerItem()->layers().size() < 2)
        m_moveButton->setVisible(false);
}

void LayerForm::updateColor()
{
    QColor bckgroundCol = m_layer->color();
    setStyleSheet("QGroupBox {background-color: " + bckgroundCol.name(QColor::HexRgb) + "}");
}

void LayerForm::updateTitle()
{
    int i = m_ec->multiLayerItem()->layers().indexOf(m_layer);
    m_collapser->setTitle("Layer " + QString::number(i)
                          + "     Material: " + m_layer->materialName());
}

void LayerForm::expand()
{
    m_collapser->setExpanded(true);
}

void LayerForm::updateLayerPositionDependentElements()
{
    if (m_roughnessRow == -1)
        return;

    updateTitle();

    const auto* multiLayer = m_ec->multiLayerItem();
    const bool isFirstLayer = multiLayer->layers().first() == m_layer;
    const bool isLastLayer = multiLayer->layers().last() == m_layer;
    const bool thicknessIsSemiInfinite =
        (isFirstLayer || isLastLayer) && (multiLayer->layers().size() != 1);
    const bool thicknessIsInfinite = multiLayer->layers().size() == 1;

    m_layouter->setRowVisible(m_roughnessRow, !isFirstLayer);

    if (m_thicknessRow == -1)
        return;
    QWidget* w = m_layouter->layout()->itemAt(m_thicknessRow, QFormLayout::FieldRole)->widget();
    if (thicknessIsSemiInfinite || thicknessIsInfinite) {
        if (info == nullptr) {
            m_layouter->removeRow(m_thicknessRow);
            info = new QLineEdit(this);
            info->setEnabled(false);
            info->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
            m_layouter->insertRow(m_thicknessRow, m_layer->thickness().label, info);
        }
        info->setText(thicknessIsSemiInfinite ? "Semi-infinite" : "Infinite");
    } else if (!thicknessIsSemiInfinite && !thicknessIsInfinite
               && (qobject_cast<QLineEdit*>(w) != nullptr)) {
        m_layouter->removeRow(m_thicknessRow);
        m_layouter->insertValue(m_thicknessRow, m_layer->thickness());
    }

    if (m_ec->multiLayerItem()->layers().size() < 2)
        m_moveButton->setVisible(false);
}

void LayerForm::onLayoutAdded(ParticleLayoutItem* newLayoutItem)
{
    int index = m_layer->layouts().indexOf(newLayoutItem);
    const int rowInLayout = m_layouter->layout()->rowCount() - m_layer->layouts().size() + index;

    m_layouter->insertRow(rowInLayout, new ParticleLayoutForm(this, newLayoutItem, m_ec));
}

void LayerForm::onAboutToRemoveLayout(ParticleLayoutItem* layoutItem)
{
    int index = m_layer->layouts().indexOf(layoutItem);
    const int rowInLayout =
        m_layouter->layout()->rowCount() - m_layer->layouts().size() - 1 + index; // -1: btn

    m_layouter->removeRow(rowInLayout);
}

LayerItem* LayerForm::layerItem() const
{
    return m_layer;
}