Newer
Older
// ************************************************************************************************
//
// BornAgain: simulate and fit reflection and scattering
//
//! @file GUI/View/Sample/SampleEditorController.cpp
//! @brief Implements class SampleEditorController.
//!
//! @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/Sample/SampleEditorController.h"

Wuttke, Joachim
committed
#include "GUI/Model/Material/MaterialsSet.h"
#include "GUI/Model/Project/ProjectDocument.h"
#include "GUI/Model/Sample/CompoundItem.h"
#include "GUI/Model/Sample/CoreAndShellItem.h"
#include "GUI/Model/Sample/InterferenceItems.h"
#include "GUI/Model/Sample/LayerItem.h"
#include "GUI/Model/Sample/LayerStackItem.h"
#include "GUI/Model/Sample/ParticleItem.h"
#include "GUI/Model/Sample/ParticleLayoutItem.h"
#include "GUI/Model/Sample/SampleItem.h"
#include "GUI/Model/Util/Backup.h"
#include "GUI/View/Sample/CompoundForm.h"
#include "GUI/View/Sample/CoreAndShellForm.h"
#include "GUI/View/Sample/InterferenceForm.h"
#include "GUI/View/Sample/LatticeTypeSelectionForm.h"
#include "GUI/View/Sample/LayerForm.h"
#include "GUI/View/Sample/LayerStackForm.h"
#include "GUI/View/Sample/MaterialInplaceForm.h"
#include "GUI/View/Sample/MesocrystalForm.h"
#include "GUI/View/Sample/ParticleLayoutForm.h"
#include "GUI/View/Sample/SampleForm.h"
SampleEditorController::SampleEditorController(SampleItem* multi)
: m_sample_item(multi)
, m_sample_form(nullptr)
{
}
void SampleEditorController::setSampleForm(SampleForm* view)
void SampleEditorController::addLayerItem(LayerStackForm& parentStackForm,
const ItemWithLayers* before)
LayerStackItem& parentStack = parentStackForm.stackItem();
const int at_index = parentStack.indexOfComponent(before) + 1;
QColor color = findColor(at_index); // before adding layer
LayerItem* new_layer = m_sample_item->createLayerItemAt(parentStack, at_index);
new_layer->setMaterial(materialModel()->defaultMaterialItem());
new_layer->setColor(color);
onComponentAdded(new_layer);
void SampleEditorController::addLayerStackItem(LayerStackForm& parentStackForm,
const ItemWithLayers* before)
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
LayerStackItem& parentStack = parentStackForm.stackItem();
const int at_index = parentStack.indexOfComponent(before) + 1;
LayerStackItem* new_stack = m_sample_item->createLayerStackItemAt(parentStack, at_index);
onComponentAdded(new_stack);
}
void SampleEditorController::duplicateItemWithLayers(const ItemWithLayers* component)
{
LayerStackItem* parentStack = m_sample_item->parentOfComponent(component);
// case of the outer stack
if (!parentStack)
return;
LayerStackForm* parentStackForm = m_sample_form->formOfStackItem(parentStack);
ASSERT(parentStackForm);
const int at_index = parentStack->indexOfComponent(component) + 1;
if (const auto* layer = dynamic_cast<const LayerItem*>(component)) {
QColor color = findColor(at_index); // before adding layer
LayerItem* new_layer = m_sample_item->createLayerItemAt(*parentStack, at_index);
new_layer->setMaterial(materialModel()->defaultMaterialItem());
GUI::Util::copyContents(layer, new_layer);
new_layer->setColor(color);
onComponentAdded(new_layer);
} else if (const auto* stack = dynamic_cast<const LayerStackItem*>(component)) {
LayerStackItem* new_stack = m_sample_item->createLayerStackItemAt(*parentStack, at_index);
GUI::Util::copyContents(stack, new_stack);
onComponentAdded(new_stack);
} else
ASSERT_NEVER;
}
void SampleEditorController::onComponentAdded(ItemWithLayers* component)
{
LayerStackItem* parentStack = m_sample_item->parentOfComponent(component);
ASSERT(parentStack);
LayerStackForm* parentStackForm = m_sample_form->formOfStackItem(parentStack);
ASSERT(parentStackForm);
parentStackForm->addComponentForm(component);
m_sample_form->updateRowVisibilities();
QColor SampleEditorController::findColor(size_t atIndex)
std::vector<LayerItem*> uniqueLayerItems = m_sample_item->uniqueLayerItems();
auto unusedColors = GUI::Util::Layer::predefinedLayerColors();
unusedColors.removeAll(l->color());
if (!unusedColors.isEmpty())
else {
// search for a color which has been used the less, and which is not the same as in the
// layers above and below
QMap<QString, int> usage;
usage[l->color().name()] += 1;
auto sortedByUsage = GUI::Util::Layer::predefinedLayerColors();
std::stable_sort(
sortedByUsage.begin(), sortedByUsage.end(),
[&](const QColor& a, const QColor& b) { return usage[a.name()] < usage[b.name()]; });
const QColor above = (atIndex > 0) ? uniqueLayerItems[atIndex - 1]->color() : QColor();
const QColor below =
(atIndex < uniqueLayerItems.size()) ? uniqueLayerItems[atIndex]->color() : QColor();

Wuttke, Joachim
committed
for (const auto& col : sortedByUsage)
if (col != above && col != below) {
break;
}
}
void SampleEditorController::removeItemWithLayers(ItemWithLayers* component)
LayerStackItem* parentStack = m_sample_item->parentOfComponent(component);
// case of the outer stack
if (!parentStack)
return;
LayerStackForm* parentStackForm = m_sample_form->formOfStackItem(parentStack);
ASSERT(parentStackForm);
parentStackForm->removeComponentForm(component);
m_sample_item->removeComponent(component);
m_sample_form->updateRowVisibilities();
emit gDoc->sampleChanged();
void SampleEditorController::onLayoutAdded(LayerForm* layerForm, ParticleLayoutItem* layout)
for (auto* layoutForms : layerForm->findChildren<ParticleLayoutForm*>())
layoutForms->updateTitle(layerForm->layerItem());
emit gDoc->sampleChanged();
void SampleEditorController::addLayoutItem(LayerForm* layerForm)
{
auto* newLayout = layerForm->layerItem()->addLayoutItem();
onLayoutAdded(layerForm, newLayout);
}
void SampleEditorController::duplicateLayoutItem(LayerForm* layerForm, ParticleLayoutItem* layout)
auto* newLayout = layerForm->layerItem()->addLayoutItem();
GUI::Util::copyContents(layout, newLayout);
onLayoutAdded(layerForm, newLayout);
void SampleEditorController::removeLayoutItem(LayerForm* layerForm, ParticleLayoutItem* layout)
emit aboutToRemoveItem(layout);
layerForm->onAboutToRemoveLayout(layout);
layerForm->layerItem()->removeLayoutItem(layout);
Matthias Puchner
committed
for (auto* layoutForm : layerForm->findChildren<ParticleLayoutForm*>())
layoutForm->updateTitle(layerForm->layerItem());
emit gDoc->sampleChanged();
void SampleEditorController::onParticleLayoutAdded(ParticleLayoutItem* layout,
emit gDoc->sampleChanged();
// search for particle layout widget for notification
ASSERT(m_sample_form);
for (auto* w : m_sample_form->findChildren<ParticleLayoutForm*>())
void SampleEditorController::addParticleLayoutItem(ParticleLayoutItem* layout,

Wuttke, Joachim
committed
FormfactorCatalog::Type formFactorType)
{
auto* newParticle = createAndInitItem(formFactorType);
layout->addItemWithParticleSelection(newParticle);
onParticleLayoutAdded(layout, newParticle);
void SampleEditorController::addParticleLayoutItem(ParticleLayoutItem* layout,

Wuttke, Joachim
committed
ParticleCatalog::Type type)
layout->addItemWithParticleSelection(newItem);
onParticleLayoutAdded(layout, newItem);
}
void SampleEditorController::duplicateItemWithParticles(ItemWithParticles* item)
{

Wuttke, Joachim
committed
auto type = ParticleCatalog::type(item);
auto* newItem = createAndInitItem(type);
GUI::Util::copyContents(item, newItem);
if (ParticleLayoutItem* parent_layout = parentLayoutItem(item)) {
parent_layout->addItemWithParticleSelection(newItem);
onParticleLayoutAdded(parent_layout, newItem);
} else if (CompoundItem* parent_compound = parentCompoundItem(item)) {
parent_compound->addItemWithParticleSelection(newItem);
onParticleCompoundAdded(parent_compound, newItem);
} else
void SampleEditorController::onParticleCompoundAdded(CompoundItem* composition,
emit gDoc->sampleChanged();
// search for composition widget for notification
ASSERT(m_sample_form);
for (auto* c : m_sample_form->findChildren<CompoundForm*>())
void SampleEditorController::addCompoundItem(CompoundItem* compositionItem,

Wuttke, Joachim
committed
ParticleCatalog::Type type)
compositionItem->addItemWithParticleSelection(newItem);
onParticleCompoundAdded(compositionItem, newItem);
void SampleEditorController::addCompoundItem(CompoundItem* compositionItem,

Wuttke, Joachim
committed
FormfactorCatalog::Type formFactorType)
compositionItem->addItemWithParticleSelection(newParticle);
onParticleCompoundAdded(compositionItem, newParticle);
Matthias Puchner
committed
ItemWithParticles*

Wuttke, Joachim
committed
SampleEditorController::createAndInitItem(FormfactorCatalog::Type formFactorType) const
Matthias Puchner
committed
{

Wuttke, Joachim
committed
newParticle->setFormfactor(FormfactorCatalog::create(formFactorType));
newParticle->setMaterial(materialModel()->defaultParticleMaterialItem());
Matthias Puchner
committed
return newParticle;
}

Wuttke, Joachim
committed
ItemWithParticles* SampleEditorController::createAndInitItem(ParticleCatalog::Type type) const
Matthias Puchner
committed
{

Wuttke, Joachim
committed
auto* newItem = ParticleCatalog::create(type, materialModel());
Matthias Puchner
committed
if (auto* p = dynamic_cast<ItemWithMaterial*>(newItem))
Matthias Puchner
committed
if (auto* cs = dynamic_cast<CoreAndShellItem*>(newItem)) {
cs->createCoreItem(materialModel());
cs->createShellItem(materialModel());
cs->coreItem()->setFormfactor(new CylinderItem());
cs->shellItem()->setFormfactor(new CylinderItem());
Matthias Puchner
committed
}
if (auto* meso = dynamic_cast<MesocrystalItem*>(newItem); meso && meso->basisItem())
if (auto* p = dynamic_cast<ItemWithMaterial*>(meso->basisItem()))
Matthias Puchner
committed
return newItem;
}
void SampleEditorController::setCoreFormfactor(CoreAndShellForm* widget,

Wuttke, Joachim
committed
FormfactorCatalog::Type type)
{
auto* particleCoreShell = widget->coreShellItem();

Wuttke, Joachim
committed
particleCoreShell->coreItem()->setFormfactor(FormfactorCatalog::create(type));
emit gDoc->sampleChanged();
void SampleEditorController::setShellFormfactor(CoreAndShellForm* widget,

Wuttke, Joachim
committed
FormfactorCatalog::Type type)
{
auto* particleCoreShell = widget->coreShellItem();
if (particleCoreShell->shellItem() == nullptr)

Wuttke, Joachim
committed
particleCoreShell->shellItem()->setFormfactor(FormfactorCatalog::create(type));
emit gDoc->sampleChanged();
ParticleLayoutItem* SampleEditorController::parentLayoutItem(ItemWithParticles* item)
for (auto* layoutForm : m_sample_form->findChildren<ParticleLayoutForm*>())
if (Vec::containsPtr(item, layoutForm->layoutItem()->itemsWithParticles()))
return layoutForm->layoutItem();
return nullptr;
}
CompoundItem* SampleEditorController::parentCompoundItem(ItemWithParticles* item)
for (auto* compoundForm : m_sample_form->findChildren<CompoundForm*>())
if (Vec::containsPtr(item, compoundForm->compositionItem()->itemsWithParticles()))
void SampleEditorController::removeParticle(ItemWithParticles* itemToRemove)
for (auto* layoutForm : m_sample_form->findChildren<ParticleLayoutForm*>())
if (Vec::containsPtr(itemToRemove, layoutForm->layoutItem()->itemsWithParticles())) {
layoutForm->onAboutToRemoveParticle(itemToRemove);
emit aboutToRemoveItem(itemToRemove);
layoutForm->layoutItem()->removeItemWithParticle(itemToRemove);
emit gDoc->sampleChanged();
return;
}
for (auto* c : m_sample_form->findChildren<CompoundForm*>())
if (Vec::containsPtr(itemToRemove, c->compositionItem()->itemsWithParticles())) {
c->onAboutToRemoveParticle(itemToRemove);
emit aboutToRemoveItem(itemToRemove);
c->compositionItem()->removeItemWithParticle(itemToRemove);
emit gDoc->sampleChanged();
return;
}

Wuttke, Joachim
committed
MaterialsSet* SampleEditorController::materialModel() const
return &m_sample_item->materialModel();
void SampleEditorController::selectMaterial(ItemWithMaterial* item,
const QString& newMaterialIdentifier)
{
item->setMaterial(newMaterialIdentifier);
// update Layer title
ASSERT(m_sample_form);
for (auto* c : m_sample_form->findChildren<LayerForm*>())
if (c->layerItem() == item)
c->updateTitle();
// #baLayerEditor notify all material users (update link info)
emit gDoc->sampleChanged();
void SampleEditorController::setMaterialValue(ItemWithMaterial* item, double value,
emit gDoc->sampleChanged();
Matthias Puchner
committed
// -- notify all other users of this material (update values in the UI)
ASSERT(m_sample_form);
for (auto* c : m_sample_form->findChildren<MaterialInplaceForm*>())
Matthias Puchner
committed
if (c->itemWithMaterial() != item
&& c->itemWithMaterial()->materialIdentifier() == item->materialIdentifier())
c->updateValues();
emit gDoc->sampleChanged();
//! notify the containing particle layout UI about changed value
void SampleEditorController::setDensityRelatedValue(InterferenceItem* interferenceItem)
{
ASSERT(m_sample_form);
for (auto* c : m_sample_form->findChildren<ParticleLayoutForm*>())
if (c->layoutItem()->interferenceSelection().certainItem() == interferenceItem) {
c->updateDensityValue();
break;
}
void SampleEditorController::onStoppedToMoveComponent(QWidget* widgetToMove,
QWidget* moveAboveThisWidget)
auto* formToMove = dynamic_cast<LayerContainerForm*>(widgetToMove);
ASSERT(formToMove);
auto* itemToMove = formToMove->item();
LayerStackItem* parentStack = m_sample_item->parentOfComponent(itemToMove);
ASSERT(parentStack);
LayerStackForm* parentStackForm = m_sample_form->formOfStackItem(parentStack);
ASSERT(parentStackForm);
const LayerContainerForm* moveAboveThisLayerForm =
parentStackForm->findNextComponentForm(moveAboveThisWidget);
auto* moveAboveThisItem = moveAboveThisLayerForm ? moveAboveThisLayerForm->item() : nullptr;
m_sample_item->moveComponent(itemToMove, moveAboveThisItem);
m_sample_form->updateRowVisibilities();
emit gDoc->sampleChanged();
void SampleEditorController::setMesocrystalBasis(MesocrystalForm* widget,

Wuttke, Joachim
committed
ParticleCatalog::Type type)
widget->createBasisWidgets();
emit gDoc->sampleChanged();
void SampleEditorController::setMesocrystalBasis(MesocrystalForm* widget,

Wuttke, Joachim
committed
FormfactorCatalog::Type type)
emit gDoc->sampleChanged();
void SampleEditorController::selectInterference(InterferenceForm* widget, int newIndex)
widget->layoutItem()->interferenceSelection().setCertainIndex(newIndex);
Matthias Puchner
committed
// Disable/enable total density property in the particle layout, depending on type of
// interference function.
QWidget* parent = widget->parentWidget();
while (parent != nullptr && dynamic_cast<ParticleLayoutForm*>(parent) == nullptr)
parent = parent->parentWidget();
if (auto* particleLayoutForm = dynamic_cast<ParticleLayoutForm*>(parent)) {
Matthias Puchner
committed
particleLayoutForm->updateDensityEnabling();
particleLayoutForm->updateDensityValue();
emit gDoc->sampleChanged();