685 lines
25 KiB
C++
685 lines
25 KiB
C++
/***************************************************************************
|
|
* *
|
|
* This is a view displaying an image or portion of an image in a box. *
|
|
* *
|
|
* Author: Graeme van der Vlugt *
|
|
* Copyright: Imetric 3D GmbH *
|
|
* Year: 2004 *
|
|
* *
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU Library General Public License as *
|
|
* published by the Free Software Foundation; either version 2 of the *
|
|
* License, or (at your option) any later version. *
|
|
* for detail see the LICENCE text file. *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
#include "PreCompiled.h"
|
|
#ifndef _PreComp_
|
|
# include <cmath>
|
|
# include <QAction>
|
|
# include <QApplication>
|
|
# include <QMenu>
|
|
# include <QMouseEvent>
|
|
# include <QStatusBar>
|
|
# include <QToolBar>
|
|
#endif
|
|
|
|
#include <App/Application.h>
|
|
#include <Base/Parameter.h>
|
|
|
|
#include "ImageView.h"
|
|
#include "XpmImages.h"
|
|
|
|
|
|
using namespace ImageGui;
|
|
|
|
|
|
/* TRANSLATOR ImageGui::ImageView */
|
|
|
|
TYPESYSTEM_SOURCE_ABSTRACT(ImageGui::ImageView, Gui::MDIView)
|
|
|
|
ImageView::ImageView(QWidget* parent)
|
|
: MDIView(nullptr, parent), _ignoreCloseEvent(false)
|
|
{
|
|
// Create an OpenGL widget for displaying images
|
|
// Since Qt5 there is a weird behaviour when creating a GLImageBox.
|
|
// It works correctly for the first time when creating an image view
|
|
// but only when no 3d view is created. For the second time or if a
|
|
// 3d view is created it fails with an assert() inside the function
|
|
// QWindowPrivate::create because QWindowsIntegration::createPlatformWindow
|
|
// fails to create an instance of QPlatformWindow.
|
|
// The reason for the failure is that for the passed parent widget
|
|
// i.e. this ImageView the QPlatformWindow is also null.
|
|
// As said above it works the very first time because at construction time
|
|
// of GLImageBox it doesn't set the ImageView as parent but the parent of
|
|
// the ImageView, i.e. the main window. This mafic happens inside the
|
|
// function QWidgetPrivate::setParent_sys at this line:
|
|
// QWidget *parentWithWindow =
|
|
// newparent ? (newparent->windowHandle() ? newparent : newparent->nativeParentWidget()) : 0;
|
|
// where newparent->nativeParentWidget() returns the main window.
|
|
// For the second time this magic fails. Interesting in this context is
|
|
// that for the 3d view this magic always works.
|
|
// In order to fix this problem we directly pass the pointer of the parent
|
|
// of this ImageView, i.e. the main window.
|
|
// Note:
|
|
// Since Qt5 the class QGLWidget is marked as deprecated and should be
|
|
// replaced by QOpenGLWidget.
|
|
|
|
_pGLImageBox = new GLImageBox(this);
|
|
setCentralWidget(_pGLImageBox);
|
|
|
|
// enable mouse tracking when moving even if no buttons are pressed
|
|
setMouseTracking(true);
|
|
|
|
// enable the mouse events
|
|
_mouseEventsEnabled = true;
|
|
|
|
// Create the default status bar for displaying messages
|
|
enableStatusBar(true);
|
|
|
|
_currMode = nothing;
|
|
_currX = 0;
|
|
_currY = 0;
|
|
|
|
// Create the actions, menus and toolbars
|
|
createActions();
|
|
|
|
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath
|
|
("User parameter:BaseApp/Preferences/View");
|
|
_invertZoom = hGrp->GetBool("InvertZoom", true);
|
|
|
|
// connect other slots
|
|
connect(_pGLImageBox, SIGNAL(drawGraphics()), this, SLOT(drawGraphics()));
|
|
}
|
|
|
|
ImageView::~ImageView()
|
|
{
|
|
// No need to delete _pGLImageBox or other widgets as this gets done automatically by QT
|
|
}
|
|
|
|
// Create the action groups, actions, menus and toolbars
|
|
void ImageView::createActions()
|
|
{
|
|
// Create actions
|
|
_pFitAct = new QAction(this);
|
|
_pFitAct->setText(tr("&Fit image"));
|
|
_pFitAct->setIcon(QPixmap(image_stretch));
|
|
_pFitAct->setStatusTip(tr("Stretch the image to fit the view"));
|
|
connect(_pFitAct, SIGNAL(triggered()), this, SLOT(fitImage()));
|
|
|
|
_pOneToOneAct = new QAction(this);
|
|
_pOneToOneAct->setText(tr("&1:1 scale"));
|
|
_pOneToOneAct->setIcon(QPixmap(image_oneToOne));
|
|
_pOneToOneAct->setStatusTip(tr("Display the image at a 1:1 scale"));
|
|
connect(_pOneToOneAct, SIGNAL(triggered()), this, SLOT(oneToOneImage()));
|
|
|
|
// Create the menus and add the actions
|
|
_pContextMenu = new QMenu(this);
|
|
_pContextMenu->addAction(_pFitAct);
|
|
_pContextMenu->addAction(_pOneToOneAct);
|
|
|
|
// Create the toolbars and add the actions
|
|
_pStdToolBar = this->addToolBar(tr("Standard"));
|
|
_pStdToolBar->addAction(_pFitAct);
|
|
_pStdToolBar->addAction(_pOneToOneAct);
|
|
}
|
|
|
|
QSize ImageView::minimumSizeHint () const
|
|
{
|
|
return QSize(40, 40);
|
|
}
|
|
|
|
// Enable or disable the status bar
|
|
void ImageView::enableStatusBar(bool Enable)
|
|
{
|
|
if (Enable)
|
|
{
|
|
// Create the default status bar for displaying messages and disable the gripper
|
|
_statusBarEnabled = true;
|
|
statusBar()->setSizeGripEnabled( false );
|
|
statusBar()->showMessage(tr("Ready..."));
|
|
}
|
|
else
|
|
{
|
|
// Delete the status bar
|
|
_statusBarEnabled = false;
|
|
QStatusBar *pStatusBar = statusBar();
|
|
delete pStatusBar;
|
|
}
|
|
}
|
|
|
|
// Enable or disable the toolbar
|
|
void ImageView::enableToolBar(bool Enable)
|
|
{
|
|
_pStdToolBar->setVisible(Enable);
|
|
}
|
|
|
|
// Enable or disable the mouse events
|
|
void ImageView::enableMouseEvents(bool Enable)
|
|
{
|
|
_mouseEventsEnabled = Enable;
|
|
}
|
|
|
|
// Enable (show) or disable (hide) the '1:1' action
|
|
// Current state (zoom, position) is left unchanged
|
|
void ImageView::enableOneToOneAction(bool Enable)
|
|
{
|
|
_pOneToOneAct->setVisible(Enable);
|
|
}
|
|
|
|
// Enable (show) or disable (hide) the 'fit image' action
|
|
// Current state (zoom, position) is left unchanged
|
|
void ImageView::enableFitImageAction(bool Enable)
|
|
{
|
|
_pFitAct->setVisible(Enable);
|
|
}
|
|
|
|
// Slot function to fit (stretch/shrink) the image to the view size
|
|
void ImageView::fitImage()
|
|
{
|
|
_pGLImageBox->stretchToFit();
|
|
}
|
|
|
|
|
|
// Slot function to display the image at a 1:1 scale"
|
|
void ImageView::oneToOneImage()
|
|
{
|
|
_pGLImageBox->setNormal();
|
|
_pGLImageBox->redraw();
|
|
updateStatusBar();
|
|
}
|
|
|
|
// Show the original colors (no enhancement)
|
|
// but image will be scaled for the number of significant bits
|
|
// (i.e if 12 significant bits (in 16-bit image) a value of 4095 will be shown as white)
|
|
void ImageView::showOriginalColors()
|
|
{
|
|
_pGLImageBox->clearColorMap();
|
|
_pGLImageBox->redraw();
|
|
}
|
|
|
|
// Create a color map
|
|
// (All red entries come first, then green, then blue, then alpha)
|
|
// returns 0 for OK, -1 for memory allocation error
|
|
// numRequestedEntries ... requested number of map entries (used if not greater than system maximum or
|
|
// if not greater than the maximum number of intensity values in the current image).
|
|
// Pass zero to use the maximum possible. Always check the actual number of entries
|
|
// created using getNumColorMapEntries() after a call to this method.
|
|
// Initialise ... flag to initialise the map to a linear scale or not
|
|
int ImageView::createColorMap(int numEntriesReq, bool Initialise)
|
|
{
|
|
return (_pGLImageBox->createColorMap(numEntriesReq, Initialise));
|
|
}
|
|
|
|
// Gets the number of entries in the color map (number of entries for each color)
|
|
int ImageView::getNumColorMapEntries() const
|
|
{
|
|
return (_pGLImageBox->getNumColorMapEntries());
|
|
}
|
|
|
|
// Clears the color map
|
|
void ImageView::clearColorMap()
|
|
{
|
|
_pGLImageBox->clearColorMap();
|
|
}
|
|
|
|
// Sets a color map RGBA value
|
|
// (All red entries come first, then green, then blue, then alpha)
|
|
// index ... index of color map RGBA entry
|
|
// red ... intensity value for this red entry (range 0 to 1)
|
|
// green ... intensity value for this green entry (range 0 to 1)
|
|
// blue ... intensity value for this blue entry (range 0 to 1)
|
|
// alpha ... intensity value for this alpha entry (range 0 to 1)
|
|
int ImageView::setColorMapRGBAValue(int index, float red, float green, float blue, float alpha)
|
|
{
|
|
return (_pGLImageBox->setColorMapRGBAValue(index, red, green, blue, alpha));
|
|
}
|
|
|
|
// Sets a color map red value
|
|
// (All red entries come first, then green, then blue, then alpha)
|
|
// index ... index of color map red entry
|
|
// value ... intensity value for this red entry (range 0 to 1)
|
|
int ImageView::setColorMapRedValue(int index, float value)
|
|
{
|
|
return (_pGLImageBox->setColorMapRedValue(index, value));
|
|
}
|
|
|
|
// Sets a color map green value
|
|
// (All red entries come first, then green, then blue, then alpha)
|
|
// index ... index of color map green entry
|
|
// value ... intensity value for this green entry (range 0 to 1)
|
|
int ImageView::setColorMapGreenValue(int index, float value)
|
|
{
|
|
return (_pGLImageBox->setColorMapGreenValue(index, value));
|
|
}
|
|
|
|
// Sets a color map blue value
|
|
// (All red entries come first, then green, then blue, then alpha)
|
|
// index ... index of color map blue entry
|
|
// value ... intensity value for this blue entry (range 0 to 1)
|
|
int ImageView::setColorMapBlueValue(int index, float value)
|
|
{
|
|
return (_pGLImageBox->setColorMapBlueValue(index, value));
|
|
}
|
|
|
|
// Sets a color map alpha value
|
|
// (All red entries come first, then green, then blue, then alpha)
|
|
// index ... index of color map alpha entry
|
|
// value ... intensity value for this alpha entry (range 0 to 1)
|
|
int ImageView::setColorMapAlphaValue(int index, float value)
|
|
{
|
|
return (_pGLImageBox->setColorMapAlphaValue(index, value));
|
|
}
|
|
|
|
// Clears the image data
|
|
void ImageView::clearImage()
|
|
{
|
|
_pGLImageBox->clearImage();
|
|
_pGLImageBox->redraw(); // clears view
|
|
updateStatusBar();
|
|
}
|
|
|
|
// Load image by copying the pixel data
|
|
// The image object inside this view object will take ownership of the copied pixel data
|
|
// (the source image is still controlled by the caller)
|
|
// If numSigBitsPerSample = 0 then the full range is assumed to be significant
|
|
// displayMode ... controls the initial display of the image, one of:
|
|
// IV_DISPLAY_NOCHANGE ... no change to view settings when displaying a new image
|
|
// IV_DISPLAY_FITIMAGE ... fit-image when displaying a new image (other settings remain the same)
|
|
// IV_DISPLAY_RESET ... reset settings when displaying a new image (image will be displayed at 1:1 scale with no color map)
|
|
// Returns:
|
|
// 0 for OK
|
|
// -1 for invalid color format
|
|
// -2 for memory allocation error
|
|
int ImageView::createImageCopy(void* pSrcPixelData, unsigned long width, unsigned long height, int format, unsigned short numSigBitsPerSample, int displayMode)
|
|
{
|
|
int ret = _pGLImageBox->createImageCopy(pSrcPixelData, width, height, format, numSigBitsPerSample, displayMode);
|
|
showOriginalColors();
|
|
updateStatusBar();
|
|
return ret;
|
|
}
|
|
|
|
// Make the image object inside this view object point to another image source
|
|
// If takeOwnership is false then:
|
|
// This object will not own (control) or copy the pixel data
|
|
// (the source image is still controlled by the caller)
|
|
// Else if takeOwnership is true then:
|
|
// This object will take ownership (control) of the pixel data
|
|
// (the source image is not (should not be) controlled by the caller anymore)
|
|
// In this case the memory must have been allocated with the new operator (because this class will use the delete operator)
|
|
// If numSigBitsPerSample = 0 then the full range is assumed to be significant
|
|
// displayMode ... controls the initial display of the image, one of:
|
|
// IV_DISPLAY_NOCHANGE ... no change to view settings when displaying a new image
|
|
// IV_DISPLAY_FITIMAGE ... fit-image when displaying a new image (other settings remain the same)
|
|
// IV_DISPLAY_RESET ... reset settings when displaying a new image (image will be displayed at 1:1 scale with no color map)
|
|
// Returns:
|
|
// 0 for OK
|
|
// -1 for invalid color format
|
|
int ImageView::pointImageTo(void* pSrcPixelData, unsigned long width, unsigned long height, int format, unsigned short numSigBitsPerSample, bool takeOwnership, int displayMode)
|
|
{
|
|
int ret = _pGLImageBox->pointImageTo(pSrcPixelData, width, height, format, numSigBitsPerSample, takeOwnership, displayMode);
|
|
showOriginalColors();
|
|
updateStatusBar();
|
|
return ret;
|
|
}
|
|
|
|
// called when user presses X
|
|
void ImageView::closeEvent(QCloseEvent *e)
|
|
{
|
|
if (_ignoreCloseEvent)
|
|
{
|
|
// ignore the close event
|
|
e->ignore();
|
|
Q_EMIT closeEventIgnored(); // and emit a signal that we ignored it
|
|
}
|
|
else
|
|
{
|
|
Gui::MDIView::closeEvent(e); // if called the window will be closed anyway
|
|
}
|
|
}
|
|
|
|
// Mouse press event
|
|
void ImageView::mousePressEvent(QMouseEvent* cEvent)
|
|
{
|
|
if (_mouseEventsEnabled)
|
|
{
|
|
// Mouse event coordinates are relative to top-left of image view (including toolbar!)
|
|
// Get current cursor position relative to top-left of image box
|
|
QPoint offset = _pGLImageBox->pos();
|
|
int box_x = cEvent->x() - offset.x();
|
|
int box_y = cEvent->y() - offset.y();
|
|
_currX = box_x;
|
|
_currY = box_y;
|
|
switch(cEvent->buttons())
|
|
{
|
|
case Qt::MiddleButton:
|
|
_currMode = panning;
|
|
this->setCursor(QCursor(Qt::ClosedHandCursor));
|
|
startDrag();
|
|
break;
|
|
//case Qt::LeftButton | Qt::MiddleButton:
|
|
// _currMode = zooming;
|
|
// break;
|
|
case Qt::LeftButton:
|
|
if (cEvent->modifiers() & Qt::ShiftModifier)
|
|
_currMode = addselection;
|
|
else
|
|
_currMode = selection;
|
|
break;
|
|
case Qt::RightButton:
|
|
_pContextMenu->exec(cEvent->globalPos());
|
|
break;
|
|
default:
|
|
_currMode = nothing;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ImageView::mouseDoubleClickEvent(QMouseEvent* cEvent)
|
|
{
|
|
if (_mouseEventsEnabled)
|
|
{
|
|
// Mouse event coordinates are relative to top-left of image view (including toolbar!)
|
|
// Get current cursor position relative to top-left of image box
|
|
QPoint offset = _pGLImageBox->pos();
|
|
int box_x = cEvent->x() - offset.x();
|
|
int box_y = cEvent->y() - offset.y();
|
|
_currX = box_x;
|
|
_currY = box_y;
|
|
if(cEvent->button() == Qt::MiddleButton)
|
|
{
|
|
double icX = _pGLImageBox->WCToIC_X(_currX);
|
|
double icY = _pGLImageBox->WCToIC_Y(_currY);
|
|
//int pixX = (int)floor(icX + 0.5);
|
|
//int pixY = (int)floor(icY + 0.5);
|
|
_pGLImageBox->setZoomFactor(_pGLImageBox->getZoomFactor(), true, (int)floor(icX + 0.5), (int)floor(icY + 0.5));
|
|
_pGLImageBox->redraw();
|
|
updateStatusBar();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Mouse move event
|
|
void ImageView::mouseMoveEvent(QMouseEvent* cEvent)
|
|
{
|
|
#if QT_VERSION < 0x050900
|
|
QApplication::flush();
|
|
#endif
|
|
|
|
// Mouse event coordinates are relative to top-left of image view (including toolbar!)
|
|
// Get current cursor position relative to top-left of image box
|
|
QPoint offset = _pGLImageBox->pos();
|
|
int box_x = cEvent->x() - offset.x();
|
|
int box_y = cEvent->y() - offset.y();
|
|
if (_mouseEventsEnabled)
|
|
{
|
|
switch(_currMode)
|
|
{
|
|
case nothing:
|
|
break;
|
|
case panning:
|
|
_pGLImageBox->relMoveWC(box_x - dragStartWCx, box_y - dragStartWCy);
|
|
break;
|
|
case zooming:
|
|
zoom(_currX, _currY, box_x, box_y);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
_currX = box_x;
|
|
_currY = box_y;
|
|
|
|
// Update the status bar
|
|
updateStatusBar();
|
|
}
|
|
|
|
// Mouse release event
|
|
void ImageView::mouseReleaseEvent(QMouseEvent* cEvent)
|
|
{
|
|
if (_mouseEventsEnabled)
|
|
{
|
|
// Mouse event coordinates are relative to top-left of image view (including toolbar!)
|
|
// Get current cursor position relative to top-left of image box
|
|
QPoint offset = _pGLImageBox->pos();
|
|
int box_x = cEvent->x() - offset.x();
|
|
int box_y = cEvent->y() - offset.y();
|
|
switch(_currMode)
|
|
{
|
|
case selection:
|
|
select(box_x, box_y);
|
|
break;
|
|
case addselection:
|
|
addSelect(box_x, box_y);
|
|
break;
|
|
case panning:
|
|
this->unsetCursor();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
_currMode = nothing;
|
|
}
|
|
}
|
|
|
|
// Mouse wheel event
|
|
void ImageView::wheelEvent(QWheelEvent * cEvent)
|
|
{
|
|
if (_mouseEventsEnabled)
|
|
{
|
|
// Mouse event coordinates are relative to top-left of image view (including toolbar!)
|
|
// Get current cursor position relative to top-left of image box
|
|
QPoint offset = _pGLImageBox->pos();
|
|
#if QT_VERSION >= QT_VERSION_CHECK(5,15,0)
|
|
QPoint pos = cEvent->position().toPoint();
|
|
int box_x = pos.x() - offset.x();
|
|
int box_y = pos.y() - offset.y();
|
|
#else
|
|
int box_x = cEvent->x() - offset.x();
|
|
int box_y = cEvent->y() - offset.y();
|
|
#endif
|
|
|
|
// Zoom around centrally displayed image point
|
|
int numTicks = cEvent->angleDelta().y() / 120;
|
|
if (_invertZoom)
|
|
numTicks = -numTicks;
|
|
|
|
int ICx, ICy;
|
|
_pGLImageBox->getCentrePoint(ICx, ICy);
|
|
_pGLImageBox->setZoomFactor(_pGLImageBox->getZoomFactor() / pow(2.0, (double)numTicks), true, ICx, ICy);
|
|
_pGLImageBox->redraw();
|
|
_currX = box_x;
|
|
_currY = box_y;
|
|
|
|
// Update the status bar
|
|
updateStatusBar();
|
|
}
|
|
}
|
|
|
|
void ImageView::showEvent (QShowEvent *)
|
|
{
|
|
_pGLImageBox->setFocus();
|
|
}
|
|
|
|
// Update the status bar with the image parameters for the current mouse position
|
|
void ImageView::updateStatusBar()
|
|
{
|
|
if (_statusBarEnabled)
|
|
{
|
|
// Create the text string to display in the status bar
|
|
QString txt = createStatusBarText();
|
|
|
|
// Update status bar with new text
|
|
statusBar()->showMessage(txt);
|
|
}
|
|
}
|
|
|
|
// Create the text to display in the status bar.
|
|
// Gets called by updateStatusBar()
|
|
// Override this function in a derived class to add your own text
|
|
QString ImageView::createStatusBarText()
|
|
{
|
|
// Get some image parameters
|
|
//unsigned short numImageSamples = _pGLImageBox->getImageNumSamplesPerPix();
|
|
double zoomFactor = _pGLImageBox->getZoomFactor();
|
|
double icX = _pGLImageBox->WCToIC_X(_currX);
|
|
double icY = _pGLImageBox->WCToIC_Y(_currY);
|
|
int pixX = (int)floor(icX + 0.5);
|
|
int pixY = (int)floor(icY + 0.5);
|
|
int colorFormat = _pGLImageBox->getImageFormat();
|
|
|
|
// Create text for status bar
|
|
QString txt;
|
|
if ((colorFormat == IB_CF_GREY8) ||
|
|
(colorFormat == IB_CF_GREY16) ||
|
|
(colorFormat == IB_CF_GREY32))
|
|
{
|
|
double grey_value;
|
|
if (_pGLImageBox->getImageSample(pixX, pixY, 0, grey_value) == 0)
|
|
txt = QString::fromLatin1("x,y = %1,%2 | %3 = %4 | %5 = %6")
|
|
.arg(icX,0,'f',2).arg(icY,0,'f',2)
|
|
.arg(tr("grey")).arg((int)grey_value)
|
|
.arg(tr("zoom")).arg(zoomFactor,0,'f',1);
|
|
else
|
|
txt = QString::fromLatin1("x,y = %1 | %2 = %3")
|
|
.arg(tr("outside image"), tr("zoom")).arg(zoomFactor,0,'f',1);
|
|
}
|
|
else if ((colorFormat == IB_CF_RGB24) ||
|
|
(colorFormat == IB_CF_RGB48))
|
|
{
|
|
double red, green, blue;
|
|
if ((_pGLImageBox->getImageSample(pixX, pixY, 0, red) != 0) ||
|
|
(_pGLImageBox->getImageSample(pixX, pixY, 1, green) != 0) ||
|
|
(_pGLImageBox->getImageSample(pixX, pixY, 2, blue) != 0))
|
|
txt = QString::fromLatin1("x,y = %1 | %2 = %3")
|
|
.arg(tr("outside image"), tr("zoom")).arg(zoomFactor,0,'f',1);
|
|
else
|
|
txt = QString::fromLatin1("x,y = %1,%2 | rgb = %3,%4,%5 | %6 = %7")
|
|
.arg(icX,0,'f',2).arg(icY,0,'f',2)
|
|
.arg((int)red).arg((int)green).arg((int)blue)
|
|
.arg(tr("zoom")).arg(zoomFactor,0,'f',1);
|
|
}
|
|
else if ((colorFormat == IB_CF_BGR24) ||
|
|
(colorFormat == IB_CF_BGR48))
|
|
{
|
|
double red, green, blue;
|
|
if ((_pGLImageBox->getImageSample(pixX, pixY, 0, blue) != 0) ||
|
|
(_pGLImageBox->getImageSample(pixX, pixY, 1, green) != 0) ||
|
|
(_pGLImageBox->getImageSample(pixX, pixY, 2, red) != 0))
|
|
txt = QString::fromLatin1("x,y = %1 | %2 = %3")
|
|
.arg(tr("outside image"), tr("zoom")).arg(zoomFactor,0,'f',1);
|
|
else
|
|
txt = QString::fromLatin1("x,y = %1,%2 | rgb = %3,%4,%5 | %6 = %7")
|
|
.arg(icX,0,'f',2).arg(icY,0,'f',2)
|
|
.arg((int)red).arg((int)green).arg((int)blue)
|
|
.arg(tr("zoom")).arg(zoomFactor,0,'f',1);
|
|
}
|
|
else if ((colorFormat == IB_CF_RGBA32) ||
|
|
(colorFormat == IB_CF_RGBA64))
|
|
{
|
|
double red, green, blue, alpha;
|
|
if ((_pGLImageBox->getImageSample(pixX, pixY, 0, red) != 0) ||
|
|
(_pGLImageBox->getImageSample(pixX, pixY, 1, green) != 0) ||
|
|
(_pGLImageBox->getImageSample(pixX, pixY, 2, blue) != 0) ||
|
|
(_pGLImageBox->getImageSample(pixX, pixY, 3, alpha) != 0))
|
|
txt = QString::fromLatin1("x,y = %1 | %2 = %3")
|
|
.arg(tr("outside image"), tr("zoom")).arg(zoomFactor,0,'f',1);
|
|
else
|
|
txt = QString::fromLatin1("x,y = %1,%2 | rgba = %3,%4,%5,%6 | %7 = %8")
|
|
.arg(icX,0,'f',2).arg(icY,0,'f',2)
|
|
.arg((int)red).arg((int)green).arg((int)blue).arg((int)alpha)
|
|
.arg(tr("zoom")).arg(zoomFactor,0,'f',1);
|
|
}
|
|
else if ((colorFormat == IB_CF_BGRA32) ||
|
|
(colorFormat == IB_CF_BGRA64))
|
|
{
|
|
double red, green, blue, alpha;
|
|
if ((_pGLImageBox->getImageSample(pixX, pixY, 0, blue) != 0) ||
|
|
(_pGLImageBox->getImageSample(pixX, pixY, 1, green) != 0) ||
|
|
(_pGLImageBox->getImageSample(pixX, pixY, 2, red) != 0) ||
|
|
(_pGLImageBox->getImageSample(pixX, pixY, 3, alpha) != 0))
|
|
txt = QString::fromLatin1("x,y = %1 | %2 = %3")
|
|
.arg(tr("outside image"), tr("zoom")).arg(zoomFactor,0,'f',1);
|
|
else
|
|
txt = QString::fromLatin1("x,y = %1,%2 | rgba = %3,%4,%5,%6 | %7 = %8")
|
|
.arg(icX,0,'f',2).arg(icY,0,'f',2)
|
|
.arg((int)red).arg((int)green).arg((int)blue).arg((int)alpha)
|
|
.arg(tr("zoom")).arg(zoomFactor,0,'f',1);
|
|
}
|
|
|
|
return txt;
|
|
}
|
|
|
|
// Starts a mouse drag in the image - stores some initial positions
|
|
void ImageView::startDrag()
|
|
{
|
|
_pGLImageBox->fixBasePosCurr(); // fixes current image position as base position
|
|
dragStartWCx = _currX;
|
|
dragStartWCy = _currY;
|
|
}
|
|
|
|
// Zoom the image using vertical mouse movement to define a zoom factor
|
|
void ImageView::zoom(int prevX, int prevY, int currX, int currY)
|
|
{
|
|
// Check we have more of a vertical shift than a hz one
|
|
int dx = currX - prevX;
|
|
int dy = currY - prevY;
|
|
if (abs(dy) > abs(dx))
|
|
{
|
|
// Get centrally displayed image point
|
|
int ICx, ICy;
|
|
_pGLImageBox->getCentrePoint(ICx, ICy);
|
|
|
|
// Compute zoom factor multiplier
|
|
double zoomFactorMultiplier = 1.05;
|
|
if (currY > prevY)
|
|
zoomFactorMultiplier = 0.95;
|
|
|
|
// Zoom around centrally displayed image point
|
|
_pGLImageBox->setZoomFactor(_pGLImageBox->getZoomFactor() * zoomFactorMultiplier, true, ICx, ICy);
|
|
_pGLImageBox->redraw();
|
|
}
|
|
}
|
|
|
|
// Select at the given position
|
|
void ImageView::select(int currX, int currY)
|
|
{
|
|
// base class implementation does nothing
|
|
// override this method and implement selection capability if required
|
|
Q_UNUSED(currX);
|
|
Q_UNUSED(currY);
|
|
}
|
|
|
|
// Add selection at the given position
|
|
void ImageView::addSelect(int currX, int currY)
|
|
{
|
|
// base class implementation does nothing
|
|
// override this method and implement selection capability if required
|
|
Q_UNUSED(currX);
|
|
Q_UNUSED(currY);
|
|
}
|
|
|
|
// Draw any 2D graphics necessary
|
|
// Use GLImageBox::ICToWC_X and ICToWC_Y methods to transform image coordinates into widget coordinates (which
|
|
// must be used by the OpenGL vertex commands).
|
|
void ImageView::drawGraphics()
|
|
{
|
|
// base class implementation does nothing
|
|
|
|
// override this method and implement OpenGL drawing commands to draw any needed graphics on top of the image
|
|
|
|
/* Example: draw a red line from image coordinates (100,100) to (120,120)
|
|
glColor3ub((GLubyte)255, (GLubyte)0, (GLubyte)0);
|
|
glBegin(GL_LINES);
|
|
glVertex2d(_pGLImageBox->ICToWC_X(100.0), _pGLImageBox->ICToWC_Y(100.0));
|
|
glVertex2d(_pGLImageBox->ICToWC_X(120.0), _pGLImageBox->ICToWC_Y(120.0));
|
|
glEnd();
|
|
*/
|
|
}
|
|
|
|
#include "moc_ImageView.cpp"
|
|
|
|
|