/* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2008-08-04 * Description : RAW postProcessedImg widget. * * Copyright (C) 2008 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. * * ============================================================ */ // TQt includes. #include #include #include #include #include #include // KDE includes. #include #include #include #include // Local includes. #include "ddebug.h" #include "paniconwidget.h" #include "managedloadsavethread.h" #include "loadingdescription.h" #include "themeengine.h" #include "rawpreview.h" #include "rawpreview.moc" namespace Digikam { class RawPreviewPriv { public: RawPreviewPriv() { panIconPopup = 0; panIconWidget = 0; cornerButton = 0; thread = 0; url = 0; currentFitWindowZoom = 0; } double currentFitWindowZoom; TQToolButton *cornerButton; TDEPopupFrame *panIconPopup; KURL url; PanIconWidget *panIconWidget; DImg demosaicedImg; DImg postProcessedImg; DRawDecoding settings; ManagedLoadSaveThread *thread; LoadingDescription loadingDesc; }; RawPreview::RawPreview(const KURL& url, TQWidget *parent) : PreviewWidget(parent) { d = new RawPreviewPriv; d->thread = new ManagedLoadSaveThread; d->url = url; setMinimumWidth(500); setSizePolicy(TQSizePolicy::Expanding, TQSizePolicy::Expanding); 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); // ------------------------------------------------------------ connect(d->thread, TQ_SIGNAL(signalImageLoaded(const LoadingDescription&, const DImg&)), this, TQ_SLOT(slotImageLoaded(const LoadingDescription&, const DImg&))); connect(d->thread, TQ_SIGNAL(signalLoadingProgress(const LoadingDescription&, float)), this, TQ_SLOT(slotLoadingProgress(const LoadingDescription&, float))); connect(d->cornerButton, TQ_SIGNAL(pressed()), this, TQ_SLOT(slotCornerButtonPressed())); connect(ThemeEngine::instance(), TQ_SIGNAL(signalThemeChanged()), this, TQ_SLOT(slotThemeChanged())); // ------------------------------------------------------------ slotReset(); } RawPreview::~RawPreview() { delete d; } void RawPreview::setPostProcessedImage(const DImg& image) { d->postProcessedImg = image; updateZoomAndSize(false); viewport()->setUpdatesEnabled(true); viewport()->update(); } DImg& RawPreview::postProcessedImage() const { return d->postProcessedImg; } DImg& RawPreview::demosaicedImage() const { return d->demosaicedImg; } void RawPreview::setDecodingSettings(const DRawDecoding& settings) { // Save post processing settings. d->settings = settings; // All post processing settings will be used after demosaicing. DRawDecoding demosaisedSettings = settings; demosaisedSettings.resetPostProcessingSettings(); d->loadingDesc = LoadingDescription(d->url.path(), demosaisedSettings); d->thread->load(d->loadingDesc, ManagedLoadSaveThread::LoadingPolicyFirstRemovePrevious); emit signalLoadingStarted(); } void RawPreview::cancelLoading() { d->thread->stopLoading(d->loadingDesc); } void RawPreview::slotLoadingProgress(const LoadingDescription& description, float progress) { if (description.filePath != d->loadingDesc.filePath) return; emit signalLoadingProgress(progress); } void RawPreview::slotImageLoaded(const LoadingDescription& description, const DImg& image) { if (description.filePath != d->loadingDesc.filePath) return; if (image.isNull()) { TQPixmap pix(visibleWidth(), visibleHeight()); pix.fill(ThemeEngine::instance()->baseColor()); TQPainter p(&pix); p.setPen(TQPen(ThemeEngine::instance()->textRegColor())); p.drawText(0, 0, pix.width(), pix.height(), TQt::AlignCenter|TQt::WordBreak, i18n("Cannot decode RAW image for\n\"%1\"") .arg(TQFileInfo(d->loadingDesc.filePath).fileName())); p.end(); // three copies - but the image is small setPostProcessedImage(DImg(pix.convertToImage())); emit signalLoadingFailed(); } else { d->demosaicedImg = image; emit signalDemosaicedImage(); // NOTE: we will apply all Raw post processing corrections into RawImport class. } } void RawPreview::slotThemeChanged() { setBackgroundColor(ThemeEngine::instance()->baseColor()); } void RawPreview::slotCornerButtonPressed() { if (d->panIconPopup) { d->panIconPopup->hide(); delete d->panIconPopup; d->panIconPopup = 0; } d->panIconPopup = new TDEPopupFrame(this); PanIconWidget *pan = new PanIconWidget(d->panIconPopup); pan->setImage(180, 120, postProcessedImage()); d->panIconPopup->setMainWidget(pan); TQRect r((int)(contentsX() / zoomFactor()), (int)(contentsY() / zoomFactor()), (int)(visibleWidth() / zoomFactor()), (int)(visibleHeight() / zoomFactor())); pan->setRegionSelection(r); pan->setMouseFocus(); connect(pan, TQ_SIGNAL(signalSelectionMoved(const TQRect&, bool)), this, TQ_SLOT(slotPanIconSelectionMoved(const TQRect&, bool))); connect(pan, TQ_SIGNAL(signalHiden()), this, TQ_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 RawPreview::slotPanIconHiden() { d->cornerButton->blockSignals(true); d->cornerButton->animateClick(); d->cornerButton->blockSignals(false); } void RawPreview::slotPanIconSelectionMoved(const TQRect& r, bool b) { setContentsPos((int)(r.x()*zoomFactor()), (int)(r.y()*zoomFactor())); if (b) { d->panIconPopup->hide(); delete d->panIconPopup; d->panIconPopup = 0; slotPanIconHiden(); } } void RawPreview::zoomFactorChanged(double zoom) { updateScrollBars(); if (horizontalScrollBar()->isVisible() || verticalScrollBar()->isVisible()) d->cornerButton->show(); else d->cornerButton->hide(); PreviewWidget::zoomFactorChanged(zoom); } void RawPreview::resizeEvent(TQResizeEvent* e) { if (!e) return; TQScrollView::resizeEvent(e); if (!d->loadingDesc.filePath.isEmpty()) d->cornerButton->hide(); updateZoomAndSize(false); } void RawPreview::updateZoomAndSize(bool alwaysFitToWindow) { // Set zoom for fit-in-window as minimum, but dont scale up images // that are smaller than the available space, only scale down. double zoom = calcAutoZoomFactor(ZoomInOnly); setZoomMin(zoom); setZoomMax(zoom*12.0); // Is currently the zoom factor set to fit to window? Then set it again to fit the new size. if (zoomFactor() < zoom || alwaysFitToWindow || zoomFactor() == d->currentFitWindowZoom) { setZoomFactor(zoom); } // store which zoom factor means it is fit to window d->currentFitWindowZoom = zoom; updateContentsSize(); } int RawPreview::previewWidth() { return d->postProcessedImg.width(); } int RawPreview::previewHeight() { return d->postProcessedImg.height(); } bool RawPreview::previewIsNull() { return d->postProcessedImg.isNull(); } void RawPreview::resetPreview() { d->postProcessedImg = DImg(); d->loadingDesc = LoadingDescription(); updateZoomAndSize(false); } void RawPreview::paintPreview(TQPixmap *pix, int sx, int sy, int sw, int sh) { DImg img = d->postProcessedImg.smoothScaleSection(sx, sy, sw, sh, tileSize(), tileSize()); TQPixmap pix2 = img.convertToPixmap(); bitBlt(pix, 0, 0, &pix2, 0, 0); } } // NameSpace Digikam