BornAgain  1.19.79
Simulate and fit neutron and x-ray scattering at grazing incidence
MultiLayerForm.cpp
Go to the documentation of this file.
1 // ************************************************************************************************
2 //
3 // BornAgain: simulate and fit reflection and scattering
4 //
5 //! @file GUI/View/SampleDesigner/MultiLayerForm.cpp
6 //! @brief Implements class MultiLayerForm
7 //!
8 //! @homepage http://www.bornagainproject.org
9 //! @license GNU General Public License v3 or higher (see COPYING)
10 //! @copyright Forschungszentrum Jülich GmbH 2021
11 //! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS)
12 //
13 // ************************************************************************************************
14 
17 #include "GUI/Util/ActionFactory.h"
26 #include <QBoxLayout>
27 #include <QLabel>
28 #include <QLineEdit>
29 #include <QPushButton>
30 #include <QTextEdit>
31 
32 namespace {
33 
34 //! Widget with a button to add a layer (the "add layer" buttons shown between layers)
35 class AddLayerWidget : public QWidget {
36 public:
37  AddLayerWidget(QWidget* parent, LayerItem* layer, SampleEditorController* ec)
38  : QWidget(parent)
39  , m_layer(layer)
40  {
41  auto* l = new QHBoxLayout(this);
42  l->setContentsMargins(0, 0, 0, 0);
43  auto* btn = new QPushButton("Add layer", this);
44  l->addStretch();
45  l->addWidget(btn);
46  l->addStretch();
47  connect(btn, &QPushButton::clicked, [=]() { ec->addLayer(layer); });
48  }
49 
50  LayerItem* m_layer;
51 };
52 
53 } // namespace
54 
55 MultiLayerForm::MultiLayerForm(QWidget* parent, MultiLayerItem* sampleItem,
57  : QWidget(parent)
58  , m_sampleItem(sampleItem)
59  , m_ec(ec)
60  , m_useAngstrom(false)
61  , m_useRadiant(false)
62 {
63  setObjectName("MultiLayerForm"); // important for style sheet addressing
64  setAttribute(Qt::WA_StyledBackground, true);
65 
66  m_layout = new QVBoxLayout(this);
67 
68  auto* props = new QGroupBox(this);
69  props->setTitle("Sample");
70  FormLayouter layouter(props, ec);
71  layouter.setContentsMargins(6, 6, 0, 6);
72 
73  auto* nameEdit = new QLineEdit(props);
74  layouter.addRow("Name:", nameEdit);
75  nameEdit->setText(sampleItem->sampleName());
76  connect(nameEdit, &QLineEdit::textEdited, ec, &SampleEditorController::setSampleName);
77 
78  auto* descriptionEdit = new QTextEdit(props);
79  descriptionEdit->setMinimumWidth(300);
80  descriptionEdit->setMaximumHeight(100);
81  descriptionEdit->setAcceptRichText(false);
82  descriptionEdit->setTabChangesFocus(true);
83  descriptionEdit->setPlainText(sampleItem->description());
84  layouter.addRow("Description:", descriptionEdit);
85  connect(descriptionEdit, &QTextEdit::textChanged,
86  [=]() { m_ec->setSampleDescription(descriptionEdit->toPlainText()); });
87 
88  layouter.addValue(sampleItem->crossCorrLength());
89  layouter.addVector(sampleItem->externalFieldVector(), false);
90  auto* collapser = GroupBoxCollapser::installIntoGroupBox(props, false);
91 
92  auto* showInRealSpaceAction = ActionFactory::createShowInRealSpaceAction(
93  this, "sample", [=] { m_ec->requestViewInRealSpace(m_sampleItem); });
94 
95  collapser->addAction(showInRealSpaceAction);
96 
97  m_layout->addWidget(props);
98 
99  for (auto* layer : sampleItem->layers()) {
100  m_layout->addWidget(new AddLayerWidget(this, layer, m_ec));
101  m_layout->addWidget(new LayerForm(this, layer, m_ec));
102  }
103  m_layout->addWidget(new AddLayerWidget(this, nullptr, m_ec));
104  m_layout->setSizeConstraint(QLayout::SetMinimumSize);
105  m_layout->addStretch(1);
106 }
107 
109 {
112 }
113 
115 {
116  const int rowInMultiLayer = m_sampleItem->layers().indexOf(layerItem);
117 
118  const int rowInLayout = rowInMultiLayer * 2 + 1;
119 
120  m_layout->insertWidget(rowInLayout, new LayerForm(this, layerItem, m_ec));
121 
122  // same row => button is above!
123  m_layout->insertWidget(rowInLayout, new AddLayerWidget(this, layerItem, m_ec));
124 
126 }
127 
129 {
130  LayerForm* wl = nullptr;
131  AddLayerWidget* al = nullptr;
132  for (int index = 0; index < m_layout->count(); index++) {
133  if (auto* w = dynamic_cast<AddLayerWidget*>(m_layout->itemAt(index)->widget()))
134  if (w->m_layer == layerItem) {
135  al = w;
136  m_layout->takeAt(index);
137  break;
138  }
139  }
140 
141  for (int index = 0; index < m_layout->count(); index++) {
142  if (auto* w = dynamic_cast<LayerForm*>(m_layout->itemAt(index)->widget()))
143  if (w->layerItem() == layerItem) {
144  wl = w;
145  m_layout->takeAt(index);
146  break;
147  }
148  }
149 
150  const int rowInMultiLayer = m_sampleItem->layers().indexOf(layerItem);
151  const int rowInLayout = rowInMultiLayer * 2 + 1;
152 
153  m_layout->insertWidget(rowInLayout, wl);
154 
155  // same row => button is above!
156  m_layout->insertWidget(rowInLayout, al);
157 
159 }
160 
162 {
163  LayerForm* layerForm = nullptr;
164  AddLayerWidget* addLayerWidget = nullptr;
165  for (auto* c : findChildren<QWidget*>()) {
166  if (auto* w = dynamic_cast<AddLayerWidget*>(c))
167  if (w->m_layer == layerItem)
168  addLayerWidget = w;
169 
170  if (auto* w = dynamic_cast<LayerForm*>(c)) {
171  if (w->layerItem() == layerItem)
172  layerForm = w;
173  }
174  }
175 
176  if (layerForm) {
177  // delete editors which are subscribed to SessionItems
178  GUI::Util::Layout::clearLayout(layerForm->layout());
179  layerForm->hide();
180  layerForm->setParent(nullptr); // so it is not findable in update routines
181  layerForm->deleteLater(); // delete later (this is the sender)
182  }
183 
184 
185  delete addLayerWidget;
186 }
187 
189 {
190  for (auto* c : findChildren<QWidget*>()) {
191  if (auto* w = dynamic_cast<LayerForm*>(c))
192  w->enableStructureEditing(m_showInlineEditButtons);
193  if (auto* w = dynamic_cast<ParticleLayoutForm*>(c))
194  w->enableStructureEditing(m_showInlineEditButtons);
195  if (auto* w = dynamic_cast<ParticleForm*>(c))
196  w->enableStructureEditing(m_showInlineEditButtons);
197  if (auto* w = dynamic_cast<ParticleCompositionForm*>(c))
198  w->enableStructureEditing(m_showInlineEditButtons);
199  if (auto* w = dynamic_cast<ParticleCoreShellForm*>(c))
200  w->enableStructureEditing(m_showInlineEditButtons);
201  if (auto* w = dynamic_cast<MesoCrystalForm*>(c))
202  w->enableStructureEditing(m_showInlineEditButtons);
203  }
204 
206 
207  for (auto* c : findChildren<LayerForm*>())
208  c->updateLayerPositionDependentElements();
209 }
210 
211 
213 {
214  const auto set = [](DoubleSpinBox* spinbox, Unit valueUnit, Unit displayUnit) {
215  if (spinbox->baseUnit() == valueUnit)
216  spinbox->setDisplayUnit(displayUnit);
217  };
218 
219  for (auto* editor : findChildren<DoubleSpinBox*>()) {
220  if (m_useAngstrom) {
221  set(editor, Unit::nanometer, Unit::angstrom);
222  set(editor, Unit::angstrom, Unit::angstrom);
223  set(editor, Unit::nanometer2, Unit::angstrom2);
224  set(editor, Unit::angstrom2, Unit::angstrom2);
227  } else {
228  set(editor, Unit::nanometer, Unit::nanometer);
229  set(editor, Unit::angstrom, Unit::nanometer);
230  set(editor, Unit::nanometer2, Unit::nanometer2);
231  set(editor, Unit::angstrom2, Unit::nanometer2);
234  }
235 
236  if (m_useRadiant) {
237  set(editor, Unit::degree, Unit::radiant);
238  set(editor, Unit::radiant, Unit::radiant);
239  } else {
240  set(editor, Unit::degree, Unit::degree);
241  set(editor, Unit::radiant, Unit::degree);
242  }
243  }
244  for (auto* label : findChildren<QLabel*>())
246 }
247 
248 void MultiLayerForm::ensureVisible(QWidget* /*w*/)
249 {
250  // #baLayerEditor implement ensureVisible
251 }
252 
254 {
256  updateUnits();
257 }
258 
260 {
261  return m_useAngstrom;
262 }
263 
265 {
267  updateUnits();
268 }
269 
271 {
272  return m_useRadiant;
273 }
274 
276 {
277  for (auto* c : findChildren<QWidget*>())
278  if (dynamic_cast<AddLayerWidget*>(c))
279  c->setVisible(show);
280 }
281 
283 {
284  while (w != nullptr && dynamic_cast<LayerForm*>(w) == nullptr) {
285  const auto index = m_layout->indexOf(w);
286  if (index + 1 < m_layout->count())
287  w = m_layout->itemAt(index + 1)->widget();
288  else
289  return nullptr;
290  }
291 
292  return dynamic_cast<LayerForm*>(w);
293 }
Defines class ActionFactory.
Defines class DoubleSpinBox.
Defines class GroupBoxCollapser.
Defines class LayerForm.
Defines class MesoCrystalForm.
Defines class MultiLayerForm.
Defines class MultiLayerItem.
Defines class ParticleCompositionForm.
Defines class ParticleCoreShellForm.
Defines class ParticleForm.
Defines class ParticleLayoutForm.
Unit
Defines units, mainly to be able to convert between units.
Definition: Unit.h:26
@ nanometerMinus2
@ angstrom
@ nanometer2
@ angstrom2
@ radiant
@ angstromMinus2
@ nanometer
@ degree
static QAction * createShowInRealSpaceAction(QObject *parent, const QString &what, std::function< void()> slot=nullptr)
Create "show in RealSpace" action.
SpinBox for DoubleDescriptors, supporting units.
Definition: DoubleSpinBox.h:22
Unit baseUnit() const
Returns the unit of the contained DoubleDescriptor.
void setDisplayUnit(Unit displayUnit)
Set a display unit.
Utility class to populate a QFormLayout.
Definition: FormLayouter.h:36
int addRow(QWidget *w)
Convenience method to add a widget.
int addValue(const DoubleDescriptor &d)
Adds a row with a bold printed label and a DoubleSpinBox.
int addVector(const VectorDescriptor &d, bool vertically=true)
Adds a row with a bold printed label and the 3 values of a 3D vector.
void setContentsMargins(int left, int top, int right, int bottom)
Convenience method to set the contents margins.
static GroupBoxCollapser * installIntoGroupBox(QGroupBox *groupBox, bool expanded=true)
Form for editing a layer.
Definition: LayerForm.h:29
Form for editing a mesocrystal.
MultiLayerForm(QWidget *parent, MultiLayerItem *sampleItem, SampleEditorController *ec)
void ensureVisible(QWidget *w)
void updateRowVisibilities()
void setUseAngstrom(bool angstrom)
Show values in Angstrom or nanometers.
LayerForm * findNextLayerForm(QWidget *w)
Search for the next LayerForm, starting from the given widget.
bool m_showInlineEditButtons
void onLayerAdded(LayerItem *layerItem)
Create widgets for the new layer.
SampleEditorController * m_ec
Ptr is borrowed, don't delete.
QVBoxLayout * m_layout
MultiLayerItem * m_sampleItem
Ptr is borrowed, don't delete.
void updateUnits()
Update the presented units in all contained widgets according to current settings.
void showAddLayerButtons(bool show)
Shows or hides the "Add Layer" buttons.
void onAboutToRemoveLayer(LayerItem *layerItem)
Call this before removing (deleting) a LayerItem.
bool useRadiant() const
void showInlineEditButtons(bool b)
Show or hide all buttons related to structure editing (like "add layer", "remove particle")
void setUseRadiant(bool radiant)
Show values in radiants or degrees.
bool useAngstrom() const
void onLayerMoved(LayerItem *layerItem)
Call this when a layerItem has been moved to a different position.
QString sampleName() const
QVector< LayerItem * > layers() const
QString description() const
DoubleDescriptor crossCorrLength() const
VectorDescriptor externalFieldVector() const
Form for editing a particle composition.
Form for editing a core/shell particle.
Form for editing a particle.
Definition: ParticleForm.h:25
Form for editing a particle layout.
Class to modify a sample from the layer oriented sample editor.
void addLayer(LayerItem *before)
void setSampleDescription(const QString &description)
void requestViewInRealSpace(SampleItem item)
void setSampleName(const QString &name)
void clearLayout(QLayout *layout, bool deleteWidgets=true)
Removes content from box layout.
Definition: LayoutUtils.cpp:68
void updateLabelUnit(QLabel *label)