summaryrefslogtreecommitdiff
path: root/noncore/multimedia/showimg/showimg.cpp
Unidiff
Diffstat (limited to 'noncore/multimedia/showimg/showimg.cpp') (more/less context) (show 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 @@
1/**********************************************************************
2** Copyright (C) 2000 Trolltech AS. All rights reserved.
3**
4** This file is part of Qtopia Environment.
5**
6** This file may be distributed and/or modified under the terms of the
7** GNU General Public License version 2 as published by the Free Software
8** Foundation and appearing in the file LICENSE.GPL included in the
9** packaging of this file.
10**
11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13**
14** See http://www.trolltech.com/gpl/ for GPL licensing information.
15**
16** Contact info@trolltech.com if any conditions of this licensing are
17** not clear to you.
18**
19**********************************************************************/
20
21//
22// Full-screen and rotation options contributed by Robert Wittams <robert@wittams.com>
23//
24
25#include "showimg.h"
26
27#include <qpe/resource.h>
28#include <qpe/fileselector.h>
29#include <qpe/applnk.h>
30
31#include <qpe/qpemenubar.h>
32#include <qwidgetstack.h>
33#include <qpe/qpetoolbar.h>
34#include <qaction.h>
35#include <qfiledialog.h>
36#include <qmessagebox.h>
37#include <qpopupmenu.h>
38#include <qlabel.h>
39#include <qpainter.h>
40#include <qkeycode.h>
41#include <qapplication.h>
42#include <qclipboard.h>
43#include <qtimer.h>
44
45
46ImagePane::ImagePane( QWidget *parent=0 ) : QWidget( parent )
47{
48 vb = new QVBoxLayout( this );
49
50 image = new ImageWidget( this );
51 connect(image, SIGNAL( clicked() ), this, SLOT( imageClicked() ));
52
53 vb->addWidget( image );
54
55 status = new QLabel( this );
56 status->setFixedHeight( fontMetrics().height() + 4 );
57 vb->addWidget( status );
58}
59
60void ImagePane::setPixmap( const QPixmap &pm )
61{
62 image->setPixmap( pm );
63 image->repaint( false );
64}
65
66void ImagePane::imageClicked()
67{
68 emit clicked();
69}
70
71void ImagePane::showStatus()
72{
73 delete vb;
74 vb = new QVBoxLayout( this );
75 vb->addWidget( image );
76 status->show();
77 vb->addWidget( status );
78}
79
80
81void ImagePane::hideStatus()
82{
83 delete vb;
84 vb = new QVBoxLayout( this );
85 vb->addWidget( image );
86 status->hide();
87}
88
89//===========================================================================
90/*
91 Draws the portion of the scaled pixmap that needs to be updated
92*/
93
94void ImageWidget::paintEvent( QPaintEvent *e )
95{
96 QPainter painter(this);
97
98 painter.setClipRect(e->rect());
99 painter.setBrush( black );
100 painter.drawRect( 0, 0, width(), height() );
101
102 if ( pixmap.size() != QSize( 0, 0 ) ) { // is an image loaded?
103 painter.drawPixmap((width() - pixmap.width()) / 2, (height() - pixmap.height()) / 2, pixmap);
104 }
105}
106
107void ImageWidget::mouseReleaseEvent(QMouseEvent *)
108{
109 emit clicked();
110}
111
112
113//===========================================================================
114
115ImageViewer::ImageViewer( QWidget *parent, const char *name, int wFlags )
116 : QMainWindow( parent, name, wFlags ), filename( 0 ),
117 pickx( -1 ), picky( -1 ), clickx( -1 ), clicky( -1 ), bFromDocView( FALSE )
118{
119 setCaption( tr("Image Viewer") );
120 setIcon( Resource::loadPixmap( "ImageViewer" ) );
121
122 isFullScreen = FALSE;
123
124 setToolBarsMovable( FALSE );
125
126 toolBar = new QPEToolBar( this );
127 toolBar->setHorizontalStretchable( TRUE );
128
129 menubar = new QPEMenuBar( toolBar );
130
131 QStrList fmt = QImage::outputFormats();
132
133 QPopupMenu *edit = new QPopupMenu( menubar );
134 QPopupMenu *view = new QPopupMenu( menubar );
135
136 menubar->insertItem( "Edit", edit );
137 menubar->insertItem( "View", view );
138
139 edit->insertItem(tr("Horizontal flip"), this, SLOT(hFlip()), 0);
140 edit->insertItem(tr("Vertical flip"), this, SLOT(vFlip()), 0);
141
142 stack = new QWidgetStack( this );
143 stack->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) );
144 setCentralWidget( stack );
145
146 imagePanel = new ImagePane( stack );
147 connect(imagePanel, SIGNAL(clicked()), this, SLOT(normalView()));
148
149 fileSelector = new FileSelector("image/*", stack, "fs");
150 fileSelector->setNewVisible(FALSE);
151 fileSelector->setCloseVisible(FALSE);
152 connect( fileSelector, SIGNAL( closeMe() ), this, SLOT( closeFileSelector() ) );
153 connect( fileSelector, SIGNAL( fileSelected( const DocLnk &) ), this, SLOT( openFile( const DocLnk & ) ) );
154
155 toolBar = new QPEToolBar( this );
156
157 QAction *a;
158
159 a = new QAction( tr( "Open" ), Resource::loadPixmap( "fileopen" ), QString::null, 0, this, 0 );
160 connect( a, SIGNAL( activated() ), this, SLOT( open() ) );
161 a->addTo( toolBar );
162
163 a = new QAction( tr( "Rotate 180" ), Resource::loadPixmap( "repeat" ), QString::null, 0, this, 0 );
164 connect( a, SIGNAL( activated() ), this, SLOT( rot180() ) );
165 a->addTo( toolBar );
166 a->addTo( edit );
167
168 a = new QAction( tr( "Rotate 90"), Resource::loadPixmap( "rotate90" ), QString::null, 0, this, 0);
169 connect( a, SIGNAL( activated() ), this, SLOT( rot90() ) );
170 a->addTo( toolBar );
171 a->addTo( edit );
172
173 a = new QAction( tr( "Fullscreen" ), Resource::loadPixmap( "fullscreen" ), QString::null, 0, this, 0 );
174 connect( a, SIGNAL( activated() ), this, SLOT( fullScreen() ) );
175 a->addTo( toolBar );
176 a->addTo( view);
177
178 stack->raiseWidget( fileSelector );
179
180 setMouseTracking( TRUE );
181}
182
183ImageViewer::~ImageViewer()
184{
185 delete imagePanel; // in case it is fullscreen
186}
187
188void ImageViewer::setDocument(const QString& fileref)
189{
190 delayLoad = fileref;
191 stack->raiseWidget(imagePanel);
192 QTimer::singleShot( 0, this, SLOT(doDelayedLoad()) );
193}
194
195void ImageViewer::doDelayedLoad()
196{
197 show(delayLoad);
198}
199
200void ImageViewer::show()
201{
202 normalView();
203 QMainWindow::show();
204}
205
206void ImageViewer::show(const QString& fileref)
207{
208 bFromDocView = TRUE;
209 closeFileSelector();
210 DocLnk link(fileref);
211 if ( link.isValid() ) {
212 openFile(link);
213 } else {
214 filename = fileref;
215 updateCaption( fileref );
216 loadImage( fileref );
217 }
218}
219
220void ImageViewer::openFile( const DocLnk &file )
221{
222 closeFileSelector();
223 DocLnk link(file);
224 updateCaption( link.name() );
225 loadImage( link.file() );
226}
227
228void ImageViewer::open()
229{
230 stack->raiseWidget(fileSelector);
231}
232
233void ImageViewer::closeFileSelector()
234{
235 stack->raiseWidget(imagePanel);
236}
237
238void ImageViewer::updateCaption( QString name )
239{
240 int sep = name.findRev( '/' );
241 if ( sep >= 0 )
242 name = name.mid( sep+1 );
243 setCaption( name + tr(" - Image Viewer") );
244}
245
246/*
247 This function loads an image from a file.
248*/
249
250void ImageViewer::loadImage( const char *fileName )
251{
252 filename = fileName;
253 if ( filename ) {
254 QApplication::setOverrideCursor( waitCursor ); // this might take time
255 imagePanel->statusLabel()->setText( tr("Loading image...") );
256 qApp->processEvents();
257 bool ok = image.load(filename, 0);
258 pickx = -1;
259 clickx = -1;
260 if ( ok )
261 ok = reconvertImage();
262 if ( !ok ) {
263 pm.resize(0,0); // couldn't load image
264 update();
265 }
266 QApplication::restoreOverrideCursor();// restore original cursor
267 }
268 updateStatus();
269 imagePanel->setPixmap( pmScaled );
270 stack->raiseWidget(imagePanel);
271}
272
273bool ImageViewer::loadSelected()
274{
275 bool ok = false;
276 if ( stack->visibleWidget() == fileSelector ) {
277 const DocLnk *link = fileSelector->selected();
278 if ( link ) {
279 if ( link->file() != filename ) {
280 updateCaption( link->name() );
281 filename = link->file();
282 imagePanel->statusLabel()->setText( tr("Loading image...") );
283 qApp->processEvents();
284 ok = image.load(filename, 0);
285 if ( ok )
286 ok = reconvertImage();
287 if ( !ok )
288 pm.resize(0,0);
289 }
290 }
291 }
292 if ( !image.isNull() ) {
293 ok = true;
294 closeFileSelector();
295 }
296
297 return ok;
298}
299
300bool ImageViewer::reconvertImage()
301{
302 bool success = FALSE;
303
304 if ( image.isNull() ) return FALSE;
305
306 QApplication::setOverrideCursor( waitCursor ); // this might take time
307 if ( pm.convertFromImage(image /*, conversion_flags */ ) )
308 {
309 pmScaled = QPixmap();
310 scale();
311 success = TRUE; // load successful
312 } else {
313 pm.resize(0,0); // couldn't load image
314 }
315 QApplication::restoreOverrideCursor();// restore original cursor
316
317 return success; // TRUE if loaded OK
318}
319
320
321int ImageViewer::calcHeight()
322{
323 if ( !isFullScreen)
324 return height() - menubar->heightForWidth( width() )
325 - imagePanel->statusLabel()->height();
326 else
327 return qApp->desktop()->height();
328}
329/*
330 This functions scales the pixmap in the member variable "pm" to fit the
331 widget size and puts the resulting pixmap in the member variable "pmScaled".
332*/
333
334void ImageViewer::scale()
335{
336 int h = calcHeight();
337 if ( image.isNull() ) return;
338
339 QApplication::setOverrideCursor( waitCursor ); // this might take time
340 if ( width() == pm.width() && h == pm.height() ) { // no need to scale if widget
341 pmScaled = pm; // size equals pixmap size
342 } else {
343 double hs = (double)h / (double)image.height();
344 double ws = (double)width() / (double)image.width();
345 double scaleFactor = (hs > ws) ? ws : hs;
346 int smoothW = (int)(scaleFactor * image.width());
347 int smoothH = (int)(scaleFactor * image.height());
348
349 pmScaled.convertFromImage( image.smoothScale( smoothW, smoothH ) /*, conversion_flags */ );
350 }
351 QApplication::restoreOverrideCursor();// restore original cursor
352}
353
354/*
355 The resize event handler, if a valid pixmap was loaded it will call
356 scale() to fit the pixmap to the new widget size.
357*/
358
359void ImageViewer::resizeEvent( QResizeEvent * )
360{
361 imagePanel->statusLabel()->setGeometry(0, height() - imagePanel->statusLabel()->height(),
362 width(), imagePanel->statusLabel()->height());
363
364 if ( pm.size() == QSize( 0, 0 ) ) // we couldn't load the image
365 return;
366
367 int h = calcHeight();
368
369 if ( width() != pmScaled.width() || h != pmScaled.height())
370 { // if new size,
371 scale(); // scale pmScaled to window
372 updateStatus();
373 }
374 if ( image.hasAlphaBuffer() )
375 erase();
376}
377
378void ImageViewer::convertEvent( QMouseEvent* e, int& x, int& y)
379{
380 if ( pm.size() != QSize( 0, 0 ) ) {
381 int h = height() - menubar->heightForWidth( width() ) - imagePanel->statusLabel()->height();
382 int nx = e->x() * image.width() / width();
383 int ny = (e->y()-menubar->heightForWidth( width() )) * image.height() / h;
384 if (nx != x || ny != y ) {
385 x = nx;
386 y = ny;
387 updateStatus();
388 }
389 }
390}
391
392void ImageViewer::mousePressEvent( QMouseEvent *e )
393{
394 convertEvent(e, clickx, clicky);
395}
396
397void ImageViewer::mouseMoveEvent( QMouseEvent *e )
398{
399 convertEvent( e, pickx, picky );
400}
401
402void ImageViewer::hFlip()
403{
404 if ( loadSelected() )
405 setImage(image.mirror(TRUE,FALSE));
406}
407
408void ImageViewer::vFlip()
409{
410 if ( loadSelected() )
411 setImage(image.mirror(FALSE,TRUE));
412}
413
414void ImageViewer::rot180()
415{
416 if ( loadSelected() )
417 setImage(image.mirror(TRUE,TRUE));
418}
419
420void ImageViewer::rot90()
421{
422 if ( loadSelected() ) {
423 QImage oldimage, newimage;
424 uchar *oldbits, *newbits;
425 int i, j, p;
426 int w, h;
427
428 oldimage = image.convertDepth(32);
429 w = oldimage.height();
430 h = oldimage.width();
431 newimage = QImage( w, h, 32);
432
433 oldbits = oldimage.bits();
434 newbits = newimage.bits();
435
436 for (i=0; i < w ; i++)
437 for (j=0; j < h; j++)
438 for (p = 0 ; p < 4 ; p++)
439 newbits[(j * w + i) * 4 + p] = oldbits[ ((i + 1) * h - j ) * 4 + p];
440
441 setImage(newimage);
442 }
443}
444
445
446
447void ImageViewer::normalView()
448{
449 if ( !imagePanel->parentWidget() ) {
450 isFullScreen = FALSE;
451 stack->addWidget( imagePanel, 1 );
452 //imagePanel->reparent(stack,0,QPoint(0,0),FALSE);
453 //imagePanel->resize(width(), calcHeight());
454 scale();
455 updateStatus();
456 imagePanel->setPixmap( pmScaled );
457 imagePanel->showStatus();
458 //imagePanel->show();
459 stack->raiseWidget( imagePanel );
460 }
461}
462
463void ImageViewer::fullScreen()
464{
465 // Full-screen and rotation options
466 // contributed by Robert Wittams <robert@wittams.com>
467
468 if ( imagePanel->parentWidget() && loadSelected() ) {
469 isFullScreen = TRUE;
470 imagePanel->reparent(0,QPoint(0,0));
471 imagePanel->resize(qApp->desktop()->width(), qApp->desktop()->height());
472
473 scale();
474 updateStatus();
475 imagePanel->hideStatus();
476 imagePanel->setPixmap( pmScaled );
477 imagePanel->showFullScreen();
478 }
479}
480
481void ImageViewer::setImage(const QImage& newimage)
482{
483 image = newimage;
484 pickx = -1;
485 clickx = -1;
486 reconvertImage();
487 imagePanel->setPixmap( pmScaled );
488 updateStatus();
489}
490
491void ImageViewer::updateStatus()
492{
493 if ( pm.size() == QSize( 0, 0 ) ) {
494 if ( filename )
495 imagePanel->statusLabel()->setText( tr("Could not load image") );
496 else
497 imagePanel->statusLabel()->setText( tr("No image - select Open from File menu.") );
498 } else {
499 QString message("%1x%2");
500 message = message.arg(image.width()).arg(image.height());
501 if ( pm.size() != pmScaled.size() )
502 message += QString(" [%1x%2]").arg(pmScaled.width()).arg(pmScaled.height());
503 if (image.valid(pickx,picky)) {
504 QString moremsg;
505 moremsg.sprintf("(%d,%d)=#%0*x ",
506 pickx, picky,
507 image.hasAlphaBuffer() ? 8 : 6,
508 image.pixel(pickx,picky));
509 message += moremsg;
510 }
511 if ( image.numColors() > 0 ) {
512 if (image.valid(pickx,picky)) {
513 message += tr(", %1/%2 colors")
514 .arg(image.pixelIndex(pickx,picky))
515 .arg(image.numColors());
516 } else {
517 message += tr(", %1 colors").arg(image.numColors());
518 }
519 } else if ( image.depth() >= 16 ) {
520 message += tr(" True color");
521 }
522 if ( image.hasAlphaBuffer() ) {
523 if ( image.depth() == 8 ) {
524 int i;
525 bool alpha[256];
526 int nalpha=0;
527
528 for (i=0; i<256; i++)
529 alpha[i] = FALSE;
530
531 for (i=0; i<image.numColors(); i++) {
532 int alevel = image.color(i) >> 24;
533 if (!alpha[alevel]) {
534 alpha[alevel] = TRUE;
535 nalpha++;
536 }
537 }
538 message += tr(", %1 alpha levels").arg(nalpha);
539 } else {
540 // Too many pixels to bother counting.
541 message += tr(", 8-bit alpha channel");
542 }
543 }
544 imagePanel->statusLabel()->setText(message);
545 }
546}
547
548void ImageViewer::closeEvent( QCloseEvent *e )
549{
550 if ( stack->visibleWidget() == imagePanel && !bFromDocView ) {
551 e->ignore();
552 open();
553 } else {
554 bFromDocView = FALSE;
555 e->accept();
556 }
557}