BornAgain  1.19.0
Simulate and fit neutron and x-ray scattering at grazing incidence
MultiLayerView.cpp
Go to the documentation of this file.
1 // ************************************************************************************************
2 //
3 // BornAgain: simulate and fit reflection and scattering
4 //
5 //! @file GUI/coregui/Views/SampleDesigner/MultiLayerView.cpp
6 //! @brief Implements class MultiLayerView
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 
21 #include <QGraphicsSceneMouseEvent>
22 #include <QPainter>
23 #include <QStyleOptionGraphicsItem>
24 
25 MultiLayerView::MultiLayerView(QGraphicsItem* parent) : ILayerView(parent)
26 {
27  setColor(QColor(Qt::blue));
28 
30  setAcceptHoverEvents(false);
31  setAcceptDrops(true);
33  connect(this, &MultiLayerView::childrenChanged, this, &MultiLayerView::updateHeight);
34 }
35 
37 {
38  // to prevent call on LayerView destruction on final scene shutdown
39  disconnect(this, &MultiLayerView::childrenChanged, this, &MultiLayerView::updateHeight);
40 }
41 
43 {
44  QRectF result = m_rect;
45  if (!m_layers.empty()) {
46  qreal toplayer_height = m_layers.front()->boundingRect().height();
47  qreal bottomlayer_height = m_layers.back()->boundingRect().height();
48  result.setTop(-toplayer_height / 2.);
49  result.setHeight(m_rect.height() + (toplayer_height + bottomlayer_height) / 2.);
50  }
51  return result;
52 }
53 
54 void MultiLayerView::paint(QPainter* painter, const QStyleOptionGraphicsItem* option,
55  QWidget* widget)
56 {
57  Q_UNUSED(widget);
58  painter->setPen(m_color);
59  if (option->state & (QStyle::State_Selected | QStyle::State_HasFocus)) {
60  painter->setPen(Qt::DashLine);
61  }
63  painter->drawRect(getRectangle());
64 }
65 
66 void MultiLayerView::addView(IView* childView, int row)
67 {
68  ILayerView* layer = dynamic_cast<ILayerView*>(childView);
69  ASSERT(layer);
70 
71  if (!childItems().contains(layer)) {
72  addNewLayer(layer, row);
73  } else {
74  int previous_row = m_layers.indexOf(layer);
75  if (previous_row != row) {
76 #if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)
77  m_layers.swapItemsAt(previous_row, row);
78 #else
79  m_layers.swap(previous_row, row);
80 #endif
81  }
82  }
84 }
85 
87 {
88  m_layers.insert(row, layer);
89  connect(layer, &ILayerView::heightChanged, this, &MultiLayerView::updateHeight,
90  Qt::UniqueConnection);
92  Qt::UniqueConnection);
93  layer->setParentItem(this);
94 }
95 
97 {
98  ILayerView* layer = qobject_cast<ILayerView*>(sender());
99  ASSERT(layer);
100  removeLayer(layer);
101 }
102 
104 {
105  ASSERT(m_layers.contains(layer));
106  disconnect(layer, &ILayerView::heightChanged, this, &MultiLayerView::updateHeight);
107  disconnect(layer, &ILayerView::aboutToBeDeleted, this,
109  m_layers.removeOne(layer);
110  updateGeometry();
111 }
112 
113 //! Updates geometry of MultiLayerView from current childs geometries.
115 {
116  updateHeight();
117  updateWidth();
118 }
119 
120 //! Updates MultiLayer height, sets y-positions of children, defines new drop areas.
122 {
123  // drop areas are rectangles covering the area of layer interfaces
124  m_drop_areas.clear();
125  m_interfaces.clear();
126 
127  int total_height = 0;
128  if (!m_layers.empty()) {
129  for (ILayerView* layer : m_layers) {
130  layer->setY(total_height);
131  layer->update();
132  qreal drop_area_height = layer->boundingRect().height();
133  qreal drop_area_ypos = total_height - drop_area_height / 2.;
134  m_drop_areas.append(
135  QRectF(0, drop_area_ypos, boundingRect().width(), drop_area_height));
136  m_interfaces.append(QLineF(m_rect.left(), total_height, m_rect.right(), total_height));
137  total_height += layer->boundingRect().height();
138  }
139  qreal drop_area_height = m_layers.back()->boundingRect().height();
140  qreal drop_area_ypos = total_height - drop_area_height / 2.;
141  m_drop_areas.append(QRectF(0, drop_area_ypos, boundingRect().width(), drop_area_height));
142  m_interfaces.append(QLineF(m_rect.left(), total_height, m_rect.right(), total_height));
143  } else {
144  total_height = DesignerHelper::getDefaultMultiLayerRect().height();
145  m_drop_areas.append(boundingRect());
146  m_interfaces.append(
147  QLineF(m_rect.left(), m_rect.center().y(), m_rect.right(), m_rect.center().y()));
148  }
149  m_rect.setHeight(total_height);
150  update();
151  emit heightChanged();
152 }
153 
154 //! Updates MultiLayerView width, sets x-positions of children.
155 //! If list of children contains another MultiLayer, then width of given MultiLayer
156 //! will be increased by 12%
158 {
159  const double wider_than_children(1.15);
160  double max_width(0);
161  for (ILayerView* layer : m_layers) {
162  if (layer->boundingRect().width() > max_width)
163  max_width = layer->boundingRect().width();
164  }
165  max_width *= wider_than_children;
166  if (max_width == 0) {
167  max_width = DesignerHelper::getDefaultMultiLayerRect().width();
168  }
169  m_rect.setWidth(max_width);
170  update();
171 
172  for (ILayerView* layer : m_layers) {
173  int xpos = ((boundingRect().width() - layer->boundingRect().width())) / 2.;
174  layer->setX(xpos);
175  layer->update();
176  }
177  emit widthChanged();
178 }
179 
180 //! Returns index of drop area for given coordinate.
182 {
183  int area(-1);
184  for (int i = 0; i < m_drop_areas.size(); ++i) {
185  if (m_drop_areas.at(i).contains(pos)) {
186  area = i;
187  break;
188  }
189  }
190  return area;
191 }
192 
193 //! Returns drop area rectangle corresponding to given row
195 {
196  if (row >= 0 && row < m_drop_areas.size()) {
197  return m_drop_areas[row];
198  } else {
199  return QRectF();
200  }
201 }
202 
203 //! Returns line representing interface
205 {
206  if (row >= 0 && row < m_interfaces.size()) {
207  return m_interfaces[row];
208  } else {
209  return QLineF();
210  }
211 }
212 
213 void MultiLayerView::dragMoveEvent(QGraphicsSceneDragDropEvent* event)
214 {
215  if (!checkDragEvent(event))
216  QGraphicsItem::dragMoveEvent(event);
217 }
218 
219 void MultiLayerView::dropEvent(QGraphicsSceneDragDropEvent* event)
220 {
221  const DesignerMimeData* mimeData = checkDragEvent(event);
222  if (mimeData) {
223  DesignerScene* designerScene = dynamic_cast<DesignerScene*>(scene());
224  if (designerScene) {
225  SampleModel* sampleModel = designerScene->getSampleModel();
226 
227  sampleModel->insertNewItem(mimeData->getClassName(), this->getItem(),
228  getDropArea(event->pos()));
229  }
230  }
231 }
232 
233 const DesignerMimeData* MultiLayerView::checkDragEvent(QGraphicsSceneDragDropEvent* event)
234 {
235  const DesignerMimeData* mimeData = qobject_cast<const DesignerMimeData*>(event->mimeData());
236  if (!mimeData) {
237  event->ignore();
238  return 0;
239  }
240  int row = getDropArea(event->pos());
241  if (mimeData->hasFormat("bornagain/widget")
242  && getItem()->acceptsAsDefaultItem(mimeData->getClassName()) && row != -1) {
243 
244  event->setAccepted(true);
245  } else {
246  event->setAccepted(false);
247  }
248  return mimeData;
249 }
250 
251 QVariant MultiLayerView::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant& value)
252 {
253  return QGraphicsItem::itemChange(change, value);
254 }
#define ASSERT(condition)
Definition: Assert.h:31
Defines class DesignerHelper.
Defines class DesignerMimeData.
Defines class DesignerScene.
Defines class LayerView.
Defines class MultiLayerView.
Defines class SampleModel.
virtual void setColor(const QColor &color)
virtual void setRectangle(QRectF rect)
virtual QRectF getRectangle() const
static QRectF getDefaultBoundingRect(const QString &name)
returns default bounding rectangle for given IvView name
static QGradient getLayerGradient(const QColor &color, const QRectF &rect)
static QRectF getDefaultMultiLayerRect()
Mime data for use with SampleDesigner drag and drop operations.
QString getClassName() const
Main class which represents SessionModel on graphics scene.
Definition: DesignerScene.h:37
SampleModel * getSampleModel()
Definition: DesignerScene.h:49
Base class for LayerView and MultiLayerView Provides functionality for moving view on top of MultiLay...
Definition: ILayerView.h:25
parent class for graphic representation of all ISampleNode's
Definition: IView.h:25
virtual SessionItem * getItem()
Definition: IView.h:59
void aboutToBeDeleted()
QVariant itemChange(GraphicsItemChange change, const QVariant &value) override
void onLayerAboutToBeDeleted()
virtual void removeLayer(ILayerView *layer)
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override
void updateGeometry()
Updates geometry of MultiLayerView from current childs geometries.
void addView(IView *childView, int row=0) override
int getDropArea(QPointF pos)
Returns index of drop area for given coordinate.
QRectF boundingRect() const override
const DesignerMimeData * checkDragEvent(QGraphicsSceneDragDropEvent *event)
void dropEvent(QGraphicsSceneDragDropEvent *event) override
void updateWidth()
Updates MultiLayerView width, sets x-positions of children.
QList< QLineF > m_interfaces
void dragMoveEvent(QGraphicsSceneDragDropEvent *event) override
QList< QRectF > m_drop_areas
QList< ILayerView * > m_layers
MultiLayerView(QGraphicsItem *parent=0)
virtual void addNewLayer(ILayerView *layer, int row)
QRectF getDropAreaRectangle(int row)
Returns drop area rectangle corresponding to given row.
QLineF getInterfaceLine(int row)
Returns line representing interface.
void updateHeight()
Updates MultiLayer height, sets y-positions of children, defines new drop areas.
Main model to hold sample items.
Definition: SampleModel.h:24
SessionItem * insertNewItem(QString model_type, SessionItem *parent_item=nullptr, int row=-1, QString tag="")