|
|
|
/* ============================================================
|
|
|
|
*
|
|
|
|
* This file is a part of digiKam project
|
|
|
|
* http://www.digikam.org
|
|
|
|
*
|
|
|
|
* Date : 2003-01-09
|
|
|
|
* Description : image editor canvas management class
|
|
|
|
*
|
|
|
|
* Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
|
|
|
|
* Copyright (C) 2004-2008 by Gilles Caulier <caulier dot gilles at gmail dot com>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it
|
|
|
|
* and/or modify it under the terms of the GNU General
|
|
|
|
* Public License as published by the Free Software Foundation;
|
|
|
|
* either version 2, or (at your option)
|
|
|
|
* any later version.
|
|
|
|
*
|
|
|
|
* This program 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 General Public License for more details.
|
|
|
|
*
|
|
|
|
* ============================================================ */
|
|
|
|
|
|
|
|
// C++ includes.
|
|
|
|
|
|
|
|
#include <cstdio>
|
|
|
|
#include <cmath>
|
|
|
|
|
|
|
|
// TQt includes.
|
|
|
|
|
|
|
|
#include <tqtooltip.h>
|
|
|
|
#include <tqfile.h>
|
|
|
|
#include <tqstring.h>
|
|
|
|
#include <tqevent.h>
|
|
|
|
#include <tqpoint.h>
|
|
|
|
#include <tqpainter.h>
|
|
|
|
#include <tqpen.h>
|
|
|
|
#include <tqpixmap.h>
|
|
|
|
#include <tqstyle.h>
|
|
|
|
#include <tqapplication.h>
|
|
|
|
#include <tqcursor.h>
|
|
|
|
#include <tqimage.h>
|
|
|
|
#include <tqregion.h>
|
|
|
|
#include <tqtimer.h>
|
|
|
|
#include <tqcache.h>
|
|
|
|
#include <tqcolor.h>
|
|
|
|
#include <tqdragobject.h>
|
|
|
|
#include <tqclipboard.h>
|
|
|
|
#include <tqtoolbutton.h>
|
|
|
|
|
|
|
|
// KDE includes.
|
|
|
|
|
|
|
|
#include <kcursor.h>
|
|
|
|
#include <klocale.h>
|
|
|
|
#include <kiconloader.h>
|
|
|
|
#include <kdatetbl.h>
|
|
|
|
#include <kglobalsettings.h>
|
|
|
|
|
|
|
|
// Local includes.
|
|
|
|
|
|
|
|
#include "ddebug.h"
|
|
|
|
#include "imagehistogram.h"
|
|
|
|
#include "imagepaniconwidget.h"
|
|
|
|
#include "dimginterface.h"
|
|
|
|
#include "iccsettingscontainer.h"
|
|
|
|
#include "exposurecontainer.h"
|
|
|
|
#include "iofilesettingscontainer.h"
|
|
|
|
#include "loadingcacheinterface.h"
|
|
|
|
#include "canvas.h"
|
|
|
|
#include "canvas.moc"
|
|
|
|
|
|
|
|
namespace Digikam
|
|
|
|
{
|
|
|
|
|
|
|
|
class CanvasPrivate
|
|
|
|
{
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
CanvasPrivate() :
|
|
|
|
tileSize(128), minZoom(0.1), maxZoom(12.0), zoomMultiplier(1.2)
|
|
|
|
{
|
|
|
|
rubber = 0;
|
|
|
|
pressedMoved = false;
|
|
|
|
pressedMoving = false;
|
|
|
|
ltActive = false;
|
|
|
|
rtActive = false;
|
|
|
|
lbActive = false;
|
|
|
|
rbActive = false;
|
|
|
|
midButtonPressed = false;
|
|
|
|
midButtonX = 0;
|
|
|
|
midButtonY = 0;
|
|
|
|
panIconPopup = 0;
|
|
|
|
panIconWidget = 0;
|
|
|
|
cornerButton = 0;
|
|
|
|
parent = 0;
|
|
|
|
im = 0;
|
|
|
|
rubber = 0;
|
|
|
|
autoZoom = false;
|
|
|
|
fullScreen = false;
|
|
|
|
zoom = 1.0;
|
|
|
|
tileTmpPix = new TQPixmap(tileSize, tileSize);
|
|
|
|
|
|
|
|
tileCache.setMaxCost((10*1024*1024)/(tileSize*tileSize*4));
|
|
|
|
tileCache.setAutoDelete(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool autoZoom;
|
|
|
|
bool fullScreen;
|
|
|
|
bool pressedMoved;
|
|
|
|
bool pressedMoving;
|
|
|
|
bool ltActive;
|
|
|
|
bool rtActive;
|
|
|
|
bool lbActive;
|
|
|
|
bool rbActive;
|
|
|
|
bool midButtonPressed;
|
|
|
|
|
|
|
|
const int tileSize;
|
|
|
|
int midButtonX;
|
|
|
|
int midButtonY;
|
|
|
|
|
|
|
|
double zoom;
|
|
|
|
const double minZoom;
|
|
|
|
const double maxZoom;
|
|
|
|
const double zoomMultiplier;
|
|
|
|
|
|
|
|
TQToolButton *cornerButton;
|
|
|
|
|
|
|
|
TQRect *rubber;
|
|
|
|
TQRect pixmapRect;
|
|
|
|
|
|
|
|
TQCache<TQPixmap> tileCache;
|
|
|
|
|
|
|
|
TQPixmap* tileTmpPix;
|
|
|
|
TQPixmap qcheck;
|
|
|
|
|
|
|
|
TQColor bgColor;
|
|
|
|
|
|
|
|
TQWidget *parent;
|
|
|
|
|
|
|
|
KPopupFrame *panIconPopup;
|
|
|
|
|
|
|
|
DImgInterface *im;
|
|
|
|
|
|
|
|
ImagePanIconWidget *panIconWidget;
|
|
|
|
};
|
|
|
|
|
|
|
|
Canvas::Canvas(TQWidget *parent)
|
|
|
|
: TQScrollView(parent)
|
|
|
|
{
|
|
|
|
d = new CanvasPrivate;
|
|
|
|
d->im = new DImgInterface();
|
|
|
|
d->parent = parent;
|
|
|
|
d->bgColor.setRgb(0, 0, 0);
|
|
|
|
|
|
|
|
d->qcheck.resize(16, 16);
|
|
|
|
TQPainter p(&d->qcheck);
|
|
|
|
p.fillRect(0, 0, 8, 8, TQColor(144, 144, 144));
|
|
|
|
p.fillRect(8, 8, 8, 8, TQColor(144, 144, 144));
|
|
|
|
p.fillRect(0, 8, 8, 8, TQColor(100, 100, 100));
|
|
|
|
p.fillRect(8, 0, 8, 8, TQColor(100, 100, 100));
|
|
|
|
p.end();
|
|
|
|
|
|
|
|
d->cornerButton = new TQToolButton(this);
|
|
|
|
d->cornerButton->setIconSet(SmallIcon("move"));
|
|
|
|
d->cornerButton->hide();
|
|
|
|
TQToolTip::add(d->cornerButton, i18n("Pan the image to a region"));
|
|
|
|
setCornerWidget(d->cornerButton);
|
|
|
|
|
|
|
|
viewport()->setBackgroundMode(TQt::NoBackground);
|
|
|
|
viewport()->setMouseTracking(false);
|
|
|
|
setFrameStyle( TQFrame::NoFrame );
|
|
|
|
|
|
|
|
// ------------------------------------------------------------
|
|
|
|
|
|
|
|
connect(this, TQT_SIGNAL(signalZoomChanged(double)),
|
|
|
|
this, TQT_SLOT(slotZoomChanged(double)));
|
|
|
|
|
|
|
|
connect(d->cornerButton, TQT_SIGNAL(pressed()),
|
|
|
|
this, TQT_SLOT(slotCornerButtonPressed()));
|
|
|
|
|
|
|
|
connect(d->im, TQT_SIGNAL(signalModified()),
|
|
|
|
this, TQT_SLOT(slotModified()));
|
|
|
|
|
|
|
|
connect(d->im, TQT_SIGNAL(signalUndoStateChanged(bool, bool, bool)),
|
|
|
|
this, TQT_SIGNAL(signalUndoStateChanged(bool, bool, bool)));
|
|
|
|
|
|
|
|
connect(d->im, TQT_SIGNAL(signalLoadingStarted(const TQString&)),
|
|
|
|
this, TQT_SIGNAL(signalLoadingStarted(const TQString&)));
|
|
|
|
|
|
|
|
connect(d->im, TQT_SIGNAL(signalImageLoaded(const TQString&, bool)),
|
|
|
|
this, TQT_SLOT(slotImageLoaded(const TQString&, bool)));
|
|
|
|
|
|
|
|
connect(d->im, TQT_SIGNAL(signalImageSaved(const TQString&, bool)),
|
|
|
|
this, TQT_SLOT(slotImageSaved(const TQString&, bool)));
|
|
|
|
|
|
|
|
connect(d->im, TQT_SIGNAL(signalLoadingProgress(const TQString&, float)),
|
|
|
|
this, TQT_SIGNAL(signalLoadingProgress(const TQString&, float)));
|
|
|
|
|
|
|
|
connect(d->im, TQT_SIGNAL(signalSavingProgress(const TQString&, float)),
|
|
|
|
this, TQT_SIGNAL(signalSavingProgress(const TQString&, float)));
|
|
|
|
|
|
|
|
connect(this, TQT_SIGNAL(signalSelected(bool)),
|
|
|
|
this, TQT_SLOT(slotSelected()));
|
|
|
|
}
|
|
|
|
|
|
|
|
Canvas::~Canvas()
|
|
|
|
{
|
|
|
|
delete d->tileTmpPix;
|
|
|
|
delete d->im;
|
|
|
|
|
|
|
|
if (d->rubber)
|
|
|
|
delete d->rubber;
|
|
|
|
|
|
|
|
delete d;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::resetImage()
|
|
|
|
{
|
|
|
|
reset();
|
|
|
|
viewport()->setUpdatesEnabled(false);
|
|
|
|
d->im->resetImage();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::reset()
|
|
|
|
{
|
|
|
|
if (d->rubber)
|
|
|
|
{
|
|
|
|
delete d->rubber;
|
|
|
|
d->rubber = 0;
|
|
|
|
if (d->im->imageValid())
|
|
|
|
emit signalSelected(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
d->tileCache.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::load(const TQString& filename, IOFileSettingsContainer *IOFileSettings)
|
|
|
|
{
|
|
|
|
reset();
|
|
|
|
|
|
|
|
viewport()->setUpdatesEnabled(false);
|
|
|
|
|
|
|
|
d->im->load( filename, IOFileSettings, d->parent );
|
|
|
|
|
|
|
|
emit signalPrepareToLoad();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::slotImageLoaded(const TQString& filePath, bool success)
|
|
|
|
{
|
|
|
|
d->zoom = 1.0;
|
|
|
|
d->im->zoom(d->zoom);
|
|
|
|
|
|
|
|
if (d->autoZoom)
|
|
|
|
updateAutoZoom();
|
|
|
|
|
|
|
|
updateContentsSize(true);
|
|
|
|
|
|
|
|
viewport()->setUpdatesEnabled(true);
|
|
|
|
viewport()->update();
|
|
|
|
|
|
|
|
emit signalZoomChanged(d->zoom);
|
|
|
|
|
|
|
|
emit signalLoadingFinished(filePath, success);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::preload(const TQString& /*filename*/)
|
|
|
|
{
|
|
|
|
// d->im->preload(filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
These code part are unused and untested
|
|
|
|
void Canvas::save(const TQString& filename, IOFileSettingsContainer *IOFileSettings)
|
|
|
|
{
|
|
|
|
d->im->save(filename, IOFileSettings);
|
|
|
|
emit signalSavingStarted(filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::saveAs(const TQString& filename,IOFileSettingsContainer *IOFileSettings,
|
|
|
|
const TQString& mimeType)
|
|
|
|
{
|
|
|
|
d->im->saveAs(filename, IOFileSettings, mimeType);
|
|
|
|
emit signalSavingStarted(filename);
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
void Canvas::saveAs(const TQString& filename, IOFileSettingsContainer *IOFileSettings,
|
|
|
|
bool setExifOrientationTag, const TQString& mimeType)
|
|
|
|
{
|
|
|
|
d->im->saveAs(filename, IOFileSettings, setExifOrientationTag, mimeType);
|
|
|
|
emit signalSavingStarted(filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::slotImageSaved(const TQString& filePath, bool success)
|
|
|
|
{
|
|
|
|
emit signalSavingFinished(filePath, success);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::switchToLastSaved(const TQString& newFilename)
|
|
|
|
{
|
|
|
|
d->im->switchToLastSaved(newFilename);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::abortSaving()
|
|
|
|
{
|
|
|
|
d->im->abortSaving();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::setModified()
|
|
|
|
{
|
|
|
|
d->im->setModified();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::readMetadataFromFile(const TQString &file)
|
|
|
|
{
|
|
|
|
d->im->readMetadataFromFile(file);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::clearUndoHistory()
|
|
|
|
{
|
|
|
|
d->im->clearUndoManager();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::setUndoHistoryOrigin()
|
|
|
|
{
|
|
|
|
d->im->setUndoManagerOrigin();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::updateUndoState()
|
|
|
|
{
|
|
|
|
d->im->updateUndoState();
|
|
|
|
}
|
|
|
|
|
|
|
|
DImg Canvas::currentImage()
|
|
|
|
{
|
|
|
|
return DImg(*d->im->getImg());
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString Canvas::currentImageFileFormat()
|
|
|
|
{
|
|
|
|
return d->im->getImageFormat();
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString Canvas::currentImageFilePath()
|
|
|
|
{
|
|
|
|
return d->im->getImageFilePath();
|
|
|
|
}
|
|
|
|
|
|
|
|
int Canvas::imageWidth()
|
|
|
|
{
|
|
|
|
return d->im->origWidth();
|
|
|
|
}
|
|
|
|
|
|
|
|
int Canvas::imageHeight()
|
|
|
|
{
|
|
|
|
return d->im->origHeight();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Canvas::isReadOnly()
|
|
|
|
{
|
|
|
|
return d->im->isReadOnly();
|
|
|
|
}
|
|
|
|
|
|
|
|
TQRect Canvas::getSelectedArea()
|
|
|
|
{
|
|
|
|
int x, y, w, h;
|
|
|
|
d->im->getSelectedArea(x, y, w, h);
|
|
|
|
return ( TQRect(x, y, w, h) );
|
|
|
|
}
|
|
|
|
|
|
|
|
DImgInterface *Canvas::interface() const
|
|
|
|
{
|
|
|
|
return d->im;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::makeDefaultEditingCanvas()
|
|
|
|
{
|
|
|
|
DImgInterface::setDefaultInterface(d->im);
|
|
|
|
}
|
|
|
|
|
|
|
|
double Canvas::calcAutoZoomFactor()
|
|
|
|
{
|
|
|
|
if (!d->im->imageValid()) return d->zoom;
|
|
|
|
|
|
|
|
double srcWidth = d->im->origWidth();
|
|
|
|
double srcHeight = d->im->origHeight();
|
|
|
|
double dstWidth = contentsRect().width();
|
|
|
|
double dstHeight = contentsRect().height();
|
|
|
|
return TQMIN(dstWidth/srcWidth, dstHeight/srcHeight);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::updateAutoZoom()
|
|
|
|
{
|
|
|
|
d->zoom = calcAutoZoomFactor();
|
|
|
|
d->im->zoom(d->zoom);
|
|
|
|
emit signalZoomChanged(d->zoom);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::updateContentsSize(bool deleteRubber)
|
|
|
|
{
|
|
|
|
viewport()->setUpdatesEnabled(false);
|
|
|
|
|
|
|
|
if (deleteRubber && d->rubber)
|
|
|
|
{
|
|
|
|
delete d->rubber;
|
|
|
|
d->rubber = 0;
|
|
|
|
d->ltActive = false;
|
|
|
|
d->rtActive = false;
|
|
|
|
d->lbActive = false;
|
|
|
|
d->rbActive = false;
|
|
|
|
d->pressedMoved = false;
|
|
|
|
viewport()->unsetCursor();
|
|
|
|
viewport()->setMouseTracking(false);
|
|
|
|
if (d->im->imageValid())
|
|
|
|
emit signalSelected(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
int wZ = d->im->width();
|
|
|
|
int hZ = d->im->height();
|
|
|
|
|
|
|
|
if (visibleWidth() > wZ || visibleHeight() > hZ)
|
|
|
|
{
|
|
|
|
// Center the image
|
|
|
|
int centerx = contentsRect().width()/2;
|
|
|
|
int centery = contentsRect().height()/2;
|
|
|
|
int xoffset = int(centerx - wZ/2);
|
|
|
|
int yoffset = int(centery - hZ/2);
|
|
|
|
xoffset = TQMAX(xoffset, 0);
|
|
|
|
yoffset = TQMAX(yoffset, 0);
|
|
|
|
|
|
|
|
d->pixmapRect = TQRect(xoffset, yoffset, wZ, hZ);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
d->pixmapRect = TQRect(0, 0, wZ, hZ);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!deleteRubber && d->rubber)
|
|
|
|
{
|
|
|
|
int xSel, ySel, wSel, hSel;
|
|
|
|
d->im->getSelectedArea(xSel, ySel, wSel, hSel);
|
|
|
|
xSel = (int)((xSel * d->tileSize) / floor(d->tileSize / d->zoom));
|
|
|
|
ySel = (int)((ySel * d->tileSize) / floor(d->tileSize / d->zoom));
|
|
|
|
wSel = (int)((wSel * d->tileSize) / floor(d->tileSize / d->zoom));
|
|
|
|
hSel = (int)((hSel * d->tileSize) / floor(d->tileSize / d->zoom));
|
|
|
|
d->rubber->setX(xSel);
|
|
|
|
d->rubber->setY(ySel);
|
|
|
|
d->rubber->setWidth(wSel);
|
|
|
|
d->rubber->setHeight(hSel);
|
|
|
|
d->rubber->moveBy(d->pixmapRect.x(), d->pixmapRect.y());
|
|
|
|
}
|
|
|
|
|
|
|
|
d->tileCache.clear();
|
|
|
|
resizeContents(wZ, hZ);
|
|
|
|
viewport()->setUpdatesEnabled(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::resizeEvent(TQResizeEvent* e)
|
|
|
|
{
|
|
|
|
if (!e)
|
|
|
|
return;
|
|
|
|
|
|
|
|
TQScrollView::resizeEvent(e);
|
|
|
|
|
|
|
|
if (d->autoZoom)
|
|
|
|
updateAutoZoom();
|
|
|
|
|
|
|
|
updateContentsSize(false);
|
|
|
|
|
|
|
|
// No need to repaint. its called
|
|
|
|
// automatically after resize
|
|
|
|
|
|
|
|
// To be sure than corner widget used to pan image will be hide/show
|
|
|
|
// accordinly with resize event.
|
|
|
|
slotZoomChanged(d->zoom);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::viewportPaintEvent(TQPaintEvent *e)
|
|
|
|
{
|
|
|
|
TQRect er(e->rect());
|
|
|
|
er = TQRect(TQMAX(er.x() - 1, 0),
|
|
|
|
TQMAX(er.y() - 1, 0),
|
|
|
|
TQMIN(er.width() + 2, contentsRect().width()),
|
|
|
|
TQMIN(er.height() + 2, contentsRect().height()));
|
|
|
|
|
|
|
|
paintViewport(er, (d->zoom <= 1.0) ? true : false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::paintViewport(const TQRect& er, bool antialias)
|
|
|
|
{
|
|
|
|
TQRect o_cr(viewportToContents(er.topLeft()), viewportToContents(er.bottomRight()));
|
|
|
|
TQRect cr = o_cr;
|
|
|
|
|
|
|
|
TQRegion clipRegion(er);
|
|
|
|
cr = d->pixmapRect.intersect(cr);
|
|
|
|
|
|
|
|
if (!cr.isEmpty() && d->im->imageValid())
|
|
|
|
{
|
|
|
|
clipRegion -= TQRect(contentsToViewport(cr.topLeft()), cr.size());
|
|
|
|
|
|
|
|
TQRect pr = TQRect(cr.x() - d->pixmapRect.x(), cr.y() - d->pixmapRect.y(),
|
|
|
|
cr.width(), cr.height());
|
|
|
|
|
|
|
|
int x1 = (int)floor((double)pr.x() / (double)d->tileSize) * d->tileSize;
|
|
|
|
int y1 = (int)floor((double)pr.y() / (double)d->tileSize) * d->tileSize;
|
|
|
|
int x2 = (int)ceilf((double)pr.right() / (double)d->tileSize) * d->tileSize;
|
|
|
|
int y2 = (int)ceilf((double)pr.bottom() / (double)d->tileSize) * d->tileSize;
|
|
|
|
|
|
|
|
TQPixmap pix(d->tileSize, d->tileSize);
|
|
|
|
int sx, sy, sw, sh;
|
|
|
|
int step = (int)floor(d->tileSize / d->zoom);
|
|
|
|
|
|
|
|
bool hasRubber = (d->rubber && d->pressedMoved && d->pressedMoving && d->rubber->intersects(pr));
|
|
|
|
if (hasRubber)
|
|
|
|
{
|
|
|
|
// remove rubber
|
|
|
|
drawRubber();
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int j = y1 ; j < y2 ; j += d->tileSize)
|
|
|
|
{
|
|
|
|
for (int i = x1 ; i < x2 ; i += d->tileSize)
|
|
|
|
{
|
|
|
|
TQString key = TQString("%1,%2").arg(i).arg(j);
|
|
|
|
TQPixmap *pix = d->tileCache.find(key);
|
|
|
|
|
|
|
|
if (!pix)
|
|
|
|
{
|
|
|
|
if (antialias)
|
|
|
|
{
|
|
|
|
pix = new TQPixmap(d->tileSize, d->tileSize);
|
|
|
|
d->tileCache.insert(key, pix);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pix = d->tileTmpPix;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (d->im->hasAlpha())
|
|
|
|
{
|
|
|
|
TQPainter p(pix);
|
|
|
|
p.drawTiledPixmap(0, 0, d->tileSize, d->tileSize,
|
|
|
|
d->qcheck, 0, 0);
|
|
|
|
p.end();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pix->fill(d->bgColor);
|
|
|
|
}
|
|
|
|
|
|
|
|
// NOTE : with implementations <= 0.9.1, the canvas doesn't work properly using high zoom level (> 500).
|
|
|
|
// The sx, sy, sw, sh values haven't be computed properly and "tile" artefacts been appears
|
|
|
|
// over the image. Look the example here:
|
|
|
|
// http://digikam3rdparty.free.fr/Screenshots/editorhighzoomartefact.png
|
|
|
|
// Note than these "tile" artifacts are not the real tiles of canvas.
|
|
|
|
// The new implementation below fix this problem to handle properly the areas to
|
|
|
|
// use from the source image to generate the canvas pixmap tiles.
|
|
|
|
|
|
|
|
sx = (int)floor((double)i / d->tileSize) * step;
|
|
|
|
sy = (int)floor((double)j / d->tileSize) * step;
|
|
|
|
sw = step;
|
|
|
|
sh = step;
|
|
|
|
|
|
|
|
if (d->rubber && d->pressedMoved && !d->pressedMoving)
|
|
|
|
{
|
|
|
|
TQRect rr(d->rubber->normalize());
|
|
|
|
TQRect r(i, j, d->tileSize, d->tileSize);
|
|
|
|
|
|
|
|
d->im->paintOnDevice(TQT_TQPAINTDEVICE(pix), sx, sy, sw, sh,
|
|
|
|
0, 0, d->tileSize, d->tileSize,
|
|
|
|
rr.x() - i - d->pixmapRect.x(),
|
|
|
|
rr.y() - j - d->pixmapRect.y(),
|
|
|
|
rr.width(), rr.height(),
|
|
|
|
antialias);
|
|
|
|
|
|
|
|
rr.moveBy(-i -d->pixmapRect.x(), -j -d->pixmapRect.y());
|
|
|
|
|
|
|
|
TQPainter p(pix);
|
|
|
|
p.setPen(TQPen(TQColor(250, 250, 255), 1));
|
|
|
|
p.drawRect(rr);
|
|
|
|
if (rr.width() >= 10 && rr.height() >= 10)
|
|
|
|
{
|
|
|
|
p.drawRect(rr.x(), rr.y(), 5, 5);
|
|
|
|
p.drawRect(rr.x(), rr.y()+rr.height()-5, 5, 5);
|
|
|
|
p.drawRect(rr.x()+rr.width()-5, rr.y()+rr.height()-5, 5, 5);
|
|
|
|
p.drawRect(rr.x()+rr.width()-5, rr.y(), 5, 5);
|
|
|
|
}
|
|
|
|
p.end();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
d->im->paintOnDevice(TQT_TQPAINTDEVICE(pix), sx, sy, sw, sh,
|
|
|
|
0, 0, d->tileSize, d->tileSize,
|
|
|
|
antialias);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TQRect r(i, j, d->tileSize, d->tileSize);
|
|
|
|
TQRect ir = pr.intersect(r);
|
|
|
|
TQPoint pt(contentsToViewport(TQPoint(ir.x() + d->pixmapRect.x(),
|
|
|
|
ir.y() + d->pixmapRect.y())));
|
|
|
|
|
|
|
|
bitBlt(viewport(), pt.x(), pt.y(),
|
|
|
|
pix,
|
|
|
|
ir.x()-r.x(), ir.y()-r.y(),
|
|
|
|
ir.width(), ir.height());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hasRubber)
|
|
|
|
{
|
|
|
|
// restore rubber
|
|
|
|
drawRubber();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TQPainter painter(viewport());
|
|
|
|
painter.setClipRegion(clipRegion);
|
|
|
|
painter.fillRect(er, d->bgColor);
|
|
|
|
painter.end();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::drawRubber()
|
|
|
|
{
|
|
|
|
if (!d->rubber || !d->im->imageValid())
|
|
|
|
return;
|
|
|
|
|
|
|
|
TQPainter p(viewport());
|
|
|
|
p.setRasterOp(TQt::NotROP );
|
|
|
|
p.setPen(TQPen(TQt::color0, 1));
|
|
|
|
p.setBrush(NoBrush);
|
|
|
|
|
|
|
|
TQRect r(d->rubber->normalize());
|
|
|
|
r = TQRect(contentsToViewport(TQPoint(r.x(), r.y())), r.size());
|
|
|
|
|
|
|
|
TQPoint pnt(r.x(), r.y());
|
|
|
|
|
|
|
|
tqstyle().tqdrawPrimitive(TQStyle::PE_FocusRect, &p,
|
|
|
|
TQRect(pnt.x(), pnt.y(), r.width(), r.height()),
|
|
|
|
colorGroup(), TQStyle::Style_Default,
|
|
|
|
TQStyleOption(colorGroup().base()));
|
|
|
|
p.end();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::contentsMousePressEvent(TQMouseEvent *e)
|
|
|
|
{
|
|
|
|
if (!e || e->button() == Qt::RightButton)
|
|
|
|
return;
|
|
|
|
|
|
|
|
d->midButtonPressed = false;
|
|
|
|
|
|
|
|
if (e->button() == Qt::LeftButton)
|
|
|
|
{
|
|
|
|
if (d->ltActive || d->rtActive ||
|
|
|
|
d->lbActive || d->rbActive)
|
|
|
|
{
|
|
|
|
Q_ASSERT( d->rubber );
|
|
|
|
if (!d->rubber)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Set diagonally opposite corner as anchor
|
|
|
|
|
|
|
|
TQRect r(d->rubber->normalize());
|
|
|
|
|
|
|
|
if (d->ltActive)
|
|
|
|
{
|
|
|
|
d->rubber->setTopLeft(r.bottomRight());
|
|
|
|
d->rubber->setBottomRight(r.topLeft());
|
|
|
|
}
|
|
|
|
else if (d->rtActive)
|
|
|
|
{
|
|
|
|
d->rubber->setTopLeft(r.bottomLeft());
|
|
|
|
d->rubber->setBottomRight(r.topRight());
|
|
|
|
}
|
|
|
|
else if (d->lbActive)
|
|
|
|
{
|
|
|
|
d->rubber->setTopLeft(r.topRight());
|
|
|
|
d->rubber->setBottomRight(r.bottomLeft());
|
|
|
|
}
|
|
|
|
else if (d->rbActive)
|
|
|
|
{
|
|
|
|
d->rubber->setTopLeft(r.topLeft());
|
|
|
|
d->rubber->setBottomRight(r.bottomLeft());
|
|
|
|
}
|
|
|
|
|
|
|
|
viewport()->setMouseTracking(false);
|
|
|
|
d->pressedMoved = false;
|
|
|
|
d->pressedMoving = true;
|
|
|
|
|
|
|
|
d->tileCache.clear();
|
|
|
|
viewport()->repaint(false);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (e->button() == Qt::MidButton)
|
|
|
|
{
|
|
|
|
if (visibleWidth() < d->im->width() ||
|
|
|
|
visibleHeight() < d->im->height())
|
|
|
|
{
|
|
|
|
viewport()->setCursor(TQt::SizeAllCursor);
|
|
|
|
d->midButtonPressed = true;
|
|
|
|
d->midButtonX = e->x();
|
|
|
|
d->midButtonY = e->y();
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (d->rubber)
|
|
|
|
{
|
|
|
|
delete d->rubber;
|
|
|
|
d->rubber = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
d->rubber = new TQRect(e->x(), e->y(), 0, 0);
|
|
|
|
|
|
|
|
if (d->pressedMoved)
|
|
|
|
{
|
|
|
|
d->tileCache.clear();
|
|
|
|
viewport()->update();
|
|
|
|
}
|
|
|
|
|
|
|
|
d->pressedMoved = false;
|
|
|
|
d->pressedMoving = true;
|
|
|
|
|
|
|
|
viewport()->setMouseTracking(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::contentsMouseMoveEvent(TQMouseEvent *e)
|
|
|
|
{
|
|
|
|
if (!e)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (e->state() & Qt::MidButton)
|
|
|
|
{
|
|
|
|
if (d->midButtonPressed)
|
|
|
|
{
|
|
|
|
scrollBy(d->midButtonX - e->x(),
|
|
|
|
d->midButtonY - e->y());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (!viewport()->hasMouseTracking())
|
|
|
|
{
|
|
|
|
if (!d->rubber)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (e->state() != Qt::LeftButton &&
|
|
|
|
!(d->ltActive || d->rtActive ||
|
|
|
|
d->lbActive || d->rbActive))
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Clear old rubber.
|
|
|
|
if (d->pressedMoved)
|
|
|
|
drawRubber();
|
|
|
|
|
|
|
|
// Move content if necessary.
|
|
|
|
blockSignals(true);
|
|
|
|
setUpdatesEnabled(false);
|
|
|
|
ensureVisible(e->x(), e->y(), 10, 10);
|
|
|
|
setUpdatesEnabled(true);
|
|
|
|
blockSignals(false);
|
|
|
|
|
|
|
|
// draw the new rubber position.
|
|
|
|
int r, b;
|
|
|
|
r = (e->x() > d->pixmapRect.left()) ? e->x() : d->pixmapRect.left();
|
|
|
|
r = (r < d->pixmapRect.right()) ? r : d->pixmapRect.right();
|
|
|
|
b = (e->y() > d->pixmapRect.top()) ? e->y() : d->pixmapRect.top();
|
|
|
|
b = (b < d->pixmapRect.bottom()) ? b : d->pixmapRect.bottom();
|
|
|
|
d->rubber->setRight(r);
|
|
|
|
d->rubber->setBottom(b);
|
|
|
|
drawRubber();
|
|
|
|
|
|
|
|
d->pressedMoved = true;
|
|
|
|
d->pressedMoving = true;
|
|
|
|
|
|
|
|
// To refresh editor status bar with current selection.
|
|
|
|
emit signalSelectionChanged(calcSeletedArea());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!d->rubber)
|
|
|
|
return;
|
|
|
|
|
|
|
|
TQRect r(d->rubber->normalize());
|
|
|
|
|
|
|
|
TQRect lt(r.x()-5, r.y()-5, 10, 10);
|
|
|
|
TQRect rt(r.x()+r.width()-5, r.y()-5, 10, 10);
|
|
|
|
TQRect lb(r.x()-5, r.y()+r.height()-5, 10, 10);
|
|
|
|
TQRect rb(r.x()+r.width()-5, r.y()+r.height()-5, 10, 10);
|
|
|
|
|
|
|
|
d->ltActive = false;
|
|
|
|
d->rtActive = false;
|
|
|
|
d->lbActive = false;
|
|
|
|
d->rbActive = false;
|
|
|
|
|
|
|
|
if (lt.contains(e->x(), e->y()))
|
|
|
|
{
|
|
|
|
viewport()->setCursor(TQt::SizeFDiagCursor);
|
|
|
|
d->ltActive = true;
|
|
|
|
}
|
|
|
|
else if (rb.contains(e->x(), e->y()))
|
|
|
|
{
|
|
|
|
viewport()->setCursor(TQt::SizeFDiagCursor);
|
|
|
|
d->rbActive = true;
|
|
|
|
}
|
|
|
|
else if (lb.contains(e->x(), e->y()))
|
|
|
|
{
|
|
|
|
viewport()->setCursor(TQt::SizeBDiagCursor);
|
|
|
|
d->lbActive = true;
|
|
|
|
}
|
|
|
|
else if (rt.contains(e->x(), e->y()))
|
|
|
|
{
|
|
|
|
viewport()->setCursor(TQt::SizeBDiagCursor);
|
|
|
|
d->rtActive = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
viewport()->unsetCursor();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::contentsMouseReleaseEvent(TQMouseEvent *e)
|
|
|
|
{
|
|
|
|
if (!e)
|
|
|
|
return;
|
|
|
|
|
|
|
|
d->midButtonPressed = false;
|
|
|
|
|
|
|
|
if (d->pressedMoving)
|
|
|
|
{
|
|
|
|
d->pressedMoving = false;
|
|
|
|
viewport()->update();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (d->pressedMoved && d->rubber)
|
|
|
|
{
|
|
|
|
// Normalize rubber rectangle to always have the selection into the image
|
|
|
|
TQRect rec = d->rubber->normalize();
|
|
|
|
|
|
|
|
if (rec.left() < d->pixmapRect.left()) rec.setLeft(d->pixmapRect.left());
|
|
|
|
if (rec.right() > d->pixmapRect.right()) rec.setRight(d->pixmapRect.right());
|
|
|
|
if (rec.top() < d->pixmapRect.top()) rec.setTop(d->pixmapRect.top());
|
|
|
|
if (rec.bottom() > d->pixmapRect.bottom()) rec.setBottom(d->pixmapRect.bottom());
|
|
|
|
|
|
|
|
d->rubber->setLeft(rec.left());
|
|
|
|
d->rubber->setRight(rec.right());
|
|
|
|
d->rubber->setTop(rec.top());
|
|
|
|
d->rubber->setBottom(rec.bottom());
|
|
|
|
|
|
|
|
d->tileCache.clear();
|
|
|
|
viewport()->setMouseTracking(true);
|
|
|
|
if (d->im->imageValid())
|
|
|
|
emit signalSelected(true);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
d->ltActive = false;
|
|
|
|
d->rtActive = false;
|
|
|
|
d->lbActive = false;
|
|
|
|
d->rbActive = false;
|
|
|
|
viewport()->setMouseTracking(false);
|
|
|
|
viewport()->unsetCursor();
|
|
|
|
if (d->im->imageValid())
|
|
|
|
emit signalSelected(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (e->button() != Qt::LeftButton)
|
|
|
|
{
|
|
|
|
viewport()->unsetCursor();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (e->button() == Qt::RightButton)
|
|
|
|
{
|
|
|
|
emit signalRightButtonClicked();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::contentsWheelEvent(TQWheelEvent *e)
|
|
|
|
{
|
|
|
|
e->accept();
|
|
|
|
|
|
|
|
if (e->state() & TQt::ShiftButton)
|
|
|
|
{
|
|
|
|
if (e->delta() < 0)
|
|
|
|
emit signalShowNextImage();
|
|
|
|
else if (e->delta() > 0)
|
|
|
|
emit signalShowPrevImage();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if (e->state() & TQt::ControlButton)
|
|
|
|
{
|
|
|
|
if (e->delta() < 0)
|
|
|
|
slotDecreaseZoom();
|
|
|
|
else if (e->delta() > 0)
|
|
|
|
slotIncreaseZoom();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQScrollView::contentsWheelEvent(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Canvas::maxZoom()
|
|
|
|
{
|
|
|
|
return ((d->zoom * d->zoomMultiplier) >= d->maxZoom);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Canvas::minZoom()
|
|
|
|
{
|
|
|
|
return ((d->zoom / d->zoomMultiplier) <= d->minZoom);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Canvas::exifRotated()
|
|
|
|
{
|
|
|
|
return d->im->exifRotated();
|
|
|
|
}
|
|
|
|
|
|
|
|
double Canvas::snapZoom(double zoom)
|
|
|
|
{
|
|
|
|
// If the zoom value gets changed from d->zoom to zoom
|
|
|
|
// across 50%, 100% or fit-to-window, then return the
|
|
|
|
// the corresponding special value. Otherwise zoom is returned unchanged.
|
|
|
|
double fit = calcAutoZoomFactor();
|
|
|
|
TQValueList<double> snapValues;
|
|
|
|
snapValues.append(0.5);
|
|
|
|
snapValues.append(1.0);
|
|
|
|
snapValues.append(fit);
|
|
|
|
|
|
|
|
qHeapSort(snapValues);
|
|
|
|
TQValueList<double>::const_iterator it;
|
|
|
|
|
|
|
|
if (d->zoom < zoom)
|
|
|
|
{
|
|
|
|
for(it = snapValues.constBegin(); it != snapValues.constEnd(); ++it)
|
|
|
|
{
|
|
|
|
double z = *it;
|
|
|
|
if ((d->zoom < z) && (zoom > z))
|
|
|
|
{
|
|
|
|
zoom = z;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// We need to go through the list in reverse order,
|
|
|
|
// however, tqCopyBackward does not seem to work here, so
|
|
|
|
// a simple for loop over integers is used instead.
|
|
|
|
for(int i=snapValues.size()-1; i>=0; i--)
|
|
|
|
{
|
|
|
|
double z = snapValues[i];
|
|
|
|
if ((d->zoom > z) && (zoom < z))
|
|
|
|
{
|
|
|
|
zoom = z;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return zoom;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::slotIncreaseZoom()
|
|
|
|
{
|
|
|
|
if (maxZoom())
|
|
|
|
return;
|
|
|
|
|
|
|
|
double zoom = d->zoom * d->zoomMultiplier;
|
|
|
|
zoom = snapZoom(zoom);
|
|
|
|
setZoomFactor(zoom);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::slotDecreaseZoom()
|
|
|
|
{
|
|
|
|
if (minZoom())
|
|
|
|
return;
|
|
|
|
|
|
|
|
double zoom = d->zoom / d->zoomMultiplier;
|
|
|
|
zoom = snapZoom(zoom);
|
|
|
|
setZoomFactor(zoom);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::setZoomFactorSnapped(double zoom)
|
|
|
|
{
|
|
|
|
double fit = calcAutoZoomFactor();
|
|
|
|
|
|
|
|
if (fabs(zoom-fit) < 0.05)
|
|
|
|
{
|
|
|
|
// If 1.0 or 0.5 are even closer to zoom than fit, then choose these.
|
|
|
|
if (fabs(zoom-fit) > fabs(zoom-1.0) )
|
|
|
|
{
|
|
|
|
zoom = 1.0;
|
|
|
|
}
|
|
|
|
else if (fabs(zoom-fit) > fabs(zoom-0.5) )
|
|
|
|
{
|
|
|
|
zoom = 0.5;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
zoom = fit;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (fabs(zoom-1.0) < 0.05)
|
|
|
|
{
|
|
|
|
zoom = 1.0;
|
|
|
|
}
|
|
|
|
if (fabs(zoom-0.5) < 0.05)
|
|
|
|
{
|
|
|
|
zoom = 0.5;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
setZoomFactor(zoom);
|
|
|
|
}
|
|
|
|
|
|
|
|
double Canvas::zoomFactor()
|
|
|
|
{
|
|
|
|
return d->zoom;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::setZoomFactor(double zoom)
|
|
|
|
{
|
|
|
|
if (d->autoZoom)
|
|
|
|
{
|
|
|
|
d->autoZoom = false;
|
|
|
|
emit signalToggleOffFitToWindow();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Zoom using center of canvas and given zoom factor.
|
|
|
|
|
|
|
|
double cpx = contentsX() + visibleWidth() / 2.0;
|
|
|
|
double cpy = contentsY() + visibleHeight() / 2.0;
|
|
|
|
|
|
|
|
cpx = (cpx / d->tileSize) * floor(d->tileSize / d->zoom);
|
|
|
|
cpy = (cpy / d->tileSize) * floor(d->tileSize / d->zoom);
|
|
|
|
|
|
|
|
d->zoom = zoom;
|
|
|
|
|
|
|
|
d->im->zoom(d->zoom);
|
|
|
|
updateContentsSize(false);
|
|
|
|
|
|
|
|
viewport()->setUpdatesEnabled(false);
|
|
|
|
center((int)((cpx * d->tileSize) / floor(d->tileSize / d->zoom)),
|
|
|
|
(int)((cpy * d->tileSize) / floor(d->tileSize / d->zoom)));
|
|
|
|
viewport()->setUpdatesEnabled(true);
|
|
|
|
viewport()->update();
|
|
|
|
|
|
|
|
emit signalZoomChanged(d->zoom);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::fitToSelect()
|
|
|
|
{
|
|
|
|
int xSel, ySel, wSel, hSel;
|
|
|
|
d->im->getSelectedArea(xSel, ySel, wSel, hSel);
|
|
|
|
|
|
|
|
if (wSel && hSel )
|
|
|
|
{
|
|
|
|
// If selected area, use center of selection
|
|
|
|
// and recompute zoom factor accordinly.
|
|
|
|
double cpx = xSel + wSel / 2.0;
|
|
|
|
double cpy = ySel + hSel / 2.0;
|
|
|
|
|
|
|
|
double srcWidth = wSel;
|
|
|
|
double srcHeight = hSel;
|
|
|
|
double dstWidth = contentsRect().width();
|
|
|
|
double dstHeight = contentsRect().height();
|
|
|
|
|
|
|
|
d->zoom = TQMIN(dstWidth/srcWidth, dstHeight/srcHeight);
|
|
|
|
|
|
|
|
d->autoZoom = false;
|
|
|
|
emit signalToggleOffFitToWindow();
|
|
|
|
d->im->zoom(d->zoom);
|
|
|
|
updateContentsSize(true);
|
|
|
|
|
|
|
|
viewport()->setUpdatesEnabled(false);
|
|
|
|
center((int)((cpx * d->tileSize) / floor(d->tileSize / d->zoom)),
|
|
|
|
(int)((cpy * d->tileSize) / floor(d->tileSize / d->zoom)));
|
|
|
|
viewport()->setUpdatesEnabled(true);
|
|
|
|
viewport()->update();
|
|
|
|
|
|
|
|
emit signalZoomChanged(d->zoom);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Canvas::fitToWindow()
|
|
|
|
{
|
|
|
|
return d->autoZoom;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::toggleFitToWindow()
|
|
|
|
{
|
|
|
|
d->autoZoom = !d->autoZoom;
|
|
|
|
|
|
|
|
if (d->autoZoom)
|
|
|
|
updateAutoZoom();
|
|
|
|
else
|
|
|
|
{
|
|
|
|
d->zoom = 1.0;
|
|
|
|
emit signalZoomChanged(d->zoom);
|
|
|
|
}
|
|
|
|
|
|
|
|
d->im->zoom(d->zoom);
|
|
|
|
updateContentsSize(false);
|
|
|
|
slotZoomChanged(d->zoom);
|
|
|
|
viewport()->update();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::slotRotate90()
|
|
|
|
{
|
|
|
|
d->im->rotate90();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::slotRotate180()
|
|
|
|
{
|
|
|
|
d->im->rotate180();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::slotRotate270()
|
|
|
|
{
|
|
|
|
d->im->rotate270();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::slotFlipHoriz()
|
|
|
|
{
|
|
|
|
d->im->flipHoriz();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::slotFlipVert()
|
|
|
|
{
|
|
|
|
d->im->flipVert();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::slotCrop()
|
|
|
|
{
|
|
|
|
int x, y, w, h;
|
|
|
|
d->im->getSelectedArea(x, y, w, h);
|
|
|
|
|
|
|
|
if (!w && !h ) // No current selection.
|
|
|
|
return;
|
|
|
|
|
|
|
|
d->im->crop(x, y, w, h);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::resizeImage(int w, int h)
|
|
|
|
{
|
|
|
|
d->im->resize(w, h);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::setBackgroundColor(const TQColor& color)
|
|
|
|
{
|
|
|
|
if (d->bgColor == color)
|
|
|
|
return;
|
|
|
|
|
|
|
|
d->bgColor = color;
|
|
|
|
viewport()->update();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::setICCSettings(ICCSettingsContainer *cmSettings)
|
|
|
|
{
|
|
|
|
d->im->setICCSettings(cmSettings);
|
|
|
|
d->tileCache.clear();
|
|
|
|
viewport()->update();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::setExposureSettings(ExposureSettingsContainer *expoSettings)
|
|
|
|
{
|
|
|
|
d->im->setExposureSettings(expoSettings);
|
|
|
|
d->tileCache.clear();
|
|
|
|
viewport()->update();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::setExifOrient(bool exifOrient)
|
|
|
|
{
|
|
|
|
d->im->setExifOrient(exifOrient);
|
|
|
|
viewport()->update();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::increaseGamma()
|
|
|
|
{
|
|
|
|
d->im->changeGamma(1);
|
|
|
|
d->tileCache.clear();
|
|
|
|
viewport()->update();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::decreaseGamma()
|
|
|
|
{
|
|
|
|
d->im->changeGamma(-1);
|
|
|
|
d->tileCache.clear();
|
|
|
|
viewport()->update();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::increaseBrightness()
|
|
|
|
{
|
|
|
|
d->im->changeBrightness(1);
|
|
|
|
d->tileCache.clear();
|
|
|
|
viewport()->update();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::decreaseBrightness()
|
|
|
|
{
|
|
|
|
d->im->changeBrightness(-1);
|
|
|
|
d->tileCache.clear();
|
|
|
|
viewport()->update();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::increaseContrast()
|
|
|
|
{
|
|
|
|
d->im->changeContrast(5);
|
|
|
|
d->tileCache.clear();
|
|
|
|
viewport()->update();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::decreaseContrast()
|
|
|
|
{
|
|
|
|
d->im->changeContrast(-5);
|
|
|
|
d->tileCache.clear();
|
|
|
|
viewport()->update();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::slotRestore()
|
|
|
|
{
|
|
|
|
d->im->restore();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::slotUndo(int steps)
|
|
|
|
{
|
|
|
|
while(steps > 0)
|
|
|
|
{
|
|
|
|
d->im->undo();
|
|
|
|
--steps;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::getUndoHistory(TQStringList &titles)
|
|
|
|
{
|
|
|
|
d->im->getUndoHistory(titles);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::getRedoHistory(TQStringList &titles)
|
|
|
|
{
|
|
|
|
d->im->getRedoHistory(titles);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::slotRedo(int steps)
|
|
|
|
{
|
|
|
|
while(steps > 0)
|
|
|
|
{
|
|
|
|
d->im->redo();
|
|
|
|
--steps;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::slotCopy()
|
|
|
|
{
|
|
|
|
int x, y, w, h;
|
|
|
|
d->im->getSelectedArea(x, y, w, h);
|
|
|
|
|
|
|
|
if (!w && !h ) // No current selection.
|
|
|
|
return;
|
|
|
|
|
|
|
|
TQApplication::setOverrideCursor (TQt::waitCursor);
|
|
|
|
uchar* data = d->im->getImageSelection();
|
|
|
|
DImg selDImg = DImg(w, h, d->im->sixteenBit(), d->im->hasAlpha(), data);
|
|
|
|
delete [] data;
|
|
|
|
|
|
|
|
TQImage selImg = selDImg.copyTQImage();
|
|
|
|
TQApplication::tqclipboard()->setData(new TQImageDrag(selImg), TQClipboard::Clipboard);
|
|
|
|
TQApplication::restoreOverrideCursor ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::slotSelected()
|
|
|
|
{
|
|
|
|
int x=0, y=0, w=0, h=0;
|
|
|
|
|
|
|
|
if (d->rubber && d->pressedMoved)
|
|
|
|
{
|
|
|
|
TQRect sel = calcSeletedArea();
|
|
|
|
x = sel.x();
|
|
|
|
y = sel.y();
|
|
|
|
w = sel.width();
|
|
|
|
h = sel.height();
|
|
|
|
}
|
|
|
|
|
|
|
|
d->im->setSelectedArea(x, y, w, h);
|
|
|
|
}
|
|
|
|
|
|
|
|
TQRect Canvas::calcSeletedArea()
|
|
|
|
{
|
|
|
|
int x=0, y=0, w=0, h=0;
|
|
|
|
TQRect r(d->rubber->normalize());
|
|
|
|
|
|
|
|
if (r.isValid())
|
|
|
|
{
|
|
|
|
r.moveBy(- d->pixmapRect.x(), - d->pixmapRect.y());
|
|
|
|
|
|
|
|
x = (int)(((double)r.x() / d->tileSize) * floor(d->tileSize / d->zoom));
|
|
|
|
y = (int)(((double)r.y() / d->tileSize) * floor(d->tileSize / d->zoom));
|
|
|
|
w = (int)(((double)r.width() / d->tileSize) * floor(d->tileSize / d->zoom));
|
|
|
|
h = (int)(((double)r.height() / d->tileSize) * floor(d->tileSize / d->zoom));
|
|
|
|
|
|
|
|
x = TQMIN(imageWidth(), TQMAX(x, 0));
|
|
|
|
y = TQMIN(imageHeight(), TQMAX(y, 0));
|
|
|
|
w = TQMIN(imageWidth(), TQMAX(w, 0));
|
|
|
|
h = TQMIN(imageHeight(), TQMAX(h, 0));
|
|
|
|
|
|
|
|
// Avoid empty selection by rubberband - at least mark one pixel
|
|
|
|
// At high zoom factors, the rubberband may operate at subpixel level!
|
|
|
|
if (w == 0)
|
|
|
|
w = 1;
|
|
|
|
if (h == 0)
|
|
|
|
h = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TQRect(x, y, w, h);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::slotModified()
|
|
|
|
{
|
|
|
|
if (d->autoZoom)
|
|
|
|
updateAutoZoom();
|
|
|
|
d->im->zoom(d->zoom);
|
|
|
|
|
|
|
|
updateContentsSize(true);
|
|
|
|
viewport()->update();
|
|
|
|
|
|
|
|
// To be sure than corner widget used to pan image will be hide/show
|
|
|
|
// accordinly with new image size (if changed).
|
|
|
|
slotZoomChanged(d->zoom);
|
|
|
|
|
|
|
|
emit signalChanged();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::slotCornerButtonPressed()
|
|
|
|
{
|
|
|
|
if (d->panIconPopup)
|
|
|
|
{
|
|
|
|
d->panIconPopup->hide();
|
|
|
|
delete d->panIconPopup;
|
|
|
|
d->panIconPopup = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
d->panIconPopup = new KPopupFrame(this);
|
|
|
|
ImagePanIconWidget *pan = new ImagePanIconWidget(180, 120, d->panIconPopup);
|
|
|
|
d->panIconPopup->setMainWidget(pan);
|
|
|
|
|
|
|
|
TQRect r((int)(contentsX() / d->zoom), (int)(contentsY() / d->zoom),
|
|
|
|
(int)(visibleWidth() / d->zoom), (int)(visibleHeight() / d->zoom));
|
|
|
|
pan->setRegionSelection(r);
|
|
|
|
pan->setMouseFocus();
|
|
|
|
|
|
|
|
connect(pan, TQT_SIGNAL(signalSelectionMoved(const TQRect&, bool)),
|
|
|
|
this, TQT_SLOT(slotPanIconSelectionMoved(const TQRect&, bool)));
|
|
|
|
|
|
|
|
connect(pan, TQT_SIGNAL(signalHiden()),
|
|
|
|
this, TQT_SLOT(slotPanIconHiden()));
|
|
|
|
|
|
|
|
TQPoint g = mapToGlobal(viewport()->pos());
|
|
|
|
g.setX(g.x()+ viewport()->size().width());
|
|
|
|
g.setY(g.y()+ viewport()->size().height());
|
|
|
|
d->panIconPopup->popup(TQPoint(g.x() - d->panIconPopup->width(),
|
|
|
|
g.y() - d->panIconPopup->height()));
|
|
|
|
|
|
|
|
pan->setCursorToLocalRegionSelectionCenter();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::slotPanIconHiden()
|
|
|
|
{
|
|
|
|
d->cornerButton->blockSignals(true);
|
|
|
|
d->cornerButton->animateClick();
|
|
|
|
d->cornerButton->blockSignals(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::slotPanIconSelectionMoved(const TQRect& r, bool b)
|
|
|
|
{
|
|
|
|
setContentsPos((int)(r.x()*d->zoom), (int)(r.y()*d->zoom));
|
|
|
|
|
|
|
|
if (b)
|
|
|
|
{
|
|
|
|
d->panIconPopup->hide();
|
|
|
|
delete d->panIconPopup;
|
|
|
|
d->panIconPopup = 0;
|
|
|
|
slotPanIconHiden();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::slotZoomChanged(double /*zoom*/)
|
|
|
|
{
|
|
|
|
updateScrollBars();
|
|
|
|
|
|
|
|
if (horizontalScrollBar()->isVisible() || verticalScrollBar()->isVisible())
|
|
|
|
d->cornerButton->show();
|
|
|
|
else
|
|
|
|
d->cornerButton->hide();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::slotSelectAll()
|
|
|
|
{
|
|
|
|
if (d->rubber)
|
|
|
|
{
|
|
|
|
delete d->rubber;
|
|
|
|
d->rubber = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
d->rubber = new TQRect(d->pixmapRect);
|
|
|
|
d->pressedMoved = true;
|
|
|
|
d->tileCache.clear();
|
|
|
|
viewport()->setMouseTracking(true);
|
|
|
|
viewport()->update();
|
|
|
|
|
|
|
|
if (d->im->imageValid())
|
|
|
|
emit signalSelected(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::slotSelectNone()
|
|
|
|
{
|
|
|
|
reset();
|
|
|
|
viewport()->update();
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace Digikam
|