📄 imageview.cc
字号:
/** @file ImageView - class for viewing images*/#include "imageview.h"#include "settings.h"#include "iconcache.h"#include "util.h"#include "image.h"#include <QKeyEvent>#include <QMouseEvent>#include <QPaintEvent>#include <QPainter>#include <QPoint>#include <QRectF>#include <QRubberBand>#include <QScrollBar>#include <QString>#include <QToolTip>#include <QWheelEvent>#include <iostream>#include <assert.h>#include <math.h>namespace gui {using namespace std;/** Icon cache instance - one for all classes */IconCache *ic=NULL;/** Internal subwidget, which is positioned inside the QScrollArea */class ImageViewPrivate : public QWidget {private: /** parent imageview */ ImageView* p; /** Selection rectangle */ QRubberBand* rb; /** Selection origin */ QPoint origin; /** True if rubber band is being moved */ bool moveRb;public: /** Default constructor @param _p parent ImageView @param parent parent widget */ ImageViewPrivate(ImageView* _p,QWidget *parent=NULL) : QWidget(parent) { setPalette(QPalette(QColor(0xff,0xff,0xff),QColor(0,0,0))); setAttribute(Qt::WA_NoSystemBackground); setAttribute(Qt::WA_OpaquePaintEvent); p=_p; rb=NULL; moveRb=false; setMouseTracking(true); } /** Return size hint from parent item */ virtual QSize sizeHint() const { return p->sizeHint(); } /** Handler called for repainting the widget @param e event data */ virtual void paintEvent(QPaintEvent *e) { int x=width(); int y=height(); QPainter pa(this); p->repaint(x,y,pa,e->rect()); e->accept(); } /** Handler called when mouse is moved over the widget @param e event data */ virtual void mouseMoveEvent(QMouseEvent *e) { if (rb && (e->buttons() & Qt::LeftButton)) { QRect r=QRect(origin, e->pos()).normalized(); rb->setGeometry(r & p->data_rect); p->selRect(rb->geometry()); } p->mouseCoordEvent(e); e->ignore(); } /** Handler called when mouse button is pressed @param e event data */ virtual void mousePressEvent(QMouseEvent *e) { if (e->button() == Qt::LeftButton) { //LMB was just pressed moveRb=true; origin=e->pos(); if (!rb) rb=new QRubberBand(QRubberBand::Rectangle, this); rb->setGeometry(QRect(origin, QSize())); rb->show(); e->accept(); } else e->ignore(); } /** Handler called when mouse button is released @param e event data */ virtual void mouseReleaseEvent(QMouseEvent *e) { if (e->buttons() & Qt::LeftButton) { // Left button is still pressed e->ignore(); return; } if (moveRb) { moveRb=false; p->selRect(rb->geometry()); p->rectCheck(); } else e->ignore(); } /** Cancel selection rectangle */ void cancelRect() { if (!rb) return; rb->setGeometry(QRect(origin, QSize())); p->selRect(rb->geometry()); } /** Move the rubberband after updating the zoom level @param newGeom New rubberband geometry */ void moveRubberBand(const QRect &newGeom) { if (!rb) return; rb->setGeometry(newGeom); }};/** constructor of ImageView @param parent parent widget containing this control*/ImageView::ImageView(QWidget *parent/*=0*/):QScrollArea(parent) { image=NULL; zoom=100; if (!ic) ic=new IconCache(); setFocusPolicy(Qt::WheelFocus); setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); d=new ImageViewPrivate(this); setWidget(d); setWidgetResizable(true); setBackgroundRole(QPalette::Dark); setMouseTracking(true); mouse_x=mouse_y=-1; mouse_ex=mouse_ey=0; data_rect=QRect(0,0,1,1); setMode(view);}/** Called when selection is finished (on releasing the mouse button) and on start*/void ImageView::rectCheck() { if (selection.isValid()) { // "Snap rect to grid" setDataRect(); d->moveRubberBand(selectionFromImageCoords(selection)); } if (!selectionText.isNull()) { emit selectionInfo(selectionText); } else { emit selectionInfo(""); } emit selectionChanged();}/** Return true, if there is image shown in imageview, otherwise false*/bool ImageView::haveImage() const { return (image!=NULL);}/**\copydoc ImageViewPrivate::cancelRect()*/void ImageView::cancelRect() { d->cancelRect(); rectCheck(); emit selectionInfo("");}/** Return true, if there is available selection*/bool ImageView::haveSelection() const { return (selection.isValid());}/** Return image shown in the widget (or NULL if nothing is shown) If the image is modified, update() should be called to redraw the new image*/Image* ImageView::getImage() { return image;}/** Update selection rectangle position @param r selection rectangle*/void ImageView::selRect(const QRect &r) { if (r.width()<=0 || r.height()<=0) { selection=QRect(); selText(QString::null); } else { selection=selectionToImageCoords(r); int x1=selection.left(); int x2=selection.right(); int y1=selection.top(); int y2=selection.bottom(); int w=selection.width(); int h=selection.height(); selText(QString::number(x1)+","+QString::number(y1)+" - "+QString::number(x2)+","+QString::number(y2) +" ("+QString::number(w)+"x"+QString::number(h)+") "); }}/** Return selection rectangle in string form. Values (x and y position of corners) are separated by spaces @param coord What to return (0=all coordinates, 1-4=single appropriate coordinate)*/QString ImageView::getRect(int coord/*=0*/) { if (!selection.isValid()) return "";//Invalid rectangle int x1=selection.left(); int x2=selection.right(); int y1=selection.top(); int y2=selection.bottom(); switch (coord) { case 1: { return QString::number(x1); } case 2: { return QString::number(y1); } case 3: { return QString::number(x2); } case 4: { return QString::number(y2); } } return QString::number(x1)+" "+QString::number(y1)+" "+QString::number(x2)+" "+QString::number(y2);}/** Return selection rectangle converted to image coordinate system @param selectionRect rectangle to convert*/QRect ImageView::selectionToImageCoords(const QRect &selectionRect) { double dw=data_rect.width(); double dh=data_rect.height(); int x=(int)floor((selectionRect.left()-data_rect.left())*image->x()/dw); int y=(int)floor((selectionRect.top()-data_rect.top())*image->y()/dh); int xr=(int)floor((selectionRect.right()-data_rect.left())*image->x()/dw); int yr=(int)floor((selectionRect.bottom()-data_rect.top())*image->y()/dh); return QRect(QPoint(x,y),QPoint(xr,yr));}/** Return selection rectangle converted from image coordinate system to window coordinate syste, @param selectionRect rectangle to convert*/QRect ImageView::selectionFromImageCoords(const QRect &selectionRect) { int x= (selectionRect.left() )*data_rect.width()/image->x()+data_rect.left(); int y= (selectionRect.top() )*data_rect.height()/image->y()+data_rect.top(); int xr=(selectionRect.right()+1)*data_rect.width()/image->x()+data_rect.left()-1; int yr=(selectionRect.bottom()+1)*data_rect.height()/image->y()+data_rect.top()-1; return QRect(QPoint(x,y),QPoint(xr,yr));}/** Send text about selection rectangle to statusbar @param txt selection-rectangle-text*/void ImageView::selText(const QString &txt) { selectionText=txt;}/** Return size hint for the widget*/QSize ImageView::sizeHint() const { if (image) { //Size of image return QSize(image->x(),image->y()); } else { //Some default return QSize(600,400); }}/** Return minimum size neede to display the widget*/QSize ImageView::minSize() const { if (image && !isSet("scale")) { //Size of image int x=image->x(); int y=image->y(); x=x*zoom/100; y=y*zoom/100; return QSize(x,y); } else { //No minimum return QSize(0,0); }}/** Set mode of operation for the widget (simple viewing, color picking, etc ... @param m new mode for the data view*/void ImageView::setMode(ImageViewMode m) { mode=m; if (!image) { d->setCursor(Qt::ArrowCursor); return; } switch(mode) { case crosshair: { QPixmap* pick=ic->getIcon("target.png"); d->setCursor(QCursor(*pick)); break; } case view: { d->setCursor(Qt::ArrowCursor); break; } default: { d->setCursor(Qt::ArrowCursor); } }}/** Open image with given name in viewer @param name name of image*/void ImageView::loadImage(const QString &name) { if (image) delete image; image=new Image(name); flushImage();}/** Open image with data from clipboard @return true if the image was loaded, false if clipboard does not contain compatible image*/bool ImageView::loadImagePaste() { Image *im=Image::loadFromPaste(); if (im) { if (image) delete image; image=im; flushImage(); return true; } return false;}/** Create image from given pixmap @param px pixmap to use as source of image*/void ImageView::loadImage(QPixmap px) { if (image) delete image; image=new Image(px); flushImage();}/** Use after new image is loaded to flush/redraw various data */void ImageView::flushImage() { update(); cancelRect(); emit zoomChanged(zoom); emit info("");}/** Handler called when widget is resized @param e Event data*/void ImageView::resizeEvent(QResizeEvent *e) { applyZoom(); //Call parent method QScrollArea::resizeEvent(e);}/** Save image in viewer under given name @param name name of image*/void ImageView::saveImage(const QString &name) { if (image) image->saveImage(name);}/** Load state of specified optional feature from settings (default value is false) @param name Feature name */bool ImageView::isSet(const QString &name) const { return globalSettings->readBool("view/"+name,false);}/** Set specified display feature to be on or off @param name Name of the feature @param state New state: true=on, false=off*/void ImageView::setFeature(const QString &name,bool state) { globalSettings->write("view/"+name,state); update();}/** Change internal widget's minimum size. Schedule this and internal widget to repaint.*/void ImageView::update() { d->setMinimumSize(minSize()); d->update(); QScrollArea::update();}/** Use when settings "view in fullscreen" was changed*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -