/* ============================================================ * * 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 * * 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 // TQt includes. #include #include #include #include #include #include #include #include #include #include // KDE includes. #include #include #include #include // 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