diff options
Diffstat (limited to 'src/libs/widgets/imageplugins/imageregionwidget.cpp')
-rw-r--r-- | src/libs/widgets/imageplugins/imageregionwidget.cpp | 473 |
1 files changed, 473 insertions, 0 deletions
diff --git a/src/libs/widgets/imageplugins/imageregionwidget.cpp b/src/libs/widgets/imageplugins/imageregionwidget.cpp new file mode 100644 index 00000000..c1392cc2 --- /dev/null +++ b/src/libs/widgets/imageplugins/imageregionwidget.cpp @@ -0,0 +1,473 @@ +/* ============================================================ + * + * 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, TQ_SIGNAL(signalZoomFactorChanged(double)), + this, TQ_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 |