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/utilities/imageeditor/rawimport/rawpreview.cpp

337 lines
8.9 KiB

/* ============================================================
*
* 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 <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.
*
* ============================================================ */
// TQt includes.
#include <tqstring.h>
#include <tqpainter.h>
#include <tqtoolbutton.h>
#include <tqtooltip.h>
#include <tqpixmap.h>
#include <tqfileinfo.h>
// KDE includes.
#include <klocale.h>
#include <kcursor.h>
#include <kdatetbl.h>
#include <kiconloader.h>
// 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;
KPopupFrame *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, TQT_SIGNAL(signalImageLoaded(const LoadingDescription&, const DImg&)),
this, TQT_SLOT(slotImageLoaded(const LoadingDescription&, const DImg&)));
connect(d->thread, TQT_SIGNAL(signalLoadingProgress(const LoadingDescription&, float)),
this, TQT_SLOT(slotLoadingProgress(const LoadingDescription&, float)));
connect(d->cornerButton, TQT_SIGNAL(pressed()),
this, TQT_SLOT(slotCornerButtonPressed()));
connect(ThemeEngine::instance(), TQT_SIGNAL(signalThemeChanged()),
this, TQT_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\"")
.tqarg(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 KPopupFrame(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, TQT_SIGNAL(signalSelectionMoved(const TQRect&, bool)),
this, TQT_SLOT(slotPanIconSelectionMoved(const TQRect&, bool)));
connect(pan, TQT_SIGNAL(signalHiden()),
this, TQT_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