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.
474 lines
15 KiB
474 lines
15 KiB
/* ============================================================
|
|
*
|
|
* This file is a part of digiKam project
|
|
* http://www.digikam.org
|
|
*
|
|
* Date : 2004-08-17
|
|
* Description : a widget to draw an image clip region.
|
|
*
|
|
* 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 <cmath>
|
|
|
|
// TQt includes.
|
|
|
|
#include <tqpainter.h>
|
|
#include <tqpixmap.h>
|
|
#include <tqtimer.h>
|
|
#include <tqpainter.h>
|
|
#include <tqpen.h>
|
|
#include <tqimage.h>
|
|
#include <tqbrush.h>
|
|
#include <tqfont.h>
|
|
#include <tqfontmetrics.h>
|
|
#include <tqpointarray.h>
|
|
|
|
// KDE includes.
|
|
|
|
#include <kstandarddirs.h>
|
|
#include <kcursor.h>
|
|
#include <tdeglobal.h>
|
|
#include <tdeapplication.h>
|
|
|
|
// Local includes.
|
|
|
|
#include "ddebug.h"
|
|
#include "imageiface.h"
|
|
#include "imageregionwidget.h"
|
|
#include "imageregionwidget.moc"
|
|
|
|
namespace Digikam
|
|
{
|
|
|
|
class ImageRegionWidgetPriv
|
|
{
|
|
|
|
public:
|
|
|
|
ImageRegionWidgetPriv()
|
|
{
|
|
iface = 0;
|
|
separateView = ImageRegionWidget::SeparateViewVertical;
|
|
}
|
|
|
|
int separateView;
|
|
int xpos;
|
|
int ypos;
|
|
|
|
TQPixmap pixmapRegion; // Pixmap of current region to render.
|
|
|
|
TQPointArray hightlightPoints;
|
|
|
|
DImg image; // Entire content image to render pixmap.
|
|
|
|
ImageIface *iface;
|
|
};
|
|
|
|
ImageRegionWidget::ImageRegionWidget(int wp, int hp, TQWidget *parent, bool scrollBar)
|
|
: PreviewWidget(parent)
|
|
{
|
|
d = new ImageRegionWidgetPriv;
|
|
d->iface = new ImageIface(0, 0);
|
|
d->image = d->iface->getOriginalImg()->copy();
|
|
|
|
setMinimumSize(wp, hp);
|
|
setBackgroundColor(colorGroup().background());
|
|
|
|
if( !scrollBar )
|
|
{
|
|
setVScrollBarMode( TQScrollView::AlwaysOff );
|
|
setHScrollBarMode( TQScrollView::AlwaysOff );
|
|
}
|
|
|
|
connect(this, TQT_SIGNAL(signalZoomFactorChanged(double)),
|
|
this, TQT_SLOT(slotZoomFactorChanged()));
|
|
}
|
|
|
|
ImageRegionWidget::~ImageRegionWidget()
|
|
{
|
|
if (d->iface) delete d->iface;
|
|
delete d;
|
|
}
|
|
|
|
void ImageRegionWidget::resizeEvent(TQResizeEvent* e)
|
|
{
|
|
if (!e) return;
|
|
|
|
TQScrollView::resizeEvent(e);
|
|
|
|
// NOTE: We will always adapt the min. zoom factor to the visible size of canvas
|
|
|
|
double srcWidth = previewWidth();
|
|
double srcHeight = previewHeight();
|
|
double dstWidth = contentsRect().width();
|
|
double dstHeight = contentsRect().height();
|
|
double zoom = TQMAX(dstWidth/srcWidth, dstHeight/srcHeight);
|
|
|
|
setZoomMin(zoom);
|
|
setZoomMax(zoom*12.0);
|
|
setZoomFactor(zoom);
|
|
}
|
|
|
|
int ImageRegionWidget::previewWidth()
|
|
{
|
|
return d->image.width();
|
|
}
|
|
|
|
int ImageRegionWidget::previewHeight()
|
|
{
|
|
return d->image.height();
|
|
}
|
|
|
|
bool ImageRegionWidget::previewIsNull()
|
|
{
|
|
return d->image.isNull();
|
|
}
|
|
|
|
void ImageRegionWidget::resetPreview()
|
|
{
|
|
d->image.reset();
|
|
}
|
|
|
|
void ImageRegionWidget::paintPreview(TQPixmap *pix, int sx, int sy, int sw, int sh)
|
|
{
|
|
DImg img = d->image.smoothScaleSection(sx, sy, sw, sh, tileSize(), tileSize());
|
|
TQPixmap pix2 = d->iface->convertToPixmap(img);
|
|
bitBlt(pix, 0, 0, &pix2, 0, 0);
|
|
}
|
|
|
|
void ImageRegionWidget::setHighLightPoints(const TQPointArray& pointsList)
|
|
{
|
|
d->hightlightPoints = pointsList;
|
|
repaintContents(false);
|
|
}
|
|
|
|
void ImageRegionWidget::slotZoomFactorChanged()
|
|
{
|
|
emit signalContentsMovedEvent(true);
|
|
}
|
|
|
|
void ImageRegionWidget::slotSeparateViewToggled(int mode)
|
|
{
|
|
d->separateView = mode;
|
|
updateContentsSize();
|
|
slotZoomFactorChanged();
|
|
}
|
|
|
|
TQRect ImageRegionWidget::getImageRegion()
|
|
{
|
|
TQRect region;
|
|
|
|
switch (d->separateView)
|
|
{
|
|
case SeparateViewVertical:
|
|
case SeparateViewHorizontal:
|
|
case SeparateViewNone:
|
|
region = TQRect(contentsX(), contentsY(), visibleWidth(), visibleHeight());
|
|
break;
|
|
case SeparateViewDuplicateVert:
|
|
region = TQRect(contentsX(), contentsY(), visibleWidth()/2, visibleHeight());
|
|
break;
|
|
case SeparateViewDuplicateHorz:
|
|
region = TQRect(contentsX(), contentsY(), visibleWidth(), visibleHeight()/2);
|
|
break;
|
|
}
|
|
|
|
return region;
|
|
}
|
|
|
|
void ImageRegionWidget::viewportPaintExtraData()
|
|
{
|
|
if (!m_movingInProgress && !d->pixmapRegion.isNull())
|
|
{
|
|
TQPainter p(viewport());
|
|
TQRect region = getLocalTargetImageRegion();
|
|
TQRect rt(contentsToViewport(region.topLeft()), contentsToViewport(region.bottomRight()));
|
|
|
|
region = getLocalImageRegionToRender();
|
|
TQRect ro(contentsToViewport(region.topLeft()), contentsToViewport(region.bottomRight()));
|
|
|
|
bitBlt(viewport(), rt.x(), rt.y(), &d->pixmapRegion, 0, 0, rt.width(), rt.height());
|
|
|
|
// Drawing separate view.
|
|
|
|
switch (d->separateView)
|
|
{
|
|
case SeparateViewVertical:
|
|
case SeparateViewDuplicateVert:
|
|
{
|
|
p.setPen(TQPen(TQt::white, 2, TQt::SolidLine));
|
|
p.drawLine(rt.topLeft().x(), rt.topLeft().y(),
|
|
rt.bottomLeft().x(), rt.bottomLeft().y());
|
|
p.setPen(TQPen(TQt::red, 2, TQt::DotLine));
|
|
p.drawLine(rt.topLeft().x(), rt.topLeft().y()+1,
|
|
rt.bottomLeft().x(), rt.bottomLeft().y()-1);
|
|
|
|
p.setPen(TQPen(TQt::red, 1)) ;
|
|
TQFontMetrics fontMt = p.fontMetrics();
|
|
|
|
TQString text(i18n("Target"));
|
|
TQRect textRect;
|
|
TQRect fontRect = fontMt.boundingRect(0, 0, contentsWidth(), contentsHeight(), 0, text);
|
|
textRect.setTopLeft(TQPoint(rt.topLeft().x()+20, rt.topLeft().y()+20));
|
|
textRect.setSize( TQSize(fontRect.width()+2, fontRect.height()+2) );
|
|
p.fillRect(textRect, TQBrush(TQColor(250, 250, 255)) );
|
|
p.drawRect(textRect);
|
|
p.drawText(textRect, TQt::AlignCenter, text);
|
|
|
|
text = i18n("Original");
|
|
fontRect = fontMt.boundingRect(0, 0, contentsWidth(), contentsHeight(), 0, text);
|
|
|
|
if (d->separateView == SeparateViewVertical)
|
|
ro.moveBy(-ro.width(), 0);
|
|
|
|
textRect.setTopLeft(TQPoint(ro.topLeft().x()+20, ro.topLeft().y()+20));
|
|
textRect.setSize( TQSize(fontRect.width()+2, fontRect.height()+2 ) );
|
|
p.fillRect(textRect, TQBrush(TQColor(250, 250, 255)) );
|
|
p.drawRect(textRect);
|
|
p.drawText(textRect, TQt::AlignCenter, text);
|
|
break;
|
|
}
|
|
case SeparateViewHorizontal:
|
|
case SeparateViewDuplicateHorz:
|
|
{
|
|
p.setPen(TQPen(TQt::white, 2, TQt::SolidLine));
|
|
p.drawLine(rt.topLeft().x()+1, rt.topLeft().y(),
|
|
rt.topRight().x()-1, rt.topRight().y());
|
|
p.setPen(TQPen(TQt::red, 2, TQt::DotLine));
|
|
p.drawLine(rt.topLeft().x(), rt.topLeft().y(),
|
|
rt.topRight().x(), rt.topRight().y());
|
|
|
|
p.setPen(TQPen(TQt::red, 1)) ;
|
|
TQFontMetrics fontMt = p.fontMetrics();
|
|
|
|
TQString text(i18n("Target"));
|
|
TQRect textRect;
|
|
TQRect fontRect = fontMt.boundingRect(0, 0, contentsWidth(), contentsHeight(), 0, text);
|
|
textRect.setTopLeft(TQPoint(rt.topLeft().x()+20, rt.topLeft().y()+20));
|
|
textRect.setSize( TQSize(fontRect.width()+2, fontRect.height()+2) );
|
|
p.fillRect(textRect, TQBrush(TQColor(250, 250, 255)) );
|
|
p.drawRect(textRect);
|
|
p.drawText(textRect, TQt::AlignCenter, text);
|
|
|
|
text = i18n("Original");
|
|
fontRect = fontMt.boundingRect(0, 0, contentsWidth(), contentsHeight(), 0, text);
|
|
|
|
if (d->separateView == SeparateViewHorizontal)
|
|
ro.moveBy(0, -ro.height());
|
|
|
|
textRect.setTopLeft(TQPoint(ro.topLeft().x()+20, ro.topLeft().y()+20));
|
|
textRect.setSize( TQSize(fontRect.width()+2, fontRect.height()+2 ) );
|
|
p.fillRect(textRect, TQBrush(TQColor(250, 250, 255)) );
|
|
p.drawRect(textRect);
|
|
p.drawText(textRect, TQt::AlignCenter, text);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Drawing HighLighted points.
|
|
|
|
if (!d->hightlightPoints.isEmpty())
|
|
{
|
|
TQPoint pt;
|
|
TQRect hpArea;
|
|
|
|
for (int i = 0 ; i < d->hightlightPoints.count() ; i++)
|
|
{
|
|
pt = d->hightlightPoints.point(i);
|
|
|
|
if ( getImageRegionToRender().contains(pt) )
|
|
{
|
|
int x = (int)(((double)pt.x() * tileSize()) / floor(tileSize() / zoomFactor()));
|
|
int y = (int)(((double)pt.y() * tileSize()) / floor(tileSize() / zoomFactor()));
|
|
|
|
TQPoint hp(contentsToViewport(TQPoint(x, y)));
|
|
hpArea.setSize(TQSize((int)(16*zoomFactor()), (int)(16*zoomFactor())));
|
|
hpArea.moveCenter(hp);
|
|
|
|
p.setPen(TQPen(TQt::white, 2, TQt::SolidLine));
|
|
p.drawLine(hp.x(), hpArea.y(),
|
|
hp.x(), hp.y()-(int)(3*zoomFactor()));
|
|
p.drawLine(hp.x(), hp.y()+(int)(3*zoomFactor()),
|
|
hp.x(), hpArea.bottom());
|
|
p.drawLine(hpArea.x(), hp.y(),
|
|
hp.x()-(int)(3*zoomFactor()), hp.y());
|
|
p.drawLine(hp.x()+(int)(3*zoomFactor()), hp.y(),
|
|
hpArea.right(), hp.y());
|
|
|
|
p.setPen(TQPen(TQt::red, 2, TQt::DotLine));
|
|
p.drawLine(hp.x(), hpArea.y(),
|
|
hp.x(), hp.y()-(int)(3*zoomFactor()));
|
|
p.drawLine(hp.x(), hp.y()+(int)(3*zoomFactor()),
|
|
hp.x(), hpArea.bottom());
|
|
p.drawLine(hpArea.x(), hp.y(),
|
|
hp.x()-(int)(3*zoomFactor()), hp.y());
|
|
p.drawLine(hp.x()+(int)(3*zoomFactor()), hp.y(),
|
|
hpArea.right(), hp.y());
|
|
}
|
|
}
|
|
}
|
|
p.end();
|
|
}
|
|
}
|
|
|
|
void ImageRegionWidget::setCenterContentsPosition()
|
|
{
|
|
center(contentsWidth()/2, contentsHeight()/2);
|
|
slotZoomFactorChanged();
|
|
}
|
|
|
|
void ImageRegionWidget::setContentsPosition(int x, int y, bool targetDone)
|
|
{
|
|
if( targetDone )
|
|
m_movingInProgress = false;
|
|
|
|
setContentsPos(x, y);
|
|
|
|
if( targetDone )
|
|
slotZoomFactorChanged();
|
|
}
|
|
|
|
void ImageRegionWidget::backupPixmapRegion()
|
|
{
|
|
d->pixmapRegion = TQPixmap();
|
|
}
|
|
|
|
void ImageRegionWidget::restorePixmapRegion()
|
|
{
|
|
m_movingInProgress = true;
|
|
viewport()->repaint(false);
|
|
}
|
|
|
|
void ImageRegionWidget::updatePreviewImage(DImg *img)
|
|
{
|
|
DImg image = img->copy();
|
|
TQRect r = getLocalImageRegionToRender();
|
|
image.resize(r.width(), r.height());
|
|
|
|
// Because image plugins are tool witch only work on image data, the DImg container
|
|
// do not contain metadata from original image. About Color Managed View, we need to
|
|
// restore the embedded ICC color profile.
|
|
image.setICCProfil(d->image.getICCProfil());
|
|
d->pixmapRegion = d->iface->convertToPixmap(image);
|
|
}
|
|
|
|
DImg ImageRegionWidget::getImageRegionImage()
|
|
{
|
|
return (d->image.copy(getImageRegionToRender()));
|
|
}
|
|
|
|
TQRect ImageRegionWidget::getImageRegionToRender()
|
|
{
|
|
TQRect r = getLocalImageRegionToRender();
|
|
|
|
int x = (int)(((double)r.x() / tileSize()) * floor(tileSize() / zoomFactor()));
|
|
int y = (int)(((double)r.y() / tileSize()) * floor(tileSize() / zoomFactor()));
|
|
int w = (int)(((double)r.width() / tileSize()) * floor(tileSize() / zoomFactor()));
|
|
int h = (int)(((double)r.height() / tileSize()) * floor(tileSize() / zoomFactor()));
|
|
|
|
TQRect rect(x, y, w, h);
|
|
return (rect);
|
|
}
|
|
|
|
TQRect ImageRegionWidget::getLocalImageRegionToRender()
|
|
{
|
|
TQRect region;
|
|
|
|
if (d->separateView == SeparateViewVertical)
|
|
{
|
|
region = TQRect((int)ceilf(contentsX()+visibleWidth()/2.0), contentsY(),
|
|
(int)ceilf(visibleWidth()/2.0), visibleHeight());
|
|
}
|
|
else if (d->separateView == SeparateViewHorizontal)
|
|
{
|
|
region = TQRect(contentsX(), (int)ceilf(contentsY()+visibleHeight()/2.0),
|
|
visibleWidth(), (int)ceilf(visibleHeight()/2.0));
|
|
}
|
|
else if (d->separateView == SeparateViewDuplicateVert)
|
|
{
|
|
region = TQRect(contentsX(), contentsY(),
|
|
(int)ceilf(visibleWidth()/2.0), visibleHeight());
|
|
}
|
|
else if (d->separateView == SeparateViewDuplicateHorz)
|
|
{
|
|
region = TQRect(contentsX(), contentsY(),
|
|
visibleWidth(), (int)ceilf(visibleHeight()/2.0));
|
|
}
|
|
else
|
|
{
|
|
region = TQRect(contentsX(), contentsY(),
|
|
visibleWidth(), visibleHeight());
|
|
}
|
|
|
|
return (region);
|
|
}
|
|
|
|
TQRect ImageRegionWidget::getLocalTargetImageRegion()
|
|
{
|
|
TQRect region = getLocalImageRegionToRender();
|
|
|
|
if (d->separateView == SeparateViewDuplicateVert)
|
|
region.moveBy(region.width(), 0);
|
|
else if (d->separateView == SeparateViewDuplicateHorz)
|
|
region.moveBy(0, region.height());
|
|
|
|
return region;
|
|
}
|
|
|
|
void ImageRegionWidget::setContentsSize()
|
|
{
|
|
switch (d->separateView)
|
|
{
|
|
case SeparateViewVertical:
|
|
case SeparateViewHorizontal:
|
|
case SeparateViewNone:
|
|
{
|
|
PreviewWidget::setContentsSize();
|
|
break;
|
|
}
|
|
case SeparateViewDuplicateVert:
|
|
{
|
|
resizeContents(zoomWidth()+visibleWidth()/2, zoomHeight());
|
|
break;
|
|
}
|
|
case SeparateViewDuplicateHorz:
|
|
{
|
|
resizeContents(zoomWidth(), zoomHeight()+visibleHeight()/2);
|
|
break;
|
|
}
|
|
default:
|
|
DWarning() << "Unknown separation view specified" << endl;
|
|
}
|
|
}
|
|
|
|
void ImageRegionWidget::contentsWheelEvent(TQWheelEvent *e)
|
|
{
|
|
e->accept();
|
|
|
|
if (e->state() & TQt::ControlButton)
|
|
{
|
|
if (e->delta() < 0 && !maxZoom())
|
|
slotIncreaseZoom();
|
|
else if (e->delta() > 0 && !minZoom())
|
|
slotDecreaseZoom();
|
|
return;
|
|
}
|
|
}
|
|
|
|
} // NameSpace Digikam
|