The interactive shift-drag (box) / shift+ctrl-drag (circle) now creates a new persistent ROI in the list instead of feeding the old single-ROI scratch panel. The base emits a roiScratchDrawn hook on release; the diffraction image turns the drawn shape into a named ROI committed via SetROIDefinition. The old JFJochViewerImageROIStatistics scratch panel and all its wiring (box/circle configuration, single-ROI result, add/subtract user mask) are removed from the side panel and window; the ROI list is now the single source. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
151 lines
5.1 KiB
C++
151 lines
5.1 KiB
C++
// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
#pragma once
|
|
|
|
#include <QGraphicsView>
|
|
#include <QMouseEvent>
|
|
#include <QTransform>
|
|
#include <QPointF>
|
|
#include "../../common/ColorScale.h"
|
|
#include "../../common/JFJochMessages.h"
|
|
|
|
// Q_DECLARE_METATYPE(ROIMessage)
|
|
|
|
class JFJochImage : public QGraphicsView {
|
|
Q_OBJECT
|
|
|
|
bool m_adjustForegroundWithWheel = false;
|
|
|
|
// Viewport-lock support: guard prevents the emit<->apply ping-pong between
|
|
// two linked views, and the helper broadcasts the current transform+center.
|
|
bool m_applyingViewport = false;
|
|
void emitViewportChanged();
|
|
|
|
void DrawROI();
|
|
virtual void addCustomOverlay();
|
|
void updateROI();
|
|
void writePixelLabels();
|
|
void wheelEvent(QWheelEvent* event) override;
|
|
void resizeEvent(QResizeEvent *event) override;
|
|
void contextMenuEvent(QContextMenuEvent *event) override;
|
|
|
|
void mousePressEvent(QMouseEvent *event) override;
|
|
void mouseMoveEvent(QMouseEvent *event) override;
|
|
void mouseReleaseEvent(QMouseEvent *event) override;
|
|
|
|
ROIMessage accumulateROI(int64_t xmin, int64_t xmax, int64_t ymin, int64_t ymax,
|
|
const std::function<bool(int64_t,int64_t)>& inside);
|
|
protected:
|
|
virtual void beforeOverlayCleared();
|
|
|
|
bool show_saturation = false;
|
|
|
|
bool auto_bg = false;
|
|
bool auto_fg = false;
|
|
bool hdr_mode = false;
|
|
|
|
double scale_factor = 1.0;
|
|
|
|
size_t W = 0, H = 0;
|
|
size_t prev_W = 0, prev_H = 0;
|
|
|
|
// Track initial fit state and last image size
|
|
bool initial_fit_done_ = false;
|
|
|
|
QColor feature_color = Qt::magenta;
|
|
|
|
// Decimal places for non-integer per-pixel value labels. Float images are
|
|
// unreadable with many decimals, so subclasses can lower this.
|
|
int label_decimals_ = 3;
|
|
|
|
float foreground = 10.0;
|
|
float background = 0.0;
|
|
ColorScale color_scale;
|
|
std::vector<rgb> image_rgb;
|
|
std::vector<float> image_fp;
|
|
QPixmap pixmap;
|
|
QImage qimg_buffer_; // reusable image buffer — avoids 64MB alloc per frame
|
|
|
|
// Persistent pixmap item — never destroyed/recreated on overlay update
|
|
QGraphicsPixmapItem *pixmap_item_ = nullptr;
|
|
// Overlay items managed separately
|
|
QList<QGraphicsItem *> overlay_items_;
|
|
|
|
// Helper: add an overlay item to the scene and track it for selective removal
|
|
void addOverlayItem(QGraphicsItem *item);
|
|
|
|
enum class MouseEventType {None, Panning, DrawingROI, MovingROI, ResizingROI, EditingExternalROI};
|
|
MouseEventType mouse_event_type = MouseEventType::None;
|
|
|
|
// Hooks for editing a named, persistent ROI drawn by a subclass (the base only
|
|
// owns the mouse events; the subclass knows the loaded ROIs). roiEditPress returns
|
|
// true to claim the gesture for ROI editing.
|
|
virtual bool roiEditPress(const QPointF &scenePos) { return false; }
|
|
virtual void roiEditMove(const QPointF &scenePos) {}
|
|
virtual void roiEditRelease() {}
|
|
virtual void roiScratchDrawn() {} // a shift/ctrl-drag finished drawing a new box/circle
|
|
QPoint lastMousePos; // To track panning movement
|
|
|
|
// Resizing which edge/corner
|
|
enum class ResizeHandle { None, Left, Right, Top, Bottom, TopLeft, TopRight, BottomLeft, BottomRight, Inside };
|
|
ResizeHandle active_handle_ = ResizeHandle::None;
|
|
ResizeHandle hover_handle_ = ResizeHandle::None;
|
|
|
|
enum class RoiType {RoiBox, RoiCircle};
|
|
RoiType roi_type = RoiType::RoiBox;
|
|
QPointF roiStartPos;
|
|
QPointF roiEndPos;
|
|
QRectF roiBox;
|
|
|
|
static QPointF RoundPoint(const QPointF& p);
|
|
virtual void mouseHover(QMouseEvent* event) = 0;
|
|
|
|
ResizeHandle hitTestROIHandle(const QPointF& scenePos, qreal tol = 3.0) const;
|
|
|
|
void updateOverlay();
|
|
void GeneratePixmap();
|
|
void Redraw();
|
|
void CalcROI();
|
|
|
|
// Invalidate pixmap_item_ and overlay tracking after scene()->clear()
|
|
void resetScenePointers();
|
|
|
|
// Perform initial fit-to-view (shorter direction), once per image size
|
|
void fitToViewShorterSideOnce();
|
|
QSize last_fit_viewport_ = {};
|
|
|
|
void copyImageToClipboard();
|
|
void copyImageWithOverlayToClipboard();
|
|
void clearROIInternal();
|
|
signals:
|
|
void autoForegroundChanged(bool input);
|
|
void foregroundChanged(float v);
|
|
void backgroundChanged(float v);
|
|
void writeStatusBar(QString string, int timeout_ms = 0);
|
|
void roiBoxUpdated(QRect box);
|
|
void roiCircleUpdated(double x, double y, double radius);
|
|
void roiCalculated(ROIMessage &output);
|
|
void viewportChanged(QTransform transform, QPointF center);
|
|
void hoverScenePos(QPointF scenePos);
|
|
private slots:
|
|
void onScroll(int value);
|
|
public slots:
|
|
void setFeatureColor(QColor input);
|
|
void setColorMap(int color_map);
|
|
virtual void changeForeground(float val);
|
|
void changeBackground(float val);
|
|
|
|
void SetROIBox(QRect box);
|
|
void SetROICircle(double x, double y, double radius);
|
|
|
|
void centerOnSpot(QPointF point);
|
|
void applyViewport(QTransform transform, QPointF center);
|
|
void fitToView();
|
|
|
|
void adjustForeground(bool input);
|
|
void setZoom(double input);
|
|
public:
|
|
explicit JFJochImage(QWidget *parent = nullptr);
|
|
double GetScaleFactor() const;
|
|
}; |