summaryrefslogtreecommitdiff
Side-by-side diff
Diffstat (more/less context) (show whitespace changes)
-rw-r--r--libopie2/opiemm/oimagescrollview.cpp585
-rw-r--r--libopie2/opiemm/oimagescrollview.h95
-rw-r--r--libopie2/opiemm/oimagezoomer.cpp233
-rw-r--r--libopie2/opiemm/oimagezoomer.h141
-rw-r--r--libopie2/opiemm/opiemm.pro4
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