Newer
Older
// ************************************************************************************************
//
// BornAgain: simulate and fit reflection and scattering
//
//! @file GUI/View/SampleDesigner/LayerEditorUtils.cpp
//! @brief Implements class LayerEditorUtils
//!
//! @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/LayerEditorUtils.h"
#include "GUI/Model/Sample/CompoundItem.h"
#include "GUI/Model/Sample/CoreAndShellItem.h"
#include "GUI/Model/Sample/FormFactorItems.h"
#include "GUI/Model/Sample/LayerRoughnessItems.h"
#include "GUI/Model/Sample/ParticleItem.h"
#include "GUI/View/Common/DoubleSpinBox.h"
#include "GUI/View/SampleDesigner/CompoundForm.h"
#include "GUI/View/SampleDesigner/CoreAndShellForm.h"
#include "GUI/View/SampleDesigner/FormLayouter.h"
#include "GUI/View/SampleDesigner/MesocrystalForm.h"
#include "GUI/View/SampleDesigner/ParticleForm.h"
#include <QLabel>
#include <QMenu>
#include <QPushButton>
using std::function;
namespace {
void updateLabelUnit(QLabel* label, const QString& unit)
{
QString text = label->text();
const bool hasColon = text.indexOf(":") > 0;
text = text.left(text.indexOf("["));
text = text.trimmed();
if (text.endsWith(":"))
text.chop(1);
if (!unit.isEmpty())
text += " [" + unit + "]";
if (hasColon)
text += ":";
label->setText(text);
}
} // namespace
void LayerEditorUtils::updateLabelUnit(QLabel* label, DoubleSpinBox* editor)
{
::updateLabelUnit(label, editor->displayUnitAsString());
}
void LayerEditorUtils::updateLabelUnit(QLabel* label)
{
if (auto* editor = dynamic_cast<DoubleSpinBox*>(label->buddy()))
::updateLabelUnit(label, editor->displayUnitAsString());
}
void LayerEditorUtils::addMultiPropertyToGrid(QGridLayout* m_gridLayout, int firstCol,
const DoublePropertyRefs& valueDescriptors,
SampleEditorController* ec, bool vertically,
bool addSpacer)
Matthias Puchner
committed
{
const auto setNewValue = [ec](double newValue, DoubleProperty& d) {
Matthias Puchner
committed
ec->setDouble(newValue, d);
};
addMultiPropertyToGrid(m_gridLayout, firstCol, valueDescriptors, setNewValue, vertically,
addSpacer);
}
void LayerEditorUtils::addMultiPropertyToGrid(QGridLayout* m_gridLayout, int firstCol,
const DoublePropertyRefs& valueDescriptors,
function<void(double, DoubleProperty&)> setNewValue,
Matthias Puchner
committed
bool vertically, bool addSpacer)
{
int col = firstCol;
for (DoubleProperty& d : valueDescriptors) {
if (d.label() == "Angle")
editor = new DoubleSpinBox(d, false, 1, 1.0);
editor = new DoubleSpinBox(d);
QObject::connect(editor, &DoubleSpinBox::baseValueChanged,
[setNewValue, &d](double newValue) { setNewValue(newValue, d); });
QString labeltext = d.label();
if (!vertically && !labeltext.endsWith(":"))
labeltext += ":";
auto* label = new QLabel(labeltext, m_gridLayout->parentWidget());
label->setBuddy(editor); // necessary for unit-updating
LayerEditorUtils::updateLabelUnit(label, editor);
if (vertically) {
m_gridLayout->addWidget(label, 0, col);
m_gridLayout->addWidget(editor, 1, col);
col++;
} else {
m_gridLayout->addWidget(label, 1, col++);
m_gridLayout->addWidget(editor, 1, col++);
}
}
if (addSpacer)
m_gridLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding), 0, col);
}
void LayerEditorUtils::addMultiPropertyToGrid(QGridLayout* m_gridLayout, int firstCol,
const DoublePropertyRefs& valueDescriptors,
SampleEditorController* ec, bool addSpacer)
addMultiPropertyToGrid(m_gridLayout, firstCol, valueDescriptors, ec,
valueDescriptors.size() > 1, addSpacer);
}
void LayerEditorUtils::addVectorToGrid(QGridLayout* m_gridLayout, int firstCol, VectorProperty& v,
SampleEditorController* ec, bool vertically, bool addSpacer)
addMultiPropertyToGrid(m_gridLayout, firstCol, {v.x(), v.y(), v.z()}, ec, vertically,
addSpacer);
Matthias Puchner
committed
void LayerEditorUtils::addVectorToGrid(QGridLayout* m_gridLayout, int firstCol, VectorProperty& v,
function<void(double, DoubleProperty&)> setNewValue,
Matthias Puchner
committed
bool vertically, bool addSpacer)
{
addMultiPropertyToGrid(m_gridLayout, firstCol, {v.x(), v.y(), v.z()}, setNewValue, vertically,
Matthias Puchner
committed
addSpacer);
}
QLabel* LayerEditorUtils::createBoldLabel(const QString& text)
{
auto* l = new QLabel(text);
QFont f = l->font();
f.setBold(true);
l->setFont(f);
return l;
}
DoublePropertyRefs LayerEditorUtils::doubleDescriptorsOfItem(RotationItem* item)
{
if (!item)
return {};
DoublePropertyRefs LayerEditorUtils::doubleDescriptorsOfItem(Profile2DItem* item)
{
return item->valueDescriptors();
}
DoublePropertyRefs LayerEditorUtils::doubleDescriptorsOfItem(Profile1DItem* item)
{
return item->valueDescriptors();
}
DoublePropertyRefs LayerEditorUtils::doubleDescriptorsOfItem(FormFactorItem* item)
{
return item->geometryValues();
}
DoublePropertyRefs LayerEditorUtils::doubleDescriptorsOfItem(LayerBasicRoughnessItem* r)
return {r->sigma(), r->hurst(), r->lateralCorrelationLength()};
return {};
}
QWidget* LayerEditorUtils::createWidgetForItemWithParticles(QWidget* parentWidget,
ItemWithParticles* itemWithParticles,
bool allowAbundance,
SampleEditorController* ec,
bool allowRemove /*= true*/)
{
if (auto* composition = dynamic_cast<CompoundItem*>(itemWithParticles))
return new CompoundForm(parentWidget, composition, ec, allowRemove);
if (auto* coreShell = dynamic_cast<CoreAndShellItem*>(itemWithParticles))
return new CoreAndShellForm(parentWidget, coreShell, ec, allowRemove);
if (auto* meso = dynamic_cast<MesocrystalItem*>(itemWithParticles))
return new MesocrystalForm(parentWidget, meso, ec, allowRemove);
if (auto* particle = dynamic_cast<ParticleItem*>(itemWithParticles))
return new ParticleForm(parentWidget, particle, allowAbundance, ec, allowRemove);
ASSERT(false);
return nullptr;
}
QPushButton* LayerEditorUtils::createAddParticleButton(
QWidget* parentWidget, std::function<void(FormFactorItemCatalog::Type t)> slotAddFormFactor,
std::function<void(ItemWithParticlesCatalog::Type t)> slotAddParticle)
{
auto* btn = new QPushButton("Add particle", parentWidget);
auto* menu = new QMenu(btn);
QMenu* menuForEntries = menu;
const auto group = [&](const QString& title) { menuForEntries = menu->addMenu(title); };
group("Hard particles");
for (const auto type : FormFactorItemCatalog::hardParticleTypes()) {
const auto ui = FormFactorItemCatalog::uiInfo(type);
QAction* a = menuForEntries->addAction(QIcon(ui.iconPath), ui.menuEntry);
a->setToolTip(ui.description);
QObject::connect(a, &QAction::triggered, [=]() { slotAddFormFactor(type); });
}
group("Ripples");
for (const auto type : FormFactorItemCatalog::rippleTypes()) {
const auto ui = FormFactorItemCatalog::uiInfo(type);
QAction* a = menuForEntries->addAction(QIcon(ui.iconPath), ui.menuEntry);
a->setToolTip(ui.description);
QObject::connect(a, &QAction::triggered, [=]() { slotAddFormFactor(type); });
}
group("Particle assemblies");
for (const auto type :
{ItemWithParticlesCatalog::Type::Composition, ItemWithParticlesCatalog::Type::CoreShell,
const auto ui = ItemWithParticlesCatalog::uiInfo(type);
QAction* a = menuForEntries->addAction(QIcon(ui.iconPath), ui.menuEntry);
a->setToolTip(ui.description);
QObject::connect(a, &QAction::triggered, [=]() { slotAddParticle(type); });
}
btn->setMenu(menu);
return btn;
}
QList<QColor> LayerEditorUtils::predefinedLayerColors()
{
static QList<QColor> colors = {QColor(230, 255, 213), QColor(194, 252, 240),
QColor(239, 228, 176), QColor(200, 191, 231),
QColor(253, 205, 193), QColor(224, 193, 253)};
return colors;
}