-rw-r--r-- | libopie2/opiemm/oimagescrollview.cpp | 585 | ||||
-rw-r--r-- | libopie2/opiemm/oimagescrollview.h | 95 | ||||
-rw-r--r-- | libopie2/opiemm/oimagezoomer.cpp | 233 | ||||
-rw-r--r-- | libopie2/opiemm/oimagezoomer.h | 141 | ||||
-rw-r--r-- | libopie2/opiemm/opiemm.pro | 4 |
5 files changed, 1056 insertions, 2 deletions
diff --git a/libopie2/opiemm/oimagescrollview.cpp b/libopie2/opiemm/oimagescrollview.cpp new file mode 100644 index 0000000..0e86bd0 --- a/dev/null +++ b/libopie2/opiemm/oimagescrollview.cpp @@ -0,0 +1,585 @@ +#include "oimagescrollview.h" + +#include <opie2/oimagezoomer.h> +#include <opie2/odebug.h> +#include <opie2/oapplication.h> +#include <opie2/owait.h> + +#include <qimage.h> +#include <qlayout.h> +#include <qpe/qcopenvelope_qws.h> + +/* for usage with the bitset */ +#define AUTO_SCALE 0 +#define AUTO_ROTATE 1 +#define SHOW_ZOOMER 2 +#define FIRST_RESIZE_DONE 3 +#define IMAGE_IS_JPEG 4 +#define IMAGE_SCALED_LOADED 5 + +#define SCROLLVIEW_BITSET_SIZE 6 + +namespace Opie { +namespace MM { +OImageScrollView::OImageScrollView( QWidget* parent, const char* name, WFlags f ) + :QScrollView(parent,name,f|Qt::WRepaintNoErase ),_image_data(),_original_data(), + m_states(SCROLLVIEW_BITSET_SIZE),m_lastName("") +{ + _zoomer = 0; + m_states[AUTO_SCALE]=true; + m_states[AUTO_ROTATE]=true; + m_states[FIRST_RESIZE_DONE]=false; + m_states[IMAGE_IS_JPEG]=false; + m_states[IMAGE_SCALED_LOADED]=false; + m_states[SHOW_ZOOMER]=true; + init(); +} + +OImageScrollView::OImageScrollView (const QImage&img, QWidget * parent, const char * name, WFlags f,bool always_scale,bool rfit) + :QScrollView(parent,name,f|Qt::WRepaintNoErase),_image_data(),_original_data(img), + m_states(SCROLLVIEW_BITSET_SIZE),m_lastName("") +{ + _zoomer = 0; + m_states[AUTO_SCALE]=always_scale; + m_states[AUTO_ROTATE]=rfit; + m_states[FIRST_RESIZE_DONE]=false; + m_states[IMAGE_IS_JPEG]=false; + m_states[IMAGE_SCALED_LOADED]=false; + m_states[SHOW_ZOOMER]=true; + _original_data.convertDepth(QPixmap::defaultDepth()); + _original_data.setAlphaBuffer(false); + init(); +} + +OImageScrollView::OImageScrollView (const QString&img, QWidget * parent, const char * name, WFlags f,bool always_scale,bool rfit) + :QScrollView(parent,name,f|Qt::WRepaintNoErase),_image_data(),_original_data(),m_states(SCROLLVIEW_BITSET_SIZE),m_lastName("") +{ + _zoomer = 0; + m_states.resize(SCROLLVIEW_BITSET_SIZE); + m_states[AUTO_SCALE]=always_scale; + m_states[AUTO_ROTATE]=rfit; + m_states[FIRST_RESIZE_DONE]=false; + m_states[IMAGE_IS_JPEG]=false; + m_states[IMAGE_SCALED_LOADED]=false; + m_states[SHOW_ZOOMER]=true; + init(); + setImage(img); +} + +void OImageScrollView::setImage(const QImage&img) +{ + _image_data = QImage(); + _original_data=img; + _original_data.convertDepth(QPixmap::defaultDepth()); + _original_data.setAlphaBuffer(false); + m_lastName = ""; + setImageIsJpeg(false); + setImageScaledLoaded(false); + if (FirstResizeDone()) { + generateImage(); + } +} + +void OImageScrollView::loadJpeg(bool interncall) +{ + if (m_lastName.isEmpty()) return; + QImageIO iio( m_lastName, 0l ); + QString param; + bool real_load = false; + if (AutoScale()) { + if (!interncall) { + int wid, hei; + wid = QApplication::desktop()->width(); + hei = QApplication::desktop()->height(); + if (hei>wid) { + wid = hei; + } else { + hei = wid; + } + param = QString( "Fast Shrink( 7 ) Scale( %1, %2, ScaleFree)" ).arg( wid ).arg( hei ); + odebug << "Load jpeg scaled \"" << param << "\"" << oendl; + iio.setParameters(param.latin1()); + setImageScaledLoaded(true); + real_load = true; + } + } else { + if (ImageScaledLoaded()||!interncall) { + odebug << "Load jpeg unscaled" << oendl; + real_load = true; + } + setImageScaledLoaded(false); + } + if (real_load) { + { + QCopEnvelope( "QPE/System", "busy()" ); + } + _original_data = iio.read() ? iio.image() : QImage(); + { + QCopEnvelope env( "QPE/System", "notBusy(QString)" ); + env << "Image loaded"; + } + } +} + +void OImageScrollView::setImage( const QString& path ) { + odebug << "load new image " << oendl; + if (m_lastName == path) return; + m_lastName = path; + QString itype = QImage::imageFormat(m_lastName); + odebug << "Image type = " << itype << oendl; + if (itype == "JPEG") { + setImageIsJpeg(true); + loadJpeg(); + } else { + { + QCopEnvelope( "QPE/System", "busy()" ); + } + setImageIsJpeg(false); + _original_data.load(path); + _original_data.convertDepth(QPixmap::defaultDepth()); + _original_data.setAlphaBuffer(false); + { + QCopEnvelope env( "QPE/System", "notBusy(QString)" ); + env << "Image loaded"; + } + } + _image_data = QImage(); + if (FirstResizeDone()) { + generateImage(); + } +} + +/* should be called every time the QImage changed it content */ +void OImageScrollView::init() +{ + odebug << "init " << oendl; + + /* + * create the zoomer + * and connect ther various signals + */ + _zoomer = new Opie::MM::OImageZoomer( this, "The Zoomer" ); + connect(_zoomer, SIGNAL( zoomAreaRel(int,int)), + this, SLOT(scrollBy(int,int)) ); + connect(_zoomer, SIGNAL( zoomArea(int,int)), + this, SLOT(center(int,int)) ); + connect(this,SIGNAL(contentsMoving(int,int)), + _zoomer, (SLOT(setVisiblePoint(int,int))) ); + connect(this,SIGNAL(imageSizeChanged(const QSize&)), + _zoomer, SLOT(setImageSize(const QSize&)) ); + connect(this,SIGNAL(viewportSizeChanged(const QSize&)), + _zoomer, SLOT(setViewPortSize(const QSize&)) ); + + viewport()->setBackgroundColor(white); + setFocusPolicy(QWidget::StrongFocus); + setImageScaledLoaded(false); + setImageIsJpeg(false); + if (FirstResizeDone()) { + m_last_rot = Rotate0; + generateImage(); + } else if (_original_data.size().isValid()) { + if (image_fit_into(_original_data.size()) || !ShowZoomer()) _zoomer->hide(); + resizeContents(_original_data.width(),_original_data.height()); + } +} + +void OImageScrollView::setAutoRotate(bool how) +{ + /* to avoid double repaints */ + if (AutoRotate() != how) { + m_states.setBit(AUTO_ROTATE,how); + _image_data = QImage(); + generateImage(); + } +} + +bool OImageScrollView::AutoRotate()const +{ + return m_states.testBit(AUTO_ROTATE); +} + +void OImageScrollView::setAutoScale(bool how) +{ + m_states.setBit(AUTO_SCALE,how); + if (!how) { + setAutoRotate(false); + } + _image_data = QImage(); + if (ImageIsJpeg() && how == false && ImageScaledLoaded()==true) { + loadJpeg(true); + } + generateImage(); +} + +bool OImageScrollView::AutoScale()const +{ + return m_states.testBit(AUTO_SCALE); +} + +OImageScrollView::~OImageScrollView() +{ +} + +void OImageScrollView::rescaleImage(int w, int h) +{ + if (_image_data.width()==w && _image_data.height()==h) { + return; + } + double hs = (double)h / (double)_image_data.height() ; + double ws = (double)w / (double)_image_data.width() ; + double scaleFactor = (hs > ws) ? ws : hs; + int smoothW = (int)(scaleFactor * _image_data.width()); + int smoothH = (int)(scaleFactor * _image_data.height()); + _image_data = _image_data.smoothScale(smoothW,smoothH); +} + +void OImageScrollView::rotate_into_data(Rotation r) +{ + /* realy - we must do this that way, 'cause when acting direct on _image_data the app will + segfault :( */ + QImage dest; + int x, y; + if ( _original_data.depth() > 8 ) + { + unsigned int *srcData, *destData; + switch ( r ) + { + case Rotate90: + dest.create(_original_data.height(), _original_data.width(), _original_data.depth()); + for ( y=0; y < _original_data.height(); ++y ) + { + srcData = (unsigned int *)_original_data.scanLine(y); + for ( x=0; x < _original_data.width(); ++x ) + { + destData = (unsigned int *)dest.scanLine(x); + destData[_original_data.height()-y-1] = srcData[x]; + } + } + break; + case Rotate180: + dest.create(_original_data.width(), _original_data.height(), _original_data.depth()); + for ( y=0; y < _original_data.height(); ++y ) + { + srcData = (unsigned int *)_original_data.scanLine(y); + destData = (unsigned int *)dest.scanLine(_original_data.height()-y-1); + for ( x=0; x < _original_data.width(); ++x ) + destData[_original_data.width()-x-1] = srcData[x]; + } + break; + case Rotate270: + dest.create(_original_data.height(), _original_data.width(), _original_data.depth()); + for ( y=0; y < _original_data.height(); ++y ) + { + srcData = (unsigned int *)_original_data.scanLine(y); + for ( x=0; x < _original_data.width(); ++x ) + { + destData = (unsigned int *)dest.scanLine(_original_data.width()-x-1); + destData[y] = srcData[x]; + } + } + break; + default: + dest = _original_data; + break; + } + } + else + { + unsigned char *srcData, *destData; + unsigned int *srcTable, *destTable; + switch ( r ) + { + case Rotate90: + dest.create(_original_data.height(), _original_data.width(), _original_data.depth()); + dest.setNumColors(_original_data.numColors()); + srcTable = (unsigned int *)_original_data.colorTable(); + destTable = (unsigned int *)dest.colorTable(); + for ( x=0; x < _original_data.numColors(); ++x ) + destTable[x] = srcTable[x]; + for ( y=0; y < _original_data.height(); ++y ) + { + srcData = (unsigned char *)_original_data.scanLine(y); + for ( x=0; x < _original_data.width(); ++x ) + { + destData = (unsigned char *)dest.scanLine(x); + destData[_original_data.height()-y-1] = srcData[x]; + } + } + break; + case Rotate180: + dest.create(_original_data.width(), _original_data.height(), _original_data.depth()); + dest.setNumColors(_original_data.numColors()); + srcTable = (unsigned int *)_original_data.colorTable(); + destTable = (unsigned int *)dest.colorTable(); + for ( x=0; x < _original_data.numColors(); ++x ) + destTable[x] = srcTable[x]; + for ( y=0; y < _original_data.height(); ++y ) + { + srcData = (unsigned char *)_original_data.scanLine(y); + destData = (unsigned char *)dest.scanLine(_original_data.height()-y-1); + for ( x=0; x < _original_data.width(); ++x ) + destData[_original_data.width()-x-1] = srcData[x]; + } + break; + case Rotate270: + dest.create(_original_data.height(), _original_data.width(), _original_data.depth()); + dest.setNumColors(_original_data.numColors()); + srcTable = (unsigned int *)_original_data.colorTable(); + destTable = (unsigned int *)dest.colorTable(); + for ( x=0; x < _original_data.numColors(); ++x ) + destTable[x] = srcTable[x]; + for ( y=0; y < _original_data.height(); ++y ) + { + srcData = (unsigned char *)_original_data.scanLine(y); + for ( x=0; x < _original_data.width(); ++x ) + { + destData = (unsigned char *)dest.scanLine(_original_data.width()-x-1); + destData[y] = srcData[x]; + } + } + break; + default: + dest = _original_data; + break; + } + + } + _image_data = dest; +} + +void OImageScrollView::generateImage() +{ + Rotation r = Rotate0; + if (_original_data.isNull()) return; + { + QCopEnvelope( "QPE/System", "busy()" ); + } + if (width()>height()&&_original_data.width()<_original_data.height() || + width()<height()&&_original_data.width()>_original_data.height()) { + if (AutoRotate()) r = Rotate90; + } + + odebug << " r = " << r << oendl; + if (AutoScale()) { + if (!_image_data.size().isValid()||width()>_image_data.width()||height()>_image_data.height()) { + odebug << "Rescaling data" << oendl; + if (r==Rotate0) { + _image_data = _original_data; + } else { + rotate_into_data(r); + } + } + rescaleImage(width(),height()); + resizeContents(_image_data.width(),_image_data.height()); + } else if (!FirstResizeDone()||r!=m_last_rot||_image_data.width()==0) { + if (r==Rotate0) { + _image_data = _original_data; + } else { + rotate_into_data(r); + } + m_last_rot = r; + resizeContents(_image_data.width(),_image_data.height()); + } + _pdata.convertFromImage(_image_data); + + + /* + * update the zoomer + */ + check_zoomer(); + emit imageSizeChanged( _image_data.size() ); + rescaleImage( 128, 128 ); + /* + * move scrollbar + */ + if (_zoomer) { + _zoomer->setGeometry( viewport()->width()-_image_data.width()/2, viewport()->height()-_image_data.height()/2, + _image_data.width()/2, _image_data.height()/2 ); + _zoomer->setImage( _image_data ); + } + /* + * invalidate + */ + _image_data=QImage(); + { + QCopEnvelope env( "QPE/System", "notBusy(QString)" ); + env << "Image generated"; + } +} + +void OImageScrollView::resizeEvent(QResizeEvent * e) +{ + odebug << "OImageScrollView resizeEvent" << oendl; + QScrollView::resizeEvent(e); + generateImage(); + setFirstResizeDone(true); + emit viewportSizeChanged( viewport()->size() ); + +} + +void OImageScrollView::keyPressEvent(QKeyEvent * e) +{ + if (!e) return; + int dx = horizontalScrollBar()->lineStep(); + int dy = verticalScrollBar()->lineStep(); + if (e->key()==Qt::Key_Right) { + scrollBy(dx,0); + e->accept(); + } else if (e->key()==Qt::Key_Left) { + scrollBy(0-dx,0); + e->accept(); + } else if (e->key()==Qt::Key_Up) { + scrollBy(0,0-dy); + e->accept(); + } else if (e->key()==Qt::Key_Down) { + scrollBy(0,dy); + e->accept(); + } else { + e->ignore(); + } + QScrollView::keyPressEvent(e); +} + +void OImageScrollView::drawContents(QPainter * p, int clipx, int clipy, int clipw, int cliph) +{ + int w = clipw; + int h = cliph; + int x = clipx; + int y = clipy; + bool erase = false; + + if (!_pdata.size().isValid()) { + p->fillRect(clipx,clipy,clipw,cliph,white); + return; + } + if (w>_pdata.width()) { + w=_pdata.width(); + x = 0; + erase = true; + } else if (x+w>_pdata.width()){ + x = _pdata.width()-w; + } + if (h>_pdata.height()) { + h=_pdata.height(); + y = 0; + erase = true; + } else if (y+h>_pdata.height()){ + y = _pdata.height()-h; + } + if (erase||_original_data.hasAlphaBuffer()) { + p->fillRect(clipx,clipy,clipw,cliph,white); + } + p->drawPixmap(clipx,clipy,_pdata,x,y,w,h); +} + +/* using the real geometry points and not the translated points is wanted! */ +void OImageScrollView::viewportMouseMoveEvent(QMouseEvent* e) +{ + odebug << "Move X and Y " << e->x() << " " << e->y() << oendl; + int mx, my; + mx = e->x(); + my = e->y(); + if (_mouseStartPosX!=-1 && _mouseStartPosY!=-1) { + int diffx = _mouseStartPosX-mx; + int diffy = _mouseStartPosY-my; +#if 0 + QScrollBar*xbar = horizontalScrollBar(); + QScrollBar*ybar = verticalScrollBar(); + if (xbar->value()+diffx>xbar->maxValue()) { + diffx = xbar->maxValue()-xbar->value(); + } else if (xbar->value()+diffx<0) { + diffx=0-xbar->value(); + } + if (ybar->value()+diffy>ybar->maxValue()) { + diffy = ybar->maxValue()-ybar->value(); + } else if (ybar->value()+diffy<0) { + diffy=0-ybar->value(); + } +#endif + scrollBy(diffx,diffy); + } + _mouseStartPosX=mx; + _mouseStartPosY=my; +} + +void OImageScrollView::contentsMousePressEvent ( QMouseEvent * e) +{ + odebug << " X and Y " << e->x() << " " << e->y() << oendl; + /* this marks the beginning of a possible mouse move. Due internal reasons of QT + the geometry values here may real differ from that set in MoveEvent (I don't know + why). For getting them in real context, we use the first move-event to set the start + position ;) + */ + _mouseStartPosX = -1; + _mouseStartPosY = -1; +} + +void OImageScrollView::setDestructiveClose() { + WFlags fl = getWFlags(); + /* clear it just in case */ + fl &= ~WDestructiveClose; + fl |= WDestructiveClose; + setWFlags( fl ); +} + +bool OImageScrollView::image_fit_into(const QSize&s ) +{ + if (s.width()>width()||s.height()>height()) { + return false; + } + return true; +} + +void OImageScrollView::setShowZoomer(bool how) +{ + m_states.setBit(SHOW_ZOOMER,how); + check_zoomer(); +} + +bool OImageScrollView::ShowZoomer()const +{ + return m_states.testBit(SHOW_ZOOMER); +} + +void OImageScrollView::check_zoomer() +{ + if (!_zoomer) return; + if ( (!ShowZoomer()||image_fit_into(_pdata.size()) ) && _zoomer->isVisible()) { + _zoomer->hide(); + } else if ( ShowZoomer() && !image_fit_into(_pdata.size()) && _zoomer->isHidden()){ + _zoomer->show(); + } +} + +bool OImageScrollView::FirstResizeDone()const +{ + return m_states.testBit(FIRST_RESIZE_DONE); +} + +void OImageScrollView::setFirstResizeDone(bool how) +{ + m_states.setBit(FIRST_RESIZE_DONE,how); +} + +bool OImageScrollView::ImageIsJpeg()const +{ + return m_states.testBit(IMAGE_IS_JPEG); +} + +void OImageScrollView::setImageIsJpeg(bool how) +{ + m_states.setBit(IMAGE_IS_JPEG,how); +} + +bool OImageScrollView::ImageScaledLoaded()const +{ + return m_states.testBit(IMAGE_SCALED_LOADED); +} + +void OImageScrollView::setImageScaledLoaded(bool how) +{ + m_states.setBit(IMAGE_SCALED_LOADED,how); +} + +} // namespace MM +} // namespace Opie diff --git a/libopie2/opiemm/oimagescrollview.h b/libopie2/opiemm/oimagescrollview.h new file mode 100644 index 0000000..3d2ea38 --- a/dev/null +++ b/libopie2/opiemm/oimagescrollview.h @@ -0,0 +1,95 @@ +#ifndef _IMAGE_SCROLL_VIEW_H +#define _IMAGE_SCROLL_VIEW_H + +#include <qscrollview.h> +#include <qimage.h> +#include <qpixmap.h> +#include <qstring.h> +#include <qdialog.h> +#include <qbitarray.h> + + +class QPainter; + +namespace Opie { namespace MM { + + class OImageZoomer; + +class OImageScrollView:public QScrollView +{ + Q_OBJECT +public: + enum Rotation { + Rotate0, + Rotate90, + Rotate180, + Rotate270 + }; + + OImageScrollView( QWidget* parent, const char* name = 0, WFlags fl = 0 ); + OImageScrollView (const QImage&, QWidget * parent=0, const char * name=0, WFlags f=0,bool always_scale=false,bool rfit=false ); + OImageScrollView (const QString&, QWidget * parent=0, const char * name=0, WFlags f=0,bool always_scale=false,bool rfit=false ); + virtual ~OImageScrollView(); + + + virtual void setDestructiveClose(); + + virtual void setAutoRotate(bool); + virtual void setAutoScale(bool); + virtual void setShowZoomer(bool); + + virtual bool AutoRotate()const; + virtual bool AutoScale()const; + virtual bool ShowZoomer()const; + +public slots: + virtual void setImage(const QImage&); + virtual void setImage( const QString& path ); + + +signals: + void imageSizeChanged( const QSize& ); + void viewportSizeChanged( const QSize& ); + +protected: + virtual void drawContents ( QPainter * p, int clipx, int clipy, int clipw, int cliph ); + void init(); + + Opie::MM::OImageZoomer *_zoomer; + QImage _image_data; + QImage _original_data; + QPixmap _pdata; + + int _mouseStartPosX,_mouseStartPosY; + + QBitArray m_states; + + Rotation m_last_rot; + QString m_lastName; + virtual void rescaleImage(int w, int h); + + virtual void rotate_into_data(Rotation r); + virtual void generateImage(); + virtual void loadJpeg(bool interncall = false); + bool image_fit_into(const QSize&s); + void check_zoomer(); + + /* internal bitset manipulation */ + virtual bool ImageIsJpeg()const; + virtual void setImageIsJpeg(bool how); + virtual bool ImageScaledLoaded()const; + virtual void setImageScaledLoaded(bool how); + virtual bool FirstResizeDone()const; + virtual void setFirstResizeDone(bool how); + +protected slots: + virtual void viewportMouseMoveEvent(QMouseEvent* e); + virtual void contentsMousePressEvent ( QMouseEvent * e); + virtual void resizeEvent(QResizeEvent * e); + virtual void keyPressEvent(QKeyEvent * e); +}; + +} +} + +#endif diff --git a/libopie2/opiemm/oimagezoomer.cpp b/libopie2/opiemm/oimagezoomer.cpp new file mode 100644 index 0000000..d1eec67 --- a/dev/null +++ b/libopie2/opiemm/oimagezoomer.cpp @@ -0,0 +1,233 @@ +#include "oimagezoomer.h" + +#include <opie2/odebug.h> + +#include <qimage.h> +#include <qpixmap.h> +#include <qpainter.h> +#include <qrect.h> +#include <qpoint.h> +#include <qsize.h> + +namespace Opie { +namespace MM { + +/** + * \brief The most simple c'tor + * The main c'tor. You still need to set a QPixmap/QIMage, + * setImageSize,setViewPortSize,setVisiblePoint + * + * @param parent The parent widget + * @param name A name for this widget + * @param fl The widget flags + * + */ +OImageZoomer::OImageZoomer( QWidget* parent, const char* name, WFlags fl ) + : QFrame( parent, name, fl ) { + init(); +} + + +/** + * \brief This c'tor takes a QPixmap additional + * + * You initially set the QPixmap but you still need to provide + * the additional data to make this widget useful + * + * @param pix A Pixmap it'll be converted to a QImage later! + * @param par The parent widget + * @param name The name of this widget + * @param fl The widget flags + */ +OImageZoomer::OImageZoomer( const QPixmap& pix, QWidget* par, const char* name, WFlags fl ) + : QFrame( par, name, fl ) { + init(); + setImage( pix ); +} + + +/** + * \brief This c'tor takes a QImage instead + * You just provide a QImage which is saved. It behaves the same as the others. + * + * @param img A Image which will be used for the zoomer content + * @param par The parent of the widget + * @param name The name of the widget + * @param fl The widgets flags + */ +OImageZoomer::OImageZoomer( const QImage& img, QWidget* par, const char* name, WFlags fl) + : QFrame( par, name, fl ) { + init(); + setImage( img ); +} + + +/** + * \brief overloaded c'tor + * + * This differs only in the arguments it takes + * + * + * @param pSize The size of the Page you show + * @param vSize The size of the viewport. The size of the visible part of the widget + * @param par The parent of the widget + * @param name The name + * @param fl The window flags + */ +OImageZoomer::OImageZoomer( const QSize& pSize, const QSize& vSize, QWidget* par, + const char* name, WFlags fl ) + : QFrame( par, name, fl ), m_imgSize( pSize ),m_visSize( vSize ) { + init(); +} + +/** + * d'tor + */ +OImageZoomer::~OImageZoomer() { + +} + +void OImageZoomer::init() { + m_mevent = false; + setFrameStyle( Panel | Sunken ); +} + + +/** + * \brief set the page/image size + * Tell us the QSize of the Data you show to the user. We need this + * to do the calculations + * + * @param size The size of the stuff you want to zoom on + */ +void OImageZoomer::setImageSize( const QSize& size ) { + m_imgSize = size; + repaint(); +} + +/** + * \brief Set the size of the viewport + * Tell us the QSize of the viewport. The viewport is the part + * of the widget which is exposed on the screen + * + * @param size Te size of the viewport + * + * @see QScrollView::viewport() + */ +void OImageZoomer::setViewPortSize( const QSize& size ) { + m_visSize = size; + repaint(); +} + +/** + * \brief the point in the topleft corner which is currently visible + * Set the visible point. This most of the times relate to QScrollView::contentsX() + * and QScrollView::contentsY() + * + * @see setVisiblePoint(int,int) + */ +void OImageZoomer::setVisiblePoint( const QPoint& pt ) { + m_visPt = pt; + repaint(); +} + + +/** + * Set the Image. The image will be resized on resizeEvent + * and it'll set the QPixmap background + * + * @param img The image will be stored internally and used as the background + */ +void OImageZoomer::setImage( const QImage& img) { + m_img = img; + resizeEvent( 0 ); + repaint(); +} + +/** + * overloaded function it calls the QImage version + */ +void OImageZoomer::setImage( const QPixmap& pix) { + setImage( pix.convertToImage() ); +} + +void OImageZoomer::resizeEvent( QResizeEvent* ev ) { + QFrame::resizeEvent( ev ); + setBackgroundOrigin( QWidget::WidgetOrigin ); + // TODO Qt3 use PalettePixmap and use size + QPixmap pix; pix.convertFromImage( m_img.smoothScale( size().width(), size().height() ) ); + setBackgroundPixmap( pix); +} + +void OImageZoomer::drawContents( QPainter* p ) { + /* + * if the page size + */ + if ( m_imgSize.isEmpty() ) + return; + + /* + * paint a red rect which represents the visible size + * + * We need to recalculate x,y and width and height of the + * rect. So image size relates to contentRect + * + */ + QRect c( contentsRect() ); + p->setPen( Qt::red ); + + /* + * the contentRect is set equal to the size of the image + * Rect/Original = NewRectORWidth/OriginalVisibleStuff and then simply we + * need to add the c.y/x due usage of QFrame + * For x and y we use the visiblePoint + * For height and width we use the size of the viewport + * if width/height would be bigger than our widget we use this width/height + * + */ + int len = m_imgSize.width(); + int x = (c.width()*m_visPt.x())/len + c.x(); + int w = (c.width()*m_visSize.width() )/len + c.x(); + if ( w > c.width() ) w = c.width(); + + len = m_imgSize.height(); + int y = (c.height()*m_visPt.y() )/len + c.y(); + int h = (c.height()*m_visSize.height() )/len + c.y(); + if ( h > c.height() ) h = c.height(); + + p->drawRect( x, y, w, h ); +} + +void OImageZoomer::mousePressEvent( QMouseEvent*ev) { + m_mouseX = m_mouseY = -1; + m_mevent = true; +} + +void OImageZoomer::mouseReleaseEvent( QMouseEvent*ev) { + if (!m_mevent) return; + int mx, my; + mx = ev->x(); + my = ev->y(); + int diffx = (mx) * m_imgSize.width() / width(); + int diffy = (my) * m_imgSize.height() / height(); + emit zoomArea(diffx,diffy); +} + +void OImageZoomer::mouseMoveEvent( QMouseEvent* ev ) { + int mx, my; + mx = ev->x(); + my = ev->y(); + + if ( m_mouseX != -1 && m_mouseY != -1 ) { + m_mevent = false; + int diffx = ( mx - m_mouseX ) * m_imgSize.width() / width(); + int diffy = ( my - m_mouseY ) * m_imgSize.height() / height(); + emit zoomAreaRel( diffx, diffy ); + } + m_mouseX = mx; + m_mouseY = my; +} + + +} +} diff --git a/libopie2/opiemm/oimagezoomer.h b/libopie2/opiemm/oimagezoomer.h new file mode 100644 index 0000000..0b356c9 --- a/dev/null +++ b/libopie2/opiemm/oimagezoomer.h @@ -0,0 +1,141 @@ +#ifndef OPIE_ODP_IMAGE_ZOOMER_H +#define OPIE_ODP_IMAGE_ZOOMER_H + +#include <qframe.h> +#include <qimage.h> + +class QPixmap; +class QRect; +class QPoint; + + +namespace Opie { +namespace MM { + +/** + * \brief small class to zoom over a Page + * + * This class represents your page but smaller. + * It can draw a Rect on top of an Image/Pixmap you supply + * and you can allow the user easily zooming/moving + * over your widget. + * All you need to do is to supply a image/pixmap, the visible size + * and the original image/pixmap size and the current visible top/left + * position. + * + * This Image works perfectly with QScrollView as you can connect + * QScrollView::contentsMoving to setVisiblePoint slot and the zoomAreRel + * to the QScrollView::scrollBy slot. Now you would only need to watch + * the resize event anf give us the new information about QScrollView::viewport + * + * You need to position and set the size of this widget! using setFixedSize() is quite + * a good idea for this widget + * + * @see QScrollView + * @see QScrollView::viewport() + * + * @since 1.2 + * + */ +class OImageZoomer : public QFrame { + Q_OBJECT +public: + OImageZoomer( QWidget* parent = 0, const char* name = 0, WFlags fl = 0 ); + OImageZoomer( const QPixmap&,QWidget* parent = 0, const char* name = 0, WFlags fl = 0 ); + OImageZoomer( const QImage&, QWidget* parent = 0, const char* name= 0, WFlags fl = 0 ); + OImageZoomer( const QSize&, const QSize&, QWidget* par, const char*, WFlags fl ); + ~OImageZoomer(); + +public slots: + void setImageSize( const QSize& ); + void setViewPortSize( const QSize& ); + void setVisiblePoint( const QPoint& ); + void setVisiblePoint( int x, int y ); + void setImage( const QImage& ); + void setImage( const QPixmap& ); + +signals: + /** + * Relative movement in the coordinates of the viewport + * This signal can easily be connected to QScrollView::scrollBy. + * This signal is emitted from within the mouseMoveEvent of this widget + * + * + * @param x The way to move relative on the X-Axis + * @param y The way to move relative on the Y-Axis + * + * @see setVisiblePoint + * @see QScrollView::scrollBy + */ + void zoomAreaRel( int x,int y); + + /** + * Here you get absolute coordinates. + * This slot will be emitted from within the mouseReleaseEvent of this widget. + * if no mouse move where done. + * So you may not delete this widget + * + * @param x The absolute X Coordinate to scroll to. + * @param y The absolute Y Coordinate to scroll to. + * + */ + void zoomArea( int x,int y); + +public: + /** + * make sure to call these if you reimplement + * @internal + */ + void resizeEvent( QResizeEvent* ); + +protected: + /** + * make sure to call these if you reimplement + * @internal + */ + void drawContents( QPainter* p ); + + /** + * make sure to call these if you reimplememt + * @internal + */ + virtual void mousePressEvent( QMouseEvent* ev ); + /** + * make sure to call these if you reimplement + * @internal + */ + virtual void mouseMoveEvent( QMouseEvent* ev ); + /** + * make sure to call these if you reimplement + * @internal + */ + virtual void mouseReleaseEvent( QMouseEvent* ev ); + +private: + /** + * @internal + */ + void init(); + QImage m_img; + QSize m_imgSize, m_visSize; + QPoint m_visPt; + int m_mouseX, m_mouseY; + bool m_mevent; +}; + +/** + * This slot is present for convience. You can connect the + * QScrollView::contentsMoved to this slot and it calls the QPoint + * version for you + * This realtes to QScrollView::contentsX() and QScrollView::contentsY() + * + * @param x The top left x coordinate + * @param y The top left y coorisnate + */ +inline void OImageZoomer::setVisiblePoint( int x, int y ) { + setVisiblePoint( QPoint( x, y ) ); +} + +} +} +#endif diff --git a/libopie2/opiemm/opiemm.pro b/libopie2/opiemm/opiemm.pro index f386618..09b5ed4 100644 --- a/libopie2/opiemm/opiemm.pro +++ b/libopie2/opiemm/opiemm.pro @@ -1,8 +1,8 @@ TEMPLATE = lib CONFIG += qt warn_on DESTDIR = $(OPIEDIR)/lib -HEADERS = osoundsystem.h -SOURCES = osoundsystem.cpp +HEADERS = osoundsystem.h oimagezoomer.h oimagescrollview.h +SOURCES = osoundsystem.cpp oimagezoomer.cpp oimagescrollview.cpp INTERFACES = TARGET = opiemm2 VERSION = 1.9.0 |