summaryrefslogtreecommitdiff
path: root/noncore/multimedia/showimg/showimg.cpp
Side-by-side diff
Diffstat (limited to 'noncore/multimedia/showimg/showimg.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--noncore/multimedia/showimg/showimg.cpp557
1 files changed, 557 insertions, 0 deletions
diff --git a/noncore/multimedia/showimg/showimg.cpp b/noncore/multimedia/showimg/showimg.cpp
new file mode 100644
index 0000000..c56994d
--- a/dev/null
+++ b/noncore/multimedia/showimg/showimg.cpp
@@ -0,0 +1,557 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qtopia Environment.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+
+//
+// Full-screen and rotation options contributed by Robert Wittams <robert@wittams.com>
+//
+
+#include "showimg.h"
+
+#include <qpe/resource.h>
+#include <qpe/fileselector.h>
+#include <qpe/applnk.h>
+
+#include <qpe/qpemenubar.h>
+#include <qwidgetstack.h>
+#include <qpe/qpetoolbar.h>
+#include <qaction.h>
+#include <qfiledialog.h>
+#include <qmessagebox.h>
+#include <qpopupmenu.h>
+#include <qlabel.h>
+#include <qpainter.h>
+#include <qkeycode.h>
+#include <qapplication.h>
+#include <qclipboard.h>
+#include <qtimer.h>
+
+
+ImagePane::ImagePane( QWidget *parent=0 ) : QWidget( parent )
+{
+ vb = new QVBoxLayout( this );
+
+ image = new ImageWidget( this );
+ connect(image, SIGNAL( clicked() ), this, SLOT( imageClicked() ));
+
+ vb->addWidget( image );
+
+ status = new QLabel( this );
+ status->setFixedHeight( fontMetrics().height() + 4 );
+ vb->addWidget( status );
+}
+
+void ImagePane::setPixmap( const QPixmap &pm )
+{
+ image->setPixmap( pm );
+ image->repaint( false );
+}
+
+void ImagePane::imageClicked()
+{
+ emit clicked();
+}
+
+void ImagePane::showStatus()
+{
+ delete vb;
+ vb = new QVBoxLayout( this );
+ vb->addWidget( image );
+ status->show();
+ vb->addWidget( status );
+}
+
+
+void ImagePane::hideStatus()
+{
+ delete vb;
+ vb = new QVBoxLayout( this );
+ vb->addWidget( image );
+ status->hide();
+}
+
+//===========================================================================
+/*
+ Draws the portion of the scaled pixmap that needs to be updated
+*/
+
+void ImageWidget::paintEvent( QPaintEvent *e )
+{
+ QPainter painter(this);
+
+ painter.setClipRect(e->rect());
+ painter.setBrush( black );
+ painter.drawRect( 0, 0, width(), height() );
+
+ if ( pixmap.size() != QSize( 0, 0 ) ) { // is an image loaded?
+ painter.drawPixmap((width() - pixmap.width()) / 2, (height() - pixmap.height()) / 2, pixmap);
+ }
+}
+
+void ImageWidget::mouseReleaseEvent(QMouseEvent *)
+{
+ emit clicked();
+}
+
+
+//===========================================================================
+
+ImageViewer::ImageViewer( QWidget *parent, const char *name, int wFlags )
+ : QMainWindow( parent, name, wFlags ), filename( 0 ),
+ pickx( -1 ), picky( -1 ), clickx( -1 ), clicky( -1 ), bFromDocView( FALSE )
+{
+ setCaption( tr("Image Viewer") );
+ setIcon( Resource::loadPixmap( "ImageViewer" ) );
+
+ isFullScreen = FALSE;
+
+ setToolBarsMovable( FALSE );
+
+ toolBar = new QPEToolBar( this );
+ toolBar->setHorizontalStretchable( TRUE );
+
+ menubar = new QPEMenuBar( toolBar );
+
+ QStrList fmt = QImage::outputFormats();
+
+ QPopupMenu *edit = new QPopupMenu( menubar );
+ QPopupMenu *view = new QPopupMenu( menubar );
+
+ menubar->insertItem( "Edit", edit );
+ menubar->insertItem( "View", view );
+
+ edit->insertItem(tr("Horizontal flip"), this, SLOT(hFlip()), 0);
+ edit->insertItem(tr("Vertical flip"), this, SLOT(vFlip()), 0);
+
+ stack = new QWidgetStack( this );
+ stack->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) );
+ setCentralWidget( stack );
+
+ imagePanel = new ImagePane( stack );
+ connect(imagePanel, SIGNAL(clicked()), this, SLOT(normalView()));
+
+ fileSelector = new FileSelector("image/*", stack, "fs");
+ fileSelector->setNewVisible(FALSE);
+ fileSelector->setCloseVisible(FALSE);
+ connect( fileSelector, SIGNAL( closeMe() ), this, SLOT( closeFileSelector() ) );
+ connect( fileSelector, SIGNAL( fileSelected( const DocLnk &) ), this, SLOT( openFile( const DocLnk & ) ) );
+
+ toolBar = new QPEToolBar( this );
+
+ QAction *a;
+
+ a = new QAction( tr( "Open" ), Resource::loadPixmap( "fileopen" ), QString::null, 0, this, 0 );
+ connect( a, SIGNAL( activated() ), this, SLOT( open() ) );
+ a->addTo( toolBar );
+
+ a = new QAction( tr( "Rotate 180" ), Resource::loadPixmap( "repeat" ), QString::null, 0, this, 0 );
+ connect( a, SIGNAL( activated() ), this, SLOT( rot180() ) );
+ a->addTo( toolBar );
+ a->addTo( edit );
+
+ a = new QAction( tr( "Rotate 90"), Resource::loadPixmap( "rotate90" ), QString::null, 0, this, 0);
+ connect( a, SIGNAL( activated() ), this, SLOT( rot90() ) );
+ a->addTo( toolBar );
+ a->addTo( edit );
+
+ a = new QAction( tr( "Fullscreen" ), Resource::loadPixmap( "fullscreen" ), QString::null, 0, this, 0 );
+ connect( a, SIGNAL( activated() ), this, SLOT( fullScreen() ) );
+ a->addTo( toolBar );
+ a->addTo( view);
+
+ stack->raiseWidget( fileSelector );
+
+ setMouseTracking( TRUE );
+}
+
+ImageViewer::~ImageViewer()
+{
+ delete imagePanel; // in case it is fullscreen
+}
+
+void ImageViewer::setDocument(const QString& fileref)
+{
+ delayLoad = fileref;
+ stack->raiseWidget(imagePanel);
+ QTimer::singleShot( 0, this, SLOT(doDelayedLoad()) );
+}
+
+void ImageViewer::doDelayedLoad()
+{
+ show(delayLoad);
+}
+
+void ImageViewer::show()
+{
+ normalView();
+ QMainWindow::show();
+}
+
+void ImageViewer::show(const QString& fileref)
+{
+ bFromDocView = TRUE;
+ closeFileSelector();
+ DocLnk link(fileref);
+ if ( link.isValid() ) {
+ openFile(link);
+ } else {
+ filename = fileref;
+ updateCaption( fileref );
+ loadImage( fileref );
+ }
+}
+
+void ImageViewer::openFile( const DocLnk &file )
+{
+ closeFileSelector();
+ DocLnk link(file);
+ updateCaption( link.name() );
+ loadImage( link.file() );
+}
+
+void ImageViewer::open()
+{
+ stack->raiseWidget(fileSelector);
+}
+
+void ImageViewer::closeFileSelector()
+{
+ stack->raiseWidget(imagePanel);
+}
+
+void ImageViewer::updateCaption( QString name )
+{
+ int sep = name.findRev( '/' );
+ if ( sep >= 0 )
+ name = name.mid( sep+1 );
+ setCaption( name + tr(" - Image Viewer") );
+}
+
+/*
+ This function loads an image from a file.
+*/
+
+void ImageViewer::loadImage( const char *fileName )
+{
+ filename = fileName;
+ if ( filename ) {
+ QApplication::setOverrideCursor( waitCursor ); // this might take time
+ imagePanel->statusLabel()->setText( tr("Loading image...") );
+ qApp->processEvents();
+ bool ok = image.load(filename, 0);
+ pickx = -1;
+ clickx = -1;
+ if ( ok )
+ ok = reconvertImage();
+ if ( !ok ) {
+ pm.resize(0,0); // couldn't load image
+ update();
+ }
+ QApplication::restoreOverrideCursor(); // restore original cursor
+ }
+ updateStatus();
+ imagePanel->setPixmap( pmScaled );
+ stack->raiseWidget(imagePanel);
+}
+
+bool ImageViewer::loadSelected()
+{
+ bool ok = false;
+ if ( stack->visibleWidget() == fileSelector ) {
+ const DocLnk *link = fileSelector->selected();
+ if ( link ) {
+ if ( link->file() != filename ) {
+ updateCaption( link->name() );
+ filename = link->file();
+ imagePanel->statusLabel()->setText( tr("Loading image...") );
+ qApp->processEvents();
+ ok = image.load(filename, 0);
+ if ( ok )
+ ok = reconvertImage();
+ if ( !ok )
+ pm.resize(0,0);
+ }
+ }
+ }
+ if ( !image.isNull() ) {
+ ok = true;
+ closeFileSelector();
+ }
+
+ return ok;
+}
+
+bool ImageViewer::reconvertImage()
+{
+ bool success = FALSE;
+
+ if ( image.isNull() ) return FALSE;
+
+ QApplication::setOverrideCursor( waitCursor ); // this might take time
+ if ( pm.convertFromImage(image /*, conversion_flags */ ) )
+ {
+ pmScaled = QPixmap();
+ scale();
+ success = TRUE; // load successful
+ } else {
+ pm.resize(0,0); // couldn't load image
+ }
+ QApplication::restoreOverrideCursor(); // restore original cursor
+
+ return success; // TRUE if loaded OK
+}
+
+
+int ImageViewer::calcHeight()
+{
+ if ( !isFullScreen)
+ return height() - menubar->heightForWidth( width() )
+ - imagePanel->statusLabel()->height();
+ else
+ return qApp->desktop()->height();
+}
+/*
+ This functions scales the pixmap in the member variable "pm" to fit the
+ widget size and puts the resulting pixmap in the member variable "pmScaled".
+*/
+
+void ImageViewer::scale()
+{
+ int h = calcHeight();
+ if ( image.isNull() ) return;
+
+ QApplication::setOverrideCursor( waitCursor ); // this might take time
+ if ( width() == pm.width() && h == pm.height() ) { // no need to scale if widget
+ pmScaled = pm; // size equals pixmap size
+ } else {
+ double hs = (double)h / (double)image.height();
+ double ws = (double)width() / (double)image.width();
+ double scaleFactor = (hs > ws) ? ws : hs;
+ int smoothW = (int)(scaleFactor * image.width());
+ int smoothH = (int)(scaleFactor * image.height());
+
+ pmScaled.convertFromImage( image.smoothScale( smoothW, smoothH ) /*, conversion_flags */ );
+ }
+ QApplication::restoreOverrideCursor(); // restore original cursor
+}
+
+/*
+ The resize event handler, if a valid pixmap was loaded it will call
+ scale() to fit the pixmap to the new widget size.
+*/
+
+void ImageViewer::resizeEvent( QResizeEvent * )
+{
+ imagePanel->statusLabel()->setGeometry(0, height() - imagePanel->statusLabel()->height(),
+ width(), imagePanel->statusLabel()->height());
+
+ if ( pm.size() == QSize( 0, 0 ) ) // we couldn't load the image
+ return;
+
+ int h = calcHeight();
+
+ if ( width() != pmScaled.width() || h != pmScaled.height())
+ { // if new size,
+ scale(); // scale pmScaled to window
+ updateStatus();
+ }
+ if ( image.hasAlphaBuffer() )
+ erase();
+}
+
+void ImageViewer::convertEvent( QMouseEvent* e, int& x, int& y)
+{
+ if ( pm.size() != QSize( 0, 0 ) ) {
+ int h = height() - menubar->heightForWidth( width() ) - imagePanel->statusLabel()->height();
+ int nx = e->x() * image.width() / width();
+ int ny = (e->y()-menubar->heightForWidth( width() )) * image.height() / h;
+ if (nx != x || ny != y ) {
+ x = nx;
+ y = ny;
+ updateStatus();
+ }
+ }
+}
+
+void ImageViewer::mousePressEvent( QMouseEvent *e )
+{
+ convertEvent(e, clickx, clicky);
+}
+
+void ImageViewer::mouseMoveEvent( QMouseEvent *e )
+{
+ convertEvent( e, pickx, picky );
+}
+
+void ImageViewer::hFlip()
+{
+ if ( loadSelected() )
+ setImage(image.mirror(TRUE,FALSE));
+}
+
+void ImageViewer::vFlip()
+{
+ if ( loadSelected() )
+ setImage(image.mirror(FALSE,TRUE));
+}
+
+void ImageViewer::rot180()
+{
+ if ( loadSelected() )
+ setImage(image.mirror(TRUE,TRUE));
+}
+
+void ImageViewer::rot90()
+{
+ if ( loadSelected() ) {
+ QImage oldimage, newimage;
+ uchar *oldbits, *newbits;
+ int i, j, p;
+ int w, h;
+
+ oldimage = image.convertDepth(32);
+ w = oldimage.height();
+ h = oldimage.width();
+ newimage = QImage( w, h, 32);
+
+ oldbits = oldimage.bits();
+ newbits = newimage.bits();
+
+ for (i=0; i < w ; i++)
+ for (j=0; j < h; j++)
+ for (p = 0 ; p < 4 ; p++)
+ newbits[(j * w + i) * 4 + p] = oldbits[ ((i + 1) * h - j ) * 4 + p];
+
+ setImage(newimage);
+ }
+}
+
+
+
+void ImageViewer::normalView()
+{
+ if ( !imagePanel->parentWidget() ) {
+ isFullScreen = FALSE;
+ stack->addWidget( imagePanel, 1 );
+// imagePanel->reparent(stack,0,QPoint(0,0),FALSE);
+// imagePanel->resize(width(), calcHeight());
+ scale();
+ updateStatus();
+ imagePanel->setPixmap( pmScaled );
+ imagePanel->showStatus();
+ // imagePanel->show();
+ stack->raiseWidget( imagePanel );
+ }
+}
+
+void ImageViewer::fullScreen()
+{
+ // Full-screen and rotation options
+ // contributed by Robert Wittams <robert@wittams.com>
+
+ if ( imagePanel->parentWidget() && loadSelected() ) {
+ isFullScreen = TRUE;
+ imagePanel->reparent(0,QPoint(0,0));
+ imagePanel->resize(qApp->desktop()->width(), qApp->desktop()->height());
+
+ scale();
+ updateStatus();
+ imagePanel->hideStatus();
+ imagePanel->setPixmap( pmScaled );
+ imagePanel->showFullScreen();
+ }
+}
+
+void ImageViewer::setImage(const QImage& newimage)
+{
+ image = newimage;
+ pickx = -1;
+ clickx = -1;
+ reconvertImage();
+ imagePanel->setPixmap( pmScaled );
+ updateStatus();
+}
+
+void ImageViewer::updateStatus()
+{
+ if ( pm.size() == QSize( 0, 0 ) ) {
+ if ( filename )
+ imagePanel->statusLabel()->setText( tr("Could not load image") );
+ else
+ imagePanel->statusLabel()->setText( tr("No image - select Open from File menu.") );
+ } else {
+ QString message("%1x%2");
+ message = message.arg(image.width()).arg(image.height());
+ if ( pm.size() != pmScaled.size() )
+ message += QString(" [%1x%2]").arg(pmScaled.width()).arg(pmScaled.height());
+ if (image.valid(pickx,picky)) {
+ QString moremsg;
+ moremsg.sprintf("(%d,%d)=#%0*x ",
+ pickx, picky,
+ image.hasAlphaBuffer() ? 8 : 6,
+ image.pixel(pickx,picky));
+ message += moremsg;
+ }
+ if ( image.numColors() > 0 ) {
+ if (image.valid(pickx,picky)) {
+ message += tr(", %1/%2 colors")
+ .arg(image.pixelIndex(pickx,picky))
+ .arg(image.numColors());
+ } else {
+ message += tr(", %1 colors").arg(image.numColors());
+ }
+ } else if ( image.depth() >= 16 ) {
+ message += tr(" True color");
+ }
+ if ( image.hasAlphaBuffer() ) {
+ if ( image.depth() == 8 ) {
+ int i;
+ bool alpha[256];
+ int nalpha=0;
+
+ for (i=0; i<256; i++)
+ alpha[i] = FALSE;
+
+ for (i=0; i<image.numColors(); i++) {
+ int alevel = image.color(i) >> 24;
+ if (!alpha[alevel]) {
+ alpha[alevel] = TRUE;
+ nalpha++;
+ }
+ }
+ message += tr(", %1 alpha levels").arg(nalpha);
+ } else {
+ // Too many pixels to bother counting.
+ message += tr(", 8-bit alpha channel");
+ }
+ }
+ imagePanel->statusLabel()->setText(message);
+ }
+}
+
+void ImageViewer::closeEvent( QCloseEvent *e )
+{
+ if ( stack->visibleWidget() == imagePanel && !bFromDocView ) {
+ e->ignore();
+ open();
+ } else {
+ bFromDocView = FALSE;
+ e->accept();
+ }
+}