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.
digikam/digikam/libs/widgets/imageplugins/imageregionwidget.cpp

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 <kglobal.h>
#include <kapplication.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 *tqparent, bool scrollBar)
: PreviewWidget(tqparent)
{
d = new ImageRegionWidgetPriv;
d->iface = new ImageIface(0, 0);
d->image = d->iface->getOriginalImg()->copy();
setMinimumSize(wp, hp);
setBackgroundColor(tqcolorGroup().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()->tqrepaint(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