DynExp
Highly flexible laboratory automation for dynamically changing experiments.
QtUtil.cpp
Go to the documentation of this file.
1 // This file is part of DynExp.
2 
3 #include "stdafx.h"
4 #include "moc_QtUtil.cpp"
5 #include "QtUtil.h"
6 
7 // Placed here to avoid circular dependencies
8 #include "DynExpCore.h"
9 
10 namespace Util
11 {
12  const QLocale& GetDefaultQtLocale()
13  {
14  static QLocale Locale(QLocale::Language::English, QLocale::Country::UnitedStates);
15 
16  return Locale;
17  }
18 
19  std::vector<QDomNode> GetChildDOMNodes(const QDomElement& Parent, const QString& ChildTagName)
20  {
21  if (Parent.isNull())
22  throw Util::InvalidDataException("Error parsing XML tree. The given parent node is invalid.");
23 
24  // Must be filtered in the following since it also contains nodes which are down deeper in the
25  // DOM hierarchy (not only direct childs).
26  auto ChildNodeList = Parent.elementsByTagName(ChildTagName);
27 
28  std::vector<QDomNode> Nodes;
29  for (int i = 0; i < ChildNodeList.length(); ++i)
30  if (ChildNodeList.at(i).parentNode() == Parent)
31  Nodes.push_back(ChildNodeList.at(i));
32 
33  return Nodes;
34  }
35 
36  QDomNode GetSingleChildDOMNode(const QDomElement& Parent, const QString& ChildTagName)
37  {
38  if (Parent.isNull())
39  throw Util::InvalidDataException("Error parsing XML tree. The given parent node is invalid.");
40 
41  auto ChildNodeList = Parent.elementsByTagName(ChildTagName);
42  int FoundDirectChildIndex = -1;
43  for (int i = 0; i < ChildNodeList.length(); ++i)
44  {
45  if (ChildNodeList.at(i).parentNode() == Parent)
46  {
47  if (FoundDirectChildIndex < 0)
48  FoundDirectChildIndex = i;
49  else
51  "Error parsing XML tree. Expecting exactly one node <" + ChildTagName.toStdString() + ">.");
52  }
53  }
54 
55  if (FoundDirectChildIndex < 0)
57  "Node <" + ChildTagName.toStdString() + "> has not been found in XML tree.");
58 
59  return ChildNodeList.item(FoundDirectChildIndex);
60  }
61 
62  QDomElement GetSingleChildDOMElement(const QDomElement& Parent, const QString& ChildTagName)
63  {
64  auto DOMElement = GetSingleChildDOMNode(Parent, ChildTagName).toElement();
65 
66  if (DOMElement.isNull())
68  "Error parsing XML tree. The node <" + ChildTagName.toStdString() + "> is not a DOM element.");
69 
70  return DOMElement;
71  }
72 
73  std::string GetStringFromDOMElement(const QDomElement& Parent, const QString& ChildTagName)
74  {
75  return GetSingleChildDOMElement(Parent, ChildTagName).text().toStdString();
76  }
77 
81  template <>
82  std::string GetTFromDOMElement(const QDomElement& Parent, const QString& ChildTagName)
83  {
84  return GetStringFromDOMElement(Parent, ChildTagName);
85  }
86 
87  QDomAttr GetDOMAttribute(const QDomElement& Element, const QString& AttributeName)
88  {
89  if (Element.isNull())
90  throw Util::InvalidDataException("Error parsing XML tree. The given node is invalid.");
91 
92  auto Attr = Element.attributes().namedItem(AttributeName).toAttr();
93  if (Attr.isNull())
94  throw Util::InvalidDataException("Error parsing XML tree. A node contains invalid attributes.");
95 
96  return Attr;
97  }
98 
99  std::string GetStringFromDOMAttribute(const QDomElement& Element, const QString& AttributeName)
100  {
101  return GetDOMAttribute(Element, AttributeName).value().toStdString();
102  }
103 
107  template <>
108  std::string GetTFromDOMAttribute(const QDomElement& Element, const QString& AttributeName)
109  {
110  return GetStringFromDOMAttribute(Element, AttributeName);
111  }
112 
113  QString PromptOpenFilePath(QWidget* Parent,
114  const QString& Title, const QString& DefaultSuffix, const QString& NameFilter, const QString& InitialDirectory)
115  {
116  QFileDialog FileDialog(Parent, Title);
117  FileDialog.setAcceptMode(QFileDialog::AcceptMode::AcceptOpen);
118  FileDialog.setFilter(QDir::Filter::Files);
119  FileDialog.setFileMode(QFileDialog::FileMode::ExistingFile);
120  FileDialog.setDefaultSuffix(DefaultSuffix);
121  FileDialog.setNameFilter(NameFilter);
122  if (!InitialDirectory.isEmpty())
123  FileDialog.setDirectory(InitialDirectory);
124 
125  return FileDialog.exec() == QDialog::Accepted ? *FileDialog.selectedFiles().begin() : "";
126  }
127 
128  QString PromptSaveFilePath(QWidget* Parent,
129  const QString& Title, const QString& DefaultSuffix, const QString& NameFilter, const QString& InitialDirectory)
130  {
131  QFileDialog FileDialog(Parent, Title);
132  FileDialog.setAcceptMode(QFileDialog::AcceptMode::AcceptSave);
133  FileDialog.setFilter(QDir::Filter::Files);
134  FileDialog.setFileMode(QFileDialog::FileMode::AnyFile);
135  FileDialog.setDefaultSuffix(DefaultSuffix);
136  FileDialog.setNameFilter(NameFilter);
137  if (!InitialDirectory.isEmpty())
138  FileDialog.setDirectory(InitialDirectory);
139 
140  return FileDialog.exec() == QDialog::Accepted ? *FileDialog.selectedFiles().begin() : "";
141  }
142 
143  QString PromptSaveFilePathModule(DynExp::QModuleWidget* Parent, const QString& Title, const QString& DefaultSuffix, const QString& NameFilter)
144  {
145  const auto FilePath = PromptSaveFilePath(Parent, Title, DefaultSuffix, NameFilter, QString::fromStdString(Parent->GetDataSaveDirectory()));
146 
147  if (!FilePath.isEmpty())
148  Parent->SetDataSaveDirectory(FilePath.toStdString());
149 
150  return FilePath;
151  }
152 
153  QImage QImageFromBlobData(BlobDataType&& BlobData, int Width, int Height, int BytesPerLine, QImage::Format Format)
154  {
155  if (!Width || !Height || !BytesPerLine || Format == QImage::Format::Format_Invalid)
156  throw InvalidArgException(
157  "Width, Height and BytesPerLine cannot be zero, Format must describe a valid image format.");
158 
159  if (!BlobData.GetPtr())
160  return {};
161 
162  // Probably not exception-safe if QImage constructor throws.
163  auto BufferPtr = BlobData.Release();
164  return QImage(BufferPtr, Width, Height, BytesPerLine, Format, [](void* Info) {
165  // Ugly due to an ugly QImage implementation...
166  auto CastInfo = static_cast<decltype(BufferPtr)>(Info);
167  delete[] CastInfo;
168  }, BufferPtr);
169  }
170 
172  {
173  auto IntensityImage = Image.convertToFormat(QImage::Format_Grayscale8);
174  const unsigned char* DataPtr = IntensityImage.constBits();
175 
176  // Initialize everything to 0 by {}.
177  ImageHistogramType Histogram{};
178 
179  for (auto i = IntensityImage.height() * IntensityImage.width(); i > 0; --i)
180  ++Histogram[*DataPtr++];
181 
182  // Histogram moved by copy elision.
183  return Histogram;
184  }
185 
187  {
188  auto RGBImage = Image.convertToFormat(QImage::Format_RGB888);
189  const unsigned char* DataPtr = RGBImage.constBits();
190 
191  // Initialize everything to 0 by {}.
192  ImageHistogramType HistogramR{}, HistogramG{}, HistogramB{};
193 
194  for (auto i = RGBImage.height() * RGBImage.width(); i > 0; --i)
195  {
196  ++HistogramR[*DataPtr++];
197  ++HistogramG[*DataPtr++];
198  ++HistogramB[*DataPtr++];
199  }
200 
201  return { std::move(HistogramR), std::move(HistogramG), std::move(HistogramB) };
202  }
203 
205  {
206  // Initialize everything to 0 by {}.
207  ImageHistogramType IntensityHistogram{};
208 
209  for (int i = 0; i < 256; ++i)
210  IntensityHistogram[i] = (std::get<0>(RGBHistogram)[i] + std::get<1>(RGBHistogram)[i] + std::get<2>(RGBHistogram)[i]) / 3.f;
211 
212  // IntensityHistogram moved by copy elision.
213  return IntensityHistogram;
214  }
215 
216  QPolygonF MakeCrossPolygon(QPointF Center, unsigned int ArmLength)
217  {
218  return QPolygonF({
219  Center,
220  QPointF(Center.x() - ArmLength, Center.y()),
221  QPointF(Center.x() + ArmLength, Center.y()),
222  Center,
223  QPointF(Center.x(), Center.y() - ArmLength),
224  QPointF(Center.x(), Center.y() + ArmLength),
225  Center,
226  });
227  }
228 
229  void ActivateWindow(QWidget& Widget)
230  {
231  Widget.setWindowState((Widget.windowState() & ~Qt::WindowMinimized) | Qt::WindowActive);
232  Widget.raise(); // for MacOS
233  Widget.activateWindow(); // for Windows
234  }
235 
236  bool SaveToFile(const QString& Filename, std::string_view Text)
237  {
238  QFile File(Filename);
239 
240  // QIODevice::WriteOnly implies QIODeviceBase::Truncate.
241  if (!File.open(QIODevice::WriteOnly | QIODevice::Text))
242  return false;
243 
244  const auto BytesWriten = File.write(Text.data(), Text.size());
245  File.close();
246 
247  return BytesWriten >= 0;
248  }
249 
250  std::string ReadFromFile(const QString& Filename)
251  {
252  QFile File(Filename);
253  if (!File.open(QIODevice::ReadOnly | QIODevice::Text))
254  throw FileIOErrorException(Filename.toStdString());
255 
256  auto Content = File.readAll();
257  File.close();
258 
259  return Content.toStdString();
260  }
261 
262  std::string ReadFromFile(const std::string& Filename)
263  {
264  return ReadFromFile(QString::fromStdString(Filename));
265  }
266 
267  std::string ReadFromFile(const std::filesystem::path& Filename)
268  {
269  return ReadFromFile(Filename.string());
270  }
271 
273  {
275  return;
276 
279  }
280 
282  {
283  static const DynExp::DynExpCore* const Core = DynExpCore;
284 
285  if (!Core)
286  throw Util::InvalidArgException("Core cannot be nullptr.");
287 
288  return *Core;
289  }
290 
291  void MarkerGraphicsView::MarkerType::SetName(std::string_view NewName)
292  {
293  Name = NewName;
294 
295  if (Marker)
296  Marker->setToolTip(QString::fromStdString(Name));
297  }
298 
300  : QGraphicsView(parent), MarkersHidden(false), MarkersChanged(true),
301  ContextMenu(new QMenu(this)), EditMarkersAction(nullptr), ShowMarkersAction(nullptr), RemoveMarkersAction(nullptr)
302  {
303  EditMarkersAction = ContextMenu->addAction("&Edit Markers");
304  EditMarkersAction->setCheckable(true);
305  EditMarkersAction->setChecked(false);
306  ShowMarkersAction = ContextMenu->addAction("S&how Markers", this, &MarkerGraphicsView::OnShowMarkers, QKeySequence(Qt::Key_NumberSign));
307  addAction(ShowMarkersAction); // for shortcuts
308  ShowMarkersAction->setCheckable(true);
309  ShowMarkersAction->setChecked(true);
310  RemoveMarkersAction = ContextMenu->addAction(QIcon(DynExpUI::Icons::Delete), "&Remove all Markers", this, &MarkerGraphicsView::OnRemoveMarkers);
311  SaveMarkersAction = ContextMenu->addAction(QIcon(DynExpUI::Icons::Save), "Sa&ve Markers to File", this, &MarkerGraphicsView::OnSaveMarkers);
312 
313  setContextMenuPolicy(Qt::CustomContextMenu);
314  connect(this, &MarkerGraphicsView::customContextMenuRequested, this, &MarkerGraphicsView::OnContextMenuRequested);
315  }
316 
317  void MarkerGraphicsView::mousePressEvent(QMouseEvent* Event)
318  {
319  if (!scene())
320  return;
321 
322  auto LocalPoint = mapFromGlobal(Event->globalPos());
323  const auto MarkerPos = mapToScene(LocalPoint).toPoint();
324 
325  if (!MarkersHidden && EditMarkersAction->isChecked() && Event->button() == Qt::MouseButton::LeftButton
326  && !items(LocalPoint).empty()) // Allow markers only on top of the displayed content - not on empty space.
327  {
328  auto HighestIDMarker = std::max_element(Markers.cbegin(), Markers.cend(), [](const auto& a, const auto& b) {
329  return a.GetID() < b.GetID();
330  });
331  auto NewID = HighestIDMarker != Markers.cend() && HighestIDMarker->GetID() >= 0 ? HighestIDMarker->GetID() + 1 : 0;
332 
333  AddMarker(MarkerPos, QColorConstants::Magenta, true, NewID);
334  }
335 
336  if (!EditMarkersAction->isChecked() && Event->button() == Qt::MouseButton::LeftButton && !items(LocalPoint).empty())
337  emit mouseClickEvent(MarkerPos);
338  }
339 
341  {
342  if (!scene() || MarkersHidden)
343  return;
344 
345  for (auto it = Markers.begin(); it != Markers.end();)
346  if (it->GetMarker()->isUnderMouse() && it->IsUserDeletable())
347  {
348  if (EditMarkersAction->isChecked())
349  {
350  scene()->removeItem(it->GetMarker());
351  it = Markers.erase(it);
352 
353  MarkersChanged = true;
354  }
355  else
356  {
357  bool OKClicked = false;
358  QString Name = QInputDialog::getText(this, "Edit name",
359  QString("Enter name of marker at position (") + QString::number(it->GetMarkerPos().x())
360  + QString(", ") + QString::number(it->GetMarkerPos().y()) + QString("):"),
361  QLineEdit::Normal, it->GetName().data(), &OKClicked);
362 
363  if (OKClicked)
364  {
365  it->SetName(Name.toStdString());
366 
367  MarkersChanged = true;
368  }
369 
370  return;
371  }
372  }
373  else
374  ++it;
375  }
376 
377  void MarkerGraphicsView::wheelEvent(QWheelEvent* Event)
378  {
379  if (Event->modifiers().testFlag(Qt::KeyboardModifier::ControlModifier))
380  {
381  if (Event->angleDelta().y() < 0)
382  ZoomOut();
383  if (Event->angleDelta().y() > 0)
384  ZoomIn();
385  }
386  else
387  QGraphicsView::wheelEvent(Event);
388  }
389 
391  {
392  bool Changed = MarkersChanged;
393  MarkersChanged = false;
394 
395  return Changed;
396  }
397 
398  void MarkerGraphicsView::AddMarker(const QPoint& MarkerPos, const QColor& Color, bool IsUserDeletable, MarkerType::IDType ID, std::string Name)
399  {
400  if (!scene())
401  return;
402 
403  float ScaleFactor = std::min(scene()->height(), scene()->width()) / 300;
404  QPolygonF MarkerPolygon = Util::MakeCrossPolygon(MarkerPos, 5 * ScaleFactor);
405  Markers.emplace_back(scene()->addPolygon(MarkerPolygon, QPen(Color, ScaleFactor)), MarkerPos, IsUserDeletable, ID, CurrentImagePos);
406  Markers.back().GetMarker()->setOpacity(DeselectedMarkerOpacity);
407  Markers.back().GetMarker()->setVisible(!MarkersHidden);
408  Markers.back().SetName(Name);
409 
410  MarkersChanged = true;
411  }
412 
413  void MarkerGraphicsView::RemoveMarker(size_t Index, bool OnlyUserDeletableMarkers)
414  {
415  if (!scene())
416  return;
417  if (Index >= Markers.size())
418  throw OutOfRangeException("The given marker index exceeds the amount of markers stored in this MarkerGraphicsView.");
419 
420  auto Marker = Markers.cbegin() + Index;
421  if (!OnlyUserDeletableMarkers || Marker->IsUserDeletable())
422  {
423  scene()->removeItem(Marker->GetMarker());
424  Markers.erase(Marker);
425 
426  MarkersChanged = true;
427  }
428  }
429 
430  void MarkerGraphicsView::RemoveMarker(const QPoint& MarkerPos, bool OnlyUserDeletableMarkers)
431  {
432  if (!scene())
433  return;
434 
435  for (auto it = Markers.cbegin(); it != Markers.cend();)
436  if (it->GetMarkerPos() == MarkerPos && (!OnlyUserDeletableMarkers || it->IsUserDeletable()))
437  {
438  scene()->removeItem(it->GetMarker());
439  it = Markers.erase(it);
440 
441  MarkersChanged = true;
442  }
443  else
444  ++it;
445  }
446 
447  void MarkerGraphicsView::RemoveMarker(std::string_view Name, bool OnlyUserDeletableMarkers)
448  {
449  if (!scene())
450  return;
451 
452  for (auto it = Markers.cbegin(); it != Markers.cend();)
453  if (it->GetName() == Name && (!OnlyUserDeletableMarkers || it->IsUserDeletable()))
454  {
455  scene()->removeItem(it->GetMarker());
456  it = Markers.erase(it);
457 
458  MarkersChanged = true;
459  }
460  else
461  ++it;
462  }
463 
464  void MarkerGraphicsView::RemoveMarkers(bool OnlyUserDeletableMarkers)
465  {
466  if (!scene())
467  return;
468 
469  for (auto it = Markers.cbegin(); it != Markers.cend();)
470  if (!OnlyUserDeletableMarkers || it->IsUserDeletable())
471  {
472  scene()->removeItem(it->GetMarker());
473  it = Markers.erase(it);
474 
475  MarkersChanged = true;
476  }
477  else
478  ++it;
479  }
480 
481  void MarkerGraphicsView::setMarkersHidden(bool MarkersHidden)
482  {
483  this->MarkersHidden = MarkersHidden;
484 
485  for (auto it = Markers.cbegin(); it != Markers.cend(); ++it)
486  it->GetMarker()->setVisible(!MarkersHidden);
487  }
488 
489  void MarkerGraphicsView::RenameMarker(const QPoint& MarkerPos, std::string_view NewName)
490  {
491  for (auto& Marker : Markers)
492  if (Marker.GetMarkerPos() == MarkerPos)
493  {
494  Marker.SetName(NewName);
495 
496  MarkersChanged = true;
497  }
498  }
499 
500  void MarkerGraphicsView::SelectMarker(const QPoint& MarkerPos)
501  {
502  for (auto& Marker : Markers)
503  Marker.GetMarker()->setOpacity(Marker.GetMarkerPos() == MarkerPos ? SelectedMarkerOpacity : DeselectedMarkerOpacity);
504  }
505 
507  {
508  for (auto& Marker : Markers)
509  Marker.GetMarker()->setOpacity(DeselectedMarkerOpacity);
510  }
511 
513  {
514  scale(ZoomFactor, ZoomFactor);
515  }
516 
518  {
519  scale(1 / ZoomFactor, 1 / ZoomFactor);
520  }
521 
523  {
524  resetTransform();
525  }
526 
528  {
529  // Except ShowMarkersAction since this action only affects how the markers are displayed.
530  EditMarkersAction->setEnabled(Enable);
531  RemoveMarkersAction->setEnabled(Enable);
532  SaveMarkersAction->setEnabled(Enable);
533  }
534 
536  {
537  ContextMenu->exec(mapToGlobal(Position));
538  }
539 
541  {
542  setMarkersHidden(!Checked);
543  }
544 
546  {
547  RemoveMarkers(true);
548  }
549 
551  {
552  if (Markers.empty())
553  {
554  QMessageBox::warning(this, "DynExp - Error", "There are not any markers set.");
555  return;
556  }
557 
558  auto Filename = Util::PromptSaveFilePath(this, "Save markers to file", ".csv", " Comma-separated values file (*.csv)");
559  if (Filename.isEmpty())
560  return;
561 
562  std::stringstream CSVData;
563  CSVData << std::setprecision(9) << "ID;X(px);Y(px);ImagePosX(nm);ImagePosY(nm);Name\n";
564 
565  for (const auto& Marker : Markers)
566  CSVData << Marker.GetID() << ";" << Marker.GetMarkerPos().x() << ";" << Marker.GetMarkerPos().y() << ";"
567  << Marker.GetImagePos().x() << ";" << Marker.GetImagePos().y() << ";"
568  << Marker.GetName() << "\n";
569 
570  if (!Util::SaveToFile(Filename, CSVData.str()))
571  QMessageBox::warning(this, "DynExp - Error", "Error writing data to file.");
572  }
573 
574  void QSortingListWidget::dropEvent(QDropEvent* event)
575  {
576  QListWidget::dropEvent(event);
577 
578  sortItems();
579  }
580 
581  bool NumericSortingTableWidgetItem::operator<(const QTableWidgetItem& Other) const
582  {
583  return GetDefaultQtLocale().toDouble(text()) < GetDefaultQtLocale().toDouble(Other.text());
584  }
585 
586  QTableWidgetItem* NumericSortingTableWidgetItem::clone() const
587  {
588  return new NumericSortingTableWidgetItem(*this);
589  }
590 
591  QWidget* NumericOnlyItemDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const
592  {
593  auto LineEdit = new QLineEdit(parent);
594  auto Validator = new QDoubleValidator(min, max, precision, LineEdit);
595  Validator->setLocale(GetDefaultQtLocale());
596  LineEdit->setValidator(Validator);
597 
598  return LineEdit;
599  }
600 }
Defines DynExp's core module as an interface between the UI and DynExp objects.
Provides utilities related to Qt and Qt widgets within DynExp's Util namespace.
DynExp's core class acts as the interface between the user interface and DynExp's internal data like ...
Definition: DynExpCore.h:127
void MoveQWorkerToWorkerThread(Util::QWorker &Worker, ItemIDType ID) const
Moves a Util::QWorker instance to WorkerThread to run its Qt event queue there. This method is thread...
Definition: DynExpCore.cpp:290
Window class for Qt-based user interfaces belonging to DynExp modules. User interface Qt window class...
Definition: Module.h:1079
std::string GetDataSaveDirectory() const
Recalls a path where modules might save recorded data to. Used by Util::PromptSaveFilePathModule() to...
Definition: Module.cpp:431
void SetDataSaveDirectory(std::string_view Directory) const
Sets a path where modules might save recorded data to. Used by Util::PromptSaveFilePathModule() to st...
Definition: Module.cpp:436
Data type which manages a binary large object. The reserved memory is freed upon destruction.
Definition: Util.h:517
Thrown when reading from or writing to a file failed.
Definition: Exception.h:315
An invalid argument like a null pointer has been passed to a function.
Definition: Exception.h:137
Data to operate on is invalid for a specific purpose. This indicates a corrupted data structure or fu...
Definition: Exception.h:163
void OnSaveMarkers(bool)
Asks the user for a file name and saves all markers to a CSV file.
Definition: QtUtil.cpp:550
void OnContextMenuRequested(QPoint Position)
Shows the context menu at position Position.
Definition: QtUtil.cpp:535
virtual void mousePressEvent(QMouseEvent *Event) override
Adds a marker to the mouse pointer position assigning the highest ID amongst all markers in the graph...
Definition: QtUtil.cpp:317
QAction * SaveMarkersAction
Definition: QtUtil.h:557
bool MarkersChanged
Holds whether the markers have changed by any of the marker operations.
Definition: QtUtil.h:547
void ZoomReset()
Resets the zoom.
Definition: QtUtil.cpp:522
void DeselectMarkers()
Deselects all selected markers.
Definition: QtUtil.cpp:506
void EnableActions(bool Enable)
Definition: QtUtil.cpp:527
QAction * ShowMarkersAction
Definition: QtUtil.h:555
static constexpr double DeselectedMarkerOpacity
Determines the opacity of a marker which is not selected.
Definition: QtUtil.h:383
void setMarkersHidden(bool MarkersHidden)
Hides or shows all markers.
Definition: QtUtil.cpp:481
void RenameMarker(const QPoint &MarkerPos, std::string_view NewName)
Assigns a name to the marker at position MarkerPos. Affects MarkersChanged.
Definition: QtUtil.cpp:489
void SelectMarker(const QPoint &MarkerPos)
Selects the marker at position MarkerPos.
Definition: QtUtil.cpp:500
std::vector< MarkerType > Markers
List of the markers.
Definition: QtUtil.h:545
bool HaveMarkersChanged() noexcept
Returns whether a marker operation has changed the stored markers. Resets the flag.
Definition: QtUtil.cpp:390
void RemoveMarker(size_t Index, bool OnlyUserDeletableMarkers=false)
Removes the n-th marker specified by Index. Affects MarkersChanged.
Definition: QtUtil.cpp:413
bool MarkersHidden
Determines whether the markers are currently displayed or not.
Definition: QtUtil.h:546
QAction * RemoveMarkersAction
Definition: QtUtil.h:556
void AddMarker(const QPoint &MarkerPos, const QColor &Color, bool IsUserDeletable=true, MarkerType::IDType ID=-1, std::string Name={})
Adds a marker to the graphics view at position MarkerPos assigning the properties passed as arguments...
Definition: QtUtil.cpp:398
MarkerGraphicsView(QWidget *parent)
Constructs a MarkerGraphicsView.
Definition: QtUtil.cpp:299
void ZoomIn()
Zooms in one step.
Definition: QtUtil.cpp:512
static constexpr double ZoomFactor
Determines the magnification of one zoom step.
Definition: QtUtil.h:382
void OnShowMarkers(bool Checked)
If Checked is true, all markers are made visible, otherwise they become hidden.
Definition: QtUtil.cpp:540
void ZoomOut()
Zooms out one step.
Definition: QtUtil.cpp:517
static constexpr double SelectedMarkerOpacity
Determines the opacity of a selected marker.
Definition: QtUtil.h:384
virtual void mouseDoubleClickEvent(QMouseEvent *Event) override
Removes the marker at the mouse pointer position if it is user-deletable. Affects MarkersChanged.
Definition: QtUtil.cpp:340
QPointF CurrentImagePos
Sample position where the image has been recorded (in nm). Refer to MarkerType::ImagePos.
Definition: QtUtil.h:548
void OnRemoveMarkers(bool)
Removes all user-deletable markers. Affects MarkersChanged.
Definition: QtUtil.cpp:545
virtual void wheelEvent(QWheelEvent *Event) override
Zooms in or out when Control is pressed on the keyboard at the same time.
Definition: QtUtil.cpp:377
void mouseClickEvent(QPoint Position)
void RemoveMarkers(bool OnlyUserDeletableMarkers)
Removes all markers from the graphics view. Affects MarkersChanged.
Definition: QtUtil.cpp:464
QAction * EditMarkersAction
Definition: QtUtil.h:554
Thrown when a requested ressource does not exist.
Definition: Exception.h:236
virtual QWidget * createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override
Definition: QtUtil.cpp:591
bool operator<(const QTableWidgetItem &Other) const
Compares the content of this table widget item with the content of another table widget item by conve...
Definition: QtUtil.cpp:581
virtual QTableWidgetItem * clone() const override
Definition: QtUtil.cpp:586
Thrown when an argument passed to a function exceeds the valid range.
Definition: Exception.h:211
virtual void dropEvent(QDropEvent *event) override
Definition: QtUtil.cpp:574
static const DynExp::DynExpCore & GetDynExpCore(const DynExp::DynExpCore *DynExpCore=nullptr)
Returns the application's DynExp::DynExpCore instance which is globally set in constructor DynExp::Dy...
Definition: QtUtil.cpp:281
void MoveToWorkerThread(DynExp::ItemIDType ID)
Moves the instance to DynExpCore's worker thread. Do not call from constructor since derived classes ...
Definition: QtUtil.cpp:272
bool HasBeenMovedToWorkerThread
Indicates whether the worker has already been moved to the worker thread.
Definition: QtUtil.h:370
constexpr auto Save
constexpr auto Delete
size_t ItemIDType
ID type of objects/items managed by DynExp.
DynExp's Util namespace contains commonly used functions and templates as well as extensions to Qt an...
Definition: circularbuf.cpp:7
std::string GetTFromDOMAttribute(const QDomElement &Element, const QString &AttributeName)
Behaves like GetDOMAttribute() but returns the content from an attribute converted to a certain type ...
Definition: QtUtil.cpp:108
ImageHistogramType ConvertRGBToIntensityHistogram(const ImageRGBHistogramType &RGBHistogram)
Computes an intensity (grayscale) histogram from a RGB histogram.
Definition: QtUtil.cpp:204
bool SaveToFile(const QString &Filename, std::string_view Text)
Saves a std::string_view to a file (using QFile). Creates a new file or truncates an existing file's ...
Definition: QtUtil.cpp:236
QDomElement GetSingleChildDOMElement(const QDomElement &Parent, const QString &ChildTagName)
Behaves like GetSingleChildDOMNode() but returns the node converted to a DOM element.
Definition: QtUtil.cpp:62
std::string GetTFromDOMElement(const QDomElement &Parent, const QString &ChildTagName)
Behaves like GetSingleChildDOMElement() but returns the content from a DOM element converted to a cer...
Definition: QtUtil.cpp:82
std::string GetStringFromDOMElement(const QDomElement &Parent, const QString &ChildTagName)
Behaves like GetSingleChildDOMElement() but returns the text from a DOM element.
Definition: QtUtil.cpp:73
const QLocale & GetDefaultQtLocale()
Returns the default locale properties to be assigned to Qt widgets.
Definition: QtUtil.cpp:12
std::vector< QDomNode > GetChildDOMNodes(const QDomElement &Parent, const QString &ChildTagName)
Finds child nodes with a certain tag name.
Definition: QtUtil.cpp:19
QPolygonF MakeCrossPolygon(QPointF Center, unsigned int ArmLength)
Returns a QPolygonF representing a cross-style marker.
Definition: QtUtil.cpp:216
QImage QImageFromBlobData(BlobDataType &&BlobData, int Width, int Height, int BytesPerLine, QImage::Format Format)
Converts raw pixel data stored in a Util::BlobDataType object to a QImage transfering the ownership o...
Definition: QtUtil.cpp:153
std::array< unsigned long long, 256 > ImageHistogramType
Alias which represents a histogram as a std::array with 256 numeric bins. The lowest (highest) index ...
Definition: QtUtil.h:244
QString PromptOpenFilePath(QWidget *Parent, const QString &Title, const QString &DefaultSuffix, const QString &NameFilter, const QString &InitialDirectory)
Opens a file dialog to ask the user to select a single existing file.
Definition: QtUtil.cpp:113
ImageHistogramType ComputeIntensityHistogram(const QImage &Image)
Computes an intensity (grayscale) histogram from a QImage object.
Definition: QtUtil.cpp:171
void ActivateWindow(QWidget &Widget)
Renders a window active and brings it to the front.
Definition: QtUtil.cpp:229
std::string ReadFromFile(const QString &Filename)
Reads the entire content from a text file.
Definition: QtUtil.cpp:250
QDomAttr GetDOMAttribute(const QDomElement &Element, const QString &AttributeName)
Extracts an attribute from a DOM element.
Definition: QtUtil.cpp:87
QDomNode GetSingleChildDOMNode(const QDomElement &Parent, const QString &ChildTagName)
Finds a single child node with a certain tag name.
Definition: QtUtil.cpp:36
std::tuple< ImageHistogramType, ImageHistogramType, ImageHistogramType > ImageRGBHistogramType
Alias which represents a RGB histogram as a std::tuple of three ImageHistogramType elements....
Definition: QtUtil.h:250
QString PromptSaveFilePath(QWidget *Parent, const QString &Title, const QString &DefaultSuffix, const QString &NameFilter, const QString &InitialDirectory)
Works as PromptOpenFilePath() but asks the user to select a single file which does not need to exist.
Definition: QtUtil.cpp:128
ImageRGBHistogramType ComputeRGBHistogram(const QImage &Image)
Computes a RGB histogram from a QImage object.
Definition: QtUtil.cpp:186
QString PromptSaveFilePathModule(DynExp::QModuleWidget *Parent, const QString &Title, const QString &DefaultSuffix, const QString &NameFilter)
Works as PromptOpenFilePath() but asks the user to select a single file which does not need to exist....
Definition: QtUtil.cpp:143
std::string GetStringFromDOMAttribute(const QDomElement &Element, const QString &AttributeName)
Behaves like GetDOMAttribute() but returns the text from the attribute.
Definition: QtUtil.cpp:99
Accumulates include statements to provide a precompiled header.
QGraphicsPolygonItem * Marker
Qt polygon object to draw the marker onto the graphics view.
Definition: QtUtil.h:428
void SetName(std::string_view NewName)
Definition: QtUtil.cpp:291
std::string Name
Name of the marker to describe it.
Definition: QtUtil.h:432