BornAgain  1.19.79
Simulate and fit neutron and x-ray scattering at grazing incidence
MaskEditorPropertyPanel.cpp
Go to the documentation of this file.
1 // ************************************************************************************************
2 //
3 // BornAgain: simulate and fit reflection and scattering
4 //
5 //! @file GUI/View/Mask/MaskEditorPropertyPanel.cpp
6 //! @brief Implements class MaskEditorPropertyPanel
7 //!
8 //! @homepage http://www.bornagainproject.org
9 //! @license GNU General Public License v3 or higher (see COPYING)
10 //! @copyright Forschungszentrum Jülich GmbH 2018
11 //! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS)
12 //
13 // ************************************************************************************************
14 
23 
24 #include <QCheckBox>
25 #include <QFormLayout>
26 #include <QGroupBox>
27 #include <QLineEdit>
28 #include <QListView>
29 
31  : QWidget(parent)
32  , m_listView(new QListView)
33  , m_plotPropertyEditor(new IntensityDataPropertyWidget)
34  , m_maskModel(nullptr)
35  , m_intensityDataItem(nullptr)
36  , m_currentMaskItem(nullptr)
37  , m_inhibitSelectionChange(false)
38 {
39  setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Expanding);
40  setObjectName(QLatin1String("MaskEditorToolPanel"));
41  setAttribute(Qt::WA_StyledBackground, true);
42  setProperty("stylable", true); // for stylesheet addressing
43 
44  m_listView->setContextMenuPolicy(Qt::CustomContextMenu);
45  connect(m_listView, &QListView::customContextMenuRequested, this,
47 
48  auto* mainLayout = new QVBoxLayout;
49  mainLayout->setContentsMargins(0, 0, 0, 0);
50  mainLayout->setSpacing(8);
51 
52  // -- plot properties
53  auto* plotPropertiesGroup = new QGroupBox("Plot properties", this);
54  auto* plotPropertiesLayout = new QVBoxLayout(plotPropertiesGroup);
55  plotPropertiesLayout->setContentsMargins(0, 0, 0, 0);
56  m_plotPropertyEditor->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
57  plotPropertiesLayout->addWidget(m_plotPropertyEditor);
58  GroupBoxCollapser::installIntoGroupBox(plotPropertiesGroup);
59 
60  // -- mask stack
61  auto* maskStackGroup = new QGroupBox("Mask stack", this);
62  auto* maskStackLayout = new QVBoxLayout(maskStackGroup);
63  maskStackLayout->setContentsMargins(0, 0, 0, 0);
64  m_listView->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
65  maskStackLayout->addWidget(m_listView);
67 
68  // -- mask properties
69  auto* maskPropertiesGroup = new QGroupBox("Mask properties", this);
70  maskPropertiesGroup->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
71  m_maskPropertiesLayout = new QFormLayout(maskPropertiesGroup);
72  m_maskPropertiesLayout->setContentsMargins(8, 8, 8, 8);
73  GroupBoxCollapser::installIntoGroupBox(maskPropertiesGroup);
74 
75  mainLayout->addWidget(plotPropertiesGroup);
76  mainLayout->addWidget(maskStackGroup);
77  mainLayout->addWidget(maskPropertiesGroup);
78  mainLayout->addSpacerItem(
79  new QSpacerItem(0, 10, QSizePolicy::Fixed, QSizePolicy::MinimumExpanding));
80 
81  setLayout(mainLayout);
82 }
83 
85 {
86  return QSize(128, 128);
87 }
88 
90 {
91  return QSize(128, 128);
92 }
93 
95  const QModelIndex& maskContainerIndex,
96  IntensityDataItem* intensityItem)
97 {
98  m_maskModel = model;
99  m_rootIndex = maskContainerIndex;
100  m_intensityDataItem = intensityItem;
101 
102  m_listView->setModel(m_maskModel);
103  m_listView->setSelectionMode(QAbstractItemView::ExtendedSelection);
104 
105  m_listView->setRootIndex(m_rootIndex);
106 
107  connect(m_listView->selectionModel(), &QItemSelectionModel::selectionChanged, this,
108  &MaskEditorPropertyPanel::onSelectionChanged, Qt::UniqueConnection);
109 
111 }
112 
114 {
115  m_maskModel = nullptr;
116  m_rootIndex = {};
117  m_intensityDataItem = nullptr;
118  m_listView->setModel(nullptr);
119  setCurrentMaskItem(nullptr);
120  m_plotPropertyEditor->setItem(nullptr);
121 }
122 
124 {
125  ASSERT(m_listView);
126  return m_listView->selectionModel();
127 }
128 
129 //! Show/Hide panel. When panel is hidden, all property editors are disabled.
131 {
132  setHidden(hidden);
133 
134  if (!m_rootIndex.isValid())
135  return;
136 
137  if (hidden) {
138  setCurrentMaskItem(nullptr);
139  m_plotPropertyEditor->setItem(nullptr);
140  } else {
141  QModelIndexList indexes = selectionModel()->selectedIndexes();
142  if (!indexes.empty())
143  setCurrentMaskItem(maskItemForIndex(indexes.front()));
144 
146  }
147 }
148 
149 void MaskEditorPropertyPanel::onSelectionChanged(const QItemSelection& selected,
150  const QItemSelection&)
151 {
153  return;
154 
155  if (!selected.empty())
156  setCurrentMaskItem(maskItemForIndex(selected.indexes().front()));
157  else
158  setCurrentMaskItem(nullptr);
159 }
160 
162 {
163  emit itemContextMenuRequest(m_listView->mapToGlobal(point));
164 }
165 
167 {
168  if (m_currentMaskItem)
170 
172 
173  m_currentMaskItem = maskItem;
174 
176 }
177 
179 {
180  if (!m_currentMaskItem)
181  return;
182 
183  auto* maskItem = m_currentMaskItem; // shorthand
184  // -- mask value (only if not RoI)
185  if (!dynamic_cast<RegionOfInterestItem*>(maskItem)) {
186  const auto maskValueGetter = [=] { return maskItem->maskValue(); };
187  const auto maskValueSetter = [=](bool b) { maskItem->setMaskValue(b); };
188  addMaskCheckBox("Mask value", maskValueGetter, maskValueSetter);
189  }
190  // -- mask visibility
191  const auto visibilityValueGetter = [=] { return maskItem->isVisibleValue(); };
192  const auto visibilityValueSetter = [=](bool b) {
194  maskItem->setIsVisibleValue(b);
195  m_inhibitSelectionChange = false;
196  };
197  addMaskCheckBox("Show", visibilityValueGetter, visibilityValueSetter);
198 
199  // -- name (only if not RoI)
200  if (!dynamic_cast<RegionOfInterestItem*>(maskItem)) {
201  auto* edit = new QLineEdit(maskItem->maskName(), m_maskPropertiesLayout->parentWidget());
202  connect(edit, &QLineEdit::textEdited, [=](const QString& t) { maskItem->setMaskName(t); });
203  m_maskPropertiesLayout->addRow("Name:", edit);
204  }
205 
206  if (auto* c = dynamic_cast<RectangleItem*>(maskItem)) {
207  addMaskSpinBox(c->xLow());
208  addMaskSpinBox(c->yLow());
209  addMaskSpinBox(c->xUp());
210  addMaskSpinBox(c->yUp());
211  } else if (auto* c = dynamic_cast<EllipseItem*>(maskItem)) {
212  addMaskSpinBox(c->xCenter());
213  addMaskSpinBox(c->yCenter());
214  addMaskSpinBox(c->xRadius());
215  addMaskSpinBox(c->yRadius());
216  addMaskSpinBox(c->angle());
217  } else if (auto* c = dynamic_cast<VerticalLineItem*>(maskItem))
218  addMaskSpinBox(c->posX());
219  else if (auto* c = dynamic_cast<HorizontalLineItem*>(maskItem))
220  addMaskSpinBox(c->posY());
221 }
222 
224 {
225  auto* spinBox = new DoubleSpinBox(m_maskPropertiesLayout->parentWidget(), d);
226  spinBox->setBaseValue(d.get());
227  QObject::connect(spinBox, &DoubleSpinBox::baseValueChanged,
228  [=](double newValue) { d.set(newValue); });
229 
231  [=](const QString&) { spinBox->updateValue(); }, this);
232 
233  m_maskPropertiesLayout->addRow(d.label + ":", spinBox);
234 }
235 
236 void MaskEditorPropertyPanel::addMaskCheckBox(const QString& title, function<bool()> getter,
237  function<void(bool)> setter)
238 {
239  auto* checkBox = new QCheckBox(title, m_maskPropertiesLayout->parentWidget());
240  checkBox->setChecked(getter());
241  connect(checkBox, &QCheckBox::stateChanged, [=]() { setter(checkBox->isChecked()); });
242 
243  // listen on property change
245  [=](const QString&) {
246  QSignalBlocker b(checkBox);
247  checkBox->setChecked(getter());
248  },
249  this);
250 
251  m_maskPropertiesLayout->addRow(checkBox);
252 }
253 
255 {
256  return dynamic_cast<MaskItem*>(m_maskModel->itemForIndex(index));
257 }
Defines class DoubleSpinBox.
Defines class GroupBoxCollapser.
Defines class IntensityDataItem.
Defines class IntensityDataPropertyWidget.
Defines namespace GUI::Util::Layout.
Defines class MaskEditorPropertyPanel.
Defines MaskItems classes.
Defines class SessionModel.
Describes properties of a double value which are necessary to allow GUI representation,...
QString label
A label text (short, no trailing colon)
function< void(double)> set
function to set the value
function< double()> get
function to get the current value
SpinBox for DoubleDescriptors, supporting units.
Definition: DoubleSpinBox.h:22
void baseValueChanged(double newBaseValue)
Emitted whenever the value changes.
static GroupBoxCollapser * installIntoGroupBox(QGroupBox *groupBox, bool expanded=true)
Widget to edit properties of an IntensityDataItem.
void setItem(IntensityDataItem *mainItem, IntensityDataItem *realItem=nullptr)
void addMaskSpinBox(DoubleDescriptor d)
Add a spinbox to edit a mask's double value.
void setPanelHidden(bool hidden)
Show/Hide panel. When panel is hidden, all property editors are disabled.
IntensityDataPropertyWidget * m_plotPropertyEditor
void onSelectionChanged(const QItemSelection &selected, const QItemSelection &)
QSize minimumSizeHint() const override
void addMaskCheckBox(const QString &title, function< bool()> getter, function< void(bool)> setter)
Add a checkbox to edit a mask's boolean value.
void itemContextMenuRequest(const QPoint &point)
IntensityDataItem * m_intensityDataItem
void setMaskContext(SessionModel *model, const QModelIndex &maskContainerIndex, IntensityDataItem *intensityItem)
void onCustomContextMenuRequested(const QPoint &point)
MaskItem * m_currentMaskItem
the mask item whose properties shall be edited
QItemSelectionModel * selectionModel()
QSize sizeHint() const override
void createMaskEditorUI()
Creates the UI to edit the current mask's properties.
MaskEditorPropertyPanel(QWidget *parent=nullptr)
MaskItem * maskItemForIndex(const QModelIndex &index)
Return the mask item for the given index. nullptr if index invalid or not pointing to a mask item.
void setCurrentMaskItem(MaskItem *maskItem)
Set the current mask and creates the UI to edit the mask's properties.
A base class for all mask items.
Definition: MaskItems.h:27
bool maskValue() const
Definition: MaskItems.cpp:80
void unsubscribe(const void *caller)
Cancels all subscriptions of given caller.
Definition: ModelMapper.cpp:78
void setOnPropertyChange(std::function< void(QString)> f, const void *caller=nullptr)
Definition: ModelMapper.cpp:39
ModelMapper * mapper()
Returns the current model mapper of this item. Creates new one if necessary.
Base class for a GUI data collection. A collection is e.g. all real data (RealDataModel)....
Definition: SessionModel.h:42
SessionItem * itemForIndex(const QModelIndex &index) const
void clearLayout(QLayout *layout, bool deleteWidgets=true)
Removes content from box layout.
Definition: LayoutUtils.cpp:68