You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1116 lines
27 KiB
1116 lines
27 KiB
/* This file is part of the KDE Project
|
|
Copyright (C) 1999 Klaas Freitag <freitag@suse.de>
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Library General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Library General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
along with this library; see the file COPYING.LIB. If not, write to
|
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include <tqapplication.h>
|
|
#include <tqfiledialog.h>
|
|
#include <tqstring.h>
|
|
#include <tqmessagebox.h>
|
|
#include <tqscrollview.h>
|
|
#include <tdepopupmenu.h>
|
|
#include <tqlabel.h>
|
|
#include <tqdict.h>
|
|
#include <tqimage.h>
|
|
#include <tqpainter.h>
|
|
|
|
#include <tdelocale.h>
|
|
#include <tdestyle.h>
|
|
#include <tdeapplication.h>
|
|
|
|
#include <kpixmapio.h>
|
|
#include <kdebug.h>
|
|
#include <kiconloader.h>
|
|
#include <kcmenumngr.h>
|
|
#include <tqpixmap.h>
|
|
|
|
#define __IMG_CANVAS_CPP__
|
|
|
|
#include "imgscaledialog.h"
|
|
#include "img_canvas.h"
|
|
|
|
|
|
|
|
#define MIN(x,y) (x<y?x:y)
|
|
|
|
|
|
inline void debug_rect( const char *name, TQRect *r )
|
|
{
|
|
kdDebug(29000) << (name ? name: "NONAME") << ": " << r->x() << ", " << r->y() << ", " << r->width() << ", " << r->height() << endl;
|
|
}
|
|
|
|
|
|
class ImageCanvas::ImageCanvasPrivate
|
|
{
|
|
public:
|
|
ImageCanvasPrivate()
|
|
: keepZoom(false),
|
|
readOnly(false),
|
|
scaleKind( UNSPEC ),
|
|
defaultScaleKind( FIT_ORIG )
|
|
{}
|
|
|
|
bool keepZoom; /* keep the zoom settings if images change */
|
|
bool readOnly;
|
|
ScaleKinds scaleKind;
|
|
ScaleKinds defaultScaleKind;
|
|
|
|
TQValueList<TQRect> highlightRects;
|
|
};
|
|
|
|
ImageCanvas::ImageCanvas(TQWidget *parent,
|
|
const TQImage *start_image,
|
|
const char *name ):
|
|
TQScrollView( parent, name ),
|
|
m_contextMenu(0)
|
|
{
|
|
d = new ImageCanvasPrivate();
|
|
|
|
scale_factor = 100; // means original size
|
|
maintain_aspect = true;
|
|
selected = new TQRect;
|
|
selected->setWidth(0);
|
|
selected->setHeight(0);
|
|
|
|
timer_id = 0;
|
|
pmScaled = 0;
|
|
|
|
image = start_image;
|
|
moving = MOVE_NONE;
|
|
|
|
TQSize img_size;
|
|
|
|
if( image && ! image->isNull() )
|
|
{
|
|
img_size = image->size();
|
|
pmScaled = new TQPixmap( img_size );
|
|
|
|
#ifdef USE_KPIXMAPIO
|
|
*pmScaled = pixIO.convertToPixmap(*image);
|
|
#else
|
|
pmScaled->convertFromImage( *image );
|
|
#endif
|
|
|
|
acquired = true;
|
|
} else {
|
|
img_size = size();
|
|
}
|
|
|
|
|
|
update_scaled_pixmap();
|
|
|
|
// timer-Start and stop
|
|
connect( this, TQ_SIGNAL( newRect()), TQ_SLOT( newRectSlot()));
|
|
connect( this, TQ_SIGNAL( noRect()), TQ_SLOT( noRectSlot()));
|
|
|
|
//zoomOut();scrollview/scrollview
|
|
viewport()->setCursor( crossCursor );
|
|
cr1 = 0;
|
|
cr2 = 0;
|
|
viewport()->setMouseTracking(TRUE);
|
|
viewport()->setBackgroundMode(PaletteBackground);
|
|
show();
|
|
|
|
}
|
|
|
|
ImageCanvas::~ImageCanvas()
|
|
{
|
|
kdDebug(29000) << "Destructor of ImageCanvas" << endl;
|
|
noRectSlot();
|
|
if( selected ) delete selected;
|
|
selected = 0;
|
|
if( pmScaled ) delete pmScaled;
|
|
pmScaled = 0;
|
|
delete d;
|
|
}
|
|
|
|
void ImageCanvas::deleteView( TQImage *delimage )
|
|
{
|
|
const TQImage *img = rootImage();
|
|
|
|
if( delimage == img )
|
|
{
|
|
kdDebug(29000) << "ImageCanvas -> emiting newImage(0L)" << endl;
|
|
newImage( 0L );
|
|
noRectSlot();
|
|
}
|
|
|
|
}
|
|
|
|
void ImageCanvas::newImageHoldZoom( TQImage *new_image )
|
|
{
|
|
bool holdZ = d->keepZoom;
|
|
|
|
d->keepZoom = true;
|
|
newImage( new_image );
|
|
d->keepZoom = holdZ;
|
|
}
|
|
|
|
void ImageCanvas::newImage( TQImage *new_image )
|
|
{
|
|
|
|
/** do cleanups **/
|
|
// dont free old image -> not yours
|
|
image = new_image;
|
|
|
|
if( ! image || image->isNull())
|
|
{
|
|
kdDebug(29000) << "newImage: Got Empty image !" << endl;
|
|
}
|
|
|
|
if( pmScaled )
|
|
{
|
|
delete pmScaled;
|
|
pmScaled = 0L;
|
|
}
|
|
|
|
if( selected )
|
|
{
|
|
noRectSlot();
|
|
}
|
|
|
|
/* throw away all highlights */
|
|
d->highlightRects.clear();
|
|
|
|
/** handle the new image **/
|
|
if( image )
|
|
{
|
|
if( image->depth() == 1 ) {
|
|
pmScaled = new TQPixmap( image->size(), 1 );
|
|
} else {
|
|
int i = TQPixmap::defaultDepth();
|
|
pmScaled = new TQPixmap( image->size(), i);
|
|
}
|
|
|
|
// image->convertDepth(32);
|
|
#ifdef USE_KPIXMAPIO
|
|
|
|
*pmScaled = pixIO.convertToPixmap(*image);
|
|
#else
|
|
pmScaled->convertFromImage( *image );
|
|
// *pmScaled = image->convertToPixmap( );
|
|
#endif
|
|
|
|
acquired = true;
|
|
|
|
if( d->keepZoom )
|
|
{
|
|
kdDebug(29000) << "Preserving Zoom settings!" << endl;
|
|
}
|
|
else
|
|
{
|
|
kdDebug(29000) << "Resetting Zoom to original size!" << endl;
|
|
setScaleKind( defaultScaleKind() );
|
|
}
|
|
|
|
update_scaled_pixmap();
|
|
setContentsPos(0,0);
|
|
} else {
|
|
kdDebug(29000) << "New image called without image => deleting!" << endl;
|
|
acquired = false;
|
|
resizeContents( 0,0 );
|
|
}
|
|
|
|
|
|
kdDebug(29000) << "going to repaint!" << endl;
|
|
repaint( true );
|
|
kdDebug(29000) << "repaint ok" << endl;
|
|
}
|
|
|
|
TQSize ImageCanvas::sizeHint() const
|
|
{
|
|
return( TQSize( 2, 2 ));
|
|
}
|
|
|
|
void ImageCanvas::enableContextMenu( bool wantContextMenu )
|
|
{
|
|
if( wantContextMenu )
|
|
{
|
|
if( ! m_contextMenu )
|
|
{
|
|
m_contextMenu = new TDEPopupMenu(this, "IMG_CANVAS");
|
|
|
|
KContextMenuManager::insert( viewport(), m_contextMenu );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* remove all items */
|
|
if( m_contextMenu ) m_contextMenu->clear();
|
|
/* contextMenu is not deleted because there is no way to remove
|
|
* it from the contextMenuManager
|
|
*/
|
|
}
|
|
|
|
}
|
|
|
|
void ImageCanvas::handle_popup( int item )
|
|
{
|
|
if( item < ID_POP_ZOOM || item > ID_ORIG_SIZE ) return;
|
|
|
|
if( ! image ) return;
|
|
ImgScaleDialog *zoomDia = 0;
|
|
|
|
switch( item )
|
|
{
|
|
case ID_POP_ZOOM:
|
|
|
|
zoomDia = new ImgScaleDialog( this, getScaleFactor() );
|
|
if( zoomDia->exec() )
|
|
{
|
|
int sf = zoomDia->getSelected();
|
|
setScaleKind(ZOOM);
|
|
setScaleFactor( sf );
|
|
}
|
|
delete zoomDia;
|
|
zoomDia = 0;
|
|
break;
|
|
case ID_ORIG_SIZE:
|
|
setScaleKind( FIT_ORIG );
|
|
break;
|
|
case ID_FIT_WIDTH:
|
|
setScaleKind( FIT_WIDTH );
|
|
break;
|
|
case ID_FIT_HEIGHT:
|
|
setScaleKind( FIT_HEIGHT );
|
|
break;
|
|
case ID_POP_CLOSE:
|
|
emit( closingRequested());
|
|
break;
|
|
|
|
default: break;
|
|
}
|
|
update_scaled_pixmap();
|
|
repaint();
|
|
}
|
|
|
|
|
|
/**
|
|
* Returns the selected rect in tenth of percent, not in absolute
|
|
* sizes, eg. 500 means 50.0 % of original width/height.
|
|
* That makes it easier to work with different scales and units
|
|
*/
|
|
TQRect ImageCanvas::sel( void )
|
|
{
|
|
TQRect retval;
|
|
retval.setCoords(0, 0, 0, 0);
|
|
|
|
if( selected && image && selected->width()>MIN_AREA_WIDTH
|
|
&& selected->height()>MIN_AREA_HEIGHT )
|
|
{
|
|
/* Get the size in real image pixels */
|
|
|
|
// debug_rect( "PRE map", selected );
|
|
TQRect mapped = inv_scale_matrix.map( (const TQRect) *selected );
|
|
// debug_rect( "Postmap", &mapped );
|
|
if( mapped.x() > 0 )
|
|
retval.setLeft((int) (1000.0/( (double)image->width() / (double)mapped.x())));
|
|
|
|
if( mapped.y() > 0 )
|
|
retval.setTop((int) (1000.0/( (double)image->height() / (double)mapped.y())));
|
|
|
|
if( mapped.width() > 0 )
|
|
retval.setWidth((int) (1000.0/( (double)image->width() / (double)mapped.width())));
|
|
|
|
if( mapped.height() > 0 )
|
|
retval.setHeight((int)(1000.0/( (double)image->height() / (double)mapped.height())));
|
|
|
|
}
|
|
// debug_rect( "sel() return", &retval );
|
|
return( retval );
|
|
|
|
}
|
|
|
|
bool ImageCanvas::selectedImage( TQImage *retImg )
|
|
{
|
|
TQRect r = sel();
|
|
bool result = false;
|
|
|
|
const TQImage* entireImg = this->rootImage();
|
|
|
|
if( entireImg )
|
|
{
|
|
TQSize s = entireImg->size();
|
|
|
|
int x = (s.width() * r.x())/1000;
|
|
int y = (s.height() * r.y())/1000;
|
|
int w = (s.width() * r.width())/1000;
|
|
int h = (s.height() * r.height())/1000;
|
|
|
|
if( w > 0 && h > 0 ) {
|
|
*retImg = entireImg->copy( x, y, w, h );
|
|
result = true;
|
|
}
|
|
}
|
|
return(result);
|
|
|
|
}
|
|
|
|
|
|
void ImageCanvas::drawContents( TQPainter * p, int clipx, int clipy, int clipw, int cliph )
|
|
{
|
|
if( !pmScaled ) return;
|
|
int x1 = 0;
|
|
int y1 = 0;
|
|
|
|
int x2 = pmScaled->width();
|
|
int y2 = pmScaled->height();
|
|
|
|
if (x1 < clipx) x1=clipx;
|
|
if (y1 < clipy) y1=clipy;
|
|
if (x2 > clipx+clipw-1) x2=clipx+clipw-1;
|
|
if (y2 > clipy+cliph-1) y2=clipy+cliph-1;
|
|
|
|
// Paint using the small coordinates...
|
|
// p->scale( used_xscaler, used_yscaler );
|
|
// p->scale( used_xscaler, used_yscaler );
|
|
if ( x2 >= x1 && y2 >= y1 ) {
|
|
p->drawPixmap( x1, y1, *pmScaled, x1, y1 ); //, clipw, cliph);
|
|
// p->setBrush( red );
|
|
// p->drawRect( x1, y1, clipw, cliph );
|
|
}
|
|
|
|
// p->fillRect(x1, y1, x2-x1+1, y2-y1+1, red);
|
|
|
|
}
|
|
|
|
void ImageCanvas::timerEvent(TQTimerEvent *)
|
|
{
|
|
if(moving!=MOVE_NONE || !acquired ) return;
|
|
cr1++;
|
|
TQPainter p(viewport());
|
|
// p.setWindow( contentsX(), contentsY(), contentsWidth(), contentsHeight());
|
|
drawAreaBorder(&p);
|
|
}
|
|
|
|
void ImageCanvas::newRectSlot( TQRect newSel )
|
|
{
|
|
TQRect to_map;
|
|
TQPainter p(viewport());
|
|
drawAreaBorder(&p,TRUE);
|
|
selected->setWidth(0);
|
|
selected->setHeight(0);
|
|
|
|
emit( noRect() );
|
|
|
|
if ( image )
|
|
{
|
|
int rx, ry, rw, rh;
|
|
int w = image->width();
|
|
int h = image->height();
|
|
|
|
kdDebug(29000) << "ImageCanvas: Image size is " << w << "x" << h << endl;
|
|
kdDebug(29000) << "ImageCanvas got selection Rect: W=" << newSel.width() << ", H=" << newSel.height() << endl;
|
|
// to_map.setWidth(static_cast<int>(w * newSel.width() / 1000.0));
|
|
rw = static_cast<int>(w * newSel.width() / 1000.0);
|
|
rx = static_cast<int>(w * newSel.x() / 1000.0);
|
|
ry = static_cast<int>(h * newSel.y() / 1000.0);
|
|
rh = static_cast<int>(h * newSel.height() / 1000.0);
|
|
kdDebug(29000) << "ImageCanvas: scaled Height is " << rh << endl;
|
|
|
|
to_map.setRect( rx, ry, rw, rh );
|
|
|
|
kdDebug(29000) << "ImageCanvas Selection: W=" << to_map.width() << " H=" << to_map.height() << endl;
|
|
*selected = scale_matrix.map( to_map );
|
|
kdDebug(29000) << "ImageCanvas Selection: W=" << selected->width() << " H=" << selected->height() << endl;
|
|
emit( newRect( sel() ));
|
|
newRectSlot();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void ImageCanvas::newRectSlot( )
|
|
{
|
|
// printf( "Timer switched on !\n" );
|
|
if( timer_id == 0 )
|
|
timer_id = startTimer( 100 );
|
|
}
|
|
|
|
void ImageCanvas::noRectSlot( void )
|
|
{
|
|
// printf( "Timer switched off !\n" );
|
|
if( timer_id ) {
|
|
killTimer( timer_id );
|
|
timer_id = 0;
|
|
}
|
|
|
|
if( selected )
|
|
selected->setCoords( 0,0,0,0 );
|
|
}
|
|
|
|
void ImageCanvas::viewportMousePressEvent(TQMouseEvent *ev)
|
|
{
|
|
if( ! acquired || ! image ) return;
|
|
|
|
if(ev->button()==TQt::LeftButton )
|
|
{
|
|
|
|
int cx = contentsX(), cy = contentsY();
|
|
int x = lx = ev->x(),y = ly = ev->y();
|
|
|
|
int ix, iy;
|
|
scale_matrix.map( image->width(), image->height(), &ix, &iy );
|
|
if( x > ix-cx || y > iy-cy ) return;
|
|
|
|
if( moving == MOVE_NONE )
|
|
{
|
|
TQPainter p( viewport());
|
|
drawAreaBorder(&p,TRUE);
|
|
moving = classifyPoint( x+cx ,y+cy);
|
|
|
|
if(moving == MOVE_NONE)
|
|
{ //Create new area
|
|
selected->setCoords( x+cx, y+cy, x+cx, y+cy );
|
|
moving = MOVE_BOTTOM_RIGHT;
|
|
}
|
|
drawAreaBorder(&p);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void ImageCanvas::viewportMouseReleaseEvent(TQMouseEvent *ev)
|
|
{
|
|
if(ev->button()!=TQt::LeftButton || !acquired ) return;
|
|
|
|
//// debug( "Mouse Release at %d/%d", ev->x(), ev->y());
|
|
if(moving!=MOVE_NONE) {
|
|
TQPainter p(viewport());
|
|
drawAreaBorder(&p,TRUE);
|
|
moving = MOVE_NONE;
|
|
*selected = selected->normalize();
|
|
|
|
if(selected->width () < MIN_AREA_WIDTH ||
|
|
selected->height() < MIN_AREA_HEIGHT)
|
|
{
|
|
selected->setWidth(0);
|
|
selected->setHeight(0);
|
|
emit noRect();
|
|
return;
|
|
}
|
|
|
|
drawAreaBorder(&p);
|
|
emit newRect( sel() );
|
|
emit newRect( );
|
|
}
|
|
}
|
|
|
|
|
|
void ImageCanvas::viewportMouseMoveEvent(TQMouseEvent *ev)
|
|
{
|
|
if( ! acquired || !image) return;
|
|
|
|
static cursor_type ps = HREN;
|
|
int x = ev->x(), y = ev->y();
|
|
int cx = contentsX(), cy = contentsY();
|
|
|
|
// debug("Mouse Coord x: %d, y: %d | cx: %d, cy: %d", x,y, cx, cy );
|
|
// dont draw out of the scaled Pixmap
|
|
if( x < 0 ) x = 0;
|
|
int ix, iy;
|
|
scale_matrix.map( image->width(), image->height(), &ix, &iy );
|
|
if( x >= ix ) return;
|
|
|
|
if( y < 0 ) y = 0;
|
|
if( y >= iy ) return;
|
|
|
|
// debug( "cx, cy: %dx%d, x,y: %d, %d",
|
|
// cx, cy, x, y );
|
|
|
|
#if 0
|
|
if( moving == MOVE_NONE )
|
|
moving = classifyPoint(x, y);
|
|
#endif
|
|
switch( moving!=MOVE_NONE ? moving:classifyPoint(x+cx,y+cy) ) {
|
|
case MOVE_NONE:
|
|
if(ps!=CROSS) {
|
|
viewport()->setCursor(crossCursor);
|
|
ps = CROSS;
|
|
}
|
|
break;
|
|
case MOVE_LEFT:
|
|
case MOVE_RIGHT:
|
|
if(ps!=HSIZE) {
|
|
viewport()->setCursor(sizeHorCursor);
|
|
ps = HSIZE;
|
|
}
|
|
break;
|
|
case MOVE_TOP:
|
|
case MOVE_BOTTOM:
|
|
if(ps!=VSIZE) {
|
|
viewport()->setCursor(sizeVerCursor);
|
|
ps = VSIZE;
|
|
}
|
|
break;
|
|
case MOVE_TOP_LEFT:
|
|
case MOVE_BOTTOM_RIGHT:
|
|
if(ps!=FDIAG) {
|
|
viewport()->setCursor(sizeFDiagCursor);
|
|
ps = FDIAG;
|
|
}
|
|
break;
|
|
case MOVE_TOP_RIGHT:
|
|
case MOVE_BOTTOM_LEFT:
|
|
if(ps!=BDIAG) {
|
|
viewport()->setCursor(sizeBDiagCursor);
|
|
ps = BDIAG;
|
|
}
|
|
break;
|
|
case MOVE_WHOLE:
|
|
if(ps!=ALL) {
|
|
viewport()->setCursor(sizeAllCursor);
|
|
ps = ALL;
|
|
}
|
|
}
|
|
//At ButtonRelease : normalize + clip
|
|
if( moving!=MOVE_NONE ) {
|
|
int mx, my;
|
|
TQPainter p(viewport());
|
|
drawAreaBorder(&p,TRUE);
|
|
switch(moving) {
|
|
case MOVE_NONE: //Just to make compiler happy
|
|
break;
|
|
case MOVE_TOP_LEFT:
|
|
selected->setLeft( x + cx );
|
|
case MOVE_TOP: // fall through
|
|
selected->setTop( y + cy );
|
|
break;
|
|
case MOVE_TOP_RIGHT:
|
|
selected->setTop( y + cy );
|
|
case MOVE_RIGHT: // fall through
|
|
selected->setRight( x + cx );
|
|
break;
|
|
case MOVE_BOTTOM_LEFT:
|
|
selected->setBottom( y + cy );
|
|
case MOVE_LEFT: // fall through
|
|
selected->setLeft( x + cx );
|
|
break;
|
|
case MOVE_BOTTOM_RIGHT:
|
|
selected->setRight( x + cx );
|
|
case MOVE_BOTTOM: // fall through
|
|
selected->setBottom( y + cy );
|
|
break;
|
|
case MOVE_WHOLE:
|
|
if( selected )
|
|
{
|
|
// lx is the Last x-Koord from the run before (global)
|
|
mx = x-lx; my = y-ly;
|
|
/* Check if rectangle would run out of the image on right and bottom */
|
|
if( selected->x()+ selected->width()+mx >= ix-cx )
|
|
{
|
|
mx = ix -cx - selected->width() - selected->x();
|
|
kdDebug(29000) << "runs out !" << endl;
|
|
}
|
|
if( selected->y()+ selected->height()+my >= iy-cy )
|
|
{
|
|
my = iy -cy - selected->height() - selected->y();
|
|
kdDebug(29000) << "runs out !" << endl;
|
|
}
|
|
|
|
/* Check if rectangle would run out of the image on left and top */
|
|
if( selected->x() +mx < 0 )
|
|
mx = -selected->x();
|
|
if( selected->y()+ +my < 0 )
|
|
my = -selected->y();
|
|
|
|
x = mx+lx; y = my+ly;
|
|
|
|
selected->moveBy( mx, my );
|
|
|
|
}
|
|
}
|
|
drawAreaBorder(&p);
|
|
lx = x;
|
|
ly = y;
|
|
}
|
|
}
|
|
|
|
|
|
void ImageCanvas::setScaleFactor( int i )
|
|
{
|
|
kdDebug(29000) << "Setting Scalefactor to " << i << endl;
|
|
scale_factor = i;
|
|
if( i == 0 ){
|
|
kdDebug(29000) << "Setting Dynamic Scaling!" << endl;
|
|
setScaleKind(DYNAMIC);
|
|
}
|
|
update_scaled_pixmap();
|
|
}
|
|
|
|
|
|
void ImageCanvas::resizeEvent( TQResizeEvent * event )
|
|
{
|
|
TQScrollView::resizeEvent( event );
|
|
update_scaled_pixmap();
|
|
|
|
}
|
|
|
|
void ImageCanvas::update_scaled_pixmap( void )
|
|
{
|
|
resizeContents( 0,0 );
|
|
updateScrollBars();
|
|
if( !pmScaled || !image)
|
|
{ // debug( "Pixmap px is null in Update_scaled" );
|
|
return;
|
|
}
|
|
|
|
TQApplication::setOverrideCursor(waitCursor);
|
|
|
|
kdDebug(28000) << "Updating scaled_pixmap" << endl;
|
|
if( scaleKind() == DYNAMIC )
|
|
kdDebug(28000) << "Scaling DYNAMIC" << endl;
|
|
TQSize noSBSize( visibleWidth(), visibleHeight());
|
|
const int sbWidth = kapp->style().pixelMetric( TQStyle::PM_ScrollBarExtent );
|
|
|
|
// if( verticalScrollBar()->visible() ) noSBSize.width()+=sbWidth;
|
|
// if( horizontalScrollBar()->visible() ) noSBSize.height()+=sbWidth;
|
|
|
|
switch( scaleKind() )
|
|
{
|
|
case DYNAMIC:
|
|
// do scaling to window-size
|
|
used_yscaler = ((double)viewport()-> height()) / ((double)image->height());
|
|
used_xscaler = ((double)viewport()-> width()) / ((double)image->width());
|
|
scale_factor = 0;
|
|
break;
|
|
case FIT_ORIG:
|
|
used_yscaler = used_xscaler = 1.0;
|
|
scale_factor = 100;
|
|
break;
|
|
case FIT_WIDTH:
|
|
used_xscaler = used_yscaler = double(noSBSize.width()) / double(image->width());
|
|
if( used_xscaler * image->height() >= noSBSize.height() )
|
|
{
|
|
/* substract for scrollbar */
|
|
used_xscaler = used_yscaler = double(noSBSize.width() - sbWidth) /
|
|
double(image->width());
|
|
kdDebug(29000) << "FIT WIDTH scrollbar to substract: " << sbWidth << endl;
|
|
}
|
|
scale_factor = 100*used_xscaler;
|
|
break;
|
|
case FIT_HEIGHT:
|
|
used_yscaler = used_xscaler = double(noSBSize.height())/double(image->height());
|
|
|
|
// scale = int(100.0 * noSBSize.height() / image->height());
|
|
if( used_xscaler * image->width() >= noSBSize.width() )
|
|
{
|
|
/* substract for scrollbar */
|
|
used_xscaler = used_yscaler = double(noSBSize.height() - sbWidth) /
|
|
double(image->height());
|
|
|
|
kdDebug(29000) << "FIT HEIGHT scrollbar to substract: " << sbWidth << endl;
|
|
// scale = int(100.0*(noSBSize.height() -sbWidth) / image->height());
|
|
}
|
|
scale_factor = 100*used_xscaler;
|
|
|
|
break;
|
|
case ZOOM:
|
|
used_xscaler = used_yscaler = double(getScaleFactor())/100.0;
|
|
scale_factor = 100*used_xscaler;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// reconvert the selection to orig size
|
|
if( selected ) {
|
|
*selected = inv_scale_matrix.map( (const TQRect) *selected );
|
|
}
|
|
|
|
scale_matrix.reset(); // transformation matrix
|
|
inv_scale_matrix.reset();
|
|
|
|
|
|
if( scaleKind() == DYNAMIC && maintain_aspect ) {
|
|
// printf( "Skaler: x: %f, y: %f\n", x_scaler, y_scaler );
|
|
used_xscaler = used_yscaler < used_xscaler ?
|
|
used_yscaler : used_xscaler;
|
|
used_yscaler = used_xscaler;
|
|
}
|
|
|
|
scale_matrix.scale( used_xscaler, used_yscaler ); // define scale factors
|
|
inv_scale_matrix = scale_matrix.invert(); // for redraw of selection
|
|
|
|
if( selected ) {
|
|
*selected = scale_matrix.map( (const TQRect )*selected );
|
|
}
|
|
|
|
#ifdef USE_KPIXMAPIO
|
|
*pmScaled = pixIO.convertToPixmap(*image);
|
|
#else
|
|
pmScaled->convertFromImage( *image );
|
|
#endif
|
|
|
|
*pmScaled = pmScaled->xForm( scale_matrix ); // create scaled pixmap
|
|
|
|
/* Resizing to 0,0 never may be dropped, otherwise there are problems
|
|
* with redrawing of new images.
|
|
*/
|
|
resizeContents( static_cast<int>(image->width() * used_xscaler),
|
|
static_cast<int>(image->height() * used_yscaler ) );
|
|
|
|
TQApplication::restoreOverrideCursor();
|
|
}
|
|
|
|
|
|
void ImageCanvas::drawHAreaBorder(TQPainter &p,int x1,int x2,int y,int r)
|
|
{
|
|
if( ! acquired || !image ) return;
|
|
|
|
if(moving!=MOVE_NONE) cr2 = 0;
|
|
int inc = 1;
|
|
int cx = contentsX(), cy = contentsY();
|
|
if(x2 < x1) inc = -1;
|
|
|
|
if(!r) {
|
|
if(cr2 & 4) p.setPen(black);
|
|
else p.setPen(white);
|
|
} else if(!acquired) p.setPen(TQPen(TQColor(150,150,150)));
|
|
|
|
for(;;) {
|
|
if(rect().contains(TQPoint(x1,y))) {
|
|
if( r && acquired ) {
|
|
int re_x1, re_y;
|
|
inv_scale_matrix.map( x1+cx, y+cy, &re_x1, &re_y );
|
|
re_x1 = MIN( image->width()-1, re_x1 );
|
|
re_y = MIN( image->height()-1, re_y );
|
|
|
|
p.setPen( TQPen( TQColor( image->pixel(re_x1, re_y))));
|
|
}
|
|
p.drawPoint(x1,y);
|
|
}
|
|
if(!r) {
|
|
cr2++;
|
|
cr2 &= 7;
|
|
if(!(cr2&3)) {
|
|
if(cr2&4) p.setPen(black);
|
|
else p.setPen(white);
|
|
}
|
|
}
|
|
if(x1==x2) break;
|
|
x1 += inc;
|
|
}
|
|
|
|
}
|
|
|
|
void ImageCanvas::drawVAreaBorder(TQPainter &p, int x, int y1, int y2, int r )
|
|
{
|
|
if( ! acquired || !image ) return;
|
|
if( moving!=MOVE_NONE ) cr2 = 0;
|
|
int inc = 1;
|
|
if( y2 < y1 ) inc = -1;
|
|
|
|
int cx = contentsX(), cy = contentsY();
|
|
|
|
|
|
if( !r ) {
|
|
if( cr2 & 4 ) p.setPen(black);
|
|
else
|
|
p.setPen(white);
|
|
} else
|
|
if( !acquired ) p.setPen( TQPen( TQColor(150,150,150) ) );
|
|
|
|
for(;;) {
|
|
if(rect().contains( TQPoint(x,y1) )) {
|
|
if( r && acquired ) {
|
|
int re_y1, re_x;
|
|
inv_scale_matrix.map( x+cx, y1+cy, &re_x, &re_y1 );
|
|
re_x = MIN( image->width()-1, re_x );
|
|
re_y1 = MIN( image->height()-1, re_y1 );
|
|
|
|
p.setPen( TQPen( TQColor( image->pixel( re_x, re_y1) )));
|
|
}
|
|
p.drawPoint(x,y1);
|
|
}
|
|
|
|
if(!r) {
|
|
cr2++;
|
|
cr2 &= 7;
|
|
if(!(cr2&3)) {
|
|
if(cr2&4) p.setPen(black);
|
|
else p.setPen(white);
|
|
}
|
|
}
|
|
if(y1==y2) break;
|
|
y1 += inc;
|
|
}
|
|
|
|
}
|
|
|
|
void ImageCanvas::drawAreaBorder(TQPainter *p,int r )
|
|
{
|
|
if(selected->isNull()) return;
|
|
|
|
cr2 = cr1;
|
|
int xinc = 1;
|
|
if( selected->right() < selected->left()) xinc = -1;
|
|
int yinc = 1;
|
|
if( selected->bottom() < selected->top()) yinc = -1;
|
|
|
|
if( selected->width() )
|
|
drawHAreaBorder(*p,
|
|
selected->left() - contentsX(),
|
|
selected->right()- contentsX(),
|
|
selected->top() - contentsY(), r );
|
|
if( selected->height() ) {
|
|
drawVAreaBorder(*p,
|
|
selected->right() - contentsX(),
|
|
selected->top()- contentsY()+yinc,
|
|
selected->bottom()- contentsY(),r);
|
|
if(selected->width()) {
|
|
drawHAreaBorder(*p,
|
|
selected->right()-xinc- contentsX(),
|
|
selected->left()- contentsX(),
|
|
selected->bottom()- contentsY(),r);
|
|
drawVAreaBorder(*p,
|
|
selected->left()- contentsX(),
|
|
selected->bottom()-yinc- contentsY(),
|
|
selected->top()- contentsY()+yinc,r);
|
|
}
|
|
}
|
|
}
|
|
|
|
// x and y come as real pixmap-coords, not contents-coords
|
|
preview_state ImageCanvas::classifyPoint(int x,int y)
|
|
{
|
|
if(selected->isEmpty()) return MOVE_NONE;
|
|
|
|
TQRect a = selected->normalize();
|
|
|
|
int top = 0,left = 0,right = 0,bottom = 0;
|
|
int lx = a.left()-x, rx = x-a.right();
|
|
int ty = a.top()-y, by = y-a.bottom();
|
|
|
|
if( a.width() > delta*2+2 )
|
|
lx = abs(lx), rx = abs(rx);
|
|
|
|
if(a.height()>delta*2+2)
|
|
ty = abs(ty), by = abs(by);
|
|
|
|
if( lx>=0 && lx<=delta ) left++;
|
|
if( rx>=0 && rx<=delta ) right++;
|
|
if( ty>=0 && ty<=delta ) top++;
|
|
if( by>=0 && by<=delta ) bottom++;
|
|
if( y>=a.top() &&y<=a.bottom() ) {
|
|
if(left) {
|
|
if(top) return MOVE_TOP_LEFT;
|
|
if(bottom) return MOVE_BOTTOM_LEFT;
|
|
return MOVE_LEFT;
|
|
}
|
|
if(right) {
|
|
if(top) return MOVE_TOP_RIGHT;
|
|
if(bottom) return MOVE_BOTTOM_RIGHT;
|
|
return MOVE_RIGHT;
|
|
}
|
|
}
|
|
if(x>=a.left()&&x<=a.right()) {
|
|
if(top) return MOVE_TOP;
|
|
if(bottom) return MOVE_BOTTOM;
|
|
if(selected->contains(TQPoint(x,y))) return MOVE_WHOLE;
|
|
}
|
|
return MOVE_NONE;
|
|
}
|
|
|
|
|
|
int ImageCanvas::getBrightness() const
|
|
{
|
|
return brightness;
|
|
}
|
|
|
|
int ImageCanvas::getContrast() const
|
|
{
|
|
return contrast;
|
|
}
|
|
|
|
int ImageCanvas::getGamma() const
|
|
{
|
|
return gamma;
|
|
}
|
|
|
|
int ImageCanvas::getScaleFactor() const
|
|
{
|
|
return( scale_factor );
|
|
}
|
|
|
|
const TQImage *ImageCanvas::rootImage( )
|
|
{
|
|
return( image );
|
|
}
|
|
|
|
void ImageCanvas::setReadOnly( bool ro )
|
|
{
|
|
d->readOnly = ro;
|
|
emit( imageReadOnly(ro) );
|
|
}
|
|
|
|
bool ImageCanvas::readOnly()
|
|
{
|
|
return d->readOnly;
|
|
}
|
|
|
|
void ImageCanvas::setBrightness(int b)
|
|
{
|
|
brightness = b;
|
|
}
|
|
|
|
void ImageCanvas::setContrast(int c)
|
|
{
|
|
contrast = c;
|
|
}
|
|
|
|
void ImageCanvas::setGamma(int c)
|
|
{
|
|
gamma = c;
|
|
}
|
|
|
|
void ImageCanvas::setKeepZoom( bool k )
|
|
{
|
|
d->keepZoom = k;
|
|
}
|
|
|
|
ImageCanvas::ScaleKinds ImageCanvas::scaleKind()
|
|
{
|
|
if( d->scaleKind == UNSPEC )
|
|
return defaultScaleKind();
|
|
else
|
|
return d->scaleKind;
|
|
}
|
|
|
|
ImageCanvas::ScaleKinds ImageCanvas::defaultScaleKind()
|
|
{
|
|
return d->defaultScaleKind;
|
|
}
|
|
|
|
void ImageCanvas::setScaleKind( ScaleKinds k )
|
|
{
|
|
if( k == d->scaleKind ) return; // no change, return
|
|
d->scaleKind = k;
|
|
|
|
emit scalingChanged(scaleKindString());
|
|
}
|
|
|
|
void ImageCanvas::setDefaultScaleKind( ScaleKinds k )
|
|
{
|
|
d->defaultScaleKind = k;
|
|
}
|
|
|
|
const TQString ImageCanvas::imageInfoString( int w, int h, int d )
|
|
{
|
|
if( w == 0 && h == 0 && d == 0 )
|
|
{
|
|
if( image )
|
|
{
|
|
w = image->width();
|
|
h = image->height();
|
|
d = image->depth();
|
|
}
|
|
else
|
|
return TQString("-");
|
|
}
|
|
return i18n("%1x%2 pixel, %3 bit").arg(w).arg(h).arg(d);
|
|
}
|
|
|
|
|
|
const TQString ImageCanvas::scaleKindString()
|
|
{
|
|
switch( scaleKind() )
|
|
{
|
|
case DYNAMIC:
|
|
return i18n("Fit window best");
|
|
break;
|
|
case FIT_ORIG:
|
|
return i18n("Original size");
|
|
break;
|
|
case FIT_WIDTH:
|
|
return i18n("Fit Width");
|
|
break;
|
|
case FIT_HEIGHT:
|
|
return i18n("Fit Height");
|
|
break;
|
|
case ZOOM:
|
|
return i18n("Zoom to %1 %%").arg( TQString::number(getScaleFactor()));
|
|
break;
|
|
default:
|
|
return i18n("Unknown scaling!");
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
int ImageCanvas::highlight( const TQRect& rect, const TQPen& pen, const TQBrush&, bool ensureVis )
|
|
{
|
|
TQRect saveRect;
|
|
saveRect.setRect( rect.x()-2, rect.y()-2, rect.width()+4, rect.height()+4 );
|
|
d->highlightRects.append( saveRect );
|
|
|
|
int idx = d->highlightRects.findIndex(saveRect);
|
|
|
|
TQRect targetRect = scale_matrix.map( rect );
|
|
|
|
TQPainter p( pmScaled );
|
|
|
|
p.setPen(pen);
|
|
p.drawLine( targetRect.x(), targetRect.y()+targetRect.height(),
|
|
targetRect.x()+targetRect.width(), targetRect.y()+targetRect.height() );
|
|
|
|
p.flush();
|
|
updateContents(targetRect.x()-1, targetRect.y()-1,
|
|
targetRect.width()+2, targetRect.height()+2 );
|
|
|
|
if( ensureVis )
|
|
{
|
|
TQPoint p = targetRect.center();
|
|
ensureVisible( p.x(), p.y(), 10+targetRect.width()/2, 10+targetRect.height()/2 );
|
|
}
|
|
|
|
return idx;
|
|
}
|
|
|
|
void ImageCanvas::removeHighlight( int idx )
|
|
{
|
|
if( (unsigned) idx >= d->highlightRects.count() )
|
|
{
|
|
kdDebug(28000) << "removeHighlight: Not a valid index" << endl;
|
|
return;
|
|
}
|
|
|
|
/* take the rectangle from the stored highlight rects and map it to the viewer scaling */
|
|
TQRect r = d->highlightRects[idx];
|
|
d->highlightRects.remove(r);
|
|
TQRect targetRect = scale_matrix.map( r );
|
|
|
|
/* create a small pixmap with a copy of the region in question of the original image */
|
|
TQPixmap origPix;
|
|
origPix.convertFromImage( image->copy(r) );
|
|
/* and scale it */
|
|
TQPixmap scaledPix = origPix.xForm( scale_matrix );
|
|
/* and finally draw it */
|
|
TQPainter p( pmScaled );
|
|
p.drawPixmap( targetRect, scaledPix );
|
|
p.flush();
|
|
|
|
/* update the viewers contents */
|
|
updateContents(targetRect.x()-1, targetRect.y()-1,
|
|
targetRect.width()+2, targetRect.height()+2 );
|
|
|
|
|
|
}
|
|
|
|
|
|
#include "img_canvas.moc"
|