4 #include "moc_QtUtil.cpp"
14 static QLocale Locale(QLocale::Language::English, QLocale::Country::UnitedStates);
19 std::vector<QDomNode>
GetChildDOMNodes(
const QDomElement& Parent,
const QString& ChildTagName)
26 auto ChildNodeList = Parent.elementsByTagName(ChildTagName);
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));
41 auto ChildNodeList = Parent.elementsByTagName(ChildTagName);
42 int FoundDirectChildIndex = -1;
43 for (
int i = 0; i < ChildNodeList.length(); ++i)
45 if (ChildNodeList.at(i).parentNode() == Parent)
47 if (FoundDirectChildIndex < 0)
48 FoundDirectChildIndex = i;
51 "Error parsing XML tree. Expecting exactly one node <" + ChildTagName.toStdString() +
">.");
55 if (FoundDirectChildIndex < 0)
57 "Node <" + ChildTagName.toStdString() +
"> has not been found in XML tree.");
59 return ChildNodeList.item(FoundDirectChildIndex);
66 if (DOMElement.isNull())
68 "Error parsing XML tree. The node <" + ChildTagName.toStdString() +
"> is not a DOM element.");
87 QDomAttr
GetDOMAttribute(
const QDomElement& Element,
const QString& AttributeName)
92 auto Attr = Element.attributes().namedItem(AttributeName).toAttr();
114 const QString& Title,
const QString& DefaultSuffix,
const QString& NameFilter,
const QString& InitialDirectory)
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);
125 return FileDialog.exec() == QDialog::Accepted ? *FileDialog.selectedFiles().begin() :
"";
129 const QString& Title,
const QString& DefaultSuffix,
const QString& NameFilter,
const QString& InitialDirectory)
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);
140 return FileDialog.exec() == QDialog::Accepted ? *FileDialog.selectedFiles().begin() :
"";
147 if (!FilePath.isEmpty())
155 if (!Width || !Height || !BytesPerLine || Format == QImage::Format::Format_Invalid)
157 "Width, Height and BytesPerLine cannot be zero, Format must describe a valid image format.");
159 if (!BlobData.GetPtr())
163 auto BufferPtr = BlobData.Release();
164 return QImage(BufferPtr, Width, Height, BytesPerLine, Format, [](
void* Info) {
166 auto CastInfo =
static_cast<decltype(BufferPtr)
>(Info);
173 auto IntensityImage = Image.convertToFormat(QImage::Format_Grayscale8);
174 const unsigned char* DataPtr = IntensityImage.constBits();
179 for (
auto i = IntensityImage.height() * IntensityImage.width(); i > 0; --i)
180 ++Histogram[*DataPtr++];
188 auto RGBImage = Image.convertToFormat(QImage::Format_RGB888);
189 const unsigned char* DataPtr = RGBImage.constBits();
194 for (
auto i = RGBImage.height() * RGBImage.width(); i > 0; --i)
196 ++HistogramR[*DataPtr++];
197 ++HistogramG[*DataPtr++];
198 ++HistogramB[*DataPtr++];
201 return { std::move(HistogramR), std::move(HistogramG), std::move(HistogramB) };
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;
213 return IntensityHistogram;
220 QPointF(Center.x() - ArmLength, Center.y()),
221 QPointF(Center.x() + ArmLength, Center.y()),
223 QPointF(Center.x(), Center.y() - ArmLength),
224 QPointF(Center.x(), Center.y() + ArmLength),
231 Widget.setWindowState((Widget.windowState() & ~Qt::WindowMinimized) | Qt::WindowActive);
233 Widget.activateWindow();
236 bool SaveToFile(
const QString& Filename, std::string_view Text)
238 QFile File(Filename);
241 if (!File.open(QIODevice::WriteOnly | QIODevice::Text))
244 const auto BytesWriten = File.write(Text.data(), Text.size());
247 return BytesWriten >= 0;
252 QFile File(Filename);
253 if (!File.open(QIODevice::ReadOnly | QIODevice::Text))
256 auto Content = File.readAll();
259 return Content.toStdString();
296 Marker->setToolTip(QString::fromStdString(
Name));
313 setContextMenuPolicy(Qt::CustomContextMenu);
322 auto LocalPoint = mapFromGlobal(Event->globalPos());
323 const auto MarkerPos = mapToScene(LocalPoint).toPoint();
326 && !items(LocalPoint).empty())
328 auto HighestIDMarker = std::max_element(
Markers.cbegin(),
Markers.cend(), [](
const auto& a,
const auto& b) {
329 return a.GetID() < b.GetID();
331 auto NewID = HighestIDMarker !=
Markers.cend() && HighestIDMarker->GetID() >= 0 ? HighestIDMarker->GetID() + 1 : 0;
333 AddMarker(MarkerPos, QColorConstants::Magenta,
true, NewID);
336 if (!
EditMarkersAction->isChecked() && Event->button() == Qt::MouseButton::LeftButton && !items(LocalPoint).empty())
346 if (it->GetMarker()->isUnderMouse() && it->IsUserDeletable())
350 scene()->removeItem(it->GetMarker());
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);
365 it->SetName(Name.toStdString());
379 if (Event->modifiers().testFlag(Qt::KeyboardModifier::ControlModifier))
381 if (Event->angleDelta().y() < 0)
383 if (Event->angleDelta().y() > 0)
387 QGraphicsView::wheelEvent(Event);
403 float ScaleFactor = std::min(scene()->height(), scene()->width()) / 300;
405 Markers.emplace_back(scene()->addPolygon(MarkerPolygon, QPen(Color, ScaleFactor)), MarkerPos, IsUserDeletable, ID,
CurrentImagePos);
418 throw OutOfRangeException(
"The given marker index exceeds the amount of markers stored in this MarkerGraphicsView.");
420 auto Marker =
Markers.cbegin() + Index;
421 if (!OnlyUserDeletableMarkers || Marker->IsUserDeletable())
423 scene()->removeItem(Marker->GetMarker());
436 if (it->GetMarkerPos() == MarkerPos && (!OnlyUserDeletableMarkers || it->IsUserDeletable()))
438 scene()->removeItem(it->GetMarker());
453 if (it->GetName() == Name && (!OnlyUserDeletableMarkers || it->IsUserDeletable()))
455 scene()->removeItem(it->GetMarker());
470 if (!OnlyUserDeletableMarkers || it->IsUserDeletable())
472 scene()->removeItem(it->GetMarker());
492 if (Marker.GetMarkerPos() == MarkerPos)
494 Marker.SetName(NewName);
554 QMessageBox::warning(
this,
"DynExp - Error",
"There are not any markers set.");
558 auto Filename =
Util::PromptSaveFilePath(
this,
"Save markers to file",
".csv",
" Comma-separated values file (*.csv)");
559 if (Filename.isEmpty())
562 std::stringstream CSVData;
563 CSVData << std::setprecision(9) <<
"ID;X(px);Y(px);ImagePosX(nm);ImagePosY(nm);Name\n";
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";
571 QMessageBox::warning(
this,
"DynExp - Error",
"Error writing data to file.");
576 QListWidget::dropEvent(event);
593 auto LineEdit =
new QLineEdit(parent);
596 LineEdit->setValidator(Validator);
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 ...
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...
Data type which manages a binary large object. The reserved memory is freed upon destruction.
Thrown when reading from or writing to a file failed.
An invalid argument like a null pointer has been passed to a function.
Data to operate on is invalid for a specific purpose. This indicates a corrupted data structure or fu...
void OnSaveMarkers(bool)
Asks the user for a file name and saves all markers to a CSV file.
void OnContextMenuRequested(QPoint Position)
Shows the context menu at position Position.
virtual void mousePressEvent(QMouseEvent *Event) override
Adds a marker to the mouse pointer position assigning the highest ID amongst all markers in the graph...
QAction * SaveMarkersAction
bool MarkersChanged
Holds whether the markers have changed by any of the marker operations.
void ZoomReset()
Resets the zoom.
void DeselectMarkers()
Deselects all selected markers.
void EnableActions(bool Enable)
QAction * ShowMarkersAction
static constexpr double DeselectedMarkerOpacity
Determines the opacity of a marker which is not selected.
void setMarkersHidden(bool MarkersHidden)
Hides or shows all markers.
void RenameMarker(const QPoint &MarkerPos, std::string_view NewName)
Assigns a name to the marker at position MarkerPos. Affects MarkersChanged.
void SelectMarker(const QPoint &MarkerPos)
Selects the marker at position MarkerPos.
std::vector< MarkerType > Markers
List of the markers.
bool HaveMarkersChanged() noexcept
Returns whether a marker operation has changed the stored markers. Resets the flag.
void RemoveMarker(size_t Index, bool OnlyUserDeletableMarkers=false)
Removes the n-th marker specified by Index. Affects MarkersChanged.
bool MarkersHidden
Determines whether the markers are currently displayed or not.
QAction * RemoveMarkersAction
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...
MarkerGraphicsView(QWidget *parent)
Constructs a MarkerGraphicsView.
void ZoomIn()
Zooms in one step.
static constexpr double ZoomFactor
Determines the magnification of one zoom step.
void OnShowMarkers(bool Checked)
If Checked is true, all markers are made visible, otherwise they become hidden.
void ZoomOut()
Zooms out one step.
static constexpr double SelectedMarkerOpacity
Determines the opacity of a selected marker.
virtual void mouseDoubleClickEvent(QMouseEvent *Event) override
Removes the marker at the mouse pointer position if it is user-deletable. Affects MarkersChanged.
QPointF CurrentImagePos
Sample position where the image has been recorded (in nm). Refer to MarkerType::ImagePos.
void OnRemoveMarkers(bool)
Removes all user-deletable markers. Affects MarkersChanged.
virtual void wheelEvent(QWheelEvent *Event) override
Zooms in or out when Control is pressed on the keyboard at the same time.
void mouseClickEvent(QPoint Position)
void RemoveMarkers(bool OnlyUserDeletableMarkers)
Removes all markers from the graphics view. Affects MarkersChanged.
QAction * EditMarkersAction
Thrown when a requested ressource does not exist.
virtual QWidget * createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override
Thrown when an argument passed to a function exceeds the valid range.
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...
void MoveToWorkerThread(DynExp::ItemIDType ID)
Moves the instance to DynExpCore's worker thread. Do not call from constructor since derived classes ...
bool HasBeenMovedToWorkerThread
Indicates whether the worker has already been moved to the worker thread.
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...
std::string GetTFromDOMAttribute(const QDomElement &Element, const QString &AttributeName)
Behaves like GetDOMAttribute() but returns the content from an attribute converted to a certain type ...
ImageHistogramType ConvertRGBToIntensityHistogram(const ImageRGBHistogramType &RGBHistogram)
Computes an intensity (grayscale) histogram from a RGB histogram.
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 ...
QDomElement GetSingleChildDOMElement(const QDomElement &Parent, const QString &ChildTagName)
Behaves like GetSingleChildDOMNode() but returns the node converted to a DOM element.
std::string GetTFromDOMElement(const QDomElement &Parent, const QString &ChildTagName)
Behaves like GetSingleChildDOMElement() but returns the content from a DOM element converted to a cer...
std::string GetStringFromDOMElement(const QDomElement &Parent, const QString &ChildTagName)
Behaves like GetSingleChildDOMElement() but returns the text from a DOM element.
const QLocale & GetDefaultQtLocale()
Returns the default locale properties to be assigned to Qt widgets.
std::vector< QDomNode > GetChildDOMNodes(const QDomElement &Parent, const QString &ChildTagName)
Finds child nodes with a certain tag name.
QPolygonF MakeCrossPolygon(QPointF Center, unsigned int ArmLength)
Returns a QPolygonF representing a cross-style marker.
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...
std::array< unsigned long long, 256 > ImageHistogramType
Alias which represents a histogram as a std::array with 256 numeric bins. The lowest (highest) index ...
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.
ImageHistogramType ComputeIntensityHistogram(const QImage &Image)
Computes an intensity (grayscale) histogram from a QImage object.
void ActivateWindow(QWidget &Widget)
Renders a window active and brings it to the front.
std::string ReadFromFile(const QString &Filename)
Reads the entire content from a text file.
QDomAttr GetDOMAttribute(const QDomElement &Element, const QString &AttributeName)
Extracts an attribute from a DOM element.
QDomNode GetSingleChildDOMNode(const QDomElement &Parent, const QString &ChildTagName)
Finds a single child node with a certain tag name.
std::tuple< ImageHistogramType, ImageHistogramType, ImageHistogramType > ImageRGBHistogramType
Alias which represents a RGB histogram as a std::tuple of three ImageHistogramType elements....
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.
ImageRGBHistogramType ComputeRGBHistogram(const QImage &Image)
Computes a RGB histogram from a QImage object.
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....
std::string GetStringFromDOMAttribute(const QDomElement &Element, const QString &AttributeName)
Behaves like GetDOMAttribute() but returns the text from the attribute.
Accumulates include statements to provide a precompiled header.
QGraphicsPolygonItem * Marker
Qt polygon object to draw the marker onto the graphics view.
void SetName(std::string_view NewName)
std::string Name
Name of the marker to describe it.