BornAgain  1.19.0
Simulate and fit neutron and x-ray scattering at grazing incidence
ILayerView.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/ILayerView.cpp
6 //! @brief Implements interface ILayerView
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 
22 #include <QGraphicsSceneMouseEvent>
23 
25 {
27  QLineF line = multilayer->getInterfaceLine(row);
28  if (line.length() != 0) {
29  QPointF p1(multilayer->mapToScene(line.p1()));
30  QPointF p2(multilayer->mapToScene(line.p2()));
31  const int prolongation = 20.0;
32  return QLineF(p1.x() - prolongation, p1.y(), p2.x() + prolongation, p2.y());
33  }
34 
35  return QLineF();
36 }
37 
39 {
40  return cmp.distance < distance;
41 }
42 
43 ILayerView::ILayerView(QGraphicsItem* parent) : ConnectableView(parent)
44 {
45  setFlag(QGraphicsItem::ItemIsMovable, true);
46  setFlag(QGraphicsItem::ItemIsSelectable, true);
47  setFlag(QGraphicsItem::ItemSendsGeometryChanges);
48 }
49 
50 //! Propagates change of 'Thickness' dynamic property to screen thickness of ILayerView.
51 void ILayerView::onPropertyChange(const QString& propertyName)
52 {
53  if (propertyName == LayerItem::P_THICKNESS) {
54  updateHeight();
55  } else if (propertyName == LayerItem::P_MATERIAL) {
56  updateColor();
57  updateLabel();
58  }
59 
60  IView::onPropertyChange(propertyName);
61 }
62 
64 {
69  update();
70  emit heightChanged();
71  }
72 }
73 
75 {
78  if (v.isValid()) {
79  ExternalProperty mp = v.value<ExternalProperty>();
80  setColor(mp.color());
81  update();
82  } else {
83  ASSERT(0);
84  }
85  }
86 }
87 
89 {
90  if (getInputPorts().size() < 1)
91  return;
92 
93  NodeEditorPort* port = getInputPorts()[0];
94 
95  QString material = "";
98  if (v.isValid()) {
99  ExternalProperty mp = v.value<ExternalProperty>();
100  material = mp.text();
101  }
102  }
103 
104  /* Thickness and roughness can be added, but the length of the string
105  * becomes prohibitive.
106  QString thickness = "" ;
107  if(m_item->isTag(LayerItem::P_THICKNESS))
108  thickness = m_item->getItemValue(LayerItem::P_THICKNESS).toString();
109 
110  QString roughness = "" ;
111  if(m_item->isTag(LayerItem::P_ROUGHNESS)){
112  QVariant x = m_item->getItemValue(LayerItem::P_ROUGHNESS);
113  {...}
114  }
115  */
116  QString infoToDisplay = material;
117  port->setLabel(infoToDisplay);
118 }
119 
120 //! Detects movement of the ILayerView and sends possible drop areas to GraphicsScene
121 //! for visualization.
122 QVariant ILayerView::itemChange(GraphicsItemChange change, const QVariant& value)
123 {
124  if (change == ItemPositionChange && scene()) {
125 
126  MultiLayerCandidate multilayerCandidate = getMultiLayerCandidate();
127  if (multilayerCandidate) {
128  DesignerScene* designerScene = dynamic_cast<DesignerScene*>(scene());
129  designerScene->setLayerInterfaceLine(multilayerCandidate.getInterfaceToScene());
130  }
131  }
132  return QGraphicsItem::itemChange(change, value);
133 }
134 
135 void ILayerView::mousePressEvent(QGraphicsSceneMouseEvent* event)
136 {
137  if (event->button() == Qt::LeftButton) {
138  m_drag_start_position = pos();
139  }
140  QGraphicsItem::mousePressEvent(event);
141 }
142 
143 //! Detects possible MultiLayerView's to drop given ILayerView and propagate
144 //! request to SessionModel.
145 void ILayerView::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
146 {
147  DesignerScene* designerScene = dynamic_cast<DesignerScene*>(scene());
148  ASSERT(designerScene);
149  designerScene->setLayerInterfaceLine(); // removing drop area hint from the scene
150 
151  if (QLineF(m_drag_start_position, pos()).length() == 0) {
152  QGraphicsItem::mouseReleaseEvent(event);
153  return;
154  }
155 
157  MultiLayerView* requested_parent = candidate.multilayer;
158  int requested_row = candidate.row;
159 
160  // Simple move of single layer on the scene
161  if (!requested_parent && !parentItem()) {
162  QGraphicsItem::mouseReleaseEvent(event);
163  return;
164  }
165 
166  // Layer was moved on top of MultiLayer but not in the right drop area:
167  // returning layer back to starting position.
168  if (requested_parent && requested_row == -1) {
169  setPos(m_drag_start_position);
170  QGraphicsItem::mouseReleaseEvent(event);
171  return;
172  }
173 
174  SampleModel* model = designerScene->getSampleModel();
175 
176  // Layer was moved only slightly, to the same row of his own MultiLayer: returning back.
177  if (requested_parent == parentItem()
178  && requested_row == getItem()->parent()->getItems().indexOf(getItem())) {
179  setPos(m_drag_start_position);
180  QGraphicsItem::mouseReleaseEvent(event);
181  return;
182  }
183 
184  // Layer was moved from MultiLayer it belongs to, to an empty place of
185  // the scene: changing ownership.
186  if (parentItem() && !requested_parent) {
187  QPointF newPos = mapToScene(event->pos()) - event->pos();
188  this->getItem()->setItemValue(SessionGraphicsItem::P_XPOS, newPos.x());
189  this->getItem()->setItemValue(SessionGraphicsItem::P_YPOS, newPos.y());
190 
191  model->moveItem(this->getItem(), nullptr);
192  QGraphicsItem::mouseReleaseEvent(event);
193  return;
194  }
195 
196  // Layer was moved either from one MultiLayer to another, or is moved inside
197  // one multilayer: changing ownership or row within same ownership.
198  if (requested_parent) {
199  model->moveItem(this->getItem(), requested_parent->getItem(), requested_row);
200  QGraphicsItem::mouseReleaseEvent(event);
201  return;
202  }
203 
204  // throw only happens when not all cases were considered previously
205  throw GUIHelpers::Error("LayerView::mouseReleaseEvent() -> Loggic error.");
206 }
207 
209 {
210  updateHeight();
211  updateColor();
212  updateLabel();
214 }
215 
216 //! Finds candidate (another MultiLayer) into which we will move our ILayerView.
217 //!
218 //! To become the candidate, the bounding rectangles of MultiLayerView and given
219 //! ILayerView should intersects and ILayerView center should be near appropriate
220 //! drop area. If more than one candidate is found, they will be sorted according
221 //! to the distance between drop area and ILayerVIew center
223 {
224  QVector<MultiLayerCandidate> candidates;
225 
226  QRectF layerRect = mapRectToScene(boundingRect());
227  for (auto item : scene()->items()) {
228  if (item->type() == ViewTypes::MULTILAYER && item != this && !childItems().contains(item)) {
229  MultiLayerView* multilayer = qgraphicsitem_cast<MultiLayerView*>(item);
230  if (multilayer->mapRectToScene(multilayer->boundingRect()).intersects(layerRect)) {
231  MultiLayerCandidate candidate;
232 
233  // calculate row number to drop ILayerView and distance to the nearest droping area
234  int row = multilayer->getDropArea(multilayer->mapFromScene(layerRect.center()));
235  QRectF droparea = multilayer->mapRectToScene(multilayer->getDropAreaRectangle(row));
236  int distance =
237  std::abs(static_cast<int>(droparea.center().y() - layerRect.center().y()));
238 
239  candidate.multilayer = multilayer;
240  candidate.row = row;
241  candidate.distance = distance;
242  candidates.push_back(candidate);
243  }
244  }
245  }
246  // sorting MultiLayerView candidates to find one whose drop area is closer
247  if (!candidates.empty()) {
248  std::sort(candidates.begin(), candidates.end());
249  return candidates.back();
250  }
251  return MultiLayerCandidate();
252 }
#define ASSERT(condition)
Definition: Assert.h:31
Defines class DesignerHelper.
Defines class DesignerScene.
Defines class ExternalProperty.
Defines class GUIHelpers functions.
Defines class LayerItem.
Defines class MultiLayerView.
Defines class SampleModel.
view of ISampleNode's with rectangular shape and node functionality
QList< NodeEditorPort * > getInputPorts()
virtual QRectF boundingRect() const
virtual void update_appearance()
updates visual appearance of the item (color, icons, size etc)
virtual void setColor(const QColor &color)
virtual void setPortCoordinates()
static int nanometerToScreen(double nanometer)
non-linear conversion of layer's thickness in nanometers to screen size to have reasonable graphics r...
Main class which represents SessionModel on graphics scene.
Definition: DesignerScene.h:37
void setLayerInterfaceLine(const QLineF &line={})
Definition: DesignerScene.h:68
SampleModel * getSampleModel()
Definition: DesignerScene.h:49
The ExternalProperty class defines custom QVariant property to carry the text, color and an identifie...
QString text() const
QColor color() const
QVariant itemChange(GraphicsItemChange change, const QVariant &value)
Detects movement of the ILayerView and sends possible drop areas to GraphicsScene for visualization.
Definition: ILayerView.cpp:122
ILayerView(QGraphicsItem *parent=0)
Definition: ILayerView.cpp:43
void updateColor()
Definition: ILayerView.cpp:74
QPointF m_drag_start_position
Definition: ILayerView.h:51
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
Detects possible MultiLayerView's to drop given ILayerView and propagate request to SessionModel.
Definition: ILayerView.cpp:145
void updateLabel()
Definition: ILayerView.cpp:88
MultiLayerCandidate getMultiLayerCandidate()
Finds candidate (another MultiLayer) into which we will move our ILayerView.
Definition: ILayerView.cpp:222
void update_appearance()
updates visual appearance of the item (color, icons, size etc)
Definition: ILayerView.cpp:208
void onPropertyChange(const QString &propertyName)
Propagates change of 'Thickness' dynamic property to screen thickness of ILayerView.
Definition: ILayerView.cpp:51
void updateHeight()
Definition: ILayerView.cpp:63
void mousePressEvent(QGraphicsSceneMouseEvent *event)
Definition: ILayerView.cpp:135
virtual SessionItem * getItem()
Definition: IView.h:59
virtual void onPropertyChange(const QString &propertyName)
Definition: IView.cpp:75
SessionItem * m_item
Definition: IView.h:51
static const QString P_MATERIAL
Definition: LayerItem.h:24
static const QString P_THICKNESS
Definition: LayerItem.h:22
Class to hold MultiLayer candidate for dropping LayerView.
Definition: ILayerView.h:55
bool operator<(const MultiLayerCandidate &cmp) const
Definition: ILayerView.cpp:38
QLineF getInterfaceToScene()
returns line representing interface of multilayer in scene coordinates
Definition: ILayerView.cpp:24
int row
requested row number to drop in
Definition: ILayerView.h:59
MultiLayerView * multilayer
pointer to the candidate
Definition: ILayerView.h:58
int distance
distance from given ILayerView and drop area
Definition: ILayerView.h:60
Class representing view of MultiLayer.
int getDropArea(QPointF pos)
Returns index of drop area for given coordinate.
QRectF boundingRect() const override
QRectF getDropAreaRectangle(int row)
Returns drop area rectangle corresponding to given row.
QLineF getInterfaceLine(int row)
Returns line representing interface.
void setLabel(QString name)
Main model to hold sample items.
Definition: SampleModel.h:24
static const QString P_XPOS
static const QString P_YPOS
bool isTag(const QString &name) const
Returns true if tag is available.
QVariant getItemValue(const QString &tag) const
Directly access value of item under given tag.
void setItemValue(const QString &tag, const QVariant &variant)
Directly set value of item under given tag.
SessionItem * moveItem(SessionItem *item, SessionItem *new_parent=0, int row=-1, const QString &tag="")
Move given parameterized item to the new_parent at given row.
@ MULTILAYER
Definition: ViewTypes.h:29