diff options
author | Michele Calgaro <[email protected]> | 2024-11-22 18:41:30 +0900 |
---|---|---|
committer | Michele Calgaro <[email protected]> | 2024-11-22 20:55:03 +0900 |
commit | 5bed6e4a4c916a97f8fe4d1b07f7eecf4d733b90 (patch) | |
tree | f89cc49efc9ca1d0e1579ecb079ee7e7088ff8c8 /src/libs/widgets | |
parent | 0bfbf616d9c1fd7abb1bd02732389ab35e5f8771 (diff) | |
download | digikam-5bed6e4a4c916a97f8fe4d1b07f7eecf4d733b90.tar.gz digikam-5bed6e4a4c916a97f8fe4d1b07f7eecf4d733b90.zip |
Rename 'digikam' folder to 'src'
Signed-off-by: Michele Calgaro <[email protected]>
(cherry picked from commit ee0d99607c14cb63d3ebdb3a970b508949fa8219)
Diffstat (limited to 'src/libs/widgets')
77 files changed, 14733 insertions, 0 deletions
diff --git a/src/libs/widgets/Makefile.am b/src/libs/widgets/Makefile.am new file mode 100644 index 00000000..699a4438 --- /dev/null +++ b/src/libs/widgets/Makefile.am @@ -0,0 +1,12 @@ +SUBDIRS = metadata imageplugins common iccprofiles + +noinst_LTLIBRARIES = libwidgets.la + +libwidgets_la_SOURCES = + +libwidgets_la_LDFLAGS = $(all_libraries) $(KDE_RPATH) $(LIB_TQT) -lDCOP $(LIB_TDECORE) $(LIB_TDEUI) -ltdefx $(LIB_TDEIO) -ltdetexteditor + +libwidgets_la_LIBADD = $(top_builddir)/src/libs/widgets/metadata/libmetadatawidgets.la \ + $(top_builddir)/src/libs/widgets/iccprofiles/libiccprofileswidgets.la \ + $(top_builddir)/src/libs/widgets/imageplugins/libimagepluginswidgets.la \ + $(top_builddir)/src/libs/widgets/common/libcommonwidgets.la diff --git a/src/libs/widgets/common/Makefile.am b/src/libs/widgets/common/Makefile.am new file mode 100644 index 00000000..287f60d8 --- /dev/null +++ b/src/libs/widgets/common/Makefile.am @@ -0,0 +1,25 @@ +METASOURCES = AUTO + +noinst_LTLIBRARIES = libcommonwidgets.la + +libcommonwidgets_la_SOURCES = histogramwidget.cpp colorgradientwidget.cpp curveswidget.cpp dlogoaction.cpp \ + sidebar.cpp squeezedcombobox.cpp filesaveoptionsbox.cpp dpopupmenu.cpp \ + statuszoombar.cpp statusnavigatebar.cpp statusprogressbar.cpp searchtextbar.cpp \ + dcursortracker.cpp paniconwidget.cpp previewwidget.cpp splashscreen.cpp statusled.cpp + +libcommonwidgets_la_LDFLAGS = $(all_libraries) $(KDE_RPATH) $(LIB_TQT) -lDCOP $(LIB_TDECORE) $(LIB_TDEUI) -ltdefx $(LIB_TDEIO) -ltdetexteditor + +INCLUDES = -I$(top_srcdir)/src/libs/histogram \ + -I$(top_srcdir)/src/libs/curves \ + -I$(top_srcdir)/src/libs/dimg \ + -I$(top_srcdir)/src/libs/dimg/loaders \ + -I$(top_srcdir)/src/digikam \ + $(LIBKDCRAW_CFLAGS) \ + $(all_includes) + + +digikaminclude_HEADERS = histogramwidget.h colorgradientwidget.h curveswidget.h sidebar.h dlogoaction.h \ + squeezedcombobox.h dpopupmenu.h statuszoombar.h statusnavigatebar.h searchtextbar.h \ + statusprogressbar.h dcursortracker.h paniconwidget.h previewwidget.h statusled.h + +digikamincludedir = $(includedir)/digikam diff --git a/src/libs/widgets/common/colorgradientwidget.cpp b/src/libs/widgets/common/colorgradientwidget.cpp new file mode 100644 index 00000000..df4c96ca --- /dev/null +++ b/src/libs/widgets/common/colorgradientwidget.cpp @@ -0,0 +1,161 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-07-28 + * Description : a color gradient widget + * + * Copyright (C) 2004-2007 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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqimage.h> +#include <tqpainter.h> +#include <tqdrawutil.h> + +// KDE includes. + +#include <kimageeffect.h> + +// Local includes. + +#include "colorgradientwidget.h" +#include "colorgradientwidget.moc" + +namespace Digikam +{ + +class ColorGradientWidgetPriv +{ + +public: + + ColorGradientWidgetPriv(){} + + int orientation; + + TQColor color1; + TQColor color2; +}; + +ColorGradientWidget::ColorGradientWidget(int o, int size, TQWidget *parent) + : TQFrame(parent, 0, TQt::WDestructiveClose) +{ + d = new ColorGradientWidgetPriv; + d->orientation = o; + + setFrameStyle(TQFrame::Box|TQFrame::Plain); + setLineWidth(1); + + if ( d->orientation ==TQt::Horizontal ) + setFixedHeight( size ); + else + setFixedWidth( size ); + + d->color1.setRgb( 0, 0, 0 ); + d->color2.setRgb( 255, 255, 255 ); +} + +ColorGradientWidget::~ColorGradientWidget() +{ + delete d; +} + +void ColorGradientWidget::setColors( const TQColor &col1, const TQColor &col2 ) +{ + d->color1 = col1; + d->color2 = col2; + update(); +} + +void ColorGradientWidget::drawContents(TQPainter *p) +{ + TQImage image(contentsRect().width(), contentsRect().height(), 32); + + TQColor col, color1, color2; + float scale; + + // Widget is disable : drawing grayed frame. + if ( !isEnabled() ) + { + color1 = palette().disabled().foreground(); + color2 = palette().disabled().background(); + } + else + { + color1 = d->color1; + color2 = d->color2; + } + + int redDiff = color2.red() - color1.red(); + int greenDiff = color2.green() - color1.green(); + int blueDiff = color2.blue() - color1.blue(); + + if ( d->orientation ==TQt::Vertical ) + { + for ( int y = 0; y < image.height(); y++ ) + { + scale = 1.0 * y / image.height(); + col.setRgb( color1.red() + int(redDiff * scale), + color1.green() + int(greenDiff * scale), + color1.blue() + int(blueDiff * scale) ); + + unsigned int *p = (uint *) image.scanLine( y ); + + for ( int x = 0; x < image.width(); x++ ) + *p++ = col.rgb(); + } + } + else + { + unsigned int *p = (uint *) image.scanLine( 0 ); + + for ( int x = 0; x < image.width(); x++ ) + { + scale = 1.0 * x / image.width(); + col.setRgb( color1.red() + int(redDiff * scale), + color1.green() + int(greenDiff * scale), + color1.blue() + int(blueDiff * scale) ); + *p++ = col.rgb(); + } + + for ( int y = 1; y < image.height(); y++ ) + { + memcpy( image.scanLine( y ), image.scanLine( y - 1), + sizeof( unsigned int ) * image.width() ); + } + } + + const int psize = 256; + TQColor ditherPalette[psize]; + + for ( int s = 0; s < psize; s++ ) + { + ditherPalette[s].setRgb( color1.red() + redDiff * s / psize, + color1.green() + greenDiff * s / psize, + color1.blue() + blueDiff * s / psize ); + } + + KImageEffect::dither(image, ditherPalette, psize); + + TQPixmap pm; + pm.convertFromImage(image); + p->drawPixmap(contentsRect(), pm); +} + +} // namespace Digikam + diff --git a/src/libs/widgets/common/colorgradientwidget.h b/src/libs/widgets/common/colorgradientwidget.h new file mode 100644 index 00000000..aafc3df6 --- /dev/null +++ b/src/libs/widgets/common/colorgradientwidget.h @@ -0,0 +1,73 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-07-28 + * Description : a color gradient widget + * + * Copyright (C) 2004-2007 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. + * + * ============================================================ */ + +#ifndef COLORGRADIENTWIDGET_H +#define COLORGRADIENTWIDGET_H + +// KDE includes. + +#include <tqframe.h> +#include <tqcolor.h> + +// Local includes. + +#include "digikam_export.h" + +namespace Digikam +{ + +class ColorGradientWidgetPriv; + +class DIGIKAM_EXPORT ColorGradientWidget : public TQFrame +{ +TQ_OBJECT + + +public: + + enum Orientation + { + Horizontal=0, + Vertical + }; + +public: + + ColorGradientWidget( int o, int size, TQWidget *parent=0 ); + + ~ColorGradientWidget(); + + void setColors( const TQColor &col1, const TQColor &col2 ); + +protected: + + void drawContents(TQPainter *); + +private: + + ColorGradientWidgetPriv* d; +}; + +} // namespace Digikam + +#endif /* COLORGRADIENTWIDGET_H */ diff --git a/src/libs/widgets/common/curveswidget.cpp b/src/libs/widgets/common/curveswidget.cpp new file mode 100644 index 00000000..281aecc9 --- /dev/null +++ b/src/libs/widgets/common/curveswidget.cpp @@ -0,0 +1,838 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-12-01 + * Description : a widget to draw histogram curves + * + * 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. + * + * ============================================================ */ + +#define CLAMP(x,l,u) ((x)<(l)?(l):((x)>(u)?(u):(x))) + +// C++ includes. + +#include <cmath> +#include <cstdlib> + +// TQt includes. + +#include <tqpixmap.h> +#include <tqpainter.h> +#include <tqpoint.h> +#include <tqpen.h> +#include <tqevent.h> +#include <tqtimer.h> +#include <tqrect.h> +#include <tqcolor.h> +#include <tqfont.h> +#include <tqfontmetrics.h> + +// KDE includes. + +#include <kcursor.h> +#include <tdelocale.h> + +// Digikam includes. + +#include "ddebug.h" +#include "imagehistogram.h" +#include "imagecurves.h" + +// Local includes. + +#include "curveswidget.h" +#include "curveswidget.moc" + +namespace Digikam +{ + +class CurvesWidgetPriv +{ +public: + + enum RepaintType + { + HistogramDataLoading = 0, // Image Data loading in progress. + HistogramNone, // No current histogram values calculation. + HistogramStarted, // Histogram values calculation started. + HistogramCompleted, // Histogram values calculation completed. + HistogramFailed // Histogram values calculation failed. + }; + + CurvesWidgetPriv() + { + blinkTimer = 0; + curves = 0; + grabPoint = -1; + last = 0; + guideVisible = false; + xMouseOver = -1; + yMouseOver = -1; + clearFlag = HistogramNone; + pos = 0; + } + + int clearFlag; // Clear drawing zone with message. + int leftMost; + int rightMost; + int grabPoint; + int last; + int xMouseOver; + int yMouseOver; + int pos; // Position of animation during loading/calculation. + + bool sixteenBits; + bool readOnlyMode; + bool guideVisible; + + DColor colorGuide; + + TQTimer *blinkTimer; + + ImageCurves *curves; // Curves data instance. + +}; + +CurvesWidget::CurvesWidget(int w, int h, TQWidget *parent, bool readOnly) + : TQWidget(parent, 0, TQt::WDestructiveClose) +{ + d = new CurvesWidgetPriv; + + setup(w, h, readOnly); +} + +CurvesWidget::CurvesWidget(int w, int h, + uchar *i_data, uint i_w, uint i_h, bool i_sixteenBits, + TQWidget *parent, bool readOnly) + : TQWidget(parent, 0, TQt::WDestructiveClose) +{ + d = new CurvesWidgetPriv; + + setup(w, h, readOnly); + updateData(i_data, i_w, i_h, i_sixteenBits); +} + +CurvesWidget::~CurvesWidget() +{ + d->blinkTimer->stop(); + + if (m_imageHistogram) + delete m_imageHistogram; + + if (d->curves) + delete d->curves; + + delete d; +} + +void CurvesWidget::setup(int w, int h, bool readOnly) +{ + d->readOnlyMode = readOnly; + d->curves = new ImageCurves(true); + m_channelType = ValueHistogram; + m_scaleType = LogScaleHistogram; + m_imageHistogram = 0; + + setMouseTracking(true); + setPaletteBackgroundColor(colorGroup().background()); + setMinimumSize(w, h); + + d->blinkTimer = new TQTimer( this ); + + connect(d->blinkTimer, TQ_SIGNAL(timeout()), + this, TQ_SLOT(slotBlinkTimerDone())); +} + +void CurvesWidget::updateData(uchar *i_data, uint i_w, uint i_h, bool i_sixteenBits) +{ + stopHistogramComputation(); + + d->sixteenBits = i_sixteenBits; + + // Remove old histogram data from memory. + if (m_imageHistogram) + delete m_imageHistogram; + + // Calc new histogram data + m_imageHistogram = new ImageHistogram(i_data, i_w, i_h, i_sixteenBits, this); + + if (d->curves) + delete d->curves; + + d->curves = new ImageCurves(i_sixteenBits); + reset(); +} + +void CurvesWidget::reset() +{ + if (d->curves) + d->curves->curvesReset(); + + d->grabPoint = -1; + d->guideVisible = false; + repaint(false); +} + +ImageCurves* CurvesWidget::curves() const +{ + return d->curves; +} + +void CurvesWidget::setDataLoading() +{ + if (d->clearFlag != CurvesWidgetPriv::HistogramDataLoading) + { + setCursor(KCursor::waitCursor()); + d->clearFlag = CurvesWidgetPriv::HistogramDataLoading; + d->pos = 0; + d->blinkTimer->start(100); + } +} + +void CurvesWidget::setLoadingFailed() +{ + d->clearFlag = CurvesWidgetPriv::HistogramFailed; + d->pos = 0; + d->blinkTimer->stop(); + repaint(false); + setCursor(KCursor::arrowCursor()); +} + +void CurvesWidget::setCurveGuide(const DColor& color) +{ + d->guideVisible = true; + d->colorGuide = color; + repaint(false); +} + +void CurvesWidget::curveTypeChanged() +{ + switch (d->curves->getCurveType(m_channelType)) + { + case ImageCurves::CURVE_SMOOTH: + + // pick representative points from the curve and make them control points + + for (int i = 0; i <= 8; i++) + { + int index = CLAMP(i * m_imageHistogram->getHistogramSegment()/8, + 0, m_imageHistogram->getHistogramSegment()-1); + + d->curves->setCurvePoint( m_channelType, + i * 2, TQPoint(index, + d->curves->getCurveValue(m_channelType, + index)) ); + } + + d->curves->curvesCalculateCurve(m_channelType); + break; + + case ImageCurves::CURVE_FREE: + break; + } + + repaint(false); + emit signalCurvesChanged(); +} + +void CurvesWidget::customEvent(TQCustomEvent *event) +{ + if (!event) return; + + ImageHistogram::EventData *ed = (ImageHistogram::EventData*) event->data(); + + if (!ed) return; + + if (ed->starting) + { + setCursor(KCursor::waitCursor()); + d->clearFlag = CurvesWidgetPriv::HistogramStarted; + d->blinkTimer->start(200); + repaint(false); + } + else + { + if (ed->success) + { + // Repaint histogram + d->clearFlag = CurvesWidgetPriv::HistogramCompleted; + d->blinkTimer->stop(); + repaint(false); + setCursor(KCursor::arrowCursor()); + } + else + { + d->clearFlag = CurvesWidgetPriv::HistogramFailed; + d->blinkTimer->stop(); + repaint(false); + setCursor(KCursor::arrowCursor()); + emit signalHistogramComputationFailed(); + } + } + + delete ed; +} + +void CurvesWidget::stopHistogramComputation() +{ + if (m_imageHistogram) + m_imageHistogram->stopCalcHistogramValues(); + + d->blinkTimer->stop(); + d->pos = 0; +} + +void CurvesWidget::slotBlinkTimerDone() +{ + repaint(false); + d->blinkTimer->start(200); +} + +void CurvesWidget::paintEvent(TQPaintEvent*) +{ + if (d->clearFlag == CurvesWidgetPriv::HistogramDataLoading || + d->clearFlag == CurvesWidgetPriv::HistogramStarted) + { + // In first, we draw an animation. + + int asize = 24; + TQPixmap anim(asize, asize); + TQPainter p2; + p2.begin(&anim, this); + p2.fillRect(0, 0, asize, asize, palette().active().background()); + p2.translate(asize/2, asize/2); + + d->pos = (d->pos + 10) % 360; + p2.setPen(TQPen(palette().active().text())); + p2.rotate(d->pos); + for ( int i=0 ; i<12 ; i++ ) + { + p2.drawLine(asize/2-5, 0, asize/2-2, 0); + p2.rotate(30); + } + p2.end(); + + // ... and we render busy text. + + TQPixmap pm(size()); + TQPainter p1; + p1.begin(&pm, this); + p1.fillRect(0, 0, width(), height(), palette().active().background()); + p1.setPen(TQPen(palette().active().foreground(), 1, TQt::SolidLine)); + p1.drawRect(0, 0, width(), height()); + p1.drawPixmap(width()/2 - asize /2, asize, anim); + p1.setPen(TQPen(palette().active().text())); + + if (d->clearFlag == CurvesWidgetPriv::HistogramDataLoading) + p1.drawText(0, 0, width(), height(), TQt::AlignCenter, + i18n("Loading image...")); + else + p1.drawText(0, 0, width(), height(), TQt::AlignCenter, + i18n("Histogram calculation...")); + + p1.end(); + bitBlt(this, 0, 0, &pm); + return; + } + + if (d->clearFlag == CurvesWidgetPriv::HistogramFailed) + { + TQPixmap pm(size()); + TQPainter p1; + p1.begin(&pm, this); + p1.fillRect(0, 0, width(), height(), palette().active().background()); + p1.setPen(TQPen(palette().active().foreground(), 1, TQt::SolidLine)); + p1.drawRect(0, 0, width(), height()); + p1.setPen(TQPen(palette().active().text())); + p1.drawText(0, 0, width(), height(), TQt::AlignCenter, + i18n("Histogram\ncalculation\nfailed.")); + p1.end(); + bitBlt(this, 0, 0, &pm); + return; + } + + if (!m_imageHistogram) return; + + int x, y; + int wWidth = width(); + int wHeight = height(); + double max; + class ImageHistogram *histogram = m_imageHistogram; + + x = 0; + y = 0; + max = 0.0; + + switch(m_channelType) + { + case CurvesWidget::GreenChannelHistogram: // Green channel. + max = histogram->getMaximum(ImageHistogram::GreenChannel); + break; + + case CurvesWidget::BlueChannelHistogram: // Blue channel. + max = histogram->getMaximum(ImageHistogram::BlueChannel); + break; + + case CurvesWidget::RedChannelHistogram: // Red channel. + max = histogram->getMaximum(ImageHistogram::RedChannel); + break; + + case CurvesWidget::AlphaChannelHistogram: // Alpha channel. + max = histogram->getMaximum(ImageHistogram::AlphaChannel); + break; + + case CurvesWidget::ValueHistogram: // Luminosity. + max = histogram->getMaximum(ImageHistogram::ValueChannel); + break; + } + + switch (m_scaleType) + { + case CurvesWidget::LinScaleHistogram: + break; + + case CurvesWidget::LogScaleHistogram: + if (max > 0.0) + max = log (max); + else + max = 1.0; + break; + } + + // Drawing selection or all histogram values. + // A TQPixmap is used for enable the double buffering. + + TQPixmap pm(size()); + TQPainter p1; + p1.begin(&pm, this); + + int curvePrevVal = 0; + + for (x = 0 ; x < wWidth ; x++) + { + double value = 0.0; + int i, j; + int curveVal; + + i = (x * histogram->getHistogramSegment()) / wWidth; + j = ((x + 1) * histogram->getHistogramSegment()) / wWidth; + + curveVal = d->curves->getCurveValue(m_channelType, i); + + do + { + double v = 0.0; + + switch(m_channelType) + { + case CurvesWidget::RedChannelHistogram: // Red channel. + v = histogram->getValue(ImageHistogram::RedChannel, i++); + break; + + case CurvesWidget::GreenChannelHistogram: // Green channel. + v = histogram->getValue(ImageHistogram::GreenChannel, i++); + break; + + case CurvesWidget::BlueChannelHistogram: // Blue channel. + v = histogram->getValue(ImageHistogram::BlueChannel, i++); + break; + + case CurvesWidget::AlphaChannelHistogram: // Alpha channel. + v = histogram->getValue(ImageHistogram::AlphaChannel, i++); + break; + + case CurvesWidget::ValueHistogram: // Luminosity. + v = histogram->getValue(ImageHistogram::ValueChannel, i++); + break; + } + + if (v > value) + value = v; + } + while (i < j); + + switch (m_scaleType) + { + case CurvesWidget::LinScaleHistogram: + y = (int) ((wHeight * value) / max); + break; + + case CurvesWidget::LogScaleHistogram: + if (value <= 0.0) value = 1.0; + y = (int) ((wHeight * log (value)) / max); + break; + + default: + y = 0; + break; + } + + // Drawing histogram + + p1.setPen(TQPen(palette().active().foreground(), 1, TQt::SolidLine)); + p1.drawLine(x, wHeight, x, wHeight - y); + p1.setPen(TQPen(palette().active().background(), 1, TQt::SolidLine)); + p1.drawLine(x, wHeight - y, x, 0); + + // Drawing curves. + + p1.setPen(TQPen(palette().active().link(), 2, TQt::SolidLine)); + p1.drawLine(x - 1, wHeight - ((curvePrevVal * wHeight) / histogram->getHistogramSegment()), + x, wHeight - ((curveVal * wHeight) / histogram->getHistogramSegment())); + + curvePrevVal = curveVal; + } + + // Drawing curves points. + + if (!d->readOnlyMode && d->curves->getCurveType(m_channelType) == ImageCurves::CURVE_SMOOTH) + { + p1.setPen(TQPen(TQt::red, 3, TQt::SolidLine)); + + for (int p = 0 ; p < 17 ; p++) + { + TQPoint curvePoint = d->curves->getCurvePoint(m_channelType, p); + + if (curvePoint.x() >= 0) + { + p1.drawEllipse( ((curvePoint.x() * wWidth) / histogram->getHistogramSegment()) - 2, + wHeight - 2 - ((curvePoint.y() * wHeight) / histogram->getHistogramSegment()), + 4, 4 ); + } + } + } + + // Drawing black/middle/highlight tone grid separators. + + p1.setPen(TQPen(palette().active().base(), 1, TQt::SolidLine)); + p1.drawLine(wWidth/4, 0, wWidth/4, wHeight); + p1.drawLine(wWidth/2, 0, wWidth/2, wHeight); + p1.drawLine(3*wWidth/4, 0, 3*wWidth/4, wHeight); + p1.drawLine(0, wHeight/4, wWidth, wHeight/4); + p1.drawLine(0, wHeight/2, wWidth, wHeight/2); + p1.drawLine(0, 3*wHeight/4, wWidth, 3*wHeight/4); + + // Drawing X,Y point position dragged by mouse over widget. + + p1.setPen(TQPen(TQt::red, 1, TQt::DotLine)); + + if (d->xMouseOver != -1 && d->yMouseOver != -1) + { + TQString string = i18n("x:%1\ny:%2").arg(d->xMouseOver).arg(d->yMouseOver); + TQFontMetrics fontMt(string); + TQRect rect = fontMt.boundingRect(0, 0, wWidth, wHeight, 0, string); + rect.moveRight(wWidth); + rect.moveBottom(wHeight); + p1.drawText(rect, TQt::AlignLeft||TQt::AlignTop, string); + } + + // Drawing color guide. + + int guidePos; + + if (d->guideVisible) + { + switch(m_channelType) + { + case CurvesWidget::RedChannelHistogram: + guidePos = d->colorGuide.red(); + break; + + case CurvesWidget::GreenChannelHistogram: + guidePos = d->colorGuide.green(); + break; + + case CurvesWidget::BlueChannelHistogram: + guidePos = d->colorGuide.blue(); + break; + + case CurvesWidget::ValueHistogram: + guidePos = TQMAX(TQMAX(d->colorGuide.red(), d->colorGuide.green()), d->colorGuide.blue()); + break; + + default: // Alpha. + guidePos = -1; + break; + } + + if (guidePos != -1) + { + int xGuide = (guidePos * wWidth) / histogram->getHistogramSegment(); + p1.drawLine(xGuide, 0, xGuide, wHeight); + + TQString string = i18n("x:%1").arg(guidePos); + TQFontMetrics fontMt( string ); + TQRect rect = fontMt.boundingRect(0, 0, wWidth, wHeight, 0, string); + p1.setPen(TQPen(TQt::red, 1, TQt::SolidLine)); + rect.moveTop(1); + + if (xGuide < wWidth/2) + { + rect.moveLeft(xGuide); + p1.fillRect(rect, TQBrush(TQColor(250, 250, 255))); + p1.drawRect(rect); + rect.moveLeft(xGuide+3); + p1.drawText(rect, TQt::AlignLeft, string); + } + else + { + rect.moveRight(xGuide); + p1.fillRect(rect, TQBrush(TQColor(250, 250, 255))); + p1.drawRect(rect); + rect.moveRight(xGuide-3); + p1.drawText(rect, TQt::AlignRight, string); + } + } + } + + // Drawing frame. + + p1.setPen(TQPen(palette().active().foreground(), 1, TQt::SolidLine)); + p1.drawRect(0, 0, width(), height()); + + p1.end(); + bitBlt(this, 0, 0, &pm); +} + +void CurvesWidget::mousePressEvent(TQMouseEvent *e) +{ + if (d->readOnlyMode || !m_imageHistogram) return; + + int i; + int closest_point; + int distance; + + if (e->button() != TQt::LeftButton || d->clearFlag == CurvesWidgetPriv::HistogramStarted) + return; + + int x = CLAMP((int)(e->pos().x() * + ((float)(m_imageHistogram->getHistogramSegment()-1) / (float)width())), + 0, m_imageHistogram->getHistogramSegment()-1 ); + int y = CLAMP((int)(e->pos().y() * + ((float)(m_imageHistogram->getHistogramSegment()-1) / (float)height())), + 0, m_imageHistogram->getHistogramSegment()-1 ); + + distance = 65536; + + for (i = 0, closest_point = 0 ; i < 17 ; i++) + { + int xcurvepoint = d->curves->getCurvePointX(m_channelType, i); + + if (xcurvepoint != -1) + { + if (abs (x - xcurvepoint) < distance) + { + distance = abs (x - xcurvepoint); + closest_point = i; + } + } + } + + int delta = m_imageHistogram->getHistogramSegment()/16; + if (distance > 8) + closest_point = (x + delta/2) / delta; + + setCursor(KCursor::crossCursor()); + + switch(d->curves->getCurveType(m_channelType)) + { + case ImageCurves::CURVE_SMOOTH: + { + // Determine the leftmost and rightmost points. + + d->leftMost = -1; + + for (i = closest_point - 1 ; i >= 0 ; i--) + { + if (d->curves->getCurvePointX(m_channelType, i) != -1) + { + d->leftMost = d->curves->getCurvePointX(m_channelType, i); + break; + } + } + + d->rightMost = m_imageHistogram->getHistogramSegment(); + + for (i = closest_point + 1 ; i < 17 ; i++) + { + if (d->curves->getCurvePointX(m_channelType, i) != -1) + { + d->rightMost = d->curves->getCurvePointX(m_channelType, i); + break; + } + } + + d->grabPoint = closest_point; + d->curves->setCurvePoint(m_channelType, d->grabPoint, + TQPoint(x, m_imageHistogram->getHistogramSegment() - y)); + + break; + } + + case ImageCurves::CURVE_FREE: + { + + d->curves->setCurveValue(m_channelType, x, m_imageHistogram->getHistogramSegment() - y); + d->grabPoint = x; + d->last = y; + break; + } + } + + d->curves->curvesCalculateCurve(m_channelType); + repaint(false); +} + +void CurvesWidget::mouseReleaseEvent(TQMouseEvent *e) +{ + if (d->readOnlyMode || !m_imageHistogram) return; + + if (e->button() != TQt::LeftButton || d->clearFlag == CurvesWidgetPriv::HistogramStarted) + return; + + setCursor(KCursor::arrowCursor()); + d->grabPoint = -1; + d->curves->curvesCalculateCurve(m_channelType); + repaint(false); + emit signalCurvesChanged(); +} + +void CurvesWidget::mouseMoveEvent(TQMouseEvent *e) +{ + if (d->readOnlyMode || !m_imageHistogram) return; + + int i; + int closest_point; + int x1, x2, y1, y2; + int distance; + + if (d->clearFlag == CurvesWidgetPriv::HistogramStarted) + return; + + int x = CLAMP( (int)(e->pos().x()*((float)(m_imageHistogram->getHistogramSegment()-1)/(float)width())), + 0, m_imageHistogram->getHistogramSegment()-1 ); + int y = CLAMP( (int)(e->pos().y()*((float)(m_imageHistogram->getHistogramSegment()-1)/(float)height())), + 0, m_imageHistogram->getHistogramSegment()-1 ); + + distance = 65536; + + for (i = 0, closest_point = 0 ; i < 17 ; i++) + { + if (d->curves->getCurvePointX(m_channelType, i) != -1) + { + if (abs (x - d->curves->getCurvePointX(m_channelType, i)) < distance) + { + distance = abs (x - d->curves->getCurvePointX(m_channelType, i)); + closest_point = i; + } + } + } + + int delta = m_imageHistogram->getHistogramSegment()/16; + if (distance > 8) + closest_point = (x + delta/2) / delta; + + switch ( d->curves->getCurveType(m_channelType) ) + { + case ImageCurves::CURVE_SMOOTH: + { + if (d->grabPoint == -1) // If no point is grabbed... + { + if ( d->curves->getCurvePointX(m_channelType, closest_point) != -1 ) + setCursor(KCursor::arrowCursor()); + else + setCursor(KCursor::crossCursor()); + } + else // Else, drag the grabbed point + { + setCursor(KCursor::crossCursor()); + + d->curves->setCurvePointX(m_channelType, d->grabPoint, -1); + + if (x > d->leftMost && x < d->rightMost) + { + closest_point = (x + delta/2) / delta; + + if (d->curves->getCurvePointX(m_channelType, closest_point) == -1) + d->grabPoint = closest_point; + + d->curves->setCurvePoint(m_channelType, d->grabPoint, + TQPoint(x, m_imageHistogram->getHistogramSegment()-1 - y)); + } + + d->curves->curvesCalculateCurve(m_channelType); + emit signalCurvesChanged(); + } + + break; + } + + case ImageCurves::CURVE_FREE: + { + if (d->grabPoint != -1) + { + if (d->grabPoint > x) + { + x1 = x; + x2 = d->grabPoint; + y1 = y; + y2 = d->last; + } + else + { + x1 = d->grabPoint; + x2 = x; + y1 = d->last; + y2 = y; + } + + if (x2 != x1) + { + for (i = x1 ; i <= x2 ; i++) + d->curves->setCurveValue(m_channelType, i, + m_imageHistogram->getHistogramSegment()-1 - (y1 + ((y2 - y1) * (i - x1)) / (x2 - x1))); + } + else + { + d->curves->setCurveValue(m_channelType, x, m_imageHistogram->getHistogramSegment()-1 - y); + } + + d->grabPoint = x; + d->last = y; + } + + emit signalCurvesChanged(); + + break; + } + } + + d->xMouseOver = x; + d->yMouseOver = m_imageHistogram->getHistogramSegment()-1 - y; + emit signalMouseMoved(d->xMouseOver, d->yMouseOver); + repaint(false); +} + +void CurvesWidget::leaveEvent(TQEvent*) +{ + d->xMouseOver = -1; + d->yMouseOver = -1; + emit signalMouseMoved(d->xMouseOver, d->yMouseOver); + repaint(false); +} + +} // NameSpace Digikam diff --git a/src/libs/widgets/common/curveswidget.h b/src/libs/widgets/common/curveswidget.h new file mode 100644 index 00000000..c9cfed4a --- /dev/null +++ b/src/libs/widgets/common/curveswidget.h @@ -0,0 +1,132 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-12-01 + * Description : a widget to draw histogram curves + * + * 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. + * + * ============================================================ */ + +#ifndef CURVESWIDGET_H +#define CURVESWIDGET_H + +// TQt includes. + +#include <tqwidget.h> + +// Local includes. + +#include "dcolor.h" +#include "digikam_export.h" + +class TQCustomEvent; + +namespace Digikam +{ + +class ImageHistogram; +class ImageCurves; +class CurvesWidgetPriv; + +class DIGIKAM_EXPORT CurvesWidget : public TQWidget +{ +TQ_OBJECT + + +public: + + enum HistogramType + { + ValueHistogram = 0, // Luminosity. + RedChannelHistogram, // Red channel. + GreenChannelHistogram, // Green channel. + BlueChannelHistogram, // Blue channel. + AlphaChannelHistogram, // Alpha channel. + }; + + enum HistogramScale + { + LinScaleHistogram=0, // Linear scale. + LogScaleHistogram // Logarithmic scale. + }; + +public: + + CurvesWidget(int w, int h, TQWidget *parent, bool readOnly=false); + + CurvesWidget(int w, int h, // Widget size. + uchar *i_data, uint i_w, uint i_h, // Full image info. + bool i_sixteenBits, // 8 or 16 bits image. + TQWidget *parent=0, // Parent widget instance. + bool readOnly=false); // If true : widget with full edition mode capabilities. + // If false : display curve data only without edition. + + ~CurvesWidget(); + + void setup(int w, int h, bool readOnly); + void updateData(uchar *i_data, uint i_w, uint i_h, bool i_sixteenBits); + + // Stop current histogram computations. + void stopHistogramComputation(); + + void setDataLoading(); + void setLoadingFailed(); + + void reset(); + void curveTypeChanged(); + void setCurveGuide(const DColor& color); + + ImageCurves* curves() const; + +public: + + int m_channelType; // Channel type to draw. + int m_scaleType; // Scale to use for drawing. + + ImageHistogram *m_imageHistogram; + +signals: + + void signalMouseMoved( int x, int y ); + void signalCurvesChanged(); + void signalHistogramComputationDone(); + void signalHistogramComputationFailed(); + +protected slots: + + void slotBlinkTimerDone(); + +protected: + + void paintEvent(TQPaintEvent*); + void mousePressEvent(TQMouseEvent*); + void mouseReleaseEvent(TQMouseEvent*); + void mouseMoveEvent(TQMouseEvent*); + void leaveEvent(TQEvent*); + +private: + + void customEvent(TQCustomEvent *event); + +private: + + CurvesWidgetPriv* d; +}; + +} // NameSpace Digikam + +#endif /* CURVESWIDGET_H */ diff --git a/src/libs/widgets/common/dcursortracker.cpp b/src/libs/widgets/common/dcursortracker.cpp new file mode 100644 index 00000000..bb9490cb --- /dev/null +++ b/src/libs/widgets/common/dcursortracker.cpp @@ -0,0 +1,109 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2007-23-03 + * Description : a tool tip widget witch follow cursor movements + * Tool tip content is displayed without delay. + * + * Copyright (C) 2007 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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqevent.h> +#include <tqtooltip.h> + +// Local includes. + +#include "dcursortracker.h" + +namespace Digikam +{ + +DCursorTracker::DCursorTracker(const TQString& txt, TQWidget *parent) + : TQLabel(txt, 0, "", WX11BypassWM) +{ + parent->setMouseTracking(true); + parent->installEventFilter(this); + setEnable(true); +} + +/** + * Overload to make sure the widget size is correct + */ +void DCursorTracker::setText(const TQString& txt) +{ + TQLabel::setText(txt); + adjustSize(); +} + +void DCursorTracker::setEnable(bool b) +{ + m_enable = b; +} + +bool DCursorTracker::eventFilter(TQObject *object, TQEvent *e) +{ + TQWidget *widget = static_cast<TQWidget*>(object); + + switch (e->type()) + { + case TQEvent::MouseMove: + { + TQMouseEvent *event = static_cast<TQMouseEvent*>(e); + if (m_enable && (widget->rect().contains(event->pos()) || + (event->stateAfter() & TQt::LeftButton))) + { + show(); + TQPoint p = widget->mapToGlobal(TQPoint(widget->width()/2, 0)); + move(p.x()-width()/2, p.y()-height()); + } + else + { + hide(); + } + break; + } + + case TQEvent::MouseButtonRelease: + { + TQMouseEvent* event = static_cast<TQMouseEvent*>(e); + if ( !widget->rect().contains(event->pos()) ) + { + hide(); + } + break; + } + + default: + break; + } + + return false; +} + + +DTipTracker::DTipTracker(const TQString& txt, TQWidget *parent) + : DCursorTracker(txt, parent) +{ + setPalette(TQToolTip::palette()); + setFrameStyle(TQFrame::Plain | TQFrame::Box); + setLineWidth(1); + setAlignment(AlignAuto | AlignTop); +} + +} // namespace Digikam diff --git a/src/libs/widgets/common/dcursortracker.h b/src/libs/widgets/common/dcursortracker.h new file mode 100644 index 00000000..33d322e1 --- /dev/null +++ b/src/libs/widgets/common/dcursortracker.h @@ -0,0 +1,76 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2007-23-03 + * Description : a tool tip widget witch follow cursor movements + * Tool tip content is displayed without delay. + * + * Copyright (C) 2007 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. + * + * ============================================================ */ + +#ifndef DCURSOR_TRACKER_H +#define DCURSOR_TRACKER_H + +// TQt includes. + +#include <tqlabel.h> + +// Local includes. + +#include "digikam_export.h" + +namespace Digikam +{ + +/** + * This class implements a decoration-less window which will follow the cursor + * when it's over a specified widget. + */ +class DIGIKAM_EXPORT DCursorTracker : public TQLabel +{ + +public: + + DCursorTracker(const TQString& txt, TQWidget *parent); + + void setText(const TQString& txt); + void setEnable(bool b); + +protected: + + bool eventFilter(TQObject*, TQEvent*); + +private: + + bool m_enable; +}; + + +/** + * A specialized CursorTracker class, which looks like a tool tip. + */ +class DTipTracker : public DCursorTracker +{ + +public: + + DTipTracker(const TQString& txt, TQWidget *parent); +}; + +} // namespace Digikam + +#endif /* DCURSOR_TRACKER_H */ diff --git a/src/libs/widgets/common/dlogoaction.cpp b/src/libs/widgets/common/dlogoaction.cpp new file mode 100644 index 00000000..60cfd77f --- /dev/null +++ b/src/libs/widgets/common/dlogoaction.cpp @@ -0,0 +1,96 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2007-27-08 + * Description : an tool bar action object to display logo + * + * Copyright (C) 2007-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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqtooltip.h> +#include <tqpixmap.h> + +// KDE includes. + +#include <kurllabel.h> +#include <tdetoolbar.h> +#include <kiconloader.h> +#include <tdeapplication.h> +#include <kstandarddirs.h> +#include <tdelocale.h> + +// Local includes. + +#include "daboutdata.h" +#include "dlogoaction.h" + +namespace Digikam +{ + +DLogoAction::DLogoAction(TQObject* parent, const char* name) + : TDEAction(parent, name) +{ + setText("digikam.org"); + setIcon("digikam"); +} + +int DLogoAction::plug(TQWidget *widget, int index) +{ + if (kapp && !kapp->authorizeTDEAction(name())) + return -1; + + if ( widget->inherits( "TDEToolBar" ) ) + { + TDEToolBar *bar = (TDEToolBar *)widget; + int id = getToolButtonID(); + KURLLabel *pixmapLogo = new KURLLabel(Digikam::webProjectUrl(), TQString(), bar); + pixmapLogo->setMargin(0); + pixmapLogo->setScaledContents(false); + pixmapLogo->setSizePolicy(TQSizePolicy(TQSizePolicy::Minimum, TQSizePolicy::Minimum)); + TQToolTip::add(pixmapLogo, i18n("Visit digiKam project website")); + TDEGlobal::dirs()->addResourceType("banner-digikam", TDEGlobal::dirs()->kde_default("data") + "digikam/data"); + TQString directory = TDEGlobal::dirs()->findResourceDir("banner-digikam", "banner-digikam.png"); + pixmapLogo->setPixmap(TQPixmap( directory + "banner-digikam.png" )); + pixmapLogo->setFocusPolicy(TQWidget::NoFocus); + + bar->insertWidget(id, pixmapLogo->width(), pixmapLogo); + bar->alignItemRight(id); + + addContainer(bar, id); + + connect(bar, TQ_SIGNAL(destroyed()), + this, TQ_SLOT(slotDestroyed())); + + connect(pixmapLogo, TQ_SIGNAL(leftClickedURL(const TQString&)), + this, TQ_SLOT(slotProcessURL(const TQString&))); + + return containerCount() - 1; + } + + int containerId = TDEAction::plug( widget, index ); + + return containerId; +} + +void DLogoAction::slotProcessURL(const TQString& url) +{ + TDEApplication::kApplication()->invokeBrowser(url); +} + +} // namespace Digikam diff --git a/src/libs/widgets/common/dlogoaction.h b/src/libs/widgets/common/dlogoaction.h new file mode 100644 index 00000000..11a0052d --- /dev/null +++ b/src/libs/widgets/common/dlogoaction.h @@ -0,0 +1,56 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2007-27-08 + * Description : an tool bar action object to display logo + * + * Copyright (C) 2007-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. + * + * ============================================================ */ + +#ifndef DLOGO_ACTION_H +#define DLOGO_ACTION_H + +// KDE includes. + +#include <tdeaction.h> + +// Local includes. + +#include "digikam_export.h" + +namespace Digikam +{ + +class DIGIKAM_EXPORT DLogoAction : public TDEAction +{ + TQ_OBJECT + + +public: + + DLogoAction(TQObject* parent, const char* name=0); + + virtual int plug(TQWidget *widget, int index=-1); + +private slots: + + void slotProcessURL(const TQString&); +}; + +} // namespace Digikam + +#endif /* DLOGO_ACTION_H */ diff --git a/src/libs/widgets/common/dpopupmenu.cpp b/src/libs/widgets/common/dpopupmenu.cpp new file mode 100644 index 00000000..f41404ce --- /dev/null +++ b/src/libs/widgets/common/dpopupmenu.cpp @@ -0,0 +1,197 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2006-11-11 + * Description : a popup menu with a decorative graphic banner + * at the left border. + * + * Copyright (C) 1996-2000 the kicker authors. + * Copyright (C) 2005 Mark Kretschmann <[email protected]> + * Copyright (C) 2006-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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqpainter.h> +#include <tqpixmap.h> +#include <tqstyle.h> + +// KDE includes. + +#include <tdeapplication.h> +#include <kiconeffect.h> +#include <tdeapplication.h> +#include <kstandarddirs.h> +#include <tdeaboutdata.h> + +// Local includes. + +#include "dpopupmenu.h" + +namespace Digikam +{ + +static TQImage s_dpopupmenu_sidePixmap; +static TQColor s_dpopupmenu_sidePixmapColor; + +DPopupMenu::DPopupMenu(TQWidget* parent, const char* name) + : TDEPopupMenu(parent, name) +{ + // Must be initialized so that we know the size on first invocation + if ( s_dpopupmenu_sidePixmap.isNull() ) + generateSidePixmap(); +} + +DPopupMenu::~DPopupMenu() +{ +} + +void DPopupMenu::generateSidePixmap() +{ + const TQColor newColor = calcPixmapColor(); + + if ( newColor != s_dpopupmenu_sidePixmapColor ) + { + s_dpopupmenu_sidePixmapColor = newColor; + + if (TDEApplication::kApplication()->aboutData()->appName() == TQString("digikam")) + s_dpopupmenu_sidePixmap.load( locate( "data","digikam/data/menusidepixmap.png" ) ); + else + s_dpopupmenu_sidePixmap.load( locate( "data","showfoto/menusidepixmap.png" ) ); + + TDEIconEffect::colorize(s_dpopupmenu_sidePixmap, newColor, 1.0); + } +} + +int DPopupMenu::sidePixmapWidth() const +{ + return s_dpopupmenu_sidePixmap.width(); +} + +TQRect DPopupMenu::sideImageRect() const +{ + return TQStyle::visualRect(TQRect(frameWidth(), frameWidth(), + s_dpopupmenu_sidePixmap.width(), + height() - 2*frameWidth()), + this); +} + +TQColor DPopupMenu::calcPixmapColor() +{ + TQColor color; + TQColor activeTitle = TQApplication::palette().active().background(); + TQColor inactiveTitle = TQApplication::palette().inactive().background(); + + // figure out which color is most suitable for recoloring to + int h1, s1, v1, h2, s2, v2, h3, s3, v3; + activeTitle.hsv(&h1, &s1, &v1); + inactiveTitle.hsv(&h2, &s2, &v2); + TQApplication::palette().active().background().hsv(&h3, &s3, &v3); + + if ( (kAbs(h1-h3)+kAbs(s1-s3)+kAbs(v1-v3) < kAbs(h2-h3)+kAbs(s2-s3)+kAbs(v2-v3)) && + ((kAbs(h1-h3)+kAbs(s1-s3)+kAbs(v1-v3) < 32) || (s1 < 32)) && (s2 > s1)) + color = inactiveTitle; + else + color = activeTitle; + + // limit max/min brightness + int r, g, b; + color.rgb(&r, &g, &b); + int gray = tqGray(r, g, b); + if (gray > 180) + { + r = (r - (gray - 180) < 0 ? 0 : r - (gray - 180)); + g = (g - (gray - 180) < 0 ? 0 : g - (gray - 180)); + b = (b - (gray - 180) < 0 ? 0 : b - (gray - 180)); + } + else if (gray < 76) + { + r = (r + (76 - gray) > 255 ? 255 : r + (76 - gray)); + g = (g + (76 - gray) > 255 ? 255 : g + (76 - gray)); + b = (b + (76 - gray) > 255 ? 255 : b + (76 - gray)); + } + color.setRgb(r, g, b); + + return color; +} + +void DPopupMenu::setMinimumSize(const TQSize & s) +{ + TDEPopupMenu::setMinimumSize(s.width() + s_dpopupmenu_sidePixmap.width(), s.height()); +} + +void DPopupMenu::setMaximumSize(const TQSize & s) +{ + TDEPopupMenu::setMaximumSize(s.width() + s_dpopupmenu_sidePixmap.width(), s.height()); +} + +void DPopupMenu::setMinimumSize(int w, int h) +{ + TDEPopupMenu::setMinimumSize(w + s_dpopupmenu_sidePixmap.width(), h); +} + +void DPopupMenu::setMaximumSize(int w, int h) +{ + TDEPopupMenu::setMaximumSize(w + s_dpopupmenu_sidePixmap.width(), h); +} + +void DPopupMenu::resizeEvent(TQResizeEvent * e) +{ + TDEPopupMenu::resizeEvent(e); + + setFrameRect(TQStyle::visualRect(TQRect(s_dpopupmenu_sidePixmap.width(), 0, + width() - s_dpopupmenu_sidePixmap.width(), height()), + this ) ); +} + +//Workaround TQt3.3.x sizing bug, by ensuring we're always wide enough. +void DPopupMenu::resize(int width, int height) +{ + width = kMax(width, maximumSize().width()); + TDEPopupMenu::resize(width, height); +} + +void DPopupMenu::paintEvent(TQPaintEvent* e) +{ + generateSidePixmap(); + + TQPainter p( this ); + + TQRect r = sideImageRect(); + r.setTop(r.bottom()-s_dpopupmenu_sidePixmap.height()+1); + if ( r.intersects( e->rect() ) ) + { + TQRect drawRect = r.intersect(e->rect()).intersect(sideImageRect()); + TQRect pixRect = drawRect; + pixRect.moveBy(-r.left(), -r.top()); + p.drawImage(drawRect.topLeft(), s_dpopupmenu_sidePixmap, pixRect); + } + + p.setClipRegion(e->region()); + + //NOTE: The order is important here. drawContents() must be called before drawPrimitive(), + // otherwise we get rendering glitches. + + drawContents(&p); + + style().drawPrimitive(TQStyle::PE_PanelPopup, &p, + TQRect(0, 0, width(), height()), + colorGroup(), TQStyle::Style_Default, + TQStyleOption( frameWidth(), 0)); +} + +} // namespace Digikam diff --git a/src/libs/widgets/common/dpopupmenu.h b/src/libs/widgets/common/dpopupmenu.h new file mode 100644 index 00000000..f3576580 --- /dev/null +++ b/src/libs/widgets/common/dpopupmenu.h @@ -0,0 +1,83 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2006-11-11 + * Description : a popup menu with a decorative graphic banner + * at the left border. + * + * Copyright (C) 1996-2000 the kicker authors. + * Copyright (C) 2005 Mark Kretschmann <[email protected]> + * Copyright (C) 2006-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. + * + * ============================================================ */ + +#ifndef DPOPUPMENU_H +#define DPOPUPMENU_H + +// TQt includes. + +#include <tqcolor.h> +#include <tqimage.h> +#include <tqrect.h> + +// KDE includes. + +#include <tdepopupmenu.h> + +// Local includes. + +#include "digikam_export.h" + +class TQSize; + +namespace Digikam +{ + +class DIGIKAM_EXPORT DPopupMenu : public TDEPopupMenu +{ + +public: + + DPopupMenu(TQWidget *parent=0, const char *name=0); + ~DPopupMenu(); + + int sidePixmapWidth() const; + +private: + + /** Loads and prepares the sidebar image */ + void generateSidePixmap(); + + /** Returns the available size for the image */ + TQRect sideImageRect() const; + + /** Calculates a color that matches the current colorscheme */ + TQColor calcPixmapColor(); + + void setMinimumSize(const TQSize& s); + void setMaximumSize(const TQSize& s); + void setMinimumSize(int w, int h); + void setMaximumSize(int w, int h); + + void resizeEvent(TQResizeEvent* e); + void resize(int width, int height); + + void paintEvent(TQPaintEvent* e); +}; + +} // namespace Digikam + +#endif /*DPOPUPMENU_H*/ diff --git a/src/libs/widgets/common/filesaveoptionsbox.cpp b/src/libs/widgets/common/filesaveoptionsbox.cpp new file mode 100644 index 00000000..26985fb5 --- /dev/null +++ b/src/libs/widgets/common/filesaveoptionsbox.cpp @@ -0,0 +1,182 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2007-08-02 + * Description : a stack of widgets to set image file save + * options into image editor. + * + * Copyright (C) 2007 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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqlayout.h> +#include <tqlabel.h> +#include <tqwidget.h> +#include <tqlabel.h> +#include <tqwhatsthis.h> +#include <tqcheckbox.h> + +// KDE includes. + +#include <kimageio.h> +#include <tdelocale.h> +#include <kdialog.h> +#include <knuminput.h> +#include <tdeconfig.h> +#include <tdeapplication.h> +#include <tdefiledialog.h> + +// Local includes. + +#include "jpegsettings.h" +#include "pngsettings.h" +#include "tiffsettings.h" +#include "jp2ksettings.h" +#include "filesaveoptionsbox.h" +#include "filesaveoptionsbox.moc" + +namespace Digikam +{ + +class FileSaveOptionsBoxPriv +{ + +public: + + FileSaveOptionsBoxPriv() + { + noneOptions = 0; + JPEGOptions = 0; + PNGOptions = 0; + TIFFOptions = 0; + JPEG2000Options = 0; + } + + TQWidget *noneOptions; + + TQGridLayout *noneGrid; + + TQLabel *labelNone; + + JPEGSettings *JPEGOptions; + + PNGSettings *PNGOptions; + + TIFFSettings *TIFFOptions; + + JP2KSettings *JPEG2000Options; +}; + +FileSaveOptionsBox::FileSaveOptionsBox(TQWidget *parent) + : TQWidgetStack(parent, 0, TQt::WDestructiveClose) +{ + d = new FileSaveOptionsBoxPriv; + + //-- NONE Settings ------------------------------------------------------ + + d->noneOptions = new TQWidget(this); + d->noneGrid = new TQGridLayout(d->noneOptions, 1, 1, KDialog::spacingHint()); + d->labelNone = new TQLabel(i18n("No options available"), d->noneOptions); + d->noneGrid->addMultiCellWidget(d->labelNone, 0, 0, 0, 1); + + //-- JPEG Settings ------------------------------------------------------ + + d->JPEGOptions = new JPEGSettings(this); + + //-- PNG Settings ------------------------------------------------------- + + d->PNGOptions = new PNGSettings(this); + + //-- TIFF Settings ------------------------------------------------------ + + d->TIFFOptions = new TIFFSettings(this); + + //-- JPEG 2000 Settings ------------------------------------------------- + + d->JPEG2000Options = new JP2KSettings(this); + + //----------------------------------------------------------------------- + + addWidget(d->noneOptions, DImg::NONE); + addWidget(d->JPEGOptions, DImg::JPEG); + addWidget(d->PNGOptions, DImg::PNG); + addWidget(d->TIFFOptions, DImg::TIFF); + addWidget(d->JPEG2000Options, DImg::JP2K); + + //----------------------------------------------------------------------- + + readSettings(); +} + +FileSaveOptionsBox::~FileSaveOptionsBox() +{ + delete d; +} + +void FileSaveOptionsBox::slotImageFileSelected(const TQString& file) +{ + TQString format = TQImageIO::imageFormat(file); + toggleFormatOptions(format); +} + +void FileSaveOptionsBox::slotImageFileFormatChanged(const TQString& filter) +{ + TQString format = KImageIO::typeForMime(filter).upper(); + toggleFormatOptions(format); +} + +void FileSaveOptionsBox::toggleFormatOptions(const TQString& format) +{ + if (format == TQString("JPEG")) + raiseWidget(DImg::JPEG); + else if (format == TQString("PNG")) + raiseWidget(DImg::PNG); + else if (format == TQString("TIFF")) + raiseWidget(DImg::TIFF); + else if (format == TQString("JP2")) + raiseWidget(DImg::JP2K); + else + raiseWidget(DImg::NONE); +} + +void FileSaveOptionsBox::applySettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("ImageViewer Settings"); + config->writeEntry("JPEGCompression", d->JPEGOptions->getCompressionValue()); + config->writeEntry("JPEGSubSampling", d->JPEGOptions->getSubSamplingValue()); + config->writeEntry("PNGCompression", d->PNGOptions->getCompressionValue()); + config->writeEntry("TIFFCompression", d->TIFFOptions->getCompression()); + config->writeEntry("JPEG2000Compression", d->JPEG2000Options->getCompressionValue()); + config->writeEntry("JPEG2000LossLess", d->JPEG2000Options->getLossLessCompression()); + config->sync(); +} + +void FileSaveOptionsBox::readSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("ImageViewer Settings"); + d->JPEGOptions->setCompressionValue( config->readNumEntry("JPEGCompression", 75) ); + d->JPEGOptions->setSubSamplingValue( config->readNumEntry("JPEGSubSampling", 1) ); // Medium subsampling + d->PNGOptions->setCompressionValue( config->readNumEntry("PNGCompression", 9) ); + d->TIFFOptions->setCompression(config->readBoolEntry("TIFFCompression", false)); + d->JPEG2000Options->setCompressionValue( config->readNumEntry("JPEG2000Compression", 75) ); + d->JPEG2000Options->setLossLessCompression( config->readBoolEntry("JPEG2000LossLess", true) ); +} + +} // namespace Digikam diff --git a/src/libs/widgets/common/filesaveoptionsbox.h b/src/libs/widgets/common/filesaveoptionsbox.h new file mode 100644 index 00000000..9d9f84fc --- /dev/null +++ b/src/libs/widgets/common/filesaveoptionsbox.h @@ -0,0 +1,72 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2007-08-02 + * Description : a stack of widgets to set image file save + * options into image editor. + * + * Copyright (C) 2007 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. + * + * ============================================================ */ + +#ifndef FILESAVEOPTIONSBOX_H +#define FILESAVEOPTIONSBOX_H + +// KDE includes. + +#include <tqwidgetstack.h> +#include <tqstring.h> + +// Local includes. + +#include "dimg.h" +#include "digikam_export.h" + +namespace Digikam +{ + +class FileSaveOptionsBoxPriv; + +class DIGIKAM_EXPORT FileSaveOptionsBox : public TQWidgetStack +{ +TQ_OBJECT + + +public: + + FileSaveOptionsBox(TQWidget *parent=0); + ~FileSaveOptionsBox(); + + void applySettings(); + +public slots: + + void slotImageFileFormatChanged(const TQString&); + void slotImageFileSelected(const TQString&); + +private: + + void toggleFormatOptions(const TQString& format); + void readSettings(); + +private: + + FileSaveOptionsBoxPriv* d; +}; + +} // namespace Digikam + +#endif /* FILESAVEOPTIONSBOX_H */ diff --git a/src/libs/widgets/common/histogramwidget.cpp b/src/libs/widgets/common/histogramwidget.cpp new file mode 100644 index 00000000..b3017201 --- /dev/null +++ b/src/libs/widgets/common/histogramwidget.cpp @@ -0,0 +1,1089 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-07-21 + * Description : a widget to display an image histogram. + * + * Copyright (C) 2004-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * + * Some code parts are inspired from from gimp 2.0 + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * 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 <tqpixmap.h> +#include <tqpainter.h> +#include <tqpen.h> +#include <tqevent.h> +#include <tqtimer.h> +#include <tqcolor.h> +#include <tqbrush.h> +#include <tqrect.h> +#include <tqfont.h> +#include <tqfontmetrics.h> +#include <tqtooltip.h> + +// KDE includes. + +#include <kcursor.h> +#include <tdelocale.h> + +// Local includes. + +#include "ddebug.h" +#include "imagehistogram.h" +#include "histogramwidget.h" +#include "histogramwidget.moc" + +namespace Digikam +{ + +class HistogramWidgetPriv +{ +public: + + enum RepaintType + { + HistogramNone = 0, // No current histogram values calculation. + HistogramDataLoading, // The image is being loaded + HistogramStarted, // Histogram values calculation started. + HistogramCompleted, // Histogram values calculation completed. + HistogramFailed // Histogram values calculation failed. + }; + + HistogramWidgetPriv() + { + blinkTimer = 0; + sixteenBits = false; + inSelected = false; + clearFlag = HistogramNone; + xmin = 0.0; + xmax = 0.0; + range = 255; + guideVisible = false; + inInitialRepaintWait = false; + pos = 0; + } + + // Current selection information. + double xmin; + double xminOrg; + double xmax; + int range; + int clearFlag; // Clear drawing zone with message. + int pos; // Position of animation during loading/calculation. + + bool sixteenBits; + bool guideVisible; // Display color guide. + bool statisticsVisible; // Display tooltip histogram statistics. + bool inSelected; + bool selectMode; // If true, a part of the histogram can be selected ! + bool showProgress; // If true, a message will be displayed during histogram computation, + // else nothing (limit flicker effect in widget especially for small + // image/computation time). + bool inInitialRepaintWait; + + TQTimer *blinkTimer; + + DColor colorGuide; +}; + +// Constructor without image data (needed to use updateData() method after instance created). + +HistogramWidget::HistogramWidget(int w, int h, + TQWidget *parent, bool selectMode, + bool showProgress, bool statisticsVisible) + : TQWidget(parent, 0, TQt::WDestructiveClose) +{ + d = new HistogramWidgetPriv; + setup(w, h, selectMode, showProgress, statisticsVisible); + + m_imageHistogram = 0L; + m_selectionHistogram = 0L; +} + +// Constructor without image selection. + +HistogramWidget::HistogramWidget(int w, int h, + uchar *i_data, uint i_w, uint i_h, + bool i_sixteenBits, + TQWidget *parent, bool selectMode, + bool showProgress, bool statisticsVisible) + : TQWidget(parent, 0, TQt::WDestructiveClose) +{ + d = new HistogramWidgetPriv; + d->sixteenBits = i_sixteenBits; + setup(w, h, selectMode, showProgress, statisticsVisible); + + m_imageHistogram = new ImageHistogram(i_data, i_w, i_h, i_sixteenBits, this); + m_selectionHistogram = 0L; +} + +// Constructor with image selection. + +HistogramWidget::HistogramWidget(int w, int h, + uchar *i_data, uint i_w, uint i_h, + uchar *s_data, uint s_w, uint s_h, + bool i_sixteenBits, + TQWidget *parent, bool selectMode, + bool showProgress, bool statisticsVisible) + : TQWidget(parent, 0, TQt::WDestructiveClose) +{ + d = new HistogramWidgetPriv; + d->sixteenBits = i_sixteenBits; + setup(w, h, selectMode, showProgress, statisticsVisible); + + m_imageHistogram = new ImageHistogram(i_data, i_w, i_h, i_sixteenBits, this); + m_selectionHistogram = new ImageHistogram(s_data, s_w, s_h, i_sixteenBits, this); +} + +HistogramWidget::~HistogramWidget() +{ + d->blinkTimer->stop(); + + if (m_imageHistogram) + delete m_imageHistogram; + + if (m_selectionHistogram) + delete m_selectionHistogram; + + delete d; +} + +void HistogramWidget::setup(int w, int h, bool selectMode, bool showProgress, bool statisticsVisible) +{ + m_channelType = ValueHistogram; + m_scaleType = LogScaleHistogram; + m_colorType = RedColor; + m_renderingType = FullImageHistogram; + d->statisticsVisible = statisticsVisible; + d->selectMode = selectMode; + d->showProgress = showProgress; + + setMouseTracking(true); + setMinimumSize(w, h); + + d->blinkTimer = new TQTimer( this ); + + connect( d->blinkTimer, TQ_SIGNAL(timeout()), + this, TQ_SLOT(slotBlinkTimerDone()) ); +} + +void HistogramWidget::setHistogramGuideByColor(const DColor& color) +{ + d->guideVisible = true; + d->colorGuide = color; + repaint(false); +} + +void HistogramWidget::reset() +{ + d->guideVisible = false; + repaint(false); +} + +void HistogramWidget::customEvent(TQCustomEvent *event) +{ + if (!event) return; + + ImageHistogram::EventData *ed = (ImageHistogram::EventData*) event->data(); + + if (!ed) return; + + if (ed->histogram != m_imageHistogram && ed->histogram != m_selectionHistogram) + return; + + if (ed->starting) + { + setCursor( KCursor::waitCursor() ); + d->clearFlag = HistogramWidgetPriv::HistogramStarted; + if (!d->inInitialRepaintWait) + { + if (d->clearFlag != HistogramWidgetPriv::HistogramDataLoading) + { + // enter initial repaint wait, repaint only after waiting + // a short time so that very fast computation does not create flicker + d->inInitialRepaintWait = true; + d->blinkTimer->start( 100 ); + } + else + { + // after the initial repaint, we can repaint immediately + repaint(false); + d->blinkTimer->start( 200 ); + } + } + } + else + { + if (ed->success) + { + // Repaint histogram + d->clearFlag = HistogramWidgetPriv::HistogramCompleted; + d->blinkTimer->stop(); + d->inInitialRepaintWait = false; + setCursor( KCursor::arrowCursor() ); + + // Send signals to refresh information if necessary. + // The signals may trigger multiple repaints, avoid this, + // we repaint once afterwards. + setUpdatesEnabled(false); + + notifyValuesChanged(); + emit signalHistogramComputationDone(d->sixteenBits); + + setUpdatesEnabled(true); + repaint(false); + } + else + { + d->clearFlag = HistogramWidgetPriv::HistogramFailed; + d->blinkTimer->stop(); + d->inInitialRepaintWait = false; + repaint(false); + setCursor( KCursor::arrowCursor() ); + // Remove old histogram data from memory. + if (m_imageHistogram) + { + delete m_imageHistogram; + m_imageHistogram = 0; + } + if (m_selectionHistogram) + { + delete m_selectionHistogram; + m_selectionHistogram = 0; + } + emit signalHistogramComputationFailed(); + } + } + + delete ed; +} + +void HistogramWidget::setDataLoading() +{ + if (d->clearFlag != HistogramWidgetPriv::HistogramDataLoading) + { + setCursor( KCursor::waitCursor() ); + d->clearFlag = HistogramWidgetPriv::HistogramDataLoading; + // enter initial repaint wait, repaint only after waiting + // a short time so that very fast computation does not create flicker + d->inInitialRepaintWait = true; + d->pos = 0; + d->blinkTimer->start( 100 ); + } +} + +void HistogramWidget::setLoadingFailed() +{ + d->clearFlag = HistogramWidgetPriv::HistogramFailed; + d->pos = 0; + d->blinkTimer->stop(); + d->inInitialRepaintWait = false; + repaint(false); + setCursor( KCursor::arrowCursor() ); +} + +void HistogramWidget::stopHistogramComputation() +{ + if (m_imageHistogram) + m_imageHistogram->stopCalcHistogramValues(); + + if (m_selectionHistogram) + m_selectionHistogram->stopCalcHistogramValues(); + + d->blinkTimer->stop(); + d->pos = 0; +} + +void HistogramWidget::updateData(uchar *i_data, uint i_w, uint i_h, + bool i_sixteenBits, + uchar *s_data, uint s_w, uint s_h, + bool showProgress) +{ + d->showProgress = showProgress; + d->sixteenBits = i_sixteenBits; + + // We are deleting the histogram data, so we must not use it to draw any more. + d->clearFlag = HistogramWidgetPriv::HistogramNone; + + // Do not using ImageHistogram::getHistogramSegment() + // method here because histogram hasn't yet been computed. + d->range = d->sixteenBits ? 65535 : 255; + emit signalMaximumValueChanged( d->range ); + + + // Remove old histogram data from memory. + if (m_imageHistogram) + delete m_imageHistogram; + + if (m_selectionHistogram) + delete m_selectionHistogram; + + // Calc new histogram data + m_imageHistogram = new ImageHistogram(i_data, i_w, i_h, i_sixteenBits, this); + + if (s_data && s_w && s_h) + m_selectionHistogram = new ImageHistogram(s_data, s_w, s_h, i_sixteenBits, this); + else + m_selectionHistogram = 0L; +} + +void HistogramWidget::updateSelectionData(uchar *s_data, uint s_w, uint s_h, + bool i_sixteenBits, + bool showProgress) +{ + d->showProgress = showProgress; + + // Remove old histogram data from memory. + + if (m_selectionHistogram) + delete m_selectionHistogram; + + // Calc new histogram data + m_selectionHistogram = new ImageHistogram(s_data, s_w, s_h, i_sixteenBits, this); +} + +void HistogramWidget::slotBlinkTimerDone() +{ + d->inInitialRepaintWait = false; + repaint(false); + d->blinkTimer->start( 200 ); +} + +void HistogramWidget::paintEvent(TQPaintEvent*) +{ + // Widget is disabled, not initialized, + // or loading, but no message shall be drawn: + // Drawing grayed frame. + if ( !isEnabled() || + d->clearFlag == HistogramWidgetPriv::HistogramNone || + (!d->showProgress && (d->clearFlag == HistogramWidgetPriv::HistogramStarted || + d->clearFlag == HistogramWidgetPriv::HistogramDataLoading)) + ) + { + TQPixmap pm(size()); + TQPainter p1; + p1.begin(&pm, this); + p1.fillRect(0, 0, size().width(), size().height(), palette().disabled().background()); + p1.setPen(TQPen(palette().active().foreground(), 1, TQt::SolidLine)); + p1.drawRect(0, 0, width(), height()); + p1.setPen(TQPen(palette().disabled().foreground(), 1, TQt::SolidLine)); + p1.drawRect(0, 0, width(), height()); + p1.end(); + bitBlt(this, 0, 0, &pm); + return; + } + // Image data is loading or histogram is being computed: + // Draw message. + else if ( d->showProgress && + (d->clearFlag == HistogramWidgetPriv::HistogramStarted || + d->clearFlag == HistogramWidgetPriv::HistogramDataLoading) + ) + { + // In first, we draw an animation. + + int asize = 24; + TQPixmap anim(asize, asize); + TQPainter p2; + p2.begin(&anim, this); + p2.fillRect(0, 0, asize, asize, palette().active().background()); + p2.translate(asize/2, asize/2); + + d->pos = (d->pos + 10) % 360; + p2.setPen(TQPen(palette().active().text())); + p2.rotate(d->pos); + for ( int i=0 ; i<12 ; i++ ) + { + p2.drawLine(asize/2-5, 0, asize/2-2, 0); + p2.rotate(30); + } + p2.end(); + + // ... and we render busy text. + + TQPixmap pm(size()); + TQPainter p1; + p1.begin(&pm, this); + p1.fillRect(0, 0, width(), height(), palette().active().background()); + p1.setPen(TQPen(palette().active().foreground(), 1, TQt::SolidLine)); + p1.drawRect(0, 0, width(), height()); + p1.drawPixmap(width()/2 - asize /2, asize, anim); + p1.setPen(TQPen(palette().active().text())); + + if (d->clearFlag == HistogramWidgetPriv::HistogramDataLoading) + p1.drawText(0, 0, width(), height(), TQt::AlignCenter, + i18n("Loading image...")); + else + p1.drawText(0, 0, width(), height(), TQt::AlignCenter, + i18n("Histogram calculation...")); + p1.end(); + + bitBlt(this, 0, 0, &pm); + return; + } + // Histogram computation failed: + // Draw message. + else if (d->clearFlag == HistogramWidgetPriv::HistogramFailed) + { + TQPixmap pm(size()); + TQPainter p1; + p1.begin(&pm, this); + p1.fillRect(0, 0, width(), height(), palette().active().background()); + p1.setPen(TQPen(palette().active().foreground(), 1, TQt::SolidLine)); + p1.drawRect(0, 0, width(), height()); + p1.setPen(TQPen(palette().active().text())); + p1.drawText(0, 0, width(), height(), TQt::AlignCenter, + i18n("Histogram\ncalculation\nfailed.")); + p1.end(); + bitBlt(this, 0, 0, &pm); + return; + } + + int x, y; + int yr, yg, yb; // For all color channels. + int wWidth = width(); + int wHeight = height(); + double max; + class ImageHistogram *histogram; + + if (m_renderingType == ImageSelectionHistogram && m_selectionHistogram) + histogram = m_selectionHistogram; + else + histogram = m_imageHistogram; + + if (!histogram) + return; + + x = 0; y = 0; + yr = 0; yg = 0; yb = 0; + max = 0.0; + + switch(m_channelType) + { + case HistogramWidget::GreenChannelHistogram: // Green channel. + max = histogram->getMaximum(ImageHistogram::GreenChannel); + break; + + case HistogramWidget::BlueChannelHistogram: // Blue channel. + max = histogram->getMaximum(ImageHistogram::BlueChannel); + break; + + case HistogramWidget::RedChannelHistogram: // Red channel. + max = histogram->getMaximum(ImageHistogram::RedChannel); + break; + + case HistogramWidget::AlphaChannelHistogram: // Alpha channel. + max = histogram->getMaximum(ImageHistogram::AlphaChannel); + break; + + case HistogramWidget::ColorChannelsHistogram: // All color channels. + max = TQMAX (TQMAX (histogram->getMaximum(ImageHistogram::RedChannel), + histogram->getMaximum(ImageHistogram::GreenChannel)), + histogram->getMaximum(ImageHistogram::BlueChannel)); + break; + + case HistogramWidget::ValueHistogram: // Luminosity. + max = histogram->getMaximum(ImageHistogram::ValueChannel); + break; + } + + switch (m_scaleType) + { + case HistogramWidget::LinScaleHistogram: + break; + + case HistogramWidget::LogScaleHistogram: + if (max > 0.0) + max = log (max); + else + max = 1.0; + break; + } + + // A TQPixmap is used to enable the double buffering. + + TQPixmap pm(size()); + TQPainter p1; + p1.begin(&pm, this); + p1.fillRect(0, 0, width(), height(), palette().active().background()); + + // Drawing selection or all histogram values. + + for (x = 0 ; x < wWidth ; x++) + { + double value = 0.0; + double value_r = 0.0, value_g = 0.0, value_b = 0.0; // For all color channels. + int i, j; + + i = (x * histogram->getHistogramSegment()) / wWidth; + j = ((x + 1) * histogram->getHistogramSegment()) / wWidth; + + do + { + double v; + double vr, vg, vb; // For all color channels. + + v = 0.0; + vr = 0.0; vg = 0.0; vb = 0.0; + + switch(m_channelType) + { + case HistogramWidget::GreenChannelHistogram: // Green channel. + v = histogram->getValue(ImageHistogram::GreenChannel, i++); + break; + + case HistogramWidget::BlueChannelHistogram: // Blue channel. + v = histogram->getValue(ImageHistogram::BlueChannel, i++); + break; + + case HistogramWidget::RedChannelHistogram: // Red channel. + v = histogram->getValue(ImageHistogram::RedChannel, i++); + break; + + case HistogramWidget::AlphaChannelHistogram: // Alpha channel. + v = histogram->getValue(ImageHistogram::AlphaChannel, i++); + break; + + case HistogramWidget::ColorChannelsHistogram: // All color channels. + vr = histogram->getValue(ImageHistogram::RedChannel, i++); + vg = histogram->getValue(ImageHistogram::GreenChannel, i); + vb = histogram->getValue(ImageHistogram::BlueChannel, i); + break; + + case HistogramWidget::ValueHistogram: // Luminosity. + v = histogram->getValue(ImageHistogram::ValueChannel, i++); + break; + } + + if ( m_channelType != HistogramWidget::ColorChannelsHistogram ) + { + if (v > value) + value = v; + } + else + { + if (vr > value_r) + value_r = vr; + if (vg > value_g) + value_g = vg; + if (vb > value_b) + value_b = vb; + } + } + while (i < j); + + if ( m_channelType != HistogramWidget::ColorChannelsHistogram ) + { + switch (m_scaleType) + { + case HistogramWidget::LinScaleHistogram: + y = (int) ((wHeight * value) / max); + break; + + case HistogramWidget::LogScaleHistogram: + if (value <= 0.0) value = 1.0; + y = (int) ((wHeight * log (value)) / max); + break; + + default: + y = 0; + break; + } + } + else + { + switch (m_scaleType) + { + case HistogramWidget::LinScaleHistogram: + yr = (int) ((wHeight * value_r) / max); + yg = (int) ((wHeight * value_g) / max); + yb = (int) ((wHeight * value_b) / max); + break; + + case HistogramWidget::LogScaleHistogram: + if (value_r <= 0.0) value_r = 1.0; + if (value_g <= 0.0) value_g = 1.0; + if (value_b <= 0.0) value_b = 1.0; + yr = (int) ((wHeight * log (value_r)) / max); + yg = (int) ((wHeight * log (value_g)) / max); + yb = (int) ((wHeight * log (value_b)) / max); + break; + + default: + yr = 0; + yg = 0; + yb = 0; + break; + } + } + + // Drawing the histogram + selection or only the histogram. + + if ( m_channelType != HistogramWidget::ColorChannelsHistogram ) + { + if ( d->selectMode == true ) // Selection mode enable ? + { + if ( x >= (int)(d->xmin * wWidth) && x <= (int)(d->xmax * wWidth) ) + { + p1.setPen(TQPen(palette().active().foreground(), 1, TQt::SolidLine)); + p1.drawLine(x, wHeight, x, 0); + p1.setPen(TQPen(palette().active().background(), 1, TQt::SolidLine)); + p1.drawLine(x, wHeight, x, wHeight - y); + } + else + { + p1.setPen(TQPen(palette().active().foreground(), 1, TQt::SolidLine)); + p1.drawLine(x, wHeight, x, wHeight - y); + p1.setPen(TQPen(palette().active().background(), 1, TQt::SolidLine)); + p1.drawLine(x, wHeight - y, x, 0); + + if ( x == wWidth/4 || x == wWidth/2 || x == 3*wWidth/4 ) + { + p1.setPen(TQPen(palette().active().base(), 1, TQt::SolidLine)); + p1.drawLine(x, wHeight, x, 0); + } + } + } + else + { + p1.setPen(TQPen(palette().active().foreground(), 1, TQt::SolidLine)); + p1.drawLine(x, wHeight, x, wHeight - y); + p1.setPen(TQPen(palette().active().background(), 1, TQt::SolidLine)); + p1.drawLine(x, wHeight - y, x, 0); + + if ( x == wWidth/4 || x == wWidth/2 || x == 3*wWidth/4 ) + { + p1.setPen(TQPen(palette().active().base(), 1, TQt::SolidLine)); + p1.drawLine(x, wHeight, x, 0); + } + } + } + else + { + if ( d->selectMode == true ) // Histogram selection mode enable ? + { + if ( x >= (int)(d->xmin * wWidth) && x <= (int)(d->xmax * wWidth) ) + { + p1.setPen(TQPen(palette().active().foreground(), 1, TQt::SolidLine)); + p1.drawLine(x, wHeight, x, 0); + p1.setPen(TQPen(palette().active().background(), 1, TQt::SolidLine)); + + // Witch color must be used on the foreground with all colors channel mode? + switch (m_colorType) + { + case HistogramWidget::RedColor: + p1.drawLine(x, wHeight, x, wHeight - yr); + break; + + case HistogramWidget::GreenColor: + p1.drawLine(x, wHeight, x, wHeight - yg); + break; + + default: + p1.drawLine(x, wHeight, x, wHeight - yb); + break; + } + } + else + { + // Which color must be used on the foreground with all colors channel mode? + switch (m_colorType) + { + case HistogramWidget::RedColor: + p1.setPen(TQPen(TQt::green, 1, TQt::SolidLine)); + p1.drawLine(x, wHeight, x, wHeight - yg); + p1.setPen(TQPen(TQt::blue, 1, TQt::SolidLine)); + p1.drawLine(x, wHeight, x, wHeight - yb); + p1.setPen(TQPen(TQt::red, 1, TQt::SolidLine)); + p1.drawLine(x, wHeight, x, wHeight - yr); + + p1.setPen(TQPen(palette().active().background(), 1, TQt::SolidLine)); + p1.drawLine(x, wHeight - TQMAX(TQMAX(yr, yg), yb), x, 0); + p1.setPen(TQPen(palette().active().foreground(), 1, TQt::SolidLine)); + p1.drawLine(x, wHeight - yg -1, x, wHeight - yg); + p1.drawLine(x, wHeight - yb -1, x, wHeight - yb); + p1.drawLine(x, wHeight - yr -1, x, wHeight - yr); + + if ( x == wWidth/4 || x == wWidth/2 || x == 3*wWidth/4 ) + { + p1.setPen(TQPen(palette().active().base(), 1, TQt::SolidLine)); + p1.drawLine(x, wHeight, x, 0); + } + + break; + + case HistogramWidget::GreenColor: + p1.setPen(TQPen(TQt::blue, 1, TQt::SolidLine)); + p1.drawLine(x, wHeight, x, wHeight - yb); + p1.setPen(TQPen(TQt::red, 1, TQt::SolidLine)); + p1.drawLine(x, wHeight, x, wHeight - yr); + p1.setPen(TQPen(TQt::green, 1, TQt::SolidLine)); + p1.drawLine(x, wHeight, x, wHeight - yg); + + p1.setPen(TQPen(palette().active().background(), 1, TQt::SolidLine)); + p1.drawLine(x, wHeight - TQMAX(TQMAX(yr, yg), yb), x, 0); + p1.setPen(TQPen(palette().active().foreground(), 1, TQt::SolidLine)); + p1.drawLine(x, wHeight - yb -1, x, wHeight - yb); + p1.drawLine(x, wHeight - yr -1, x, wHeight - yr); + p1.drawLine(x, wHeight - yg -1, x, wHeight - yg); + + if ( x == wWidth/4 || x == wWidth/2 || x == 3*wWidth/4 ) + { + p1.setPen(TQPen(palette().active().base(), 1, TQt::SolidLine)); + p1.drawLine(x, wHeight, x, 0); + } + + break; + + default: + p1.setPen(TQPen(TQt::red, 1, TQt::SolidLine)); + p1.drawLine(x, wHeight, x, wHeight - yr); + p1.setPen(TQPen(TQt::green, 1, TQt::SolidLine)); + p1.drawLine(x, wHeight, x, wHeight - yg); + p1.setPen(TQPen(TQt::blue, 1, TQt::SolidLine)); + p1.drawLine(x, wHeight, x, wHeight - yb); + + p1.setPen(TQPen(palette().active().background(), 1, TQt::SolidLine)); + p1.drawLine(x, wHeight - TQMAX(TQMAX(yr, yg), yb), x, 0); + p1.setPen(TQPen(palette().active().foreground(), 1, TQt::SolidLine)); + p1.drawLine(x, wHeight - yr -1, x, wHeight - yr); + p1.drawLine(x, wHeight - yg -1, x, wHeight - yg); + p1.drawLine(x, wHeight - yb -1, x, wHeight - yb); + + if ( x == wWidth/4 || x == wWidth/2 || x == 3*wWidth/4 ) + { + p1.setPen(TQPen(palette().active().base(), 1, TQt::SolidLine)); + p1.drawLine(x, wHeight, x, 0); + } + + break; + } + } + } + else + { + // Which color must be used on the foreground with all colors channel mode? + switch (m_colorType) + { + case HistogramWidget::RedColor: + p1.setPen(TQPen(TQt::green, 1, TQt::SolidLine)); + p1.drawLine(x, wHeight, x, wHeight - yg); + p1.setPen(TQPen(TQt::blue, 1, TQt::SolidLine)); + p1.drawLine(x, wHeight, x, wHeight - yb); + p1.setPen(TQPen(TQt::red, 1, TQt::SolidLine)); + p1.drawLine(x, wHeight, x, wHeight - yr); + + p1.setPen(TQPen(palette().active().background(), 1, TQt::SolidLine)); + p1.drawLine(x, wHeight - TQMAX(TQMAX(yr, yg), yb), x, 0); + p1.setPen(TQPen(palette().active().foreground(), 1, TQt::SolidLine)); + p1.drawLine(x, wHeight - yg -1, x, wHeight - yg); + p1.drawLine(x, wHeight - yb -1, x, wHeight - yb); + p1.drawLine(x, wHeight - yr -1, x, wHeight - yr); + + if ( x == wWidth/4 || x == wWidth/2 || x == 3*wWidth/4 ) + { + p1.setPen(TQPen(palette().active().base(), 1, TQt::SolidLine)); + p1.drawLine(x, wHeight, x, 0); + } + + break; + + case HistogramWidget::GreenColor: + p1.setPen(TQPen(TQt::blue, 1, TQt::SolidLine)); + p1.drawLine(x, wHeight, x, wHeight - yb); + p1.setPen(TQPen(TQt::red, 1, TQt::SolidLine)); + p1.drawLine(x, wHeight, x, wHeight - yr); + p1.setPen(TQPen(TQt::green, 1, TQt::SolidLine)); + p1.drawLine(x, wHeight, x, wHeight - yg); + + p1.setPen(TQPen(palette().active().background(), 1, TQt::SolidLine)); + p1.drawLine(x, wHeight - TQMAX(TQMAX(yr, yg), yb), x, 0); + p1.setPen(TQPen(palette().active().foreground(), 1, TQt::SolidLine)); + p1.drawLine(x, wHeight - yb -1, x, wHeight - yb); + p1.drawLine(x, wHeight - yr -1, x, wHeight - yr); + p1.drawLine(x, wHeight - yg -1, x, wHeight - yg); + + if ( x == wWidth/4 || x == wWidth/2 || x == 3*wWidth/4 ) + { + p1.setPen(TQPen(palette().active().base(), 1, TQt::SolidLine)); + p1.drawLine(x, wHeight, x, 0); + } + + break; + + default: + p1.setPen(TQPen(TQt::red, 1, TQt::SolidLine)); + p1.drawLine(x, wHeight, x, wHeight - yr); + p1.setPen(TQPen(TQt::green, 1, TQt::SolidLine)); + p1.drawLine(x, wHeight, x, wHeight - yg); + p1.setPen(TQPen(TQt::blue, 1, TQt::SolidLine)); + p1.drawLine(x, wHeight, x, wHeight - yb); + + p1.setPen(TQPen(palette().active().background(), 1, TQt::SolidLine)); + p1.drawLine(x, wHeight - TQMAX(TQMAX(yr, yg), yb), x, 0); + p1.setPen(TQPen(palette().active().foreground(), 1, TQt::SolidLine)); + p1.drawLine(x, wHeight - yr -1, x, wHeight - yr); + p1.drawLine(x, wHeight - yg -1, x, wHeight - yg); + p1.drawLine(x, wHeight - yb -1, x, wHeight - yb); + + if ( x == wWidth/4 || x == wWidth/2 || x == 3*wWidth/4 ) + { + p1.setPen(TQPen(palette().active().base(), 1, TQt::SolidLine)); + p1.drawLine(x, wHeight, x, 0); + } + + break; + } + } + } + } + + // Drawing color guide. + + p1.setPen(TQPen(TQt::red, 1, TQt::DotLine)); + int guidePos; + + if (d->guideVisible) + { + switch(m_channelType) + { + case HistogramWidget::RedChannelHistogram: + guidePos = d->colorGuide.red(); + break; + + case HistogramWidget::GreenChannelHistogram: + guidePos = d->colorGuide.green(); + break; + + case HistogramWidget::BlueChannelHistogram: + guidePos = d->colorGuide.blue(); + break; + + case HistogramWidget::ValueHistogram: + guidePos = TQMAX(TQMAX(d->colorGuide.red(), d->colorGuide.green()), d->colorGuide.blue()); + break; + + case HistogramWidget::ColorChannelsHistogram: + { + switch(m_channelType) + { + case HistogramWidget::RedChannelHistogram: + guidePos = d->colorGuide.red(); + break; + + case HistogramWidget::GreenChannelHistogram: + guidePos = d->colorGuide.green(); + break; + + case HistogramWidget::BlueChannelHistogram: + guidePos = d->colorGuide.blue(); + break; + } + } + + default: + guidePos = d->colorGuide.alpha(); + break; + } + + if (guidePos != -1) + { + int xGuide = (guidePos * wWidth) / histogram->getHistogramSegment(); + p1.drawLine(xGuide, 0, xGuide, wHeight); + + TQString string = i18n("x:%1").arg(guidePos); + TQFontMetrics fontMt( string ); + TQRect rect = fontMt.boundingRect(0, 0, wWidth, wHeight, 0, string); + p1.setPen(TQPen(TQt::red, 1, TQt::SolidLine)); + rect.moveTop(1); + + if (xGuide < wWidth/2) + { + rect.moveLeft(xGuide); + p1.fillRect(rect, TQBrush(TQColor(250, 250, 255)) ); + p1.drawRect(rect); + rect.moveLeft(xGuide+3); + p1.drawText(rect, TQt::AlignLeft, string); + } + else + { + rect.moveRight(xGuide); + p1.fillRect(rect, TQBrush(TQColor(250, 250, 255)) ); + p1.drawRect(rect); + rect.moveRight(xGuide-3); + p1.drawText(rect, TQt::AlignRight, string); + } + } + } + + if (d->statisticsVisible) + { + TQString tipText, value; + TQString cellBeg("<tr><td><nobr><font size=-1>"); + TQString cellMid("</font></nobr></td><td><nobr><font size=-1>"); + TQString cellEnd("</font></nobr></td></tr>"); + tipText = "<table cellspacing=0 cellpadding=0>"; + + tipText += cellBeg + i18n("Mean:") + cellMid; + double mean = histogram->getMean(m_channelType, 0, histogram->getHistogramSegment()-1); + tipText += value.setNum(mean, 'f', 1) + cellEnd; + + tipText += cellBeg + i18n("Pixels:") + cellMid; + double pixels = histogram->getPixels(); + tipText += value.setNum((float)pixels, 'f', 0) + cellEnd; + + tipText += cellBeg + i18n("Std dev.:") + cellMid; + double stddev = histogram->getStdDev(m_channelType, 0, histogram->getHistogramSegment()-1); + tipText += value.setNum(stddev, 'f', 1) + cellEnd; + + tipText += cellBeg + i18n("Count:") + cellMid; + double counts = histogram->getCount(m_channelType, 0, histogram->getHistogramSegment()-1); + tipText += value.setNum((float)counts, 'f', 0) + cellEnd; + + tipText += cellBeg + i18n("Median:") + cellMid; + double median = histogram->getMedian(m_channelType, 0, histogram->getHistogramSegment()-1); + tipText += value.setNum(median, 'f', 1) + cellEnd; + + tipText += cellBeg + i18n("Percent:") + cellMid; + double percentile = (pixels > 0 ? (100.0 * counts / pixels) : 0.0); + tipText += value.setNum(percentile, 'f', 1) + cellEnd; + + tipText += "</table>"; + + TQToolTip::add( this, tipText); + } + + p1.setPen(TQPen(palette().active().foreground(), 1, TQt::SolidLine)); + p1.drawRect(0, 0, width(), height()); + p1.end(); + bitBlt(this, 0, 0, &pm); +} + +void HistogramWidget::mousePressEvent(TQMouseEvent* e) +{ + if ( d->selectMode == true && d->clearFlag == HistogramWidgetPriv::HistogramCompleted ) + { + if (!d->inSelected) + { + d->inSelected = true; + repaint(false); + } + + d->xmin = ((double)e->pos().x()) / ((double)width()); + d->xminOrg = d->xmin; + notifyValuesChanged(); + //emit signalValuesChanged( (int)(d->xmin * d->range), ); + d->xmax = 0.0; + } +} + +void HistogramWidget::mouseReleaseEvent(TQMouseEvent*) +{ + if ( d->selectMode == true && d->clearFlag == HistogramWidgetPriv::HistogramCompleted ) + { + d->inSelected = false; + // Only single click without mouse move? Remove selection. + if (d->xmax == 0.0) + { + d->xmin = 0.0; + //emit signalMinValueChanged( 0 ); + //emit signalMaxValueChanged( d->range ); + notifyValuesChanged(); + repaint(false); + } + } +} + +void HistogramWidget::mouseMoveEvent(TQMouseEvent *e) +{ + if ( d->selectMode == true && d->clearFlag == HistogramWidgetPriv::HistogramCompleted ) + { + setCursor( KCursor::crossCursor() ); + + if (d->inSelected) + { + double max = ((double)e->pos().x()) / ((double)width()); + //int max = (int)(e->pos().x()*((float)m_imageHistogram->getHistogramSegment()/(float)width())); + + if (max < d->xminOrg) + { + d->xmax = d->xminOrg; + d->xmin = max; + //emit signalMinValueChanged( (int)(d->xmin * d->range) ); + } + else + { + d->xmin = d->xminOrg; + d->xmax = max; + } + + notifyValuesChanged(); + //emit signalMaxValueChanged( d->xmax == 0.0 ? d->range : (int)(d->xmax * d->range) ); + + repaint(false); + } + } +} + +void HistogramWidget::notifyValuesChanged() +{ + emit signalIntervalChanged( (int)(d->xmin * d->range), d->xmax == 0.0 ? d->range : (int)(d->xmax * d->range) ); +} + +void HistogramWidget::slotMinValueChanged( int min ) +{ + if ( d->selectMode == true && d->clearFlag == HistogramWidgetPriv::HistogramCompleted ) + { + if (min == 0 && d->xmax == 1.0) + { + // everything is selected means no selection + d->xmin = 0.0; + d->xmax = 0.0; + } + if (min >= 0 && min < d->range) + { + d->xmin = ((double)min)/d->range; + } + repaint(false); + } +} + +void HistogramWidget::slotMaxValueChanged(int max) +{ + if ( d->selectMode == true && d->clearFlag == HistogramWidgetPriv::HistogramCompleted ) + { + if (d->xmin == 0.0 && max == d->range) + { + // everything is selected means no selection + d->xmin = 0.0; + d->xmax = 0.0; + } + else if (max > 0 && max <= d->range) + { + d->xmax = ((double)max)/d->range; + } + repaint(false); + } +} + +} // namespace Digikam diff --git a/src/libs/widgets/common/histogramwidget.h b/src/libs/widgets/common/histogramwidget.h new file mode 100644 index 00000000..26157170 --- /dev/null +++ b/src/libs/widgets/common/histogramwidget.h @@ -0,0 +1,177 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-07-21 + * Description : a widget to display an image histogram. + * + * 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. + * + * ============================================================ */ + +#ifndef HISTOGRAMWIDGET_H +#define HISTOGRAMWIDGET_H + +// TQt includes. + +#include <tqwidget.h> + +// Local includes. + +#include "dcolor.h" +#include "digikam_export.h" + +class TQCustomEvent; + +namespace Digikam +{ + +class ImageHistogram; +class HistogramWidgetPriv; + +class DIGIKAM_EXPORT HistogramWidget : public TQWidget +{ +TQ_OBJECT + + +public: + + enum HistogramType + { + ValueHistogram = 0, // Luminosity. + RedChannelHistogram, // Red channel. + GreenChannelHistogram, // Green channel. + BlueChannelHistogram, // Blue channel. + AlphaChannelHistogram, // Alpha channel. + ColorChannelsHistogram // All color channels. + }; + + enum HistogramScale + { + LinScaleHistogram=0, // Linear scale. + LogScaleHistogram // Logarithmic scale. + }; + + enum HistogramAllColorMode + { + RedColor=0, // Red color to foreground in All Colors Channel mode. + GreenColor, // Green color to foreground in All Colors Channel mode. + BlueColor // Blue color to foreground in All Colors Channel mode. + }; + + enum HistogramRenderingType + { + FullImageHistogram=0, // Full image histogram rendering. + ImageSelectionHistogram // Image selection histogram rendering. + }; + +public: + + /** Constructor without image data. Needed to use updateData() method after to create instance.*/ + HistogramWidget(int w, int h, // Widget size. + TQWidget *parent=0, bool selectMode=true, + bool showProgress=true, + bool statisticsVisible=false); + + /** Constructor with image data and without image selection data.*/ + HistogramWidget(int w, int h, // Widget size. + uchar *i_data, uint i_w, uint i_h, // Full image info. + bool i_sixteenBits, // 8 or 16 bits image. + TQWidget *parent=0, bool selectMode=true, + bool showProgress=true, + bool statisticsVisible=false); + + /** Constructor with image data and image selection data.*/ + HistogramWidget(int w, int h, // Widget size. + uchar *i_data, uint i_w, uint i_h, // Full image info. + uchar *s_data, uint s_w, uint s_h, // Image selection info. + bool i_sixteenBits, // 8 or 16 bits image. + TQWidget *parent=0, bool selectMode=true, + bool showProgress=true, + bool statisticsVisible=false); + + void setup(int w, int h, bool selectMode=true, + bool showProgress=true, + bool statisticsVisible=false); + + ~HistogramWidget(); + + /** Stop current histogram computations.*/ + void stopHistogramComputation(void); + + /** Update full image histogram data methods.*/ + void updateData(uchar *i_data, uint i_w, uint i_h, + bool i_sixteenBits, // 8 or 16 bits image. + uchar *s_data=0, uint s_w=0, uint s_h=0, + bool showProgress=true); + + /** Update image selection histogram data methods.*/ + void updateSelectionData(uchar *s_data, uint s_w, uint s_h, + bool i_sixteenBits, // 8 or 16 bits image. + bool showProgress=true); + + void setDataLoading(); + void setLoadingFailed(); + + void setHistogramGuideByColor(const DColor& color); + + void reset(); + +public: + + int m_channelType; // Channel type to draw. + int m_scaleType; // Scale to use for drawing. + int m_colorType; // Color to use for drawing in All Colors Channel mode. + int m_renderingType; // Using full image or image selection for histogram rendering. + + ImageHistogram *m_imageHistogram; // Full image. + ImageHistogram *m_selectionHistogram; // Image selection. + +signals: + + void signalIntervalChanged(int min, int max); + void signalMaximumValueChanged(int); + void signalHistogramComputationDone(bool); + void signalHistogramComputationFailed(); + +public slots: + + void slotMinValueChanged(int min); + void slotMaxValueChanged(int max); + +protected slots: + + void slotBlinkTimerDone(); + +protected: + + void paintEvent(TQPaintEvent*); + void mousePressEvent(TQMouseEvent*); + void mouseReleaseEvent(TQMouseEvent*); + void mouseMoveEvent(TQMouseEvent*); + +private : + + void customEvent(TQCustomEvent*); + void notifyValuesChanged(); + +private: + + HistogramWidgetPriv* d; +}; + +} // namespace Digikam + +#endif /* HISTOGRAMWIDGET_H */ diff --git a/src/libs/widgets/common/paniconwidget.cpp b/src/libs/widgets/common/paniconwidget.cpp new file mode 100644 index 00000000..d5549691 --- /dev/null +++ b/src/libs/widgets/common/paniconwidget.cpp @@ -0,0 +1,324 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-08-22 + * Description : a generic widget to display a panel to choose + * a rectangular image area. + * + * 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 <tqpen.h> +#include <tqtimer.h> + +// KDE includes. + +#include <kcursor.h> + +// Local includes. + +#include "ddebug.h" +#include "paniconwidget.h" +#include "paniconwidget.moc" + +namespace Digikam +{ + +class PanIconWidgetPriv +{ + +public: + + PanIconWidgetPriv() + { + moveSelection = false; + } + + bool moveSelection; + + int xpos; + int ypos; + + TQRect regionSelection; // Original size image selection. + + TQImage image; +}; + +PanIconWidget::PanIconWidget(TQWidget *parent, WFlags flags) + : TQWidget(parent, 0, flags) +{ + d = new PanIconWidgetPriv; + m_flicker = false; + m_timerID = 0; + m_pixmap = 0; + m_zoomFactor = 1.0; + + setBackgroundMode(TQt::NoBackground); + setMouseTracking(true); +} + +PanIconWidget::~PanIconWidget() +{ + if (m_timerID) killTimer(m_timerID); + + if (m_pixmap) delete m_pixmap; + + delete d; +} + +void PanIconWidget::setImage(int previewWidth, int previewHeight, const TQImage& image) +{ + TQSize sz(image.width(), image.height()); + sz.scale(previewWidth, previewHeight, TQSize::ScaleMin); + m_pixmap = new TQPixmap(previewWidth, previewHeight); + m_width = sz.width(); + m_height = sz.height(); + d->image = image.smoothScale(sz.width(), sz.height()); + m_orgWidth = image.width(); + m_orgHeight = image.height(); + m_zoomedOrgWidth = image.width(); + m_zoomedOrgHeight = image.height(); + setFixedSize(m_width, m_height); + + m_rect = TQRect(width()/2-m_width/2, height()/2-m_height/2, m_width, m_height); + updatePixmap(); + m_timerID = startTimer(800); +} + +void PanIconWidget::setImage(int previewWidth, int previewHeight, const DImg& image) +{ + DImg img(image); + setImage(previewWidth, previewHeight, img.copyTQImage()); +} + +void PanIconWidget::slotZoomFactorChanged(double factor) +{ + if (m_zoomFactor == factor) return; + m_zoomFactor = factor; + m_zoomedOrgWidth = (int)(m_orgWidth * factor); + m_zoomedOrgHeight = (int)(m_orgHeight * factor); + updatePixmap(); + repaint(false); +} + +void PanIconWidget::setRegionSelection(const TQRect& regionSelection) +{ + d->regionSelection = regionSelection; + m_localRegionSelection.setX( m_rect.x() + (int)((float)d->regionSelection.x() * + ((float)m_width / (float)m_zoomedOrgWidth)) ); + + m_localRegionSelection.setY( m_rect.y() + (int)((float)d->regionSelection.y() * + ((float)m_height / (float)m_zoomedOrgHeight)) ); + + m_localRegionSelection.setWidth( (int)((float)d->regionSelection.width() * + ((float)m_width / (float)m_zoomedOrgWidth)) ); + + m_localRegionSelection.setHeight( (int)((float)d->regionSelection.height() * + ((float)m_height / (float)m_zoomedOrgHeight)) ); + + updatePixmap(); + repaint(false); +} + +TQRect PanIconWidget::getRegionSelection() +{ + return (d->regionSelection); +} + +void PanIconWidget::setCursorToLocalRegionSelectionCenter() +{ + TQCursor::setPos(mapToGlobal(m_localRegionSelection.center())); +} + +void PanIconWidget::setCenterSelection() +{ + setRegionSelection(TQRect( + (int)(((float)m_zoomedOrgWidth / 2.0) - ((float)d->regionSelection.width() / 2.0)), + (int)(((float)m_zoomedOrgHeight / 2.0) - ((float)d->regionSelection.height() / 2.0)), + d->regionSelection.width(), + d->regionSelection.height())); +} + +void PanIconWidget::regionSelectionMoved(bool targetDone) +{ + if (targetDone) + { + updatePixmap(); + repaint(false); + } + + int x = (int)lround( ((float)m_localRegionSelection.x() - (float)m_rect.x() ) * + ((float)m_zoomedOrgWidth / (float)m_width) ); + + int y = (int)lround( ((float)m_localRegionSelection.y() - (float)m_rect.y() ) * + ((float)m_zoomedOrgHeight / (float)m_height) ); + + int w = (int)lround( (float)m_localRegionSelection.width() * + ((float)m_zoomedOrgWidth / (float)m_width) ); + + int h = (int)lround( (float)m_localRegionSelection.height() * + ((float)m_zoomedOrgHeight / (float)m_height) ); + + d->regionSelection.setX(x); + d->regionSelection.setY(y); + d->regionSelection.setWidth(w); + d->regionSelection.setHeight(h); + + emit signalSelectionMoved( d->regionSelection, targetDone ); +} + +void PanIconWidget::updatePixmap() +{ + // Drawing background and image. + m_pixmap->fill(colorGroup().background()); + bitBlt(m_pixmap, m_rect.x(), m_rect.y(), &d->image, 0, 0); + + TQPainter p(m_pixmap); + + // Drawing selection border + + if (m_flicker) p.setPen(TQPen(TQt::white, 1, TQt::SolidLine)); + else p.setPen(TQPen(TQt::red, 1, TQt::SolidLine)); + + p.drawRect(m_localRegionSelection.x(), + m_localRegionSelection.y(), + m_localRegionSelection.width(), + m_localRegionSelection.height()); + + if (m_flicker) p.setPen(TQPen(TQt::red, 1, TQt::DotLine)); + else p.setPen(TQPen(TQt::white, 1, TQt::DotLine)); + + p.drawRect(m_localRegionSelection.x(), + m_localRegionSelection.y(), + m_localRegionSelection.width(), + m_localRegionSelection.height()); + + p.end(); +} + +void PanIconWidget::paintEvent(TQPaintEvent*) +{ + bitBlt(this, 0, 0, m_pixmap); +} + +void PanIconWidget::setMouseFocus() +{ + raise(); + d->xpos = m_localRegionSelection.center().x(); + d->ypos = m_localRegionSelection.center().y(); + d->moveSelection = true; + setCursor( KCursor::sizeAllCursor() ); + emit signalSelectionTakeFocus(); +} + +void PanIconWidget::hideEvent(TQHideEvent *e) +{ + TQWidget::hideEvent(e); + + if ( d->moveSelection ) + { + d->moveSelection = false; + setCursor( KCursor::arrowCursor() ); + emit signalHiden(); + } +} + +void PanIconWidget::mousePressEvent ( TQMouseEvent * e ) +{ + if ( (e->button() == TQt::LeftButton || e->button() == TQt::MidButton) && + m_localRegionSelection.contains( e->x(), e->y() ) ) + { + d->xpos = e->x(); + d->ypos = e->y(); + d->moveSelection = true; + setCursor( KCursor::sizeAllCursor() ); + emit signalSelectionTakeFocus(); + } +} + +void PanIconWidget::mouseMoveEvent ( TQMouseEvent * e ) +{ + if ( d->moveSelection && + (e->state() == TQt::LeftButton || e->state() == TQt::MidButton) ) + { + int newxpos = e->x(); + int newypos = e->y(); + + m_localRegionSelection.moveBy (newxpos - d->xpos, newypos - d->ypos); + + d->xpos = newxpos; + d->ypos = newypos; + + // Perform normalization of selection area. + + if (m_localRegionSelection.left() < m_rect.left()) + m_localRegionSelection.moveLeft(m_rect.left()); + + if (m_localRegionSelection.top() < m_rect.top()) + m_localRegionSelection.moveTop(m_rect.top()); + + if (m_localRegionSelection.right() > m_rect.right()) + m_localRegionSelection.moveRight(m_rect.right()); + + if (m_localRegionSelection.bottom() > m_rect.bottom()) + m_localRegionSelection.moveBottom(m_rect.bottom()); + + updatePixmap(); + repaint(false); + regionSelectionMoved(false); + return; + } + else + { + if ( m_localRegionSelection.contains( e->x(), e->y() ) ) + setCursor( KCursor::handCursor() ); + else + setCursor( KCursor::arrowCursor() ); + } +} + +void PanIconWidget::mouseReleaseEvent ( TQMouseEvent * ) +{ + if ( d->moveSelection ) + { + d->moveSelection = false; + setCursor( KCursor::arrowCursor() ); + regionSelectionMoved(true); + } +} + +void PanIconWidget::timerEvent(TQTimerEvent * e) +{ + if (e->timerId() == m_timerID) + { + m_flicker = !m_flicker; + updatePixmap(); + repaint(false); + } + else + TQWidget::timerEvent(e); +} + +} // NameSpace Digikam diff --git a/src/libs/widgets/common/paniconwidget.h b/src/libs/widgets/common/paniconwidget.h new file mode 100644 index 00000000..40b0758e --- /dev/null +++ b/src/libs/widgets/common/paniconwidget.h @@ -0,0 +1,120 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-08-22 + * Description : a generic widget to display a panel to choose + * a rectangular image area. + * + * 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. + * + * ============================================================ */ + +#ifndef PANICONWIDGET_H +#define PANICONWIDGET_H + +// TQt includes. + +#include <tqwidget.h> +#include <tqrect.h> +#include <tqimage.h> + +// Local includes. + +#include "dimg.h" + +namespace Digikam +{ + +class ImagePanIconWidget; +class PanIconWidgetPriv; + +class PanIconWidget : public TQWidget +{ +TQ_OBJECT + + +public: + + PanIconWidget(TQWidget *parent=0, WFlags flags=TQt::WDestructiveClose); + ~PanIconWidget(); + + void setImage(int previewWidth, int previewHeight, const TQImage& image); + void setImage(int previewWidth, int previewHeight, const DImg& image); + + void setRegionSelection(const TQRect& regionSelection); + TQRect getRegionSelection(); + void setCenterSelection(); + + void setCursorToLocalRegionSelectionCenter(); + void setMouseFocus(); + +signals: + + // Used with ImagePreview widget. + // Emit when selection have been moved with mouse. 'targetDone' booleen + // value is used for indicate if the mouse have been released. + void signalSelectionMoved(const TQRect& rect, bool targetDone ); + + void signalSelectionTakeFocus(); + + void signalHiden(); + +public slots: + + void slotZoomFactorChanged(double); + +protected: + + void hideEvent(TQHideEvent*); + void paintEvent(TQPaintEvent*); + void mousePressEvent(TQMouseEvent*); + void mouseReleaseEvent(TQMouseEvent*); + void mouseMoveEvent(TQMouseEvent*); + void timerEvent(TQTimerEvent*); + + /** Recalculate the target selection position and emit 'signalSelectionMoved'.*/ + void regionSelectionMoved(bool targetDone); + + virtual void updatePixmap(); + +protected: + + bool m_flicker; + + int m_timerID; + int m_width; + int m_height; + int m_zoomedOrgWidth; + int m_zoomedOrgHeight; + int m_orgWidth; + int m_orgHeight; + + double m_zoomFactor; + + TQRect m_rect; + TQRect m_localRegionSelection; // Thumbnail size selection. + + TQPixmap *m_pixmap; + + +private: + + PanIconWidgetPriv* d; +}; + +} // NameSpace Digikam + +#endif /* PANICONWIDGET_H */ diff --git a/src/libs/widgets/common/previewwidget.cpp b/src/libs/widgets/common/previewwidget.cpp new file mode 100644 index 00000000..0fe5cb29 --- /dev/null +++ b/src/libs/widgets/common/previewwidget.cpp @@ -0,0 +1,640 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2006-06-13 + * Description : a widget to display an image preview + * + * Copyright (C) 2006-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. + * + * ============================================================ */ + +// C++ includes. + +#include <cmath> + +// TQt includes. + +#include <tqstring.h> +#include <tqcache.h> +#include <tqpainter.h> +#include <tqimage.h> +#include <tqpixmap.h> +#include <tqrect.h> +#include <tqtimer.h> +#include <tqguardedptr.h> + +// KDE includes. + +#include <kcursor.h> +#include <tdelocale.h> + +// Local includes. + +#include "ddebug.h" +#include "previewwidget.h" +#include "previewwidget.moc" + +namespace Digikam +{ + +class PreviewWidgetPriv +{ +public: + + PreviewWidgetPriv() : + tileSize(128), zoomMultiplier(1.2) + { + midButtonX = 0; + midButtonY = 0; + autoZoom = false; + fullScreen = false; + zoom = 1.0; + minZoom = 0.1; + maxZoom = 12.0; + zoomWidth = 0; + zoomHeight = 0; + tileTmpPix = new TQPixmap(tileSize, tileSize); + + tileCache.setMaxCost((10*1024*1024)/(tileSize*tileSize*4)); + tileCache.setAutoDelete(true); + } + + bool autoZoom; + bool fullScreen; + + const int tileSize; + int midButtonX; + int midButtonY; + int zoomWidth; + int zoomHeight; + + double zoom; + double minZoom; + double maxZoom; + const double zoomMultiplier; + + TQPoint centerZoomPoint; + + TQRect pixmapRect; + + TQCache<TQPixmap> tileCache; + + TQPixmap* tileTmpPix; + + TQColor bgColor; +}; + +PreviewWidget::PreviewWidget(TQWidget *parent) + : TQScrollView(parent, 0, TQt::WDestructiveClose) +{ + d = new PreviewWidgetPriv; + d->bgColor.setRgb(0, 0, 0); + m_movingInProgress = false; + + viewport()->setBackgroundMode(TQt::NoBackground); + viewport()->setMouseTracking(false); + + horizontalScrollBar()->setLineStep( 1 ); + horizontalScrollBar()->setPageStep( 1 ); + verticalScrollBar()->setLineStep( 1 ); + verticalScrollBar()->setPageStep( 1 ); + + setFrameStyle(TQFrame::GroupBoxPanel|TQFrame::Plain); + setMargin(0); + setLineWidth(1); +} + +PreviewWidget::~PreviewWidget() +{ + delete d->tileTmpPix; + delete d; +} + +void PreviewWidget::setBackgroundColor(const TQColor& color) +{ + if (d->bgColor == color) + return; + + d->bgColor = color; + viewport()->update(); +} + +void PreviewWidget::slotReset() +{ + d->tileCache.clear(); + resetPreview(); +} + +TQRect PreviewWidget::previewRect() +{ + return d->pixmapRect; +} + +int PreviewWidget::tileSize() +{ + return d->tileSize; +} + +int PreviewWidget::zoomWidth() +{ + return d->zoomWidth; +} + +int PreviewWidget::zoomHeight() +{ + return d->zoomHeight; +} + +double PreviewWidget::zoomMax() +{ + return d->maxZoom; +} + +double PreviewWidget::zoomMin() +{ + return d->minZoom; +} + +void PreviewWidget::setZoomMax(double z) +{ + d->maxZoom = ceilf(z * 10000.0) / 10000.0; +} + +void PreviewWidget::setZoomMin(double z) +{ + d->minZoom = floor(z * 10000.0) / 10000.0; +} + +bool PreviewWidget::maxZoom() +{ + return (d->zoom >= d->maxZoom); +} + +bool PreviewWidget::minZoom() +{ + return (d->zoom <= d->minZoom); +} + +double PreviewWidget::snapZoom(double zoom) +{ + // If the zoom value gets changed from d->zoom to zoom + // across 50%, 100% or fit-to-window, then return the + // the corresponding special value. Otherwise zoom is returned unchanged. + double fit = calcAutoZoomFactor(ZoomInOrOut); + TQValueList<double> snapValues; + snapValues.append(0.5); + snapValues.append(1.0); + snapValues.append(fit); + qHeapSort(snapValues); + TQValueList<double>::const_iterator it; + + if (d->zoom < zoom) + { + for(it = snapValues.constBegin(); it != snapValues.constEnd(); ++it) + { + double z = *it; + if ((d->zoom < z) && (zoom > z)) + { + zoom = z; + break; + } + } + } + else + { + for(it = snapValues.constEnd(); it != snapValues.constBegin(); --it) + { + double z = *it; + if ((d->zoom > z) && (zoom < z)) + { + zoom = z; + break; + } + } + } + + return zoom; +} + +void PreviewWidget::slotIncreaseZoom() +{ + double zoom = d->zoom * d->zoomMultiplier; + zoom = snapZoom(zoom > zoomMax() ? zoomMax() : zoom); + setZoomFactor(zoom); +} + +void PreviewWidget::slotDecreaseZoom() +{ + double zoom = d->zoom / d->zoomMultiplier; + zoom = snapZoom(zoom < zoomMin() ? zoomMin() : zoom); + setZoomFactor(zoom); +} + +void PreviewWidget::setZoomFactorSnapped(double zoom) +{ + double fit = calcAutoZoomFactor(ZoomInOrOut); + if (fabs(zoom-1.0) < 0.05) + { + zoom = 1.0; + } + if (fabs(zoom-0.5) < 0.05) + { + zoom = 0.5; + } + if (fabs(zoom-fit) < 0.05) + { + zoom = fit; + } + + setZoomFactor(zoom); +} + +void PreviewWidget::setZoomFactor(double zoom) +{ + setZoomFactor(zoom, false); +} + +void PreviewWidget::setZoomFactor(double zoom, bool centerView) +{ + // Zoom using center of canvas and given zoom factor. + + double oldZoom = d->zoom; + double cpx, cpy; + + if (d->centerZoomPoint.isNull()) + { + // center on current center + // store old center pos + cpx = contentsX() + visibleWidth() / 2.0; + cpy = contentsY() + visibleHeight() / 2.0; + + cpx = ( cpx / d->tileSize ) * floor(d->tileSize / d->zoom); + cpy = ( cpy / d->tileSize ) * floor(d->tileSize / d->zoom); + } + else + { + // keep mouse pointer position constant + // store old content pos + cpx = contentsX(); + cpy = contentsY(); + } + + // To limit precision of zoom value and reduce error with check of max/min zoom. + d->zoom = floor(zoom * 10000.0) / 10000.0; + d->zoomWidth = (int)(previewWidth() * d->zoom); + d->zoomHeight = (int)(previewHeight() * d->zoom); + + updateContentsSize(); + + // adapt step size to zoom factor. Overall, using a finer step size than scrollbar default. + int step = TQMAX(2, 2*lround(d->zoom)); + horizontalScrollBar()->setLineStep( step ); + horizontalScrollBar()->setPageStep( step * 10 ); + verticalScrollBar()->setLineStep( step ); + verticalScrollBar()->setPageStep( step * 10 ); + + viewport()->setUpdatesEnabled(false); + if (d->centerZoomPoint.isNull()) + { + cpx = ( cpx * d->tileSize ) / floor(d->tileSize / d->zoom); + cpy = ( cpy * d->tileSize ) / floor(d->tileSize / d->zoom); + + if (centerView) + { + cpx = d->zoomWidth/2.0; + cpy = d->zoomHeight/2.0; + } + + center((int)cpx, (int)(cpy)); + } + else + { + cpx = d->zoom * d->centerZoomPoint.x() / oldZoom - d->centerZoomPoint.x() + cpx; + cpy = d->zoom * d->centerZoomPoint.y() / oldZoom - d->centerZoomPoint.y() + cpy; + + setContentsPos((int)cpx, (int)(cpy)); + } + viewport()->setUpdatesEnabled(true); + viewport()->update(); + + zoomFactorChanged(d->zoom); +} + +double PreviewWidget::zoomFactor() +{ + return d->zoom; +} + +bool PreviewWidget::isFitToWindow() +{ + return d->autoZoom; +} + +void PreviewWidget::fitToWindow() +{ + updateAutoZoom(); + updateContentsSize(); + zoomFactorChanged(d->zoom); + viewport()->update(); +} + +void PreviewWidget::toggleFitToWindow() +{ + d->autoZoom = !d->autoZoom; + + if (d->autoZoom) + { + updateAutoZoom(); + } + else + { + d->zoom = 1.0; + zoomFactorChanged(d->zoom); + } + + updateContentsSize(); + viewport()->update(); +} + +void PreviewWidget::toggleFitToWindowOr100() +{ + // If the current zoom is 100%, then fit to window. + if (d->zoom == 1.0) + { + fitToWindow(); + } + else + { + setZoomFactor(1.0, true); + } +} + +void PreviewWidget::updateAutoZoom(AutoZoomMode mode) +{ + d->zoom = calcAutoZoomFactor(mode); + d->zoomWidth = (int)(previewWidth() * d->zoom); + d->zoomHeight = (int)(previewHeight() * d->zoom); + + zoomFactorChanged(d->zoom); +} + +double PreviewWidget::calcAutoZoomFactor(AutoZoomMode mode) +{ + if (previewIsNull()) return d->zoom; + + double srcWidth = previewWidth(); + double srcHeight = previewHeight(); + double dstWidth = contentsRect().width(); + double dstHeight = contentsRect().height(); + + double zoom = TQMIN(dstWidth/srcWidth, dstHeight/srcHeight); + // limit precision as above + zoom = floor(zoom * 10000.0) / 10000.0; + if (mode == ZoomInOrOut) + // fit to available space, scale up or down + return zoom; + else + // ZoomInOnly: accept that an image is smaller than available space, dont scale up + return TQMIN(1.0, zoom); +} + +void PreviewWidget::updateContentsSize() +{ + viewport()->setUpdatesEnabled(false); + + if (visibleWidth() > d->zoomWidth || visibleHeight() > d->zoomHeight) + { + // Center the image + int centerx = contentsRect().width()/2; + int centery = contentsRect().height()/2; + int xoffset = int(centerx - d->zoomWidth/2); + int yoffset = int(centery - d->zoomHeight/2); + xoffset = TQMAX(xoffset, 0); + yoffset = TQMAX(yoffset, 0); + + d->pixmapRect = TQRect(xoffset, yoffset, d->zoomWidth, d->zoomHeight); + } + else + { + d->pixmapRect = TQRect(0, 0, d->zoomWidth, d->zoomHeight); + } + + d->tileCache.clear(); + setContentsSize(); + viewport()->setUpdatesEnabled(true); +} + +void PreviewWidget::setContentsSize() +{ + resizeContents(d->zoomWidth, d->zoomHeight); +} + +void PreviewWidget::resizeEvent(TQResizeEvent* e) +{ + if (!e) return; + + TQScrollView::resizeEvent(e); + + if (d->autoZoom) + updateAutoZoom(); + + updateContentsSize(); + + // No need to repaint. its called + // automatically after resize + + // To be sure than corner widget used to pan image will be hide/show + // accordinly with resize event. + zoomFactorChanged(d->zoom); +} + +void PreviewWidget::viewportPaintEvent(TQPaintEvent *e) +{ + TQRect er(e->rect()); + er = TQRect(TQMAX(er.x() - 1, 0), + TQMAX(er.y() - 1, 0), + TQMIN(er.width() + 2, contentsRect().width()), + TQMIN(er.height() + 2, contentsRect().height())); + + bool antialias = (d->zoom <= 1.0) ? true : false; + + TQRect o_cr(viewportToContents(er.topLeft()), viewportToContents(er.bottomRight())); + TQRect cr = o_cr; + + TQRegion clipRegion(er); + cr = d->pixmapRect.intersect(cr); + + if (!cr.isEmpty() && !previewIsNull()) + { + clipRegion -= TQRect(contentsToViewport(cr.topLeft()), cr.size()); + + TQRect pr = TQRect(cr.x() - d->pixmapRect.x(), cr.y() - d->pixmapRect.y(), + cr.width(), cr.height()); + + int x1 = (int)floor((double)pr.x() / (double)d->tileSize) * d->tileSize; + int y1 = (int)floor((double)pr.y() / (double)d->tileSize) * d->tileSize; + int x2 = (int)ceilf((double)pr.right() / (double)d->tileSize) * d->tileSize; + int y2 = (int)ceilf((double)pr.bottom() / (double)d->tileSize) * d->tileSize; + + TQPixmap pix(d->tileSize, d->tileSize); + int sx, sy, sw, sh; + int step = (int)floor(d->tileSize / d->zoom); + + for (int j = y1 ; j < y2 ; j += d->tileSize) + { + for (int i = x1 ; i < x2 ; i += d->tileSize) + { + TQString key = TQString("%1,%2").arg(i).arg(j); + TQPixmap *pix = d->tileCache.find(key); + + if (!pix) + { + if (antialias) + { + pix = new TQPixmap(d->tileSize, d->tileSize); + d->tileCache.insert(key, pix); + } + else + { + pix = d->tileTmpPix; + } + + pix->fill(d->bgColor); + + sx = (int)floor((double)i / d->tileSize ) * step; + sy = (int)floor((double)j / d->tileSize ) * step; + sw = step; + sh = step; + + paintPreview(pix, sx, sy, sw, sh); + } + + TQRect r(i, j, d->tileSize, d->tileSize); + TQRect ir = pr.intersect(r); + TQPoint pt(contentsToViewport(TQPoint(ir.x() + d->pixmapRect.x(), + ir.y() + d->pixmapRect.y()))); + + bitBlt(viewport(), pt.x(), pt.y(), + pix, + ir.x()-r.x(), ir.y()-r.y(), + ir.width(), ir.height()); + } + } + } + + TQPainter p(viewport()); + p.setClipRegion(clipRegion); + p.fillRect(er, d->bgColor); + p.end(); + + viewportPaintExtraData(); +} + +void PreviewWidget::contentsMousePressEvent(TQMouseEvent *e) +{ + if (!e || e->button() == TQt::RightButton) + return; + + m_movingInProgress = false; + + if (e->button() == TQt::LeftButton) + { + emit signalLeftButtonClicked(); + } + else if (e->button() == TQt::MidButton) + { + if (visibleWidth() < d->zoomWidth || + visibleHeight() < d->zoomHeight) + { + m_movingInProgress = true; + d->midButtonX = e->x(); + d->midButtonY = e->y(); + viewport()->repaint(false); + viewport()->setCursor(TQt::SizeAllCursor); + } + return; + } + + viewport()->setMouseTracking(false); +} + +void PreviewWidget::contentsMouseMoveEvent(TQMouseEvent *e) +{ + if (!e) return; + + if (e->state() & TQt::MidButton) + { + if (m_movingInProgress) + { + scrollBy(d->midButtonX - e->x(), + d->midButtonY - e->y()); + emit signalContentsMovedEvent(false); + } + } +} + +void PreviewWidget::contentsMouseReleaseEvent(TQMouseEvent *e) +{ + if (!e) return; + + m_movingInProgress = false; + + if (e->button() == TQt::MidButton) + { + emit signalContentsMovedEvent(true); + viewport()->unsetCursor(); + viewport()->repaint(false); + } + + if (e->button() == TQt::RightButton) + { + emit signalRightButtonClicked(); + } +} + +void PreviewWidget::contentsWheelEvent(TQWheelEvent *e) +{ + e->accept(); + + if (e->state() & TQt::ShiftButton) + { + if (e->delta() < 0) + emit signalShowNextImage(); + else if (e->delta() > 0) + emit signalShowPrevImage(); + return; + } + else if (e->state() & TQt::ControlButton) + { + // When zooming with the mouse-wheel, the image center is kept fixed. + d->centerZoomPoint = e->pos(); + if (e->delta() < 0 && !minZoom()) + slotDecreaseZoom(); + else if (e->delta() > 0 && !maxZoom()) + slotIncreaseZoom(); + d->centerZoomPoint = TQPoint(); + return; + } + + TQScrollView::contentsWheelEvent(e); +} + +void PreviewWidget::zoomFactorChanged(double zoom) +{ + emit signalZoomFactorChanged(zoom); +} + +} // NameSpace Digikam diff --git a/src/libs/widgets/common/previewwidget.h b/src/libs/widgets/common/previewwidget.h new file mode 100644 index 00000000..03369a42 --- /dev/null +++ b/src/libs/widgets/common/previewwidget.h @@ -0,0 +1,131 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2006-06-13 + * Description : a widget to display an image preview + * + * Copyright (C) 2006-2007 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. + * + * ============================================================ */ + +#ifndef PREVIEWWIDGET_H +#define PREVIEWWIDGET_H + +// TQt includes. + +#include <tqscrollview.h> + +// Local includes. + +#include "digikam_export.h" + +class TQPainter; +class TQPixmap; +class TQColor; + +namespace Digikam +{ + +class PreviewWidgetPriv; + +class DIGIKAM_EXPORT PreviewWidget : public TQScrollView +{ +TQ_OBJECT + + +public: + + PreviewWidget(TQWidget *parent=0); + ~PreviewWidget(); + + void setZoomFactor(double z); + void setZoomFactor(double z, bool centerView); + void setZoomFactorSnapped(double z); + + void setBackgroundColor(const TQColor& color); + void fitToWindow(); + bool isFitToWindow(); + void toggleFitToWindow(); + void toggleFitToWindowOr100(); + + int zoomWidth(); + int zoomHeight(); + bool maxZoom(); + bool minZoom(); + double snapZoom(double zoom); + + double zoomFactor(); + double zoomMax(); + double zoomMin(); + void setZoomMax(double z); + void setZoomMin(double z); + +signals: + + void signalRightButtonClicked(); + void signalLeftButtonClicked(); + void signalShowNextImage(); + void signalShowPrevImage(); + void signalZoomFactorChanged(double); + void signalContentsMovedEvent(bool); + +public slots: + + void slotIncreaseZoom(); + void slotDecreaseZoom(); + void slotReset(); + +protected: + + bool m_movingInProgress; + +protected: + + enum AutoZoomMode + { + ZoomInOrOut, + ZoomInOnly + }; + + double calcAutoZoomFactor(AutoZoomMode mode = ZoomInOrOut); + int tileSize(); + void updateAutoZoom(AutoZoomMode mode = ZoomInOrOut); + void updateContentsSize(); + TQRect previewRect(); + + virtual void resizeEvent(TQResizeEvent *); + virtual void viewportPaintEvent(TQPaintEvent *); + virtual void contentsMousePressEvent(TQMouseEvent *); + virtual void contentsMouseMoveEvent(TQMouseEvent *); + virtual void contentsMouseReleaseEvent(TQMouseEvent *); + virtual void contentsWheelEvent(TQWheelEvent *); + virtual void setContentsSize(); + virtual void viewportPaintExtraData(){}; + virtual int previewWidth()=0; + virtual int previewHeight()=0; + virtual bool previewIsNull()=0; + virtual void resetPreview()=0; + virtual void paintPreview(TQPixmap *pix, int sx, int sy, int sw, int sh)=0; + virtual void zoomFactorChanged(double zoom); + +private: + + PreviewWidgetPriv* d; +}; + +} // NameSpace Digikam + +#endif /* PREVIEWWIDGET_H */ diff --git a/src/libs/widgets/common/searchtextbar.cpp b/src/libs/widgets/common/searchtextbar.cpp new file mode 100644 index 00000000..1a81c03b --- /dev/null +++ b/src/libs/widgets/common/searchtextbar.cpp @@ -0,0 +1,260 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2007-11-25 + * Description : a bar used to search a string. + * + * Copyright (C) 2007-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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqcolor.h> +#include <tqpalette.h> +#include <tqpainter.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqtoolbutton.h> + +// KDE includes. + +#include <tdeapplication.h> +#include <kiconloader.h> +#include <kdialogbase.h> +#include <tdeconfig.h> + +// Local includes. + +#include "searchtextbar.h" +#include "searchtextbar.moc" + +namespace Digikam +{ + +class DLineEditPriv +{ +public: + + DLineEditPriv() + { + drawMsg = true; + } + + bool drawMsg; + + TQString message; +}; + +DLineEdit::DLineEdit(const TQString &msg, TQWidget *parent) + : KLineEdit(parent) +{ + d = new DLineEditPriv; + setMessage(msg); +} + +DLineEdit::~DLineEdit() +{ + delete d; +} + +TQString DLineEdit::message() const +{ + return d->message; +} + +void DLineEdit::setMessage(const TQString &msg) +{ + d->message = msg; + repaint(); +} + +void DLineEdit::setText(const TQString &txt) +{ + d->drawMsg = txt.isEmpty(); + repaint(); + KLineEdit::setText(txt); +} + +void DLineEdit::drawContents(TQPainter *p) +{ + KLineEdit::drawContents(p); + + if (d->drawMsg && !hasFocus()) + { + TQPen tmp = p->pen(); + p->setPen(palette().color(TQPalette::Disabled, TQColorGroup::Text)); + TQRect cr = contentsRect(); + + // Add two pixel margin on the left side + cr.rLeft() += 3; + p->drawText(cr, AlignAuto | AlignVCenter, d->message); + p->setPen( tmp ); + } +} + +void DLineEdit::dropEvent(TQDropEvent *e) +{ + d->drawMsg = false; + KLineEdit::dropEvent(e); +} + +void DLineEdit::focusInEvent(TQFocusEvent *e) +{ + if (d->drawMsg) + { + d->drawMsg = false; + repaint(); + } + TQLineEdit::focusInEvent(e); +} + +void DLineEdit::focusOutEvent(TQFocusEvent *e) +{ + if (text().isEmpty()) + { + d->drawMsg = true; + repaint(); + } + TQLineEdit::focusOutEvent(e); +} + +// --------------------------------------------------------------------- + +class SearchTextBarPriv +{ +public: + + SearchTextBarPriv() + { + textQueryCompletion = false; + searchEdit = 0; + clearButton = 0; + } + + bool textQueryCompletion; + + TQToolButton *clearButton; + + DLineEdit *searchEdit; +}; + +SearchTextBar::SearchTextBar(TQWidget *parent, const char* name, const TQString &msg) + : TQWidget(parent, 0, TQt::WDestructiveClose) +{ + d = new SearchTextBarPriv; + setFocusPolicy(TQWidget::NoFocus); + setName(name); + + TQHBoxLayout *hlay = new TQHBoxLayout(this); + + d->clearButton = new TQToolButton(this); + d->clearButton->setEnabled(false); + d->clearButton->setAutoRaise(true); + d->clearButton->setIconSet(kapp->iconLoader()->loadIcon("clear_left", + TDEIcon::Toolbar, TDEIcon::SizeSmall)); + + d->searchEdit = new DLineEdit(msg, this); + TDECompletion *kcom = new TDECompletion; + kcom->setOrder(TDECompletion::Sorted); + d->searchEdit->setCompletionObject(kcom, true); + d->searchEdit->setAutoDeleteCompletionObject(true); + d->searchEdit->setSizePolicy(TQSizePolicy(TQSizePolicy::Expanding, TQSizePolicy::Minimum)); + + hlay->setSpacing(0); + hlay->setMargin(0); + hlay->addWidget(d->searchEdit); + hlay->addWidget(d->clearButton); + + connect(d->clearButton, TQ_SIGNAL(clicked()), + d->searchEdit, TQ_SLOT(clear())); + + connect(d->searchEdit, TQ_SIGNAL(textChanged(const TQString&)), + this, TQ_SLOT(slotTextChanged(const TQString&))); + + TDEConfig *config = kapp->config(); + config->setGroup(name + TQString(" Search Text Tool")); + d->searchEdit->setCompletionMode((TDEGlobalSettings::Completion)config->readNumEntry("AutoCompletionMode", + (int)TDEGlobalSettings::CompletionAuto)); +} + +SearchTextBar::~SearchTextBar() +{ + TDEConfig *config = kapp->config(); + config->setGroup(name() + TQString(" Search Text Tool")); + config->writeEntry("AutoCompletionMode", (int)d->searchEdit->completionMode()); + config->sync(); + + delete d; +} + +void SearchTextBar::setEnableTextQueryCompletion(bool b) +{ + d->textQueryCompletion = b; +} + +bool SearchTextBar::textQueryCompletion() const +{ + return d->textQueryCompletion; +} + +void SearchTextBar::setText(const TQString& text) +{ + d->searchEdit->setText(text); +} + +TQString SearchTextBar::text() const +{ + return d->searchEdit->text(); +} + +DLineEdit *SearchTextBar::lineEdit() const +{ + return d->searchEdit; +} + +void SearchTextBar::slotTextChanged(const TQString& text) +{ + if (d->searchEdit->text().isEmpty()) + d->searchEdit->unsetPalette(); + + d->clearButton->setEnabled(text.isEmpty() ? false : true); + + emit signalTextChanged(text); +} + +void SearchTextBar::slotSearchResult(bool match) +{ + if (d->searchEdit->text().isEmpty()) + { + d->searchEdit->unsetPalette(); + return; + } + + TQPalette pal = d->searchEdit->palette(); + pal.setColor(TQPalette::Active, TQColorGroup::Base, + match ? TQColor(200, 255, 200) : + TQColor(255, 200, 200)); + pal.setColor(TQPalette::Active, TQColorGroup::Text, TQt::black); + d->searchEdit->setPalette(pal); + + // If search result match the text query, we put the text + // in auto-completion history. + if (d->textQueryCompletion && match) + d->searchEdit->completionObject()->addItem(d->searchEdit->text()); +} + +} // namespace Digikam diff --git a/src/libs/widgets/common/searchtextbar.h b/src/libs/widgets/common/searchtextbar.h new file mode 100644 index 00000000..04ef9947 --- /dev/null +++ b/src/libs/widgets/common/searchtextbar.h @@ -0,0 +1,111 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2007-11-25 + * Description : a bar used to search a string. + * + * Copyright (C) 2007-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. + * + * ============================================================ */ + +#ifndef SEARCH_TEXT_BAR_H +#define SEARCH_TEXT_BAR_H + +// TQt includes. + +#include <tqwidget.h> +#include <tqstring.h> + +// KDE includes. + +#include <klineedit.h> +#include <tdelocale.h> + +// Local includes. + +#include "digikam_export.h" + +namespace Digikam +{ + +class DLineEditPriv; +class SearchTextBarPriv; + +class DIGIKAM_EXPORT DLineEdit : public KLineEdit +{ + TQ_OBJECT + + +public: + + DLineEdit(const TQString &msg, TQWidget *parent); + ~DLineEdit(); + + void setMessage(const TQString &msg); + TQString message() const; + + void setText(const TQString& txt); + +protected: + + void drawContents(TQPainter *p); + void dropEvent(TQDropEvent *e); + void focusInEvent(TQFocusEvent *e); + void focusOutEvent(TQFocusEvent *e); + +private : + + DLineEditPriv* d; +}; + +class DIGIKAM_EXPORT SearchTextBar : public TQWidget +{ +TQ_OBJECT + + +public: + + SearchTextBar(TQWidget *parent, const char* name, const TQString &msg=i18n("Search...")); + ~SearchTextBar(); + + void setText(const TQString& text); + TQString text() const; + + void setEnableTextQueryCompletion(bool b); + bool textQueryCompletion() const; + + DLineEdit *lineEdit() const; + +signals: + + void signalTextChanged(const TQString&); + +public slots: + + void slotSearchResult(bool); + +private slots: + + void slotTextChanged(const TQString&); + +private : + + SearchTextBarPriv* d; +}; + +} // namespace Digikam + +#endif /* SEARCH_TEXT_BAR_H */ diff --git a/src/libs/widgets/common/sidebar.cpp b/src/libs/widgets/common/sidebar.cpp new file mode 100644 index 00000000..a1bcd752 --- /dev/null +++ b/src/libs/widgets/common/sidebar.cpp @@ -0,0 +1,363 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-03-22 + * Description : a widget to manage sidebar in gui. + * + * Copyright (C) 2005-2006 by Joern Ahrens <[email protected]> + * Copyright (C) 2006-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. + * + * ============================================================ */ + +/** @file sidebar.cpp */ + +// TQt includes. + +#include <tqsplitter.h> +#include <tqwidgetstack.h> +#include <tqdatastream.h> +#include <tqtimer.h> + +// KDE includes. + +#include <tdeapplication.h> +#include <tdeconfig.h> +#include <tdeversion.h> +#include <kiconloader.h> + +// Local includes. + +#include "ddebug.h" +#include "sidebar.h" +#include "sidebar.moc" + +namespace Digikam +{ + +class SidebarPriv +{ +public: + + SidebarPriv() + { + minimizedDefault = false; + minimized = false; + isMinimized = false; + + tabs = 0; + activeTab = -1; + minSize = 0; + maxSize = 0; + dragSwitchId = -1; + + stack = 0; + splitter = 0; + dragSwitchTimer = 0; + } + + bool minimizedDefault; + bool minimized; + bool isMinimized; // Backup of minimized status (used with Fullscreen) + + int tabs; + int activeTab; + int minSize; + int maxSize; + int dragSwitchId; + + TQWidgetStack *stack; + TQSplitter *splitter; + TQSize bigSize; + TQTimer *dragSwitchTimer; + + Sidebar::Side side; +}; + +Sidebar::Sidebar(TQWidget *parent, const char *name, Side side, bool minimizedDefault) + : KMultiTabBar(KMultiTabBar::Vertical, parent, name) +{ + d = new SidebarPriv; + d->minimizedDefault = minimizedDefault; + d->side = side; + d->dragSwitchTimer = new TQTimer(this); + + connect(d->dragSwitchTimer, TQ_SIGNAL(timeout()), + this, TQ_SLOT(slotDragSwitchTimer())); +} + +Sidebar::~Sidebar() +{ + saveViewState(); + delete d; +} + +void Sidebar::updateMinimumWidth() +{ + int width = 0; + for (int i = 0; i < d->tabs; i++) + { + TQWidget *w = d->stack->widget(i); + if (w && w->width() > width) + width = w->width(); + } + d->stack->setMinimumWidth(width); +} + +void Sidebar::setSplitter(TQSplitter *sp) +{ +#if KDE_IS_VERSION(3,3,0) + setStyle(KMultiTabBar::VSNET); +#else + setStyle(KMultiTabBar::KDEV3); +#endif + + d->splitter = sp; + d->stack = new TQWidgetStack(d->splitter); + + if(d->side == Left) + setPosition(KMultiTabBar::Left); + else + setPosition(KMultiTabBar::Right); +} + +TQSplitter* Sidebar::splitter() const +{ + return d->splitter; +} + +void Sidebar::loadViewState() +{ + TDEConfig *config = kapp->config(); + config->setGroup(TQString("%1").arg(name())); + + int tab = config->readNumEntry("ActiveTab", 0); + bool minimized = config->readBoolEntry("Minimized", d->minimizedDefault); + + // validate + if(tab >= d->tabs || tab < 0) + tab = 0; + + if (minimized) + { + d->activeTab = tab; + //setTab(d->activeTab, true); + d->stack->raiseWidget(d->activeTab); + emit signalChangedTab(d->stack->visibleWidget()); + } + else + { + d->activeTab = -1; + } + + clicked(tab); +} + +void Sidebar::saveViewState() +{ + TDEConfig *config = kapp->config(); + config->setGroup(TQString("%1").arg(name())); + config->writeEntry("ActiveTab", d->activeTab); + config->writeEntry("Minimized", d->minimized); + config->sync(); +} + +void Sidebar::backup() +{ + d->isMinimized = d->minimized; + + if (!d->isMinimized) + shrink(); + + KMultiTabBar::hide(); +} + +void Sidebar::restore() +{ + if (!d->isMinimized) + expand(); + + KMultiTabBar::show(); +} + +void Sidebar::appendTab(TQWidget *w, const TQPixmap &pic, const TQString &title) +{ + w->reparent(d->stack, TQPoint(0, 0)); + KMultiTabBar::appendTab(pic, d->tabs, title); + d->stack->addWidget(w, d->tabs); + + tab(d->tabs)->setAcceptDrops(true); + tab(d->tabs)->installEventFilter(this); + + connect(tab(d->tabs), TQ_SIGNAL(clicked(int)), + this, TQ_SLOT(clicked(int))); + + d->tabs++; +} + +void Sidebar::deleteTab(TQWidget *w) +{ + int tab = d->stack->id(w); + if(tab < 0) + return; + + if(tab == d->activeTab) + d->activeTab = -1; + + d->stack->removeWidget(d->stack->widget(tab)); + removeTab(tab); + d->tabs--; + updateMinimumWidth(); + + //TODO show another widget +} + +void Sidebar::clicked(int tab) +{ + if(tab >= d->tabs || tab < 0) + return; + + if(tab == d->activeTab) + { + d->stack->isHidden() ? expand() : shrink(); + } + else + { + if(d->activeTab >= 0) + setTab(d->activeTab, false); + + d->activeTab = tab; + setTab(d->activeTab, true); + d->stack->raiseWidget(d->activeTab); + + if(d->minimized) + expand(); + + emit signalChangedTab(d->stack->visibleWidget()); + } +} + +void Sidebar::setActiveTab(TQWidget *w) +{ + int tab = d->stack->id(w); + if(tab < 0) + return; + + if(d->activeTab >= 0) + setTab(d->activeTab, false); + + d->activeTab = tab; + setTab(d->activeTab, true); + d->stack->raiseWidget(d->activeTab); + + if(d->minimized) + expand(); + + emit signalChangedTab(d->stack->visibleWidget()); +} + +TQWidget* Sidebar::getActiveTab() +{ + return d->stack->visibleWidget(); +} + +void Sidebar::shrink() +{ + d->minimized = true; + d->bigSize = size(); + d->minSize = minimumWidth(); + d->maxSize = maximumWidth(); + + d->stack->hide(); + + KMultiTabBarTab* tab = tabs()->first(); + if (tab) + setFixedWidth(tab->width()); + else + setFixedWidth(width()); + + emit signalViewChanged(); +} + +void Sidebar::expand() +{ + d->minimized = false; + d->stack->show(); + resize(d->bigSize); + setMinimumWidth(d->minSize); + setMaximumWidth(d->maxSize); + emit signalViewChanged(); +} + +bool Sidebar::isExpanded() +{ + return !d->minimized; +} + +bool Sidebar::eventFilter(TQObject *obj, TQEvent *ev) +{ + TQPtrList<KMultiTabBarTab>* pTabs = tabs(); + + for (TQPtrListIterator<KMultiTabBarTab> it(*pTabs); it.current(); ++it) + { + if ( obj == *it ) + { + if ( ev->type() == TQEvent::DragEnter) + { + TQDragEnterEvent *e = static_cast<TQDragEnterEvent *>(ev); + enterEvent(e); + e->accept(true); + return false; + } + else if (ev->type() == TQEvent::DragMove) + { + if (!d->dragSwitchTimer->isActive()) + { + d->dragSwitchTimer->start(800, true); + d->dragSwitchId = (*it)->id(); + } + return false; + } + else if (ev->type() == TQEvent::DragLeave) + { + d->dragSwitchTimer->stop(); + TQDragLeaveEvent *e = static_cast<TQDragLeaveEvent *>(ev); + leaveEvent(e); + return false; + } + else if (ev->type() == TQEvent::Drop) + { + d->dragSwitchTimer->stop(); + TQDropEvent *e = static_cast<TQDropEvent *>(ev); + leaveEvent(e); + return false; + } + else + { + return false; + } + } + } + + // Else, pass the event on to the parent class + return KMultiTabBar::eventFilter(obj, ev); +} + +void Sidebar::slotDragSwitchTimer() +{ + clicked(d->dragSwitchId); +} + +} // namespace Digikam diff --git a/src/libs/widgets/common/sidebar.h b/src/libs/widgets/common/sidebar.h new file mode 100644 index 00000000..8d2dc519 --- /dev/null +++ b/src/libs/widgets/common/sidebar.h @@ -0,0 +1,178 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-03-22 + * Description : a widget to manage sidebar in gui. + * + * Copyright (C) 2005-2006 by Joern Ahrens <[email protected]> + * Copyright (C) 2006-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. + * + * ============================================================ */ + +/** @file sidebar.h */ + +#ifndef _SIDEBAR_H_ +#define _SIDEBAR_H_ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +// KDE includes. + +#include <tdemultitabbar.h> + +// Local includes. + +#include "digikam_export.h" + +class TQSplitter; + +namespace Digikam +{ + +class SidebarPriv; + +/** + * This class handles a sidebar view + */ +class DIGIKAM_EXPORT Sidebar : public KMultiTabBar +{ + TQ_OBJECT + + +public: + + /** + * The side where the bar should be visible + */ + enum Side + { + Left, + Right + }; + + /** + * Creates a new sidebar + * @param parent sidebar's parent + * @param name the name of the widget is used to store its state to config + * @param side where the sidebar should be displayed. At the left or right border. + * @param minimizedDefault hide the sidebar when the program is started the first time? + */ + Sidebar(TQWidget *parent, const char *name, Side side=Left, bool mimimizedDefault=false); + virtual ~Sidebar(); + + /** + * The width of the widget stack can be changed by a TQSplitter. + * @param sp sets the splitter, which should handle the width. The splitter normally + * is part of the main view. + */ + void setSplitter(TQSplitter *sp); + void setSplitterSizePolicy(TQSizePolicy p); + + TQSplitter* splitter() const; + + /** + * Appends a new tab to the sidebar + * @param w widget which is activated by this tab + * @param pic icon which is shown in this tab + * @param title text which is shown it this tab + */ + void appendTab(TQWidget *w, const TQPixmap &pic, const TQString &title); + + /** + * Deletes a tab from the tabbar + */ + void deleteTab(TQWidget *w); + + /** + * Activates a tab + */ + void setActiveTab(TQWidget *w); + + /** + * Returns the currently activated tab, or 0 if no tab is active + */ + TQWidget* getActiveTab(); + + /** + * Hides the sidebar (display only the activation buttons) + */ + void shrink(); + + /** + * redisplays the whole sidebar + */ + void expand(); + + /** + * load the last view state from disk + */ + void loadViewState(); + + /** + * hide sidebar and backup minimized state. + */ + void backup(); + + /** + * show sidebar and restore minimized state. + */ + void restore(); + + /** + * return the visible status of current sidebar tab. + */ + bool isExpanded(); + +private: + + /** + * save the view state to disk + */ + void saveViewState(); + bool eventFilter(TQObject *o, TQEvent *e); + void updateMinimumWidth(); + +private slots: + + /** + * Activates a tab + */ + void clicked(int tab); + + void slotDragSwitchTimer(); + +signals: + + /** + * is emitted, when another tab is activated + */ + void signalChangedTab(TQWidget *w); + + /** + * is emitted, when tab is shrink or expanded + */ + void signalViewChanged(); + +private: + + SidebarPriv* d; +}; + +} // namespace Digikam + +#endif // _SIDEBAR_H_ diff --git a/src/libs/widgets/common/splashscreen.cpp b/src/libs/widgets/common/splashscreen.cpp new file mode 100644 index 00000000..7a8cbba1 --- /dev/null +++ b/src/libs/widgets/common/splashscreen.cpp @@ -0,0 +1,160 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2003-02-10 + * Description : a widget to display spash with progress bar + * + * Copyright (C) 2003-2005 by Renchi Raju <[email protected]> + * Copyright (C) 2006-2009 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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqtimer.h> +#include <tqfont.h> +#include <tqstring.h> +#include <tqcolor.h> + +// KDE includes. + +#include <tdelocale.h> +#include <kstandarddirs.h> +#include <tdeglobalsettings.h> + +// Local includes. + +#include "splashscreen.h" +#include "splashscreen.moc" + +namespace Digikam +{ + +class SplashScreenPriv +{ +public: + + SplashScreenPriv() + { + state = 0; + progressBarSize = 3; + state = 0; + color = TQt::black; + alignment = TQt::AlignLeft; + } + + int state; + int progressBarSize; + int alignment; + + TQString string; + + TQColor color; +}; + +SplashScreen::SplashScreen(const TQString& splash, WFlags f) + : KSplashScreen(TQPixmap(locate("appdata", splash)), f) +{ + d = new SplashScreenPriv; + + TQTimer *timer = new TQTimer(this); + + connect(timer, TQ_SIGNAL(timeout()), + this, TQ_SLOT(animate())); + + timer->start(150); +} + +SplashScreen::~SplashScreen() +{ + delete d; +} + +void SplashScreen::animate() +{ + d->state = ((d->state + 1) % (2*d->progressBarSize-1)); + repaint(); +} + +void SplashScreen::setColor(const TQColor& color) +{ + d->color = color; +} +void SplashScreen::setAlignment(int alignment) +{ + d->alignment = alignment; +} + +void SplashScreen::message(const TQString& message) +{ + d->string = message; + TQSplashScreen::message(d->string, d->alignment, d->color); + animate(); +} + +void SplashScreen::drawContents(TQPainter* painter) +{ + int position; + TQColor basecolor(155, 192, 231); + + // Draw background circles + painter->setPen(NoPen); + painter->setBrush(TQColor(225, 234, 231)); + painter->drawEllipse(21, 7, 9, 9); + painter->drawEllipse(32, 7, 9, 9); + painter->drawEllipse(43, 7, 9, 9); + + // Draw animated circles, increments are chosen + // to get close to background's color + // (didn't work well with TQColor::light function) + for (int i=0; i < d->progressBarSize; i++) + { + position = (d->state+i)%(2*d->progressBarSize-1); + if (position < 3) + { + painter->setBrush(TQColor(basecolor.red() -18*i, + basecolor.green()-28*i, + basecolor.blue() -10*i)); + + painter->drawEllipse(21+position*11, 7, 9, 9); + } + } + + painter->setPen(d->color); + + TQFont fnt(TDEGlobalSettings::generalFont()); + int fntSize = fnt.pointSize(); + if (fntSize > 0) + { + fnt.setPointSize(fntSize-2); + } + else + { + fntSize = fnt.pixelSize(); + fnt.setPixelSize(fntSize-2); + } + painter->setFont(fnt); + + TQRect r = rect(); + r.setRect( r.x() + 59, r.y() + 5, r.width() - 10, r.height() - 10 ); + + // Draw message at given position, limited to 43 chars + // If message is too long, string is truncated + if (d->string.length() > 40) {d->string.truncate(39); d->string += "...";} + painter->drawText(r, d->alignment, d->string); +} + +} // namespace Digikam diff --git a/src/libs/widgets/common/splashscreen.h b/src/libs/widgets/common/splashscreen.h new file mode 100644 index 00000000..d2d4cf45 --- /dev/null +++ b/src/libs/widgets/common/splashscreen.h @@ -0,0 +1,74 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2003-02-10 + * Description : a widget to display spash with progress bar + * + * Copyright (C) 2003-2005 by Renchi Raju <[email protected]> + * Copyright (C) 2006-2009 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. + * + * ============================================================ */ + +#ifndef SPLASHSCREEN_H +#define SPLASHSCREEN_H + +// TQt includes. + +#include <tqpainter.h> + +// KDE includes. + +#include <ksplashscreen.h> + +// Local includes. + +#include "digikam_export.h" + +namespace Digikam +{ + +class SplashScreenPriv; + +class DIGIKAM_EXPORT SplashScreen : public KSplashScreen +{ +TQ_OBJECT + + +public: + + SplashScreen(const TQString& splash, WFlags f=0); + virtual ~SplashScreen(); + + void setAlignment(int alignment); + void setColor(const TQColor& color); + +protected: + + void drawContents (TQPainter *); + +public slots: + + void animate(); + void message(const TQString &message); + +private: + + SplashScreenPriv* d; +}; + +} // namespace Digikam + +#endif /* SPLASHSCREEN_H */ diff --git a/src/libs/widgets/common/squeezedcombobox.cpp b/src/libs/widgets/common/squeezedcombobox.cpp new file mode 100644 index 00000000..b70da094 --- /dev/null +++ b/src/libs/widgets/common/squeezedcombobox.cpp @@ -0,0 +1,198 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-01-01 + * Description : a combo box with a width not depending of text + * content size + * + * Copyright (C) 2005 by Tom Albers <[email protected]> + * Copyright (C) 2006-2007 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. + * + * ============================================================ */ + +/** @file squeezedcombobox.cpp */ + +// TQt includes. + +#include <tqlistbox.h> +#include <tqcombobox.h> +#include <tqpair.h> +#include <tqtimer.h> +#include <tqvaluelist.h> +#include <tqstyle.h> +#include <tqapplication.h> +#include <tqtooltip.h> +#include <tqmap.h> + +// Local includes. + +#include "squeezedcombobox.h" +#include "squeezedcombobox.moc" + +namespace Digikam +{ + +class SqueezedComboBoxPriv +{ +public: + + SqueezedComboBoxPriv() + { + timer = 0; + tooltip = 0; + } + + TQMap<int, TQString> originalItems; + + TQTimer *timer; + + SqueezedComboBoxTip *tooltip; +}; + +SqueezedComboBox::SqueezedComboBox(TQWidget *parent, const char *name) + : TQComboBox(parent, name) +{ + d = new SqueezedComboBoxPriv; + d->timer = new TQTimer(this); + + // See B.K.O #138747 : always for TQComboBox instance to use a TQListbox to + // render content independently of Widget style used. + setListBox(new TQListBox(this)); + + d->tooltip = new SqueezedComboBoxTip(listBox()->viewport(), this); + setMinimumWidth(100); + + connect(d->timer, TQ_SIGNAL(timeout()), + this, TQ_SLOT(slotTimeOut())); + + connect(this, TQ_SIGNAL(activated( int )), + this, TQ_SLOT(slotUpdateToolTip( int ))); +} + +SqueezedComboBox::~SqueezedComboBox() +{ + delete d->tooltip; + delete d->timer; + delete d; +} + +TQSize SqueezedComboBox::sizeHint() const +{ + constPolish(); + TQFontMetrics fm = fontMetrics(); + + int maxW = count() ? 18 : 7 * fm.width(TQChar('x')) + 18; + int maxH = TQMAX( fm.lineSpacing(), 14 ) + 2; + + return style().sizeFromContents(TQStyle::CT_ComboBox, this, + TQSize(maxW, maxH)).expandedTo(TQApplication::globalStrut()); +} + +void SqueezedComboBox::insertSqueezedItem(const TQString& newItem, int index) +{ + d->originalItems[index] = newItem; + insertItem( squeezeText(newItem), index ); + + // if this is the first item, set the tooltip. + if (index == 0) + slotUpdateToolTip(0); +} + +void SqueezedComboBox::insertSqueezedList(const TQStringList& newItems, int index) +{ + for(TQStringList::const_iterator it = newItems.begin() ; it != newItems.end() ; ++it) + { + insertSqueezedItem(*it, index); + index++; + } +} + +void SqueezedComboBox::resizeEvent(TQResizeEvent *) +{ + d->timer->start(200, true); +} + +void SqueezedComboBox::slotTimeOut() +{ + TQMapIterator<int,TQString> it; + for (it = d->originalItems.begin() ; it != d->originalItems.end(); + ++it) + { + changeItem(squeezeText(it.data()), it.key()); + } +} + +TQString SqueezedComboBox::squeezeText(const TQString& original) +{ + // not the complete widgetSize is usable. Need to compensate for that. + int widgetSize = width()-30; + TQFontMetrics fm(fontMetrics()); + + // If we can fit the full text, return that. + if (fm.width(original) < widgetSize) + return(original); + + // We need to squeeze. + TQString sqItem = original; // prevent empty return value; + widgetSize = widgetSize-fm.width("..."); + for (uint i = 0 ; i != original.length(); ++i) + { + if ((int)fm.width(original.right(i)) > widgetSize) + { + sqItem = TQString(original.left(i) + "..."); + break; + } + } + return sqItem; +} + +void SqueezedComboBox::slotUpdateToolTip(int index) +{ + TQToolTip::remove(this); + TQToolTip::add(this, d->originalItems[index]); +} + +TQString SqueezedComboBox::itemHighlighted() +{ + int curItem = listBox()->currentItem(); + return d->originalItems[curItem]; +} + +// ------------------------------------------------------------------------ + +SqueezedComboBoxTip::SqueezedComboBoxTip(TQWidget *parent, SqueezedComboBox *name) + : TQToolTip( parent ) +{ + m_originalWidget = name; +} + +void SqueezedComboBoxTip::maybeTip(const TQPoint &pos) +{ + TQListBox* listBox = m_originalWidget->listBox(); + if (!listBox) + return; + + TQListBoxItem* selectedItem = listBox->itemAt( pos ); + if (selectedItem) + { + TQRect positionToolTip = listBox->itemRect(selectedItem); + TQString toolTipText = m_originalWidget->itemHighlighted(); + if (!toolTipText.isNull()) + tip(positionToolTip, toolTipText); + } +} + +} // namespace Digikam diff --git a/src/libs/widgets/common/squeezedcombobox.h b/src/libs/widgets/common/squeezedcombobox.h new file mode 100644 index 00000000..7baaeca1 --- /dev/null +++ b/src/libs/widgets/common/squeezedcombobox.h @@ -0,0 +1,164 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-01-01 + * Description : a combo box with a width not depending of text + * content size + * + * Copyright (C) 2005 by Tom Albers <[email protected]> + * Copyright (C) 2006-2007 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. + * + * ============================================================ */ + +/** @file squeezedcombobox.h */ + +#ifndef SQUEEZEDCOMBOBOX_H +#define SQUEEZEDCOMBOBOX_H + +// TQt includes. + +#include <tqcombobox.h> +#include <tqtooltip.h> + +// Local includes. + +#include "digikam_export.h" + +namespace Digikam +{ + +class SqueezedComboBoxPriv; + +/** @class SqueezedComboBox + * + * This widget is a TQComboBox, but then a little bit + * different. It only shows the right part of the items + * depending on de size of the widget. When it is not + * possible to show the complete item, it will be shortened + * and "..." will be prepended. + * + * @image html squeezedcombobox.png "This is how it looks" + * @author Tom Albers + */ +class DIGIKAM_EXPORT SqueezedComboBox : public TQComboBox +{ + TQ_OBJECT + + +public: + + /** + * Constructor + * @param parent parent widget + * @param name name to give to the widget + */ + SqueezedComboBox(TQWidget *parent = 0, const char *name = 0 ); + + /** + * destructor + */ + virtual ~SqueezedComboBox(); + + /** + * This inserts a item to the list. See TQComboBox::insertItem() + * for details. Please do not use TQComboBox::insertItem() to this + * widget, as that will fail. + * @param newItem the original (long version) of the item which needs + * to be added to the combobox + * @param index the position in the widget. + */ + void insertSqueezedItem(const TQString& newItem, int index); + + /** + * This inserts items to the list. See TQComboBox::insertStringList() + * for details. Please do not use TQComboBox::insertStringList() to this + * widget, as that will fail. + * @param newItems the originals (long version) of the items which needs + * to be added to the combobox + * @param index the position in the widget. + */ + void insertSqueezedList(const TQStringList& newItems, int index); + + /** + * This method returns the full text (not squeezed) of the currently + * highlighted item. + * @return full text of the highlighted item + */ + TQString itemHighlighted(); + + /** + * Sets the sizeHint() of this widget. + */ + virtual TQSize sizeHint() const; + +private slots: + + void slotTimeOut(); + void slotUpdateToolTip(int index); + +private: + + void resizeEvent(TQResizeEvent *); + TQString squeezeText(const TQString& original); + +private: + + SqueezedComboBoxPriv *d; +}; + +// ---------------------------------------------------------------- + +/** @class SqueezedComboBoxTip + * This class shows a tooltip for a SqueezedComboBox + * the tooltip will contain the full text and helps + * the user find the correct entry. It is automatically + * activated when starting a SqueezedComboBox. This is + * inherited from TQToolTip + * + * @author Tom Albers + */ +class SqueezedComboBoxTip : public TQToolTip +{ + +public: + /** + * Constructor. An example call (as done in + * SqueezedComboBox::SqueezedComboBox): + * @code + * t = new SqueezedComboBoxTip( this->listBox()->viewport(), this ); + * @endcode + * + * @param parent parent widget (viewport) + * @param name parent widget + */ + SqueezedComboBoxTip(TQWidget *parent, SqueezedComboBox *name); + +protected: + /** + * Reimplemented version from TQToolTip which shows the + * tooltip when needed. + * @param pos the point where the mouse currently is + */ + void maybeTip(const TQPoint& pos); + +private: + + SqueezedComboBox *m_originalWidget; +}; + +} // namespace Digikam + +#endif // SQUEEZEDCOMBOBOX_H diff --git a/src/libs/widgets/common/statusled.cpp b/src/libs/widgets/common/statusled.cpp new file mode 100644 index 00000000..e0475057 --- /dev/null +++ b/src/libs/widgets/common/statusled.cpp @@ -0,0 +1,84 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2008-02-15 + * Description : a led indicator. + * + * Copyright (C) 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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqpixmap.h> +#include <tqstring.h> + +// KDE includes. + +#include <tdeglobalsettings.h> +#include <kstandarddirs.h> + +// Local includes. + +#include "statusled.h" +#include "statusled.moc" + +namespace Digikam +{ + +StatusLed::StatusLed(TQWidget *parent) + : TQLabel(parent) +{ + setLedColor(Gray); + setFocusPolicy(TQWidget::NoFocus); +} + +StatusLed::~StatusLed() +{ +} + +void StatusLed::setLedColor(LedColor color) +{ + m_color = color; + + TQString file; + switch(m_color) + { + case Green: + file = TQString("indicator-green"); + break; + + case Red: + file = TQString("indicator-red"); + break; + + default: + file = TQString("indicator-gray"); + break; + } + + TDEGlobal::dirs()->addResourceType(file.ascii(), TDEGlobal::dirs()->kde_default("data") + "digikam/data"); + TQString directory = TDEGlobal::dirs()->findResourceDir(file.ascii(), file + TQString(".png")); + setPixmap(TQPixmap(directory + file + TQString(".png"))); +} + +StatusLed::LedColor StatusLed::ledColor() const +{ + return m_color; +} + +} // namespace Digikam + diff --git a/src/libs/widgets/common/statusled.h b/src/libs/widgets/common/statusled.h new file mode 100644 index 00000000..2fd94cb2 --- /dev/null +++ b/src/libs/widgets/common/statusled.h @@ -0,0 +1,72 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2008-02-15 + * Description : a led indicator. + * + * Copyright (C) 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. + * + * ============================================================ */ + +#ifndef STATUS_LED_H +#define STATUS_LED_H + +// TQt includes. + +#include <tqlabel.h> + +// Local includes. + +#include "digikam_export.h" + +namespace Digikam +{ + +class StatusNavigateBarPriv; + +class DIGIKAM_EXPORT StatusLed : public TQLabel +{ +TQ_OBJECT + + +public: + + enum LedColor + { + Gray=0, + Green, + Red + }; + +public: + + StatusLed(TQWidget *parent=0); + ~StatusLed(); + + LedColor ledColor() const; + +public slots: + + void setLedColor(LedColor color); + +private: + + LedColor m_color; +}; + +} // namespace Digikam + +#endif /* STATUS_LED_H */ diff --git a/src/libs/widgets/common/statusnavigatebar.cpp b/src/libs/widgets/common/statusnavigatebar.cpp new file mode 100644 index 00000000..0ebcaf84 --- /dev/null +++ b/src/libs/widgets/common/statusnavigatebar.cpp @@ -0,0 +1,172 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2007-01-30 + * Description : a button bar to navigate between album items + * using status bar. + * + * Copyright (C) 2007 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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqlayout.h> +#include <tqtoolbutton.h> +#include <tqtooltip.h> + +// KDE includes. + +#include <kiconloader.h> +#include <tdelocale.h> + +// Local includes. + +#include "statusnavigatebar.h" +#include "statusnavigatebar.moc" + +namespace Digikam +{ + +class StatusNavigateBarPriv +{ +public: + + StatusNavigateBarPriv() + { + firstButton = 0; + prevButton = 0; + nextButton = 0; + lastButton = 0; + itemType = StatusNavigateBar::ItemCurrent; + } + + int itemType; + + TQToolButton *firstButton; + TQToolButton *prevButton; + TQToolButton *nextButton; + TQToolButton *lastButton; +}; + +StatusNavigateBar::StatusNavigateBar(TQWidget *parent) + : TQWidget(parent, 0, TQt::WDestructiveClose) +{ + d = new StatusNavigateBarPriv; + setFocusPolicy(TQWidget::NoFocus); + + TQHBoxLayout *lay = new TQHBoxLayout(this); + + d->firstButton = new TQToolButton(this); + d->firstButton->setFocusPolicy(TQWidget::NoFocus); + d->firstButton->setAutoRaise(true); + d->firstButton->setIconSet(SmallIconSet("go-first")); + TQToolTip::add(d->firstButton, i18n("Go to the first item")); + + d->prevButton = new TQToolButton(this); + d->prevButton->setFocusPolicy(TQWidget::NoFocus); + d->prevButton->setAutoRaise(true); + d->prevButton->setIconSet(SmallIconSet("back")); + TQToolTip::add(d->prevButton, i18n("Go to the previous item")); + + d->nextButton = new TQToolButton(this); + d->nextButton->setFocusPolicy(TQWidget::NoFocus); + d->nextButton->setAutoRaise(true); + d->nextButton->setIconSet(SmallIconSet("forward")); + TQToolTip::add(d->nextButton, i18n("Go to the next item")); + + d->lastButton = new TQToolButton(this); + d->lastButton->setFocusPolicy(TQWidget::NoFocus); + d->lastButton->setAutoRaise(true); + d->lastButton->setIconSet(SmallIconSet("go-last")); + TQToolTip::add(d->lastButton, i18n("Go to the last item")); + + lay->addWidget(d->firstButton); + lay->addWidget(d->prevButton); + lay->addWidget(d->nextButton); + lay->addWidget(d->lastButton); + + connect(d->firstButton, TQ_SIGNAL(clicked()), + this, TQ_SIGNAL(signalFirstItem())); + + connect(d->prevButton, TQ_SIGNAL(clicked()), + this, TQ_SIGNAL(signalPrevItem())); + + connect(d->nextButton, TQ_SIGNAL(clicked()), + this, TQ_SIGNAL(signalNextItem())); + + connect(d->lastButton, TQ_SIGNAL(clicked()), + this, TQ_SIGNAL(signalLastItem())); +} + +StatusNavigateBar::~StatusNavigateBar() +{ + delete d; +} + +void StatusNavigateBar::setNavigateBarState(bool hasPrev, bool hasNext) +{ + if (hasPrev && hasNext) + setButtonsState(ItemCurrent); + else if (!hasPrev && hasNext) + setButtonsState(ItemFirst); + else if (hasPrev && !hasNext) + setButtonsState(ItemLast); + else + setButtonsState(NoNavigation); +} + +void StatusNavigateBar::setButtonsState(int itemType) +{ + d->itemType = itemType; + + if (d->itemType == ItemFirst) + { + d->firstButton->setEnabled(false); + d->prevButton->setEnabled(false); + d->nextButton->setEnabled(true); + d->lastButton->setEnabled(true); + } + else if (d->itemType == ItemLast) + { + d->firstButton->setEnabled(true); + d->prevButton->setEnabled(true); + d->nextButton->setEnabled(false); + d->lastButton->setEnabled(false); + } + else if (d->itemType == ItemCurrent) + { + d->firstButton->setEnabled(true); + d->prevButton->setEnabled(true); + d->nextButton->setEnabled(true); + d->lastButton->setEnabled(true); + } + else if (d->itemType == NoNavigation) + { + d->firstButton->setEnabled(false); + d->prevButton->setEnabled(false); + d->nextButton->setEnabled(false); + d->lastButton->setEnabled(false); + } +} + +int StatusNavigateBar::getButtonsState() +{ + return (d->itemType); +} + +} // namespace Digikam + diff --git a/src/libs/widgets/common/statusnavigatebar.h b/src/libs/widgets/common/statusnavigatebar.h new file mode 100644 index 00000000..7972f740 --- /dev/null +++ b/src/libs/widgets/common/statusnavigatebar.h @@ -0,0 +1,80 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2007-01-30 + * Description : a button bar to navigate between album items + * using status bar. + * + * Copyright (C) 2007 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. + * + * ============================================================ */ + +#ifndef STATUS_NAVIGATE_BAR_H +#define STATUS_NAVIGATE_BAR_H + +// TQt includes. + +#include <tqwidget.h> +#include <tqstring.h> + +// Local includes. + +#include "digikam_export.h" + +namespace Digikam +{ + +class StatusNavigateBarPriv; + +class DIGIKAM_EXPORT StatusNavigateBar : public TQWidget +{ +TQ_OBJECT + + +public: + + enum CurrentItemPosition + { + ItemCurrent=0, + ItemFirst, + ItemLast, + NoNavigation + }; + +public: + + StatusNavigateBar(TQWidget *parent=0); + ~StatusNavigateBar(); + + void setNavigateBarState(bool hasPrev, bool hasNext); + void setButtonsState(int itemType); + int getButtonsState(); + +signals: + + void signalFirstItem(void); + void signalPrevItem(void); + void signalNextItem(void); + void signalLastItem(void); + +private : + + StatusNavigateBarPriv* d; +}; + +} // namespace Digikam + +#endif /* STATUS_NAVIGATE_BAR_H */ diff --git a/src/libs/widgets/common/statusprogressbar.cpp b/src/libs/widgets/common/statusprogressbar.cpp new file mode 100644 index 00000000..215f81fe --- /dev/null +++ b/src/libs/widgets/common/statusprogressbar.cpp @@ -0,0 +1,171 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2007-01-24 + * Description : a progress bar used to display file access + * progress or a text in status bar. + * + * Copyright (C) 2007-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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqlayout.h> +#include <tqwidget.h> +#include <tqpushbutton.h> + +// KDE includes. + +#include <ksqueezedtextlabel.h> +#include <kprogress.h> +#include <tdelocale.h> +#include <kiconloader.h> +#include <kcursor.h> + +// Local includes. + +#include "statusprogressbar.h" +#include "statusprogressbar.moc" + +namespace Digikam +{ + +class StatusProgressBarPriv +{ + +public: + + enum WidgetStackEnum + { + TextLabel=0, + ProgressBar + }; + + StatusProgressBarPriv() + { + textLabel = 0; + progressBar = 0; + progressWidget = 0; + cancelButton = 0; + } + + + TQWidget *progressWidget; + + TQPushButton *cancelButton; + + KSqueezedTextLabel *textLabel; + + KProgress *progressBar; +}; + +StatusProgressBar::StatusProgressBar(TQWidget *parent) + : TQWidgetStack(parent, 0, TQt::WDestructiveClose) +{ + d = new StatusProgressBarPriv; + setFocusPolicy(TQWidget::NoFocus); + + d->textLabel = new KSqueezedTextLabel(this); + d->progressWidget = new TQWidget(this); + TQHBoxLayout *hBox = new TQHBoxLayout(d->progressWidget); + d->progressBar = new KProgress(d->progressWidget); + setProgressTotalSteps(100); + d->cancelButton = new TQPushButton(d->progressWidget); + d->cancelButton->setFocusPolicy(TQWidget::NoFocus); + d->cancelButton->setSizePolicy( TQSizePolicy( TQSizePolicy::Minimum, TQSizePolicy::Minimum ) ); + d->cancelButton->setPixmap(SmallIcon("cancel")); + + // Parent widget will probably have the wait cursor set. + // Set arrow cursor to indicate the button can be clicked + d->cancelButton->setCursor(KCursor::arrowCursor()); + + hBox->addWidget(d->progressBar); + hBox->addWidget(d->cancelButton); + + addWidget(d->textLabel, StatusProgressBarPriv::TextLabel); + addWidget(d->progressWidget, StatusProgressBarPriv::ProgressBar); + + connect( d->cancelButton, TQ_SIGNAL( clicked() ), + this, TQ_SIGNAL( signalCancelButtonPressed() ) ); + + progressBarMode(TextMode); +} + +StatusProgressBar::~StatusProgressBar() +{ + delete d; +} + +void StatusProgressBar::setText(const TQString& text) +{ + d->textLabel->setText(text); +} + +void StatusProgressBar::setAlignment(int a) +{ + d->textLabel->setAlignment(a); +} + +int StatusProgressBar::progressValue() +{ + return d->progressBar->progress(); +} + +void StatusProgressBar::setProgressValue(int v) +{ + d->progressBar->setProgress(v); +} + +void StatusProgressBar::setProgressTotalSteps(int v) +{ + d->progressBar->setTotalSteps(v); +} + +int StatusProgressBar::progressTotalSteps() +{ + return d->progressBar->totalSteps(); +} + +void StatusProgressBar::setProgressText(const TQString& text) +{ + d->progressBar->setFormat( text + TQString ("%p%") ); + d->progressBar->update(); +} + +void StatusProgressBar::progressBarMode(int mode, const TQString& text) +{ + if ( mode == TextMode) + { + raiseWidget(StatusProgressBarPriv::TextLabel); + setProgressValue(0); + setText( text ); + } + else if ( mode == ProgressBarMode ) + { + d->cancelButton->hide(); + raiseWidget(StatusProgressBarPriv::ProgressBar); + setProgressText( text ); + } + else // CancelProgressBarMode + { + d->cancelButton->show(); + raiseWidget(StatusProgressBarPriv::ProgressBar); + setProgressText( text ); + } +} + +} // namespace Digikam diff --git a/src/libs/widgets/common/statusprogressbar.h b/src/libs/widgets/common/statusprogressbar.h new file mode 100644 index 00000000..e227a6de --- /dev/null +++ b/src/libs/widgets/common/statusprogressbar.h @@ -0,0 +1,87 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2007-01-24 + * Description : a progress bar used to display file access + * progress or a text in status bar. + * + * Copyright (C) 2007-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. + * + * ============================================================ */ + +#ifndef STATUSPROGRESSBAR_H +#define STATUSPROGRESSBAR_H + +// KDE includes. + +#include <tqwidgetstack.h> +#include <tqstring.h> + +// Local includes. + +#include "digikam_export.h" + +namespace Digikam +{ + +class StatusProgressBarPriv; + +class DIGIKAM_EXPORT StatusProgressBar : public TQWidgetStack +{ +TQ_OBJECT + + +public: + + enum StatusProgressBarMode + { + TextMode=0, + ProgressBarMode, + CancelProgressBarMode + }; + +public: + + StatusProgressBar(TQWidget *parent=0); + ~StatusProgressBar(); + + void setAlignment(int a); + + void progressBarMode(int mode, const TQString& text=TQString()); + + int progressValue(); + + int progressTotalSteps(); + void setProgressTotalSteps(int v); + +public slots: + + void setText(const TQString& text); + void setProgressValue(int v); + void setProgressText(const TQString& text); + +signals: + + void signalCancelButtonPressed(); + +private: + + StatusProgressBarPriv* d; +}; + +} // namespace Digikam + +#endif /* STATUSPROGRESSBAR_H */ diff --git a/src/libs/widgets/common/statuszoombar.cpp b/src/libs/widgets/common/statuszoombar.cpp new file mode 100644 index 00000000..44302481 --- /dev/null +++ b/src/libs/widgets/common/statuszoombar.cpp @@ -0,0 +1,208 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2007-04-15 + * Description : a zoom bar used in status bar. + * + * Copyright (C) 2007 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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqtoolbutton.h> +#include <tqtimer.h> +#include <tqslider.h> +#include <tqtooltip.h> +#include <tqevent.h> + +// KDE includes. + +#include <tdelocale.h> +#include <kiconloader.h> + +// Local includes. + +#include "thumbnailsize.h" +#include "dcursortracker.h" +#include "statuszoombar.h" +#include "statuszoombar.moc" + +namespace Digikam +{ + +TQSliderReverseWheel::TQSliderReverseWheel(TQWidget *parent) + : TQSlider(parent) +{ + // empty, we just need to re-implement wheelEvent to reverse the wheel +} + +TQSliderReverseWheel::~TQSliderReverseWheel() +{ +} + +void TQSliderReverseWheel::wheelEvent(TQWheelEvent * e) +{ + if ( e->orientation() != orientation() && !rect().contains(e->pos()) ) + return; + + static float offset = 0; + static TQSlider* offset_owner = 0; + if (offset_owner != this){ + offset_owner = this; + offset = 0; + } + // note: different sign in front of e->delta vs. original implementation + offset += e->delta()*TQMAX(pageStep(),lineStep())/120; + if (TQABS(offset)<1) + return; + setValue( value() + int(offset) ); + offset -= int(offset); + e->accept(); +} + +// ---------------------------------------------------------------------- + +class StatusZoomBarPriv +{ + +public: + + StatusZoomBarPriv() + { + zoomTracker = 0; + zoomMinusButton = 0; + zoomPlusButton = 0; + zoomSlider = 0; + zoomTimer = 0; + } + + TQToolButton *zoomPlusButton; + TQToolButton *zoomMinusButton; + + TQTimer *zoomTimer; + + TQSlider *zoomSlider; + + DTipTracker *zoomTracker; +}; + +StatusZoomBar::StatusZoomBar(TQWidget *parent) + : TQHBox(parent, 0, TQt::WDestructiveClose) +{ + d = new StatusZoomBarPriv; + setFocusPolicy(TQWidget::NoFocus); + + d->zoomMinusButton = new TQToolButton(this); + d->zoomMinusButton->setAutoRaise(true); + d->zoomMinusButton->setFocusPolicy(TQWidget::NoFocus); + d->zoomMinusButton->setIconSet(SmallIconSet("zoom-out")); + TQToolTip::add(d->zoomMinusButton, i18n("Zoom Out")); + + d->zoomSlider = new TQSliderReverseWheel(this); + d->zoomSlider->setMinValue(ThumbnailSize::Small); + d->zoomSlider->setMaxValue(ThumbnailSize::Huge); + d->zoomSlider->setPageStep(ThumbnailSize::Step); + d->zoomSlider->setValue(ThumbnailSize::Medium); + d->zoomSlider->setOrientation(TQt::Horizontal); + d->zoomSlider->setLineStep(ThumbnailSize::Step); + d->zoomSlider->setMaximumHeight(fontMetrics().height()+2); + d->zoomSlider->setFixedWidth(120); + d->zoomSlider->setFocusPolicy(TQWidget::NoFocus); + + d->zoomPlusButton = new TQToolButton(this); + d->zoomPlusButton->setAutoRaise(true); + d->zoomPlusButton->setIconSet(SmallIconSet("zoom-in")); + d->zoomPlusButton->setFocusPolicy(TQWidget::NoFocus); + TQToolTip::add(d->zoomPlusButton, i18n("Zoom In")); + + d->zoomTracker = new DTipTracker("", d->zoomSlider); + + // ------------------------------------------------------------- + + connect(d->zoomMinusButton, TQ_SIGNAL(clicked()), + this, TQ_SIGNAL(signalZoomMinusClicked())); + + connect(d->zoomPlusButton, TQ_SIGNAL(clicked()), + this, TQ_SIGNAL(signalZoomPlusClicked())); + + connect(d->zoomSlider, TQ_SIGNAL(valueChanged(int)), + this, TQ_SIGNAL(signalZoomSliderChanged(int))); + + connect(d->zoomSlider, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotZoomSliderChanged(int))); + + connect(d->zoomSlider, TQ_SIGNAL(sliderReleased()), + this, TQ_SLOT(slotZoomSliderReleased())); +} + +StatusZoomBar::~StatusZoomBar() +{ + if (d->zoomTimer) + delete d->zoomTimer; + + delete d->zoomTracker; + delete d; +} + +void StatusZoomBar::slotZoomSliderChanged(int) +{ + if (d->zoomTimer) + { + d->zoomTimer->stop(); + delete d->zoomTimer; + } + + d->zoomTimer = new TQTimer( this ); + connect(d->zoomTimer, TQ_SIGNAL(timeout()), + this, TQ_SLOT(slotDelayedZoomSliderChanged()) ); + d->zoomTimer->start(300, true); +} + +void StatusZoomBar::slotDelayedZoomSliderChanged() +{ + emit signalDelayedZoomSliderChanged(d->zoomSlider->value()); +} + +void StatusZoomBar::slotZoomSliderReleased() +{ + emit signalZoomSliderReleased(d->zoomSlider->value()); +} + +void StatusZoomBar::setZoomSliderValue(int v) +{ + d->zoomSlider->blockSignals(true); + d->zoomSlider->setValue(v); + d->zoomSlider->blockSignals(false); +} + +void StatusZoomBar::setZoomTrackerText(const TQString& text) +{ + d->zoomTracker->setText(text); +} + +void StatusZoomBar::setEnableZoomPlus(bool e) +{ + d->zoomPlusButton->setEnabled(e); +} + +void StatusZoomBar::setEnableZoomMinus(bool e) +{ + d->zoomMinusButton->setEnabled(e); +} + +} // namespace Digikam + diff --git a/src/libs/widgets/common/statuszoombar.h b/src/libs/widgets/common/statuszoombar.h new file mode 100644 index 00000000..adf69416 --- /dev/null +++ b/src/libs/widgets/common/statuszoombar.h @@ -0,0 +1,100 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2007-04-15 + * Description : a zoom bar used in status bar. + * + * Copyright (C) 2007 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. + * + * ============================================================ */ + +#ifndef STATUSSTATUSBAR_H +#define STATUSSTATUSBAR_H + +// TQt includes. + +#include <tqslider.h> +#include <tqevent.h> + +// KDE includes. + +#include <tqhbox.h> +#include <tqstring.h> + +// Local includes. + +#include "digikam_export.h" + +namespace Digikam +{ + +class StatusZoomBarPriv; + + +class DIGIKAM_EXPORT TQSliderReverseWheel : public TQSlider +{ + +public: + + TQSliderReverseWheel(TQWidget *parent=0); + ~TQSliderReverseWheel(); + +private: + + void wheelEvent(TQWheelEvent *e); +}; + +// ---------------------------------------------------------------------- + +class DIGIKAM_EXPORT StatusZoomBar : public TQHBox +{ + +TQ_OBJECT + + +public: + + StatusZoomBar( TQWidget *parent=0 ); + ~StatusZoomBar(); + + void setEnableZoomPlus(bool e); + void setEnableZoomMinus(bool e); + + void setZoomSliderValue(int v); + void setZoomTrackerText(const TQString& text); + +signals: + + void signalZoomPlusClicked(); + void signalZoomMinusClicked(); + void signalZoomSliderChanged(int); + void signalDelayedZoomSliderChanged(int); + void signalZoomSliderReleased(int); + +private slots: + + void slotZoomSliderChanged(int); + void slotDelayedZoomSliderChanged(); + void slotZoomSliderReleased(); + +private: + + StatusZoomBarPriv* d; +}; + +} // namespace Digikam + +#endif /* STATUSSTATUSBAR_H */ diff --git a/src/libs/widgets/iccprofiles/Makefile.am b/src/libs/widgets/iccprofiles/Makefile.am new file mode 100644 index 00000000..8888d326 --- /dev/null +++ b/src/libs/widgets/iccprofiles/Makefile.am @@ -0,0 +1,23 @@ +METASOURCES = AUTO + +noinst_LTLIBRARIES = libiccprofileswidgets.la + +libiccprofileswidgets_la_SOURCES = iccprofilewidget.cpp cietonguewidget.cpp iccpreviewwidget.cpp + +libiccprofileswidgets_la_LDFLAGS = $(all_libraries) $(KDE_RPATH) $(LIB_TQT) -lDCOP $(LIB_TDECORE) $(LIB_TDEUI) -ltdefx $(LIB_TDEIO) -ltdetexteditor + +libiccprofileswidgets_la_LIBADD = $(top_builddir)/src/libs/lprof/liblprof.la + +INCLUDES = -I$(top_srcdir)/src/libs/widgets/metadata \ + -I$(top_srcdir)/src/libs/widgets/common \ + -I$(top_srcdir)/src/libs/lprof \ + -I$(top_srcdir)/src/libs/dimg \ + -I$(top_srcdir)/src/libs/dmetadata \ + -I$(top_srcdir)/src/digikam \ + $(LIBKDCRAW_CFLAGS) \ + $(LIBKEXIV2_CFLAGS) \ + $(all_includes) + +digikaminclude_HEADERS = cietonguewidget.h iccprofilewidget.h iccpreviewwidget.h + +digikamincludedir = $(includedir)/digikam diff --git a/src/libs/widgets/iccprofiles/cietonguewidget.cpp b/src/libs/widgets/iccprofiles/cietonguewidget.cpp new file mode 100644 index 00000000..2ec738b3 --- /dev/null +++ b/src/libs/widgets/iccprofiles/cietonguewidget.cpp @@ -0,0 +1,816 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2006-01-10 + * Description : a widget to display CIE tongue from + * an ICC profile. + * + * Copyright (C) 2006-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * + * Any source code are inspired from lprof project and + * Copyright (C) 1998-2001 Marti Maria + * + * 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 <tqimage.h> +#include <tqpainter.h> +#include <tqpixmap.h> +#include <tqfile.h> +#include <tqtimer.h> + +// KDE includes. + +#include <tdelocale.h> + +// Local includes. + +#include "ddebug.h" +#include "lcmsprf.h" +#include "cietonguewidget.h" +#include "cietonguewidget.moc" + +namespace Digikam +{ + + // The following table gives the CIE colour matching functions + // \bar{x}(\lambda), \bar{y}(\lambda), and \bar{z}(\lambda), for + // wavelengths \lambda at 5 nanometre increments from 380 nm through + // 780 nm. This table is used in conjunction with Planck's law for + // the energy spectrum of a black body at a given temperature to plot + // the black body curve on the CIE chart. + + // The following table gives the spectral chromaticity co-ordinates + // x(\lambda) and y(\lambda) for wavelengths in 5 nanometre increments + // from 380 nm through 780 nm. These co-ordinates represent the + // position in the CIE x-y space of pure spectral colours of the given + // wavelength, and thus define the outline of the CIE "tongue" + // diagram. + + static const double spectral_chromaticity[81][3] = + { + { 0.1741, 0.0050 }, // 380 nm + { 0.1740, 0.0050 }, + { 0.1738, 0.0049 }, + { 0.1736, 0.0049 }, + { 0.1733, 0.0048 }, + { 0.1730, 0.0048 }, + { 0.1726, 0.0048 }, + { 0.1721, 0.0048 }, + { 0.1714, 0.0051 }, + { 0.1703, 0.0058 }, + { 0.1689, 0.0069 }, + { 0.1669, 0.0086 }, + { 0.1644, 0.0109 }, + { 0.1611, 0.0138 }, + { 0.1566, 0.0177 }, + { 0.1510, 0.0227 }, + { 0.1440, 0.0297 }, + { 0.1355, 0.0399 }, + { 0.1241, 0.0578 }, + { 0.1096, 0.0868 }, + { 0.0913, 0.1327 }, + { 0.0687, 0.2007 }, + { 0.0454, 0.2950 }, + { 0.0235, 0.4127 }, + { 0.0082, 0.5384 }, + { 0.0039, 0.6548 }, + { 0.0139, 0.7502 }, + { 0.0389, 0.8120 }, + { 0.0743, 0.8338 }, + { 0.1142, 0.8262 }, + { 0.1547, 0.8059 }, + { 0.1929, 0.7816 }, + { 0.2296, 0.7543 }, + { 0.2658, 0.7243 }, + { 0.3016, 0.6923 }, + { 0.3373, 0.6589 }, + { 0.3731, 0.6245 }, + { 0.4087, 0.5896 }, + { 0.4441, 0.5547 }, + { 0.4788, 0.5202 }, + { 0.5125, 0.4866 }, + { 0.5448, 0.4544 }, + { 0.5752, 0.4242 }, + { 0.6029, 0.3965 }, + { 0.6270, 0.3725 }, + { 0.6482, 0.3514 }, + { 0.6658, 0.3340 }, + { 0.6801, 0.3197 }, + { 0.6915, 0.3083 }, + { 0.7006, 0.2993 }, + { 0.7079, 0.2920 }, + { 0.7140, 0.2859 }, + { 0.7190, 0.2809 }, + { 0.7230, 0.2770 }, + { 0.7260, 0.2740 }, + { 0.7283, 0.2717 }, + { 0.7300, 0.2700 }, + { 0.7311, 0.2689 }, + { 0.7320, 0.2680 }, + { 0.7327, 0.2673 }, + { 0.7334, 0.2666 }, + { 0.7340, 0.2660 }, + { 0.7344, 0.2656 }, + { 0.7346, 0.2654 }, + { 0.7347, 0.2653 }, + { 0.7347, 0.2653 }, + { 0.7347, 0.2653 }, + { 0.7347, 0.2653 }, + { 0.7347, 0.2653 }, + { 0.7347, 0.2653 }, + { 0.7347, 0.2653 }, + { 0.7347, 0.2653 }, + { 0.7347, 0.2653 }, + { 0.7347, 0.2653 }, + { 0.7347, 0.2653 }, + { 0.7347, 0.2653 }, + { 0.7347, 0.2653 }, + { 0.7347, 0.2653 }, + { 0.7347, 0.2653 }, + { 0.7347, 0.2653 }, + { 0.7347, 0.2653 } // 780 nm + }; + +class CIETongueWidgetPriv +{ +public: + + CIETongueWidgetPriv() + { + hMonitorProfile = 0; + hXYZProfile = 0; + hXFORM = 0; + + Measurement.Patches = 0; + Measurement.Allowed = 0; + blinkTimer = 0; + pos = 0; + + profileDataAvailable = true; + loadingImageMode = false; + loadingImageSucess = false; + } + + bool profileDataAvailable; + bool loadingImageMode; + bool loadingImageSucess; + + double gridside; + + int xBias; + int yBias; + int pxcols; + int pxrows; + int pos; // Position of animation during loading/calculation. + + TQPainter painter; + TQPixmap pixmap; + TQTimer *blinkTimer; + + cmsHPROFILE hMonitorProfile; + cmsHPROFILE hXYZProfile; + cmsHTRANSFORM hXFORM; + cmsCIExyYTRIPLE Primaries; + cmsCIEXYZ MediaWhite; + + MEASUREMENT Measurement; +}; + +CIETongueWidget::CIETongueWidget(int w, int h, TQWidget *parent, cmsHPROFILE hMonitor) + : TQWidget(parent, 0, TQt::WDestructiveClose) +{ + d = new CIETongueWidgetPriv; + d->blinkTimer = new TQTimer( this ); + setMinimumSize(w, h); + cmsErrorAction(LCMS_ERROR_SHOW); + + if (hMonitor) + d->hMonitorProfile = hMonitor; + else + d->hMonitorProfile = cmsCreate_sRGBProfile(); + + d->hXYZProfile = cmsCreateXYZProfile(); + d->hXFORM = cmsCreateTransform(d->hXYZProfile, TYPE_XYZ_16, + d->hMonitorProfile, TYPE_RGB_8, + INTENT_PERCEPTUAL, 0); + + connect(d->blinkTimer, TQ_SIGNAL(timeout()), + this, TQ_SLOT(slotBlinkTimerDone())); +} + +CIETongueWidget::~CIETongueWidget() +{ + if (d->Measurement.Patches) + free(d->Measurement.Patches); + + if (d->Measurement.Allowed) + free(d->Measurement.Allowed); + + cmsDeleteTransform(d->hXFORM); + cmsCloseProfile(d->hXYZProfile); + cmsCloseProfile(d->hMonitorProfile); + delete d; +} + +int CIETongueWidget::grids(double val) const +{ + return (int) floor(val * d->gridside + 0.5); +} + +bool CIETongueWidget::setProfileData(const TQByteArray &profileData) +{ + if (!profileData.isEmpty()) + { + cmsHPROFILE hProfile = cmsOpenProfileFromMem(const_cast<char*>(profileData.data()), + (DWORD)profileData.size()); + + if (!hProfile) + { + d->profileDataAvailable = false; + d->loadingImageSucess = false; + } + else + { + setProfile(hProfile); + cmsCloseProfile(hProfile); + d->profileDataAvailable = true; + d->loadingImageSucess = true; + } + } + else + { + d->profileDataAvailable = false; + d->loadingImageSucess = false; + } + + d->loadingImageMode = false; + + d->blinkTimer->stop(); + repaint(false); + return (d->profileDataAvailable); +} + +bool CIETongueWidget::setProfileFromFile(const KURL& file) +{ + if (!file.isEmpty() && file.isValid()) + { + cmsHPROFILE hProfile = cmsOpenProfileFromFile(TQFile::encodeName(file.path()), "r"); + + if (!hProfile) + { + d->profileDataAvailable = false; + d->loadingImageSucess = false; + } + else + { + setProfile(hProfile); + cmsCloseProfile(hProfile); + d->profileDataAvailable = true; + d->loadingImageSucess = true; + } + } + else + { + d->profileDataAvailable = false; + d->loadingImageSucess = false; + } + + d->blinkTimer->stop(); + repaint(false); + return (d->profileDataAvailable); +} + +void CIETongueWidget::setProfile(cmsHPROFILE hProfile) +{ + // Get the white point. + + ZeroMemory(&(d->MediaWhite), sizeof(cmsCIEXYZ)); + cmsTakeMediaWhitePoint(&(d->MediaWhite), hProfile); + cmsCIExyY White; + cmsXYZ2xyY(&White, &(d->MediaWhite)); + + // Get the colorant matrix. + + ZeroMemory(&(d->Primaries), sizeof(cmsCIExyYTRIPLE)); + + if (cmsIsTag(hProfile, icSigRedColorantTag) && + cmsIsTag(hProfile, icSigGreenColorantTag) && + cmsIsTag(hProfile, icSigBlueColorantTag)) + { + MAT3 Mat; + + if (cmsReadICCMatrixRGB2XYZ(&Mat, hProfile)) + { + // Undo chromatic adaptation + if (cmsAdaptMatrixFromD50(&Mat, &White)) + { + cmsCIEXYZ tmp; + + tmp.X = Mat.v[0].n[0]; + tmp.Y = Mat.v[1].n[0]; + tmp.Z = Mat.v[2].n[0]; + + // ScaleToWhite(&MediaWhite, &tmp); + cmsXYZ2xyY(&(d->Primaries.Red), &tmp); + + tmp.X = Mat.v[0].n[1]; + tmp.Y = Mat.v[1].n[1]; + tmp.Z = Mat.v[2].n[1]; + // ScaleToWhite(&MediaWhite, &tmp); + cmsXYZ2xyY(&(d->Primaries.Green), &tmp); + + tmp.X = Mat.v[0].n[2]; + tmp.Y = Mat.v[1].n[2]; + tmp.Z = Mat.v[2].n[2]; + // ScaleToWhite(&MediaWhite, &tmp); + cmsXYZ2xyY(&(d->Primaries.Blue), &tmp); + } + } + } + + // Get target data stored in profile + + ZeroMemory(&(d->Measurement), sizeof(MEASUREMENT)); + char* CharTarget; + size_t CharTargetSize; + + if (cmsTakeCharTargetData(hProfile, &CharTarget, &CharTargetSize)) + { + LCMSHANDLE hSheet = cmsxIT8LoadFromMem(CharTarget, CharTargetSize); + if (hSheet != NULL) + { + cmsxPCollLoadFromSheet(&(d->Measurement), hSheet); + cmsxIT8Free(hSheet); + cmsxPCollValidatePatches(&(d->Measurement), PATCH_HAS_XYZ|PATCH_HAS_RGB); + } + } +} + +void CIETongueWidget::mapPoint(int& icx, int& icy, LPcmsCIExyY xyY) +{ + icx = (int) floor((xyY->x * (d->pxcols - 1)) + .5); + icy = (int) floor(((d->pxrows - 1) - xyY->y * (d->pxrows - 1)) + .5); +} + +void CIETongueWidget::biasedLine(int x1, int y1, int x2, int y2) +{ + d->painter.drawLine(x1 + d->xBias, y1, x2 + d->xBias, y2); +} + +void CIETongueWidget::biasedText(int x, int y, TQString Txt) +{ + d->painter.drawText(TQPoint(d->xBias + x, y), Txt); +} + +TQRgb CIETongueWidget::colorByCoord(double x, double y) +{ + // Get xyz components scaled from coordinates + + double cx = ((double) x) / (d->pxcols - 1); + double cy = 1.0 - ((double) y) / (d->pxrows - 1); + double cz = 1.0 - cx - cy; + + // Project xyz to XYZ space. Note that in this + // particular case we are substituting XYZ with xyz + + cmsCIEXYZ XYZ = { cx , cy , cz }; + + WORD XYZW[3]; + BYTE RGB[3]; + + cmsFloat2XYZEncoded(XYZW, &XYZ); + cmsDoTransform(d->hXFORM, XYZW, RGB, 1); + + return tqRgb(RGB[0], RGB[1], RGB[2]); +} + +void CIETongueWidget::outlineTongue() +{ + int lx = 0, ly = 0; + int fx=0, fy=0; + + for (int x = 380; x <= 700; x += 5) + { + int ix = (x - 380) / 5; + + cmsCIExyY p = {spectral_chromaticity[ix][0], + spectral_chromaticity[ix][1], 1}; + + int icx, icy; + mapPoint(icx, icy, &p); + + if (x > 380) + { + biasedLine(lx, ly, icx, icy); + } + else + { + fx = icx; + fy = icy; + } + + lx = icx; + ly = icy; + } + + biasedLine(lx, ly, fx, fy); +} + +void CIETongueWidget::fillTongue() +{ + + TQImage Img = d->pixmap.convertToImage(); + + int x; + + for (int y = 0; y < d->pxrows; y++) + { + int xe = 0; + + // Find horizontal extents of tongue on this line. + + for (x = 0; x < d->pxcols; x++) + { + if ((TQColor) Img.pixel(x + d->xBias, y) != TQt::black) + { + for (xe = d->pxcols - 1; xe >= x; xe--) + { + if ((TQColor) Img.pixel(xe + d->xBias, y) != TQt::black) + { + break; + } + } + + break; + } + } + + if (x < d->pxcols) + { + for ( ; x <= xe; x++) + { + TQRgb Color = colorByCoord(x, y); + Img.setPixel(x + d->xBias, y, Color); + } + } + } + + d->pixmap.convertFromImage(Img, TQPixmap::AvoidDither ); +} + +void CIETongueWidget::drawTongueAxis() +{ + TQFont font; + font.setPointSize(6); + d->painter.setFont(font); + + d->painter.setPen(tqRgb(255, 255, 255)); + + biasedLine(0, 0, 0, d->pxrows - 1); + biasedLine(0, d->pxrows-1, d->pxcols-1, d->pxrows - 1); + + for (int y = 1; y <= 9; y += 1) + { + TQString s; + int xstart = (y * (d->pxcols - 1)) / 10; + int ystart = (y * (d->pxrows - 1)) / 10; + + s.sprintf("0.%d", y); + biasedLine(xstart, d->pxrows - grids(1), xstart, d->pxrows - grids(4)); + biasedText(xstart - grids(11), d->pxrows + grids(15), s); + + s.sprintf("0.%d", 10 - y); + biasedLine(0, ystart, grids(3), ystart); + biasedText(grids(-25), ystart + grids(5), s); + } +} + +void CIETongueWidget::drawTongueGrid() +{ + d->painter.setPen(tqRgb(80, 80, 80)); + + for (int y = 1; y <= 9; y += 1) + { + int xstart = (y * (d->pxcols - 1)) / 10; + int ystart = (y * (d->pxrows - 1)) / 10; + + biasedLine(xstart, grids(4), xstart, d->pxrows - grids(4) - 1); + biasedLine(grids(7), ystart, d->pxcols-1-grids(7), ystart); + } +} + +void CIETongueWidget::drawLabels() +{ + TQFont font; + font.setPointSize(5); + d->painter.setFont(font); + + for (int x = 450; x <= 650; x += (x > 470 && x < 600) ? 5 : 10) + { + TQString wl; + int bx = 0, by = 0, tx, ty; + + if (x < 520) + { + bx = grids(-22); + by = grids(2); + } + else if (x < 535) + { + bx = grids(-8); + by = grids(-6); + } + else + { + bx = grids(4); + } + + int ix = (x - 380) / 5; + + cmsCIExyY p = {spectral_chromaticity[ix][0], + spectral_chromaticity[ix][1], 1}; + + int icx, icy; + mapPoint(icx, icy, &p); + + tx = icx + ((x < 520) ? grids(-2) : ((x >= 535) ? grids(2) : 0)); + ty = icy + ((x < 520) ? 0 : ((x >= 535) ? grids(-1) : grids(-2))); + + d->painter.setPen(tqRgb(255, 255, 255)); + biasedLine(icx, icy, tx, ty); + + TQRgb Color = colorByCoord(icx, icy); + d->painter.setPen(Color); + + wl.sprintf("%d", x); + biasedText(icx+bx, icy+by, wl); + } +} + +void CIETongueWidget::drawSmallElipse(LPcmsCIExyY xyY, BYTE r, BYTE g, BYTE b, int sz) +{ + int icx, icy; + + mapPoint(icx, icy, xyY); + d->painter.setPen(tqRgb(r, g, b)); + d->painter.drawEllipse(icx + d->xBias- sz/2, icy-sz/2, sz, sz); +} + +void CIETongueWidget::drawPatches() +{ + for (int i=0; i < d->Measurement.nPatches; i++) + { + LPPATCH p = d->Measurement.Patches + i; + + if (d->Measurement.Allowed[i]) + { + LPcmsCIEXYZ XYZ = &p ->XYZ; + cmsCIExyY xyY; + cmsXYZ2xyY(&xyY, XYZ); + + drawSmallElipse(&xyY, 0, 0, 0, 4); + + if (p->dwFlags & PATCH_HAS_XYZ_PROOF) + { + if (p->XYZ.Y < 0.03) + continue; + + if (p->XYZProof.Y < 0.03) + continue; + + cmsCIExyY Pt; + cmsXYZ2xyY(&Pt, &p->XYZProof); + int icx1, icx2, icy1, icy2; + + mapPoint(icx1, icy1, &xyY); + mapPoint(icx2, icy2, &Pt); + + if (icx2 < 5 || icy2 < 5 || icx1 < 5 || icy1 < 5) + continue; + + d->painter.setPen(tqRgb(255, 255, 0)); + biasedLine(icx1, icy1, icx2, icy2); + } + } + } +} + +void CIETongueWidget::drawColorantTriangle() +{ + drawSmallElipse(&(d->Primaries.Red), 255, 128, 128, 6); + drawSmallElipse(&(d->Primaries.Green), 128, 255, 128, 6); + drawSmallElipse(&(d->Primaries.Blue), 128, 128, 255, 6); + + int x1, y1, x2, y2, x3, y3; + + mapPoint(x1, y1, &(d->Primaries.Red)); + mapPoint(x2, y2, &(d->Primaries.Green)); + mapPoint(x3, y3, &(d->Primaries.Blue)); + + d->painter.setPen(tqRgb(255, 255, 255)); + + biasedLine(x1, y1, x2, y2); + biasedLine(x2, y2, x3, y3); + biasedLine(x3, y3, x1, y1); +} + +void CIETongueWidget::sweep_sRGB() +{ + int r, g, b; + cmsHPROFILE hXYZ, hsRGB; + + hXYZ = cmsCreateXYZProfile(); + hsRGB = cmsCreate_sRGBProfile(); + + cmsHTRANSFORM xform = cmsCreateTransform(hsRGB, TYPE_RGB_16, hXYZ, TYPE_XYZ_16, + INTENT_ABSOLUTE_COLORIMETRIC, cmsFLAGS_NOTPRECALC); + WORD RGB[3], XYZ[3]; + cmsCIEXYZ xyz, MediaWhite; + cmsCIExyY xyY, WhitePt; + int x1, y1; + + cmsTakeMediaWhitePoint(&MediaWhite, hsRGB); + cmsXYZ2xyY(&WhitePt, &MediaWhite); + + for (r=0; r < 65536; r += 1024) + { + for (g=0; g < 65536; g += 1024) + { + for (b=0; b < 65536; b += 1024) + { + RGB[0] = r; RGB[1] = g; RGB[2] = b; + cmsDoTransform(xform, RGB, XYZ, 1); + cmsXYZEncoded2Float(&xyz, XYZ); + cmsXYZ2xyY(&xyY, &xyz); + mapPoint(x1, y1, &xyY); + d->painter.drawPoint(x1 + d->xBias, y1); + } + } + } + + cmsDeleteTransform(xform); + cmsCloseProfile(hXYZ); + cmsCloseProfile(hsRGB); +} + +void CIETongueWidget::drawWhitePoint() +{ + cmsCIExyY Whitem_pntxyY; + cmsXYZ2xyY(&Whitem_pntxyY, &(d->MediaWhite)); + drawSmallElipse(&Whitem_pntxyY, 255, 255, 255, 8); +} + +void CIETongueWidget::loadingStarted() +{ + d->pos = 0; + d->loadingImageMode = true; + d->loadingImageSucess = false; + repaint(false); + d->blinkTimer->start(200); +} + +void CIETongueWidget::loadingFailed() +{ + d->blinkTimer->stop(); + d->pos = 0; + d->loadingImageMode = false; + d->loadingImageSucess = false; + repaint(false); +} + +void CIETongueWidget::paintEvent(TQPaintEvent*) +{ + d->pixmap = TQPixmap(size()); + d->pixmap.setOptimization(TQPixmap::BestOptim); + + // Widget is disable : drawing grayed frame. + + if ( !isEnabled() ) + { + d->painter.begin(&d->pixmap); + d->painter.fillRect(0, 0, size().width(), size().height(), palette().disabled().background()); + d->painter.setPen(TQPen(palette().disabled().foreground(), 1, TQt::SolidLine)); + d->painter.drawRect(0, 0, width(), height()); + d->painter.end(); + bitBlt(this, 0, 0, &d->pixmap); + return; + } + + // Loading image mode. + + if (d->loadingImageMode && !d->loadingImageSucess) + { + // In first, we draw an animation. + + int asize = 24; + TQPixmap anim(asize, asize); + TQPainter p2; + p2.begin(&anim, this); + p2.fillRect(0, 0, asize, asize, palette().active().background()); + p2.translate(asize/2, asize/2); + + d->pos = (d->pos + 10) % 360; + p2.setPen(TQPen(palette().active().text())); + p2.rotate(d->pos); + for ( int i=0 ; i<12 ; i++ ) + { + p2.drawLine(asize/2-5, 0, asize/2-2, 0); + p2.rotate(30); + } + p2.end(); + + // ... and we render busy text. + + d->painter.begin(&d->pixmap); + d->painter.fillRect(0, 0, size().width(), size().height(), palette().active().background()); + d->painter.drawPixmap(width()/2 - asize /2, asize, anim); + d->painter.setPen(TQPen(palette().active().text(), 1, TQt::SolidLine)); + d->painter.drawRect(0, 0, width(), height()); + d->painter.drawText(0, 0, size().width(), size().height(), TQt::AlignCenter, + i18n("Loading image...")); + + d->painter.end(); + bitBlt(this, 0, 0, &d->pixmap); + return; + } + + // No profile data to show. + + if (!d->profileDataAvailable || (!d->loadingImageMode && !d->loadingImageSucess)) + { + d->painter.begin(&d->pixmap); + d->painter.fillRect(0, 0, size().width(), size().height(), palette().active().background()); + d->painter.setPen(TQPen(palette().active().text(), 1, TQt::SolidLine)); + d->painter.drawRect(0, 0, width(), height()); + d->painter.drawText(0, 0, size().width(), size().height(), TQt::AlignCenter, + i18n("No profile available...")); + + d->painter.end(); + bitBlt(this, 0, 0, &d->pixmap); + return; + } + + // Draw the CIE tongue curve. + + d->pixmap.fill(TQt::black); + d->painter.begin(&d->pixmap); + + int pixcols = d->pixmap.width(); + int pixrows = d->pixmap.height(); + + d->gridside = (TQMIN(pixcols, pixrows)) / 512.0; + d->xBias = grids(32); + d->yBias = grids(20); + d->pxcols = pixcols - d->xBias; + d->pxrows = pixrows - d->yBias; + + d->painter.setBackgroundColor(tqRgb(0, 0, 0)); + d->painter.setPen(tqRgb(255, 255, 255)); + + outlineTongue(); + fillTongue(); + + drawTongueAxis(); + drawLabels(); + drawTongueGrid(); + + if (d->MediaWhite.Y > 0.0) + drawWhitePoint(); + + if (d->Primaries.Red.Y != 0.0) + drawColorantTriangle(); + + if (d->Measurement.Patches && d->Measurement.Allowed) + drawPatches(); + + d->painter.end(); + + bitBlt(this, 0, 0, &d->pixmap); +} + +void CIETongueWidget::slotBlinkTimerDone() +{ + repaint(false); + d->blinkTimer->start( 200 ); +} + +} // namespace Digikam diff --git a/src/libs/widgets/iccprofiles/cietonguewidget.h b/src/libs/widgets/iccprofiles/cietonguewidget.h new file mode 100644 index 00000000..9fc8503d --- /dev/null +++ b/src/libs/widgets/iccprofiles/cietonguewidget.h @@ -0,0 +1,115 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2006-01-10 + * Description : a widget to display CIE tongue from + * an ICC profile. + * + * Copyright (C) 2006-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * + * Any source code are inspired from lprof project and + * Copyright (C) 1998-2001 Marti Maria + * + * 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. + * + * ============================================================ */ + +#ifndef CIETONGUEWIDGET_H +#define CIETONGUEWIDGET_H + +#include <config.h> + +// TQt includes. + +#include <tqwidget.h> +#include <tqcolor.h> + +// KDE includes. + +#include <kurl.h> + +// lcms includes. + +#include LCMS_HEADER +#if LCMS_VERSION < 114 +#define cmsTakeCopyright(profile) "Unknown" +#endif // LCMS_VERSION < 114 + +// Local includes. + +#include "digikam_export.h" + +namespace Digikam +{ + +class CIETongueWidgetPriv; + +class DIGIKAM_EXPORT CIETongueWidget : public TQWidget +{ +TQ_OBJECT + + +public: + + CIETongueWidget(int w, int h, TQWidget *parent=0, cmsHPROFILE hMonitor=0); + ~CIETongueWidget(); + + bool setProfileData(const TQByteArray& profileData=TQByteArray()); + bool setProfileFromFile(const KURL& file=KURL()); + + void loadingStarted(); + void loadingFailed(); + +protected: + + int grids(double val) const; + + void outlineTongue(); + void fillTongue(); + void drawTongueAxis(); + void drawTongueGrid(); + void drawLabels(); + + TQRgb colorByCoord(double x, double y); + void drawSmallElipse(LPcmsCIExyY xyY, BYTE r, BYTE g, BYTE b, int sz); + + void paintEvent( TQPaintEvent * ); + +private: + + void drawColorantTriangle(); + void drawWhitePoint(); + void drawPatches(); + + void mapPoint(int& icx, int& icy, LPcmsCIExyY xyY); + void biasedLine(int x1, int y1, int x2, int y2); + void biasedText(int x, int y, TQString Txt); + + void sweep_sRGB(); + + void setProfile(cmsHPROFILE hProfile); + +private slots: + + void slotBlinkTimerDone(); + +private : + + CIETongueWidgetPriv* d; + +}; + +} // namespace Digikam + +#endif /* CIETONGUEWIDGET_H */ diff --git a/src/libs/widgets/iccprofiles/iccpreviewwidget.cpp b/src/libs/widgets/iccprofiles/iccpreviewwidget.cpp new file mode 100644 index 00000000..3398b37f --- /dev/null +++ b/src/libs/widgets/iccprofiles/iccpreviewwidget.cpp @@ -0,0 +1,83 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2006-01-12 + * Description : a widget to display ICC profiles descriptions + * in file dialog preview. + * + * Copyright (C) 2006-2007 by Francisco J. Cruz <[email protected]> + * + * 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 <tqfileinfo.h> +#include <tqlayout.h> +#include <tqvgroupbox.h> + +// KDE includes. + +#include <kurl.h> + +// Local includes. + +#include "ddebug.h" +#include "iccprofilewidget.h" +#include "iccpreviewwidget.h" +#include "iccpreviewwidget.moc" + +namespace Digikam +{ + +ICCPreviewWidget::ICCPreviewWidget(TQWidget *parent) + : KPreviewWidgetBase( parent ) +{ + TQVBoxLayout *layout = new TQVBoxLayout( this ); + TQVGroupBox *box = new TQVGroupBox( this ); + box->setInsideMargin(0); + box->setFrameStyle(TQFrame::NoFrame|TQFrame::Plain); + m_iccProfileWidget = new ICCProfileWidget(box); + layout->addWidget( box ); +} + +ICCPreviewWidget::~ICCPreviewWidget() +{ +} + +void ICCPreviewWidget::showPreview( const KURL &url) +{ + clearPreview(); + TQFileInfo fInfo(url.path()); + + if ( url.isLocalFile() && fInfo.isFile() && fInfo.isReadable() ) + { + DDebug() << url << " is a readble local file" << endl; + m_iccProfileWidget->loadFromURL(url); + } + else + { + DDebug() << url << " is not a readable local file" << endl; + } +} + +void ICCPreviewWidget::clearPreview() +{ + m_iccProfileWidget->loadFromURL(KURL()); +} + +} // namespace Digikam + + diff --git a/src/libs/widgets/iccprofiles/iccpreviewwidget.h b/src/libs/widgets/iccprofiles/iccpreviewwidget.h new file mode 100644 index 00000000..89b1f4b5 --- /dev/null +++ b/src/libs/widgets/iccprofiles/iccpreviewwidget.h @@ -0,0 +1,71 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2006-01-12 + * Description : a widget to display ICC profiles descriptions + * in file dialog preview. + * + * Copyright (C) 2006-2007 by Francisco J. Cruz <[email protected]> + * + * 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. + * + * ============================================================ */ + +#ifndef ICCPREVIEWWIDGET_H +#define ICCPREVIEWWIDGET_H + +// KDE includes. + +#include <kpreviewwidgetbase.h> + +// Local includes. + +#include "digikam_export.h" + +class KURL; + +namespace Digikam +{ + +class ICCProfileWidget; + +class DIGIKAM_EXPORT ICCPreviewWidget : public KPreviewWidgetBase +{ + +TQ_OBJECT + + +public: + + ICCPreviewWidget(TQWidget *parent); + ~ICCPreviewWidget(); + +public slots: + + virtual void showPreview(const KURL &url); + +protected: + + virtual void clearPreview(); + virtual void virtual_hook(int, void*){}; + +private : + + ICCProfileWidget *m_iccProfileWidget; + +}; + +} // namespace Digikam + +#endif /* ICCPREVIEWWIDGET_H */ diff --git a/src/libs/widgets/iccprofiles/iccprofilewidget.cpp b/src/libs/widgets/iccprofiles/iccprofilewidget.cpp new file mode 100644 index 00000000..2e5152f7 --- /dev/null +++ b/src/libs/widgets/iccprofiles/iccprofilewidget.cpp @@ -0,0 +1,448 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2006-06-23 + * Description : a tab widget to display ICC profile infos + * + * Copyright (C) 2006-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. + * + * ============================================================ */ + +#include <config.h> + +// TQt includes. + +#include <tqlayout.h> +#include <tqpushbutton.h> +#include <tqwhatsthis.h> +#include <tqlabel.h> +#include <tqmap.h> +#include <tqhbox.h> +#include <tqfile.h> +#include <tqcombobox.h> +#include <tqgroupbox.h> +#include <tqmap.h> + +// KDE includes. + +#include <kdialogbase.h> +#include <tdelocale.h> +#include <tdeapplication.h> + +// Lcms includes. + +#include LCMS_HEADER +#if LCMS_VERSION < 114 +#define cmsTakeCopyright(profile) "Unknown" +#endif // LCMS_VERSION < 114 + +// Local includes. + +#include "ddebug.h" +#include "metadatalistview.h" +#include "cietonguewidget.h" +#include "iccprofilewidget.h" +#include "iccprofilewidget.moc" + +namespace Digikam +{ + +static const char* ICCHumanList[] = +{ + "ColorSpace", + "Copyright", + "DeviceClass", + "Name", + "Description", + "RenderingIntent", + "-1" +}; + +// This entry list is only require for compatibility with MetadataWidget implementation. +static const char* ICCEntryList[] = +{ + "Header", + "-1" +}; + +class ICCTagInfo +{ + +public: + + ICCTagInfo(){} + + ICCTagInfo(const TQString& title, const TQString& description) + : m_title(title), m_description(description){} + + TQString title() const { return m_title; } + TQString description() const { return m_description; } + +private: + + TQString m_title; + TQString m_description; +}; + +typedef TQMap<TQString, ICCTagInfo> ICCTagInfoMap; + +class ICCProfileWidgetPriv +{ + +public: + + ICCProfileWidgetPriv() + { + cieTongue = 0; + } + + TQStringList tagsfilter; + TQStringList keysFilter; + + CIETongueWidget *cieTongue; + + ICCTagInfoMap iccTagsDescription; +}; + + +ICCProfileWidget::ICCProfileWidget(TQWidget* parent, const char* name, int w, int h) + : MetadataWidget(parent, name) +{ + cmsErrorAction(LCMS_ERROR_SHOW); + + d = new ICCProfileWidgetPriv; + + // Set the translated ICC tags titles/descriptions list + d->iccTagsDescription["Icc.Header.Name"] = ICCTagInfo(i18n("Name"), + i18n("The ICC profile product name")); + d->iccTagsDescription["Icc.Header.Description"] = ICCTagInfo(i18n("Description"), + i18n("The ICC profile product description")); + d->iccTagsDescription["Icc.Header.Information"] = ICCTagInfo(i18n("Information"), + i18n("Additional ICC profile information")); + d->iccTagsDescription["Icc.Header.Manufacturer"] = ICCTagInfo(i18n("Manufacturer"), + i18n("Raw information about the ICC profile manufacturer")); + d->iccTagsDescription["Icc.Header.Model"] = ICCTagInfo(i18n("Model"), + i18n("Raw information about the ICC profile model")); + d->iccTagsDescription["Icc.Header.Copyright"] = ICCTagInfo(i18n("Copyright"), + i18n("Raw information about the ICC profile copyright")); + d->iccTagsDescription["Icc.Header.ProfileID"] = ICCTagInfo(i18n("Profile ID"), + i18n("The ICC profile ID number")); + d->iccTagsDescription["Icc.Header.ColorSpace"] = ICCTagInfo(i18n("Color Space"), + i18n("The color space used by the ICC profile")); + d->iccTagsDescription["Icc.Header.ConnectionSpace"] = ICCTagInfo(i18n("Connection Space"), + i18n("The connection space used by the ICC profile")); + d->iccTagsDescription["Icc.Header.DeviceClass"] = ICCTagInfo(i18n("Device Class"), + i18n("The ICC profile device class")); + d->iccTagsDescription["Icc.Header.RenderingIntent"] = ICCTagInfo(i18n("Rendering Intent"), + i18n("The ICC profile rendering intent")); + d->iccTagsDescription["Icc.Header.ProfileVersion"] = ICCTagInfo(i18n("Profile Version"), + i18n("The ICC version used to record the profile")); + d->iccTagsDescription["Icc.Header.CMMFlags"] = ICCTagInfo(i18n("CMM Flags"), + i18n("The ICC profile color management flags")); + + // Set the list of keys and tags filters. + for (int i=0 ; TQString(ICCEntryList[i]) != TQString("-1") ; i++) + d->keysFilter << ICCEntryList[i]; + + for (int i=0 ; TQString(ICCHumanList[i]) != TQString("-1") ; i++) + d->tagsfilter << ICCHumanList[i]; + + // Add CIE tongue graph to the widget area + + d->cieTongue = new CIETongueWidget(w, h, this); + TQWhatsThis::add( d->cieTongue, i18n("<p>This area contains a CIE or chromaticity diagram. " + "A CIE diagram is a representation of all the colors " + "that a person with normal vision can see. This is represented " + "by the colored sail-shaped area. In addition you will see a " + "triangle that is superimposed on the diagram outlined in white. " + "This triangle represents the outer boundaries of the color space " + "of the device that is characterized by the inspected profile. " + "This is called the device gamut.<p>" + "In addition there are black dots and yellow lines on the diagram. " + "Each black dot represents one of the measurement points that were " + "used to create this profile. The yellow line represents the " + "amount that each point is corrected by the profile, and the " + "direction of this correction.")); + + setUserAreaWidget(d->cieTongue); + decodeMetadata(); +} + +ICCProfileWidget::~ICCProfileWidget() +{ + delete d; +} + +void ICCProfileWidget::setDataLoading() +{ + d->cieTongue->loadingStarted(); +} + +void ICCProfileWidget::setLoadingFailed() +{ + d->cieTongue->loadingFailed(); +} + +TQString ICCProfileWidget::getMetadataTitle() +{ + return i18n("ICC Color Profile Information"); +} + +bool ICCProfileWidget::loadFromURL(const KURL& url) +{ + setFileName(url.path()); + + if (url.isEmpty()) + { + setMetadata(); + d->cieTongue->setProfileData(); + return false; + } + else + { + TQFile file(url.path()); + if ( !file.open(IO_ReadOnly) ) + { + setMetadata(); + d->cieTongue->setProfileData(); + return false; + } + + TQByteArray iccData(file.size()); + TQDataStream stream( &file ); + stream.readRawBytes(iccData.data(), iccData.size()); + file.close(); + + if (iccData.isEmpty()) + { + setMetadata(); + d->cieTongue->setProfileData(); + return false; + } + else + { + setMetadata(iccData); + d->cieTongue->setProfileData(iccData); + } + } + + return true; +} + +bool ICCProfileWidget::decodeMetadata() +{ + TQByteArray iccData = getMetadata(); + if (iccData.isNull()) + return false; + + d->cieTongue->setProfileData(iccData); + + cmsHPROFILE hProfile = cmsOpenProfileFromMem(iccData.data(), (DWORD)iccData.size()); + + if (!hProfile) + { + DDebug() << "Cannot parse ICC profile tags using LCMS" << endl; + return false; + } + + DMetadata::MetaDataMap metaDataMap; + + if ( !TQString(cmsTakeProductName(hProfile)).isEmpty() ) + metaDataMap.insert("Icc.Header.Name", TQString(cmsTakeProductName(hProfile)).replace("\n", " ")); + + if ( !TQString(cmsTakeProductDesc(hProfile)).isEmpty() ) + metaDataMap.insert("Icc.Header.Description", TQString(cmsTakeProductDesc(hProfile)).replace("\n", " ")); + + if ( !TQString(cmsTakeProductInfo(hProfile)).isEmpty() ) + metaDataMap.insert("Icc.Header.Information", TQString(cmsTakeProductInfo(hProfile)).replace("\n", " ")); + + if ( !TQString(cmsTakeManufacturer(hProfile)).isEmpty() ) + metaDataMap.insert("Icc.Header.Manufacturer", TQString(cmsTakeManufacturer(hProfile)).replace("\n", " ")); + + if ( !TQString(cmsTakeModel(hProfile)).isEmpty() ) + metaDataMap.insert("Icc.Header.Model", TQString(cmsTakeModel(hProfile)).replace("\n", " ")); + + if ( !TQString(cmsTakeCopyright(hProfile)).isEmpty() ) + metaDataMap.insert("Icc.Header.Copyright", TQString(cmsTakeCopyright(hProfile)).replace("\n", " ")); + + metaDataMap.insert("Icc.Header.ProfileID", TQString::number((uint)*cmsTakeProfileID(hProfile))); + metaDataMap.insert("Icc.Header.ProfileVersion", TQString::number((uint)cmsGetProfileICCversion(hProfile))); + metaDataMap.insert("Icc.Header.CMMFlags", TQString::number((uint)cmsTakeHeaderFlags(hProfile))); + + TQString colorSpace; + switch (cmsGetColorSpace(hProfile)) + { + case icSigLabData: + colorSpace = i18n("Lab"); + break; + case icSigLuvData: + colorSpace = i18n("Luv"); + break; + case icSigRgbData: + colorSpace = i18n("RGB"); + break; + case icSigGrayData: + colorSpace = i18n("GRAY"); + break; + case icSigHsvData: + colorSpace = i18n("HSV"); + break; + case icSigHlsData: + colorSpace = i18n("HLS"); + break; + case icSigCmykData: + colorSpace = i18n("CMYK"); + break; + case icSigCmyData: + colorSpace= i18n("CMY"); + break; + default: + colorSpace = i18n("Unknown"); + break; + } + metaDataMap.insert("Icc.Header.ColorSpace", colorSpace); + + TQString connectionSpace; + switch (cmsGetPCS(hProfile)) + { + case icSigLabData: + connectionSpace = i18n("Lab"); + break; + case icSigLuvData: + connectionSpace = i18n("Luv"); + break; + case icSigRgbData: + connectionSpace = i18n("RGB"); + break; + case icSigGrayData: + connectionSpace = i18n("GRAY"); + break; + case icSigHsvData: + connectionSpace = i18n("HSV"); + break; + case icSigHlsData: + connectionSpace = i18n("HLS"); + break; + case icSigCmykData: + connectionSpace = i18n("CMYK"); + break; + case icSigCmyData: + connectionSpace= i18n("CMY"); + break; + default: + connectionSpace = i18n("Unknown"); + break; + } + metaDataMap.insert("Icc.Header.ConnectionSpace", connectionSpace); + + TQString device; + switch ((int)cmsGetDeviceClass(hProfile)) + { + case icSigInputClass: + device = i18n("Input device"); + break; + case icSigDisplayClass: + device = i18n("Display device"); + break; + case icSigOutputClass: + device = i18n("Output device"); + break; + case icSigColorSpaceClass: + device = i18n("Color space"); + break; + case icSigLinkClass: + device = i18n("Link device"); + break; + case icSigAbstractClass: + device = i18n("Abstract"); + break; + case icSigNamedColorClass: + device = i18n("Named color"); + break; + default: + device = i18n("Unknown"); + break; + } + metaDataMap.insert("Icc.Header.DeviceClass", device); + + TQString intent; + switch (cmsTakeRenderingIntent(hProfile)) + { + case 0: + intent = i18n("Perceptual"); + break; + case 1: + intent = i18n("Relative Colorimetric"); + break; + case 2: + intent = i18n("Saturation"); + break; + case 3: + intent = i18n("Absolute Colorimetric"); + break; + default: + intent = i18n("Unknown"); + break; + } + metaDataMap.insert("Icc.Header.RenderingIntent", intent); + + cmsCloseProfile(hProfile); + + // Update all metadata contents. + setMetadataMap(metaDataMap); + return true; +} + +void ICCProfileWidget::buildView() +{ + if (getMode() == SIMPLE) + { + setIfdList(getMetadataMap(), d->keysFilter, d->tagsfilter); + } + else + { + setIfdList(getMetadataMap(), d->keysFilter, TQStringList()); + } + + MetadataWidget::buildView(); +} + +TQString ICCProfileWidget::getTagTitle(const TQString& key) +{ + ICCTagInfoMap::Iterator it = d->iccTagsDescription.find(key); + if (it != d->iccTagsDescription.end()) + return(it.data().title()); + + return key.section('.', 2, 2); +} + +void ICCProfileWidget::slotSaveMetadataToFile() +{ + KURL url = saveMetadataToFile(i18n("ICC color profile File to Save"), + TQString("*.icc *.icm|"+i18n("ICC Files (*.icc; *.icm)"))); + storeMetadataToFile(url); +} + +TQString ICCProfileWidget::getTagDescription(const TQString& key) +{ + ICCTagInfoMap::Iterator it = d->iccTagsDescription.find(key); + if (it != d->iccTagsDescription.end()) + return(it.data().description()); + + return key.section('.', 2, 2); +} + +} // namespace Digikam diff --git a/src/libs/widgets/iccprofiles/iccprofilewidget.h b/src/libs/widgets/iccprofiles/iccprofilewidget.h new file mode 100644 index 00000000..d753f30e --- /dev/null +++ b/src/libs/widgets/iccprofiles/iccprofilewidget.h @@ -0,0 +1,79 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2006-06-23 + * Description : a tab widget to display ICC profile infos + * + * Copyright (C) 2006-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. + * + * ============================================================ */ + +#ifndef ICCPROFILEWIDGET_H +#define ICCPROFILEWIDGET_H + +// TQt includes. + +#include <tqwidget.h> +#include <tqstring.h> + +// Local includes. + +#include "metadatawidget.h" +#include "digikam_export.h" + +namespace Digikam +{ + +class ICCProfileWidgetPriv; + +class DIGIKAM_EXPORT ICCProfileWidget : public MetadataWidget +{ + TQ_OBJECT + + +public: + + ICCProfileWidget(TQWidget* parent, const char* name=0, int w=256, int h=256); + ~ICCProfileWidget(); + + bool loadFromURL(const KURL& url); + + TQString getTagDescription(const TQString& key); + TQString getTagTitle(const TQString& key); + + TQString getMetadataTitle(); + + void setLoadingFailed(); + void setDataLoading(); + +protected slots: + + virtual void slotSaveMetadataToFile(); + +private: + + bool decodeMetadata(); + void buildView(); + +private: + + ICCProfileWidgetPriv *d; + +}; + +} // namespace Digikam + +#endif /* ICCPROFILEWIDGET_H */ diff --git a/src/libs/widgets/imageplugins/Makefile.am b/src/libs/widgets/imageplugins/Makefile.am new file mode 100644 index 00000000..d223cb05 --- /dev/null +++ b/src/libs/widgets/imageplugins/Makefile.am @@ -0,0 +1,22 @@ +METASOURCES = AUTO + +noinst_LTLIBRARIES = libimagepluginswidgets.la + +libimagepluginswidgets_la_SOURCES = imageregionwidget.cpp imagepaniconwidget.cpp imageguidewidget.cpp \ + imagewidget.cpp listboxpreviewitem.cpp imagepanelwidget.cpp + +libimagepluginswidgets_la_LDFLAGS = $(all_libraries) $(KDE_RPATH) $(LIB_TQT) -lDCOP $(LIB_TDECORE) $(LIB_TDEUI) -ltdefx $(LIB_TDEIO) -ltdetexteditor + +INCLUDES = -I$(top_srcdir)/src/utilities/imageeditor/editor \ + -I$(top_srcdir)/src/libs/dimg \ + -I$(top_srcdir)/src/libs/dmetadata \ + -I$(top_srcdir)/src/libs/widgets/common \ + -I$(top_srcdir)/src/digikam \ + $(LIBKDCRAW_CFLAGS) \ + $(all_includes) + +digikaminclude_HEADERS = imageregionwidget.h imagepaniconwidget.h \ + imagepanelwidget.h imageguidewidget.h \ + listboxpreviewitem.h imagewidget.h + +digikamincludedir = $(includedir)/digikam diff --git a/src/libs/widgets/imageplugins/imageguidewidget.cpp b/src/libs/widgets/imageplugins/imageguidewidget.cpp new file mode 100644 index 00000000..4ed7f254 --- /dev/null +++ b/src/libs/widgets/imageplugins/imageguidewidget.cpp @@ -0,0 +1,625 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-11-16 + * Description : a widget to display an image with guides + * + * 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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqregion.h> +#include <tqpainter.h> +#include <tqpen.h> +#include <tqpixmap.h> +#include <tqtooltip.h> +#include <tqtimer.h> +#include <tqrect.h> +#include <tqbrush.h> +#include <tqfont.h> +#include <tqfontmetrics.h> + +// KDE includes. + +#include <kstandarddirs.h> +#include <kcursor.h> +#include <tdeglobal.h> + +// Local includes. + +#include "ddebug.h" +#include "dimg.h" +#include "imageiface.h" +#include "imageguidewidget.h" +#include "imageguidewidget.moc" + +namespace Digikam +{ + +class ImageGuideWidgetPriv +{ +public: + + ImageGuideWidgetPriv() + { + pixmap = 0; + iface = 0; + flicker = 0; + timerID = 0; + focus = false; + onMouseMovePreviewToggled = true; + renderingPreviewMode = ImageGuideWidget::NoPreviewMode; + underExposureIndicator = false; + overExposureIndicator = false; + } + + bool sixteenBit; + bool focus; + bool spotVisible; + bool onMouseMovePreviewToggled; + bool underExposureIndicator; + bool overExposureIndicator; + + int width; + int height; + int timerID; + int guideMode; + int guideSize; + int flicker; + int renderingPreviewMode; + + // Current spot position in preview coordinates. + TQPoint spot; + + TQRect rect; + + TQColor guideColor; + + TQPixmap *pixmap; + + ImageIface *iface; + + DImg preview; +}; + +ImageGuideWidget::ImageGuideWidget(int w, int h, TQWidget *parent, + bool spotVisible, int guideMode, + const TQColor& guideColor, int guideSize, + bool blink, bool useImageSelection) + : TQWidget(parent, 0, TQt::WDestructiveClose) +{ + d = new ImageGuideWidgetPriv; + d->spotVisible = spotVisible; + d->guideMode = guideMode; + d->guideColor = guideColor; + d->guideSize = guideSize; + + setBackgroundMode(TQt::NoBackground); + setMinimumSize(w, h); + setMouseTracking(true); + + d->iface = new ImageIface(w, h); + d->iface->setPreviewType(useImageSelection); + uchar *data = d->iface->getPreviewImage(); + d->width = d->iface->previewWidth(); + d->height = d->iface->previewHeight(); + bool sixteenBit = d->iface->previewSixteenBit(); + bool hasAlpha = d->iface->previewHasAlpha(); + d->preview = DImg(d->width, d->height, sixteenBit, hasAlpha, data); + d->preview.setICCProfil( d->iface->getOriginalImg()->getICCProfil() ); + + delete [] data; + + d->pixmap = new TQPixmap(w, h); + d->rect = TQRect(w/2-d->width/2, h/2-d->height/2, d->width, d->height); + + resetSpotPosition(); + setSpotVisible(d->spotVisible, blink); +} + +ImageGuideWidget::~ImageGuideWidget() +{ + delete d->iface; + + if (d->timerID) + killTimer(d->timerID); + + if (d->pixmap) + delete d->pixmap; + + delete d; +} + +ImageIface* ImageGuideWidget::imageIface() +{ + return d->iface; +} + +void ImageGuideWidget::slotToggleUnderExposure(bool u) +{ + d->underExposureIndicator = u; + updatePreview(); +} + +void ImageGuideWidget::slotToggleOverExposure(bool o) +{ + d->overExposureIndicator = o; + updatePreview(); +} + +void ImageGuideWidget::resetSpotPosition() +{ + d->spot.setX( d->width / 2 ); + d->spot.setY( d->height / 2 ); + updatePreview(); +} + +void ImageGuideWidget::slotChangeRenderingPreviewMode(int mode) +{ + d->renderingPreviewMode = mode; + updatePreview(); +} + +int ImageGuideWidget::getRenderingPreviewMode() +{ + return (d->renderingPreviewMode); +} + +TQPoint ImageGuideWidget::getSpotPosition() +{ + return (TQPoint( (int)((float)d->spot.x() * (float)d->iface->originalWidth() / (float)d->width), + (int)((float)d->spot.y() * (float)d->iface->originalHeight() / (float)d->height))); +} + +DColor ImageGuideWidget::getSpotColor(int getColorFrom) +{ + if (getColorFrom == OriginalImage) // Get point color from full original image + return (d->iface->getColorInfoFromOriginalImage(getSpotPosition())); + else if (getColorFrom == PreviewImage) // Get point color from full preview image + return (d->iface->getColorInfoFromPreviewImage(d->spot)); + + // In other cases, get point color from preview target image + return (d->iface->getColorInfoFromTargetPreviewImage(d->spot)); +} + +void ImageGuideWidget::setSpotVisible(bool spotVisible, bool blink) +{ + d->spotVisible = spotVisible; + + if (blink) + { + if (d->spotVisible) + d->timerID = startTimer(800); + else + { + killTimer(d->timerID); + d->timerID = 0; + } + } + + updatePreview(); +} + +void ImageGuideWidget::slotChangeGuideColor(const TQColor &color) +{ + d->guideColor = color; + updatePreview(); +} + +void ImageGuideWidget::slotChangeGuideSize(int size) +{ + d->guideSize = size; + updatePreview(); +} + +void ImageGuideWidget::updatePixmap() +{ + TQPainter p(d->pixmap); + TQString text; + TQRect textRect, fontRect; + TQFontMetrics fontMt = p.fontMetrics(); + p.setPen(TQPen(TQt::red, 1)) ; + + d->pixmap->fill(colorGroup().background()); + + if (d->renderingPreviewMode == PreviewOriginalImage || + (d->renderingPreviewMode == PreviewToggleOnMouseOver && d->onMouseMovePreviewToggled == false )) + { + p.drawPixmap(d->rect, d->iface->convertToPixmap(d->preview)); + + text = i18n("Original"); + fontRect = fontMt.boundingRect(0, 0, d->rect.width(), d->rect.height(), 0, text); + textRect.setTopLeft(TQPoint(d->rect.x() + 20, d->rect.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); + } + else if (d->renderingPreviewMode == PreviewTargetImage || d->renderingPreviewMode == NoPreviewMode || + (d->renderingPreviewMode == PreviewToggleOnMouseOver && d->onMouseMovePreviewToggled == true )) + { + d->iface->paint(d->pixmap, d->rect.x(), d->rect.y(), + d->rect.width(), d->rect.height(), + d->underExposureIndicator, d->overExposureIndicator); + + if (d->renderingPreviewMode == PreviewTargetImage || + d->renderingPreviewMode == PreviewToggleOnMouseOver) + { + text = i18n("Target"); + fontRect = fontMt.boundingRect(0, 0, d->rect.width(), d->rect.height(), 0, text); + textRect.setTopLeft(TQPoint(d->rect.x() + 20, d->rect.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); + } + } + else if (d->renderingPreviewMode == PreviewBothImagesVert || + d->renderingPreviewMode == PreviewBothImagesVertCont) + { + if (d->renderingPreviewMode == PreviewBothImagesVert) + { + // Drawing the original image. + p.drawPixmap(d->rect, d->iface->convertToPixmap(d->preview)); + + // Drawing the target image under the original. + d->iface->paint(d->pixmap, + d->rect.x()+d->rect.width()/2, + d->rect.y(), + d->rect.width()/2, + d->rect.height(), + d->underExposureIndicator, + d->overExposureIndicator); + } + else + { + // Drawing the target image. + d->iface->paint(d->pixmap, + d->rect.x(), + d->rect.y(), + d->rect.width(), + d->rect.height(), + d->underExposureIndicator, + d->overExposureIndicator); + + // Drawing the original image under the target. + p.drawPixmap(d->rect.x(), d->rect.y(), d->iface->convertToPixmap(d->preview), + 0, 0, d->rect.width()/2, d->rect.height()); + } + + // Drawing the information and others stuff. + p.fillRect(d->rect.right(), 0, width(), height(), colorGroup().background()); + + p.setPen(TQPen(TQt::white, 2, TQt::SolidLine)); + p.drawLine(d->rect.x()+d->rect.width()/2-1, + d->rect.y(), + d->rect.x()+d->rect.width()/2-1, + d->rect.y()+d->rect.height()); + p.setPen(TQPen(TQt::red, 2, TQt::DotLine)); + p.drawLine(d->rect.x()+d->rect.width()/2-1, + d->rect.y(), + d->rect.x()+d->rect.width()/2-1, + d->rect.y()+d->rect.height()); + + p.setPen(TQPen(TQt::red, 1)) ; + + text = i18n("Target"); + fontRect = fontMt.boundingRect(0, 0, d->rect.width(), d->rect.height(), 0, text); + textRect.setTopLeft(TQPoint(d->rect.x() + d->rect.width()/2 + 20, + d->rect.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, d->rect.width(), d->rect.height(), 0, text); + textRect.setTopLeft(TQPoint(d->rect.x() + 20, d->rect.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); + } + else if (d->renderingPreviewMode == PreviewBothImagesHorz || + d->renderingPreviewMode == PreviewBothImagesHorzCont) + { + if (d->renderingPreviewMode == PreviewBothImagesHorz) + { + // Drawing the original image. + p.drawPixmap(d->rect, d->iface->convertToPixmap(d->preview)); + + // Drawing the target image under the original. + d->iface->paint(d->pixmap, + d->rect.x(), + d->rect.y()+d->rect.height()/2, + d->rect.width(), + d->rect.height()/2, + d->underExposureIndicator, + d->overExposureIndicator); + } + else + { + // Drawing the target image. + d->iface->paint(d->pixmap, + d->rect.x(), + d->rect.y(), + d->rect.width(), + d->rect.height(), + d->underExposureIndicator, + d->overExposureIndicator); + + // Drawing the original image under the target. + p.drawPixmap(d->rect.x(), d->rect.y(), d->iface->convertToPixmap(d->preview), + 0, 0, d->rect.width(), d->rect.height()/2); + } + + p.fillRect(0, d->rect.bottom(), width(), height(), colorGroup().background()); + + p.setPen(TQPen(TQt::white, 2, TQt::SolidLine)); + p.drawLine(d->rect.x(), + d->rect.y()+d->rect.height()/2-1, + d->rect.x()+d->rect.width(), + d->rect.y()+d->rect.height()/2-1); + p.setPen(TQPen(TQt::red, 2, TQt::DotLine)); + p.drawLine(d->rect.x(), + d->rect.y()+d->rect.height()/2-1, + d->rect.x()+d->rect.width(), + d->rect.y()+d->rect.height()/2-1); + + p.setPen(TQPen(TQt::red, 1)) ; + + text = i18n("Target"); + fontRect = fontMt.boundingRect(0, 0, d->rect.width(), d->rect.height(), 0, text); + textRect.setTopLeft(TQPoint(d->rect.x() + 20, + d->rect.y() + d->rect.height()/2 + 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, d->rect.width(), d->rect.height(), 0, text); + textRect.setTopLeft(TQPoint(d->rect.x() + 20, d->rect.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); + } + + if (d->spotVisible) + { + // Adapt spot from image coordinate to widget coordinate. + int xspot = d->spot.x() + d->rect.x(); + int yspot = d->spot.y() + d->rect.y(); + + switch (d->guideMode) + { + case HVGuideMode: + { + p.setPen(TQPen(TQt::white, d->guideSize, TQt::SolidLine)); + p.drawLine(xspot, d->rect.top() + d->flicker, xspot, d->rect.bottom() - d->flicker); + p.drawLine(d->rect.left() + d->flicker, yspot, d->rect.right() - d->flicker, yspot); + p.setPen(TQPen(d->guideColor, d->guideSize, TQt::DotLine)); + p.drawLine(xspot, d->rect.top() + d->flicker, xspot, d->rect.bottom() - d->flicker); + p.drawLine(d->rect.left() + d->flicker, yspot, d->rect.right() - d->flicker, yspot); + break; + } + + case PickColorMode: + { + p.setPen(TQPen(d->guideColor, 1, TQt::SolidLine)); + p.drawLine(xspot-10, yspot-10, xspot+10, yspot+10); + p.drawLine(xspot+10, yspot-10, xspot-10, yspot+10); + p.setPen(TQPen(d->guideColor, 3, TQt::SolidLine)); + p.drawEllipse( xspot-5, yspot-5, 11, 11 ); + + if (d->flicker%2 != 0) + { + p.setPen(TQPen(TQt::white, 1, TQt::SolidLine)); + p.drawEllipse( xspot-5, yspot-5, 11, 11 ); + } + + break; + } + } + } + + p.end(); +} + +void ImageGuideWidget::paintEvent(TQPaintEvent*) +{ + bitBlt(this, 0, 0, d->pixmap); +} + +void ImageGuideWidget::updatePreview() +{ + updatePixmap(); + repaint(false); +} + +void ImageGuideWidget::timerEvent(TQTimerEvent* e) +{ + if (e->timerId() == d->timerID) + { + if (d->flicker == 5) d->flicker=0; + else d->flicker++; + updatePreview(); + } + else + TQWidget::timerEvent(e); +} + +void ImageGuideWidget::resizeEvent(TQResizeEvent* e) +{ + blockSignals(true); + delete d->pixmap; + int w = e->size().width(); + int h = e->size().height(); + int old_w = d->width; + int old_h = d->height; + + uchar *data = d->iface->setPreviewImageSize(w, h); + d->width = d->iface->previewWidth(); + d->height = d->iface->previewHeight(); + bool sixteenBit = d->iface->previewSixteenBit(); + bool hasAlpha = d->iface->previewHasAlpha(); + d->preview = DImg(d->width, d->height, sixteenBit, hasAlpha, data); + d->preview.setICCProfil( d->iface->getOriginalImg()->getICCProfil() ); + + delete [] data; + + d->pixmap = new TQPixmap(w, h); + d->rect = TQRect(w/2-d->width/2, h/2-d->height/2, d->width, d->height); + + d->spot.setX((int)((float)d->spot.x() * ( (float)d->width / (float)old_w))); + d->spot.setY((int)((float)d->spot.y() * ( (float)d->height / (float)old_h))); + updatePixmap(); + blockSignals(false); + emit signalResized(); +} + +void ImageGuideWidget::mousePressEvent(TQMouseEvent* e) +{ + if ( !d->focus && e->button() == TQt::LeftButton && + d->rect.contains( e->x(), e->y() ) && d->spotVisible ) + { + d->focus = true; + d->spot.setX(e->x()-d->rect.x()); + d->spot.setY(e->y()-d->rect.y()); + updatePreview(); + } +} + +void ImageGuideWidget::mouseReleaseEvent(TQMouseEvent* e) +{ + if ( d->rect.contains( e->x(), e->y() ) && d->focus && d->spotVisible) + { + d->focus = false; + updatePreview(); + d->spot.setX(e->x()-d->rect.x()); + d->spot.setY(e->y()-d->rect.y()); + + DColor color; + TQPoint point = getSpotPosition(); + + if (d->renderingPreviewMode == PreviewOriginalImage) + { + color = getSpotColor(OriginalImage); + emit spotPositionChangedFromOriginal( color, d->spot ); + } + else if (d->renderingPreviewMode == PreviewTargetImage || d->renderingPreviewMode == NoPreviewMode) + { + color = getSpotColor(TargetPreviewImage); + emit spotPositionChangedFromTarget( color, d->spot ); + } + else if (d->renderingPreviewMode == PreviewBothImagesVert) + { + if (d->spot.x() > d->rect.width()/2) + { + color = getSpotColor(TargetPreviewImage); + emit spotPositionChangedFromTarget(color, TQPoint(d->spot.x() - d->rect.width()/2, + d->spot.y())); + } + else + { + color = getSpotColor(OriginalImage); + emit spotPositionChangedFromOriginal( color, d->spot ); + } + } + else if (d->renderingPreviewMode == PreviewBothImagesVertCont) + { + if (d->spot.x() > d->rect.width()/2) + { + color = getSpotColor(TargetPreviewImage); + emit spotPositionChangedFromTarget( color, d->spot); + } + else + { + color = getSpotColor(OriginalImage); + emit spotPositionChangedFromOriginal( color, d->spot ); + } + } + else if (d->renderingPreviewMode == PreviewBothImagesHorz) + { + if (d->spot.y() > d->rect.height()/2) + { + color = getSpotColor(TargetPreviewImage); + emit spotPositionChangedFromTarget(color, TQPoint(d->spot.x(), + d->spot.y() - d->rect.height()/2 )); + } + else + { + color = getSpotColor(OriginalImage); + emit spotPositionChangedFromOriginal( color, d->spot ); + } + } + else if (d->renderingPreviewMode == PreviewBothImagesHorzCont) + { + if (d->spot.y() > d->rect.height()/2) + { + color = getSpotColor(TargetPreviewImage); + emit spotPositionChangedFromTarget( color, d->spot); + } + else + { + color = getSpotColor(OriginalImage); + emit spotPositionChangedFromOriginal( color, d->spot ); + } + } + } +} + +void ImageGuideWidget::mouseMoveEvent(TQMouseEvent* e) +{ + if ( d->rect.contains( e->x(), e->y() ) && !d->focus && d->spotVisible ) + { + setCursor( KCursor::crossCursor() ); + } + else if ( d->rect.contains( e->x(), e->y() ) && d->focus && d->spotVisible ) + { + d->spot.setX(e->x()-d->rect.x()); + d->spot.setY(e->y()-d->rect.y()); + } + else + { + unsetCursor(); + } +} + +void ImageGuideWidget::enterEvent(TQEvent*) +{ + if ( !d->focus && d->renderingPreviewMode == PreviewToggleOnMouseOver ) + { + d->onMouseMovePreviewToggled = false; + updatePixmap(); + repaint(false); + } +} + +void ImageGuideWidget::leaveEvent(TQEvent*) +{ + if ( !d->focus && d->renderingPreviewMode == PreviewToggleOnMouseOver ) + { + d->onMouseMovePreviewToggled = true; + updatePixmap(); + repaint(false); + } +} + +} // NameSpace Digikam diff --git a/src/libs/widgets/imageplugins/imageguidewidget.h b/src/libs/widgets/imageplugins/imageguidewidget.h new file mode 100644 index 00000000..48d6d246 --- /dev/null +++ b/src/libs/widgets/imageplugins/imageguidewidget.h @@ -0,0 +1,132 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-08-20 + * Description : a widget to display an image with guides + * + * Copyright (C) 2004-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. + * + * ============================================================ */ + +#ifndef IMAGEGUIDEWIDGET_H +#define IMAGEGUIDEWIDGET_H + +// TQt includes. + +#include <tqwidget.h> +#include <tqpoint.h> +#include <tqcolor.h> + +// Local includes. + +#include "dcolor.h" +#include "digikam_export.h" + +class TQPixmap; + +namespace Digikam +{ + +class DColor; +class ImageIface; +class ImageGuideWidgetPriv; + +class DIGIKAM_EXPORT ImageGuideWidget : public TQWidget +{ +TQ_OBJECT + + +public: + + enum GuideToolMode + { + HVGuideMode=0, + PickColorMode + }; + + enum RenderingPreviewMode + { + PreviewOriginalImage=0, // Original image only. + PreviewBothImagesHorz, // Horizontal with original and target duplicated. + PreviewBothImagesVert, // Vertical with original and target duplicated. + PreviewBothImagesHorzCont, // Horizontal with original and target in contiguous. + PreviewBothImagesVertCont, // Vertical with original and target in contiguous. + PreviewTargetImage, // Target image only. + PreviewToggleOnMouseOver, // Original image if mouse is over image area, else target image. + NoPreviewMode // Target image only without information displayed. + }; + + enum ColorPointSrc + { + OriginalImage=0, + PreviewImage, + TargetPreviewImage + }; + +public: + + ImageGuideWidget(int w, int h, TQWidget *parent=0, + bool spotVisible=true, int guideMode=HVGuideMode, + const TQColor& guideColor=TQt::red, int guideSize=1, + bool blink=false, bool useImageSelection=false); + ~ImageGuideWidget(); + + ImageIface* imageIface(); + + TQPoint getSpotPosition(); + DColor getSpotColor(int getColorFrom); + void setSpotVisible(bool spotVisible, bool blink=false); + int getRenderingPreviewMode(); + void resetSpotPosition(); + void updatePreview(); + +public slots: + + void slotChangeGuideColor(const TQColor &color); + void slotChangeGuideSize(int size); + void slotChangeRenderingPreviewMode(int mode); + void slotToggleUnderExposure(bool); + void slotToggleOverExposure(bool); + +signals: + + void spotPositionChangedFromOriginal(const Digikam::DColor &color, const TQPoint &position); + void spotPositionChangedFromTarget(const Digikam::DColor &color, const TQPoint &position); + void signalResized(); + +protected: + + void paintEvent(TQPaintEvent*); + void resizeEvent(TQResizeEvent*); + void timerEvent(TQTimerEvent*); + void mousePressEvent(TQMouseEvent*); + void mouseReleaseEvent(TQMouseEvent*); + void mouseMoveEvent(TQMouseEvent*); + void enterEvent(TQEvent*); + void leaveEvent(TQEvent*); + +private: + + void updatePixmap(); + +private: + + ImageGuideWidgetPriv *d; +}; + +} // NameSpace Digikam + +#endif /* IMAGEGUIDEWIDGET_H */ diff --git a/src/libs/widgets/imageplugins/imagepanelwidget.cpp b/src/libs/widgets/imageplugins/imagepanelwidget.cpp new file mode 100644 index 00000000..4551e09e --- /dev/null +++ b/src/libs/widgets/imageplugins/imagepanelwidget.cpp @@ -0,0 +1,335 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-07-01 + * Description : a widget to draw a control panel image tool. + * + * Copyright (C) 2005-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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqframe.h> +#include <tqvgroupbox.h> +#include <tqlabel.h> +#include <tqpixmap.h> +#include <tqtooltip.h> +#include <tqwhatsthis.h> +#include <tqtimer.h> +#include <tqhbuttongroup.h> +#include <tqpushbutton.h> +#include <tqlayout.h> +#include <tqpixmap.h> + +// KDE includes. + +#include <kdialog.h> +#include <tdelocale.h> +#include <kcursor.h> +#include <tdeapplication.h> +#include <kiconloader.h> +#include <tdeconfig.h> +#include <kstandarddirs.h> + +// Local includes. + +#include "ddebug.h" +#include "thumbnailsize.h" +#include "imageregionwidget.h" +#include "imagepaniconwidget.h" +#include "imagepanelwidget.h" +#include "imagepanelwidget.moc" + +namespace Digikam +{ + +class ImagePanelWidgetPriv +{ +public: + + ImagePanelWidgetPriv() + { + imagePanIconWidget = 0; + imageRegionWidget = 0; + separateView = 0; + } + + TQString settingsSection; + + TQHButtonGroup *separateView; + + ImagePanIconWidget *imagePanIconWidget; + + ImageRegionWidget *imageRegionWidget; +}; + +ImagePanelWidget::ImagePanelWidget(uint w, uint h, const TQString& settingsSection, + ImagePanIconWidget *pan, TQWidget *parent, int separateViewMode) + : TQWidget(parent, 0, TQt::WDestructiveClose) +{ + d = new ImagePanelWidgetPriv; + d->settingsSection = settingsSection; + d->imagePanIconWidget = pan; + TQGridLayout *grid = new TQGridLayout(this, 2, 3); + + // ------------------------------------------------------------- + + TQFrame *preview = new TQFrame(this); + TQVBoxLayout* l1 = new TQVBoxLayout(preview, 5, 0); + d->imageRegionWidget = new ImageRegionWidget(w, h, preview, false); + d->imageRegionWidget->setFrameStyle(TQFrame::NoFrame); + preview->setFrameStyle(TQFrame::Panel|TQFrame::Sunken); + TQWhatsThis::add( d->imageRegionWidget, i18n("<p>Here you can see the original clip image " + "which will be used for the preview computation." + "<p>Click and drag the mouse cursor in the " + "image to change the clip focus.")); + l1->addWidget(d->imageRegionWidget, 0); + + // ------------------------------------------------------------- + + TQString directory; + d->separateView = new TQHButtonGroup(this); + d->separateView->setExclusive(true); + d->separateView->setInsideMargin( 0 ); + d->separateView->setFrameShape(TQFrame::NoFrame); + + if (separateViewMode == SeparateViewDuplicate || + separateViewMode == SeparateViewAll) + { + TQPushButton *duplicateHorButton = new TQPushButton( d->separateView ); + d->separateView->insert(duplicateHorButton, ImageRegionWidget::SeparateViewDuplicateHorz); + TDEGlobal::dirs()->addResourceType("duplicatebothhorz", TDEGlobal::dirs()->kde_default("data") + "digikam/data"); + directory = TDEGlobal::dirs()->findResourceDir("duplicatebothhorz", "duplicatebothhorz.png"); + duplicateHorButton->setPixmap( TQPixmap( directory + "duplicatebothhorz.png" ) ); + duplicateHorButton->setToggleButton(true); + TQWhatsThis::add( duplicateHorButton, i18n("<p>If you enable this option, you will separate the preview area " + "horizontally, displaying the original and target image " + "at the same time. The target is duplicated from the original " + "below the red dashed line." ) ); + + TQPushButton *duplicateVerButton = new TQPushButton( d->separateView ); + d->separateView->insert(duplicateVerButton, ImageRegionWidget::SeparateViewDuplicateVert); + TDEGlobal::dirs()->addResourceType("duplicatebothvert", TDEGlobal::dirs()->kde_default("data") + "digikam/data"); + directory = TDEGlobal::dirs()->findResourceDir("duplicatebothvert", "duplicatebothvert.png"); + duplicateVerButton->setPixmap( TQPixmap( directory + "duplicatebothvert.png" ) ); + duplicateVerButton->setToggleButton(true); + TQWhatsThis::add( duplicateVerButton, i18n("<p>If you enable this option, you will separate the preview area " + "vertically, displaying the original and target image " + "at the same time. The target is duplicated from the original to " + "the right of the red dashed line." ) ); + } + + if (separateViewMode == SeparateViewNormal || + separateViewMode == SeparateViewAll) + { + TQPushButton *separateHorButton = new TQPushButton( d->separateView ); + d->separateView->insert(separateHorButton, ImageRegionWidget::SeparateViewHorizontal); + TDEGlobal::dirs()->addResourceType("bothhorz", TDEGlobal::dirs()->kde_default("data") + "digikam/data"); + directory = TDEGlobal::dirs()->findResourceDir("bothhorz", "bothhorz.png"); + separateHorButton->setPixmap( TQPixmap( directory + "bothhorz.png" ) ); + separateHorButton->setToggleButton(true); + TQWhatsThis::add( separateHorButton, i18n( "<p>If you enable this option, you will separate the preview area " + "horizontally, displaying the original and target image " + "at the same time. The original is above the " + "red dashed line, the target below it." ) ); + + TQPushButton *separateVerButton = new TQPushButton( d->separateView ); + d->separateView->insert(separateVerButton, ImageRegionWidget::SeparateViewVertical); + TDEGlobal::dirs()->addResourceType("bothvert", TDEGlobal::dirs()->kde_default("data") + "digikam/data"); + directory = TDEGlobal::dirs()->findResourceDir("bothvert", "bothvert.png"); + separateVerButton->setPixmap( TQPixmap( directory + "bothvert.png" ) ); + separateVerButton->setToggleButton(true); + TQWhatsThis::add( separateVerButton, i18n( "<p>If you enable this option, you will separate the preview area " + "vertically, displaying the original and target image " + "at the same time. The original is to the left of the " + "red dashed line, the target to the right of it." ) ); + } + + TQPushButton *noSeparateButton = new TQPushButton( d->separateView ); + d->separateView->insert(noSeparateButton, ImageRegionWidget::SeparateViewNone); + TDEGlobal::dirs()->addResourceType("target", TDEGlobal::dirs()->kde_default("data") + "digikam/data"); + directory = TDEGlobal::dirs()->findResourceDir("target", "target.png"); + noSeparateButton->setPixmap( TQPixmap( directory + "target.png" ) ); + noSeparateButton->setToggleButton(true); + TQWhatsThis::add( noSeparateButton, i18n( "<p>If you enable this option, the preview area will not " + "be separated." ) ); + + // ------------------------------------------------------------- + + grid->addMultiCellWidget(preview, 0, 1, 0, 3); + grid->addMultiCellWidget(d->separateView, 2, 2, 3, 3); + grid->setRowStretch(1, 10); + grid->setColStretch(1, 10); + grid->setMargin(0); + grid->setSpacing(KDialog::spacingHint()); + + // ------------------------------------------------------------- + + TQTimer::singleShot(0, this, TQ_SLOT(slotInitGui())); + + // ------------------------------------------------------------- + + connect(d->imageRegionWidget, TQ_SIGNAL(signalContentsMovedEvent(bool)), + this, TQ_SLOT(slotOriginalImageRegionChanged(bool))); + + connect(d->imagePanIconWidget, TQ_SIGNAL(signalSelectionMoved(const TQRect&, bool)), + this, TQ_SLOT(slotSetImageRegionPosition(const TQRect&, bool))); + + connect(d->imagePanIconWidget, TQ_SIGNAL(signalSelectionTakeFocus()), + this, TQ_SLOT(slotPanIconTakeFocus())); + + connect(d->separateView, TQ_SIGNAL(released(int)), + d->imagePanIconWidget, TQ_SLOT(slotSeparateViewToggled(int))); + + connect(d->separateView, TQ_SIGNAL(released(int)), + d->imageRegionWidget, TQ_SLOT(slotSeparateViewToggled(int))); +} + +ImagePanelWidget::~ImagePanelWidget() +{ + writeSettings(); + delete d; +} + +ImageRegionWidget *ImagePanelWidget::previewWidget() const +{ + return d->imageRegionWidget; +} + +void ImagePanelWidget::readSettings() +{ + TDEConfig *config = kapp->config(); + config->setGroup(d->settingsSection); + int mode = config->readNumEntry("Separate View", ImageRegionWidget::SeparateViewDuplicateVert); + mode = TQMAX(ImageRegionWidget::SeparateViewHorizontal, mode); + mode = TQMIN(ImageRegionWidget::SeparateViewDuplicateHorz, mode); + + d->imageRegionWidget->blockSignals(true); + d->imagePanIconWidget->blockSignals(true); + d->separateView->blockSignals(true); + d->imageRegionWidget->slotSeparateViewToggled( mode ); + d->imagePanIconWidget->slotSeparateViewToggled( mode ); + d->separateView->setButton( mode ); + d->imageRegionWidget->blockSignals(false); + d->imagePanIconWidget->blockSignals(false); + d->separateView->blockSignals(false); +} + +void ImagePanelWidget::writeSettings() +{ + TDEConfig *config = kapp->config(); + config->setGroup(d->settingsSection); + config->writeEntry( "Separate View", d->separateView->selectedId() ); + config->sync(); +} + +void ImagePanelWidget::slotOriginalImageRegionChanged(bool target) +{ + d->imagePanIconWidget->slotZoomFactorChanged(d->imageRegionWidget->zoomFactor()); + TQRect rect = getOriginalImageRegion(); + d->imagePanIconWidget->setRegionSelection(rect); + updateSelectionInfo(rect); + + if (target) + { + d->imageRegionWidget->backupPixmapRegion(); + emit signalOriginalClipFocusChanged(); + } +} + +void ImagePanelWidget::slotZoomSliderChanged(int size) +{ + double h = (double)ThumbnailSize::Huge; + double s = (double)ThumbnailSize::Small; + double zmin = d->imageRegionWidget->zoomMin(); + double zmax = d->imageRegionWidget->zoomMax(); + double b = (zmin-(zmax*s/h))/(1-s/h); + double a = (zmax-b)/h; + double z = a*size+b; + + d->imageRegionWidget->setZoomFactorSnapped(z); +} + +void ImagePanelWidget::resizeEvent(TQResizeEvent *) +{ + emit signalResized(); +} + +void ImagePanelWidget::slotInitGui() +{ + readSettings(); + setCenterImageRegionPosition(); + slotOriginalImageRegionChanged(true); +} + +void ImagePanelWidget::setPanIconHighLightPoints(const TQPointArray& pt) +{ + d->imageRegionWidget->setHighLightPoints(pt); + d->imagePanIconWidget->setHighLightPoints(pt); +} + +void ImagePanelWidget::slotPanIconTakeFocus() +{ + d->imageRegionWidget->restorePixmapRegion(); +} + +void ImagePanelWidget::setEnable(bool b) +{ + d->imageRegionWidget->setEnabled(b); + d->separateView->setEnabled(b); +} + +TQRect ImagePanelWidget::getOriginalImageRegion() +{ + return ( d->imageRegionWidget->getImageRegion() ); +} + +TQRect ImagePanelWidget::getOriginalImageRegionToRender() +{ + return ( d->imageRegionWidget->getImageRegionToRender() ); +} + +DImg ImagePanelWidget::getOriginalRegionImage() +{ + return ( d->imageRegionWidget->getImageRegionImage() ); +} + +void ImagePanelWidget::setPreviewImage(DImg img) +{ + d->imageRegionWidget->updatePreviewImage(&img); + d->imageRegionWidget->repaintContents(false); +} + +void ImagePanelWidget::setCenterImageRegionPosition() +{ + d->imageRegionWidget->setCenterContentsPosition(); +} + +void ImagePanelWidget::slotSetImageRegionPosition(const TQRect& rect, bool targetDone) +{ + d->imageRegionWidget->setContentsPosition(rect.x(), rect.y(), targetDone); +} + +void ImagePanelWidget::updateSelectionInfo(const TQRect& rect) +{ + TQToolTip::add( d->imagePanIconWidget, + i18n("<nobr>(%1,%2)(%3x%4)</nobr>") + .arg(rect.left()).arg(rect.top()) + .arg(rect.width()).arg(rect.height())); +} + +} // NameSpace Digikam diff --git a/src/libs/widgets/imageplugins/imagepanelwidget.h b/src/libs/widgets/imageplugins/imagepanelwidget.h new file mode 100644 index 00000000..32179da9 --- /dev/null +++ b/src/libs/widgets/imageplugins/imagepanelwidget.h @@ -0,0 +1,117 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-07-01 + * Description : a widget to draw a control panel image tool. + * + * Copyright (C) 2005-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. + * + * ============================================================ */ + +#ifndef IMAGEPANELWIDGET_H +#define IMAGEPANELWIDGET_H + +// TQt includes. + +#include <tqwidget.h> +#include <tqimage.h> +#include <tqrect.h> +#include <tqstring.h> + +// Local includes. + +#include "dimg.h" +#include "digikam_export.h" + +class KProgress; + +namespace Digikam +{ + +class ImagePanelWidgetPriv; +class ImageRegionWidget; +class ImagePanIconWidget; + +class DIGIKAM_EXPORT ImagePanelWidget : public TQWidget +{ +TQ_OBJECT + + +public: + + enum SeparateViewOptions + { + SeparateViewNormal=0, + SeparateViewDuplicate, + SeparateViewAll + }; + +public: + + ImagePanelWidget(uint w, uint h, const TQString& settingsSection, ImagePanIconWidget *pan, + TQWidget *parent=0, int separateViewMode=SeparateViewAll); + ~ImagePanelWidget(); + + TQRect getOriginalImageRegion(); + TQRect getOriginalImageRegionToRender(); + DImg getOriginalRegionImage(); + void setPreviewImage(DImg img); + void setCenterImageRegionPosition(); + + void setEnable(bool b); + + void setPanIconHighLightPoints(const TQPointArray& pt); + + void writeSettings(); + + ImageRegionWidget *previewWidget() const; + +signals: + + void signalOriginalClipFocusChanged(); + void signalResized(); + +public slots: + + // Set the top/Left conner clip position. + void slotSetImageRegionPosition(const TQRect& rect, bool targetDone); + + // Slot used when the original image clip focus is changed by the user. + void slotOriginalImageRegionChanged(bool target); + +protected: + + void resizeEvent(TQResizeEvent *e); + +private slots: + + void slotPanIconTakeFocus(); + void slotInitGui(); + void slotZoomSliderChanged(int); + +private: + + void updateSelectionInfo(const TQRect& rect); + void readSettings(); + +private: + + ImagePanelWidgetPriv* d; +}; + +} // NameSpace Digikam + +#endif /* IMAGEPANNELWIDGET_H */ diff --git a/src/libs/widgets/imageplugins/imagepaniconwidget.cpp b/src/libs/widgets/imageplugins/imagepaniconwidget.cpp new file mode 100644 index 00000000..38564228 --- /dev/null +++ b/src/libs/widgets/imageplugins/imagepaniconwidget.cpp @@ -0,0 +1,198 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-08-22 + * Description : a widget to display a panel to choose + * a rectangular image area. + * + * 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 <tqpen.h> +#include <tqtimer.h> + +// Local includes. + +#include "ddebug.h" +#include "imageiface.h" +#include "imageregionwidget.h" +#include "imagepaniconwidget.h" +#include "imagepaniconwidget.moc" + +namespace Digikam +{ + +class ImagePanIconWidgetPriv +{ +public: + + ImagePanIconWidgetPriv() + { + iface = 0; + data = 0; + separateView = ImageRegionWidget::SeparateViewNone; + } + + uchar *data; + + int separateView; + + TQPointArray hightlightPoints; + + ImageIface *iface; +}; + +ImagePanIconWidget::ImagePanIconWidget(int w, int h, TQWidget *parent, WFlags flags) + : PanIconWidget(parent, flags) +{ + d = new ImagePanIconWidgetPriv; + + d->iface = new ImageIface(w, h); + d->data = d->iface->getPreviewImage(); + m_width = d->iface->previewWidth(); + m_height = d->iface->previewHeight(); + m_orgWidth = d->iface->originalWidth(); + m_orgHeight = d->iface->originalHeight(); + m_zoomedOrgWidth = d->iface->originalWidth(); + m_zoomedOrgHeight = d->iface->originalHeight(); + m_pixmap = new TQPixmap(w, h); + + setFixedSize(m_width, m_height); + + m_rect = TQRect(width()/2-m_width/2, height()/2-m_height/2, m_width, m_height); + updatePixmap(); + m_timerID = startTimer(800); +} + +ImagePanIconWidget::~ImagePanIconWidget() +{ + delete d->iface; + delete [] d->data; + delete d; +} + +void ImagePanIconWidget::setHighLightPoints(const TQPointArray& pointsList) +{ + d->hightlightPoints = pointsList; + updatePixmap(); + repaint(false); +} + +void ImagePanIconWidget::updatePixmap() +{ + // Drawing background and image. + m_pixmap->fill(colorGroup().background()); + d->iface->paint(m_pixmap, m_rect.x(), m_rect.y(), m_rect.width(), m_rect.height()); + + TQPainter p(m_pixmap); + + // Drawing HighLighted points. + + if (!d->hightlightPoints.isEmpty()) + { + TQPoint pt; + + for (int i = 0 ; i < d->hightlightPoints.count() ; i++) + { + pt = d->hightlightPoints.point(i); + pt.setX((int)(pt.x() * (float)(m_width) / (float)d->iface->originalWidth())); + pt.setY((int)(pt.y() * (float)(m_height) / (float)d->iface->originalHeight())); + p.setPen(TQPen(TQt::black, 1, TQt::SolidLine)); + p.drawLine(pt.x(), pt.y()-1, pt.x(), pt.y()+1); + p.drawLine(pt.x()-1, pt.y(), pt.x()+1, pt.y()); + p.setPen(TQPen(TQt::white, 1, TQt::SolidLine)); + p.drawPoint(pt.x()-1, pt.y()-1); + p.drawPoint(pt.x()+1, pt.y()+1); + p.drawPoint(pt.x()-1, pt.y()+1); + p.drawPoint(pt.x()+1, pt.y()-1); + } + } + + // Drawing selection border + + if (m_flicker) p.setPen(TQPen(TQt::white, 1, TQt::SolidLine)); + else p.setPen(TQPen(TQt::red, 1, TQt::SolidLine)); + + p.drawRect(m_localRegionSelection.x(), + m_localRegionSelection.y(), + m_localRegionSelection.width(), + m_localRegionSelection.height()); + + if (m_flicker) p.setPen(TQPen(TQt::red, 1, TQt::DotLine)); + else p.setPen(TQPen(TQt::white, 1, TQt::DotLine)); + + p.drawRect(m_localRegionSelection.x(), + m_localRegionSelection.y(), + m_localRegionSelection.width(), + m_localRegionSelection.height()); + + if (d->separateView == ImageRegionWidget::SeparateViewVertical) + { + if (m_flicker) p.setPen(TQPen(TQt::white, 1, TQt::SolidLine)); + else p.setPen(TQPen(TQt::red, 1, TQt::SolidLine)); + + p.drawLine(m_localRegionSelection.topLeft().x() + m_localRegionSelection.width()/2, + m_localRegionSelection.topLeft().y(), + m_localRegionSelection.bottomLeft().x() + m_localRegionSelection.width()/2, + m_localRegionSelection.bottomLeft().y()); + + if (m_flicker) p.setPen(TQPen(TQt::red, 1, TQt::DotLine)); + else p.setPen(TQPen(TQt::white, 1, TQt::DotLine)); + + p.drawLine(m_localRegionSelection.topLeft().x() + m_localRegionSelection.width()/2, + m_localRegionSelection.topLeft().y() + 1, + m_localRegionSelection.bottomLeft().x() + m_localRegionSelection.width()/2, + m_localRegionSelection.bottomLeft().y() - 1); + } + else if (d->separateView == ImageRegionWidget::SeparateViewHorizontal) + { + if (m_flicker) p.setPen(TQPen(TQt::white, 1, TQt::SolidLine)); + else p.setPen(TQPen(TQt::red, 1, TQt::SolidLine)); + + p.drawLine(m_localRegionSelection.topLeft().x(), + m_localRegionSelection.topLeft().y() + m_localRegionSelection.height()/2, + m_localRegionSelection.topRight().x(), + m_localRegionSelection.topRight().y() + m_localRegionSelection.height()/2); + + if (m_flicker) p.setPen(TQPen(TQt::red, 1, TQt::DotLine)); + else p.setPen(TQPen(TQt::white, 1, TQt::DotLine)); + + p.drawLine(m_localRegionSelection.topLeft().x() + 1, + m_localRegionSelection.topLeft().y() + m_localRegionSelection.height()/2, + m_localRegionSelection.topRight().x() - 1, + m_localRegionSelection.topRight().y() + m_localRegionSelection.height()/2); + } + + p.end(); +} + +void ImagePanIconWidget::slotSeparateViewToggled(int t) +{ + d->separateView = t; + updatePixmap(); + repaint(false); +} + +} // NameSpace Digikam diff --git a/src/libs/widgets/imageplugins/imagepaniconwidget.h b/src/libs/widgets/imageplugins/imagepaniconwidget.h new file mode 100644 index 00000000..e7d6ffb7 --- /dev/null +++ b/src/libs/widgets/imageplugins/imagepaniconwidget.h @@ -0,0 +1,68 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-08-22 + * Description : a widget to display a panel to choose + * a rectangular image area. + * + * 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. + * + * ============================================================ */ + +#ifndef IMAGEPANICONWIDGET_H +#define IMAGEPANICONWIDGET_H + +// TQt includes. + +#include <tqpointarray.h> + +// Local includes. + +#include "paniconwidget.h" + +namespace Digikam +{ + +class ImagePanIconWidgetPriv; + +class ImagePanIconWidget : public PanIconWidget +{ +TQ_OBJECT + + +public: + + ImagePanIconWidget(int width, int height, TQWidget *parent=0, WFlags flags=TQt::WDestructiveClose); + ~ImagePanIconWidget(); + + void setHighLightPoints(const TQPointArray& pointsList); + +public slots: + + void slotSeparateViewToggled(int t); + +private: + + void updatePixmap(); + +private: + + ImagePanIconWidgetPriv *d; +}; + +} // NameSpace Digikam + +#endif /* IMAGEPANICONWIDGET_H */ diff --git a/src/libs/widgets/imageplugins/imagepannelwidget.cpp b/src/libs/widgets/imageplugins/imagepannelwidget.cpp new file mode 100644 index 00000000..cebf0f3c --- /dev/null +++ b/src/libs/widgets/imageplugins/imagepannelwidget.cpp @@ -0,0 +1,477 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-07-01 + * Description : a widget to draw a control pannel image tool. + * + * Copyright (C) 2005-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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqframe.h> +#include <tqvgroupbox.h> +#include <tqlabel.h> +#include <tqpixmap.h> +#include <tqtooltip.h> +#include <tqwhatsthis.h> +#include <tqtimer.h> +#include <tqhbuttongroup.h> +#include <tqpushbutton.h> +#include <tqlayout.h> +#include <tqpixmap.h> + +// KDE includes. + +#include <kdialog.h> +#include <tdelocale.h> +#include <kcursor.h> +#include <kprogress.h> +#include <tdeapplication.h> +#include <kiconloader.h> +#include <tdeconfig.h> +#include <kstandarddirs.h> +#include <kseparator.h> + +// Local includes. + +#include "ddebug.h" +#include "sidebar.h" +#include "statuszoombar.h" +#include "thumbnailsize.h" +#include "imageregionwidget.h" +#include "imagepaniconwidget.h" +#include "imagepannelwidget.h" +#include "imagepannelwidget.moc" + +namespace Digikam +{ + +class ImagePannelWidgetPriv +{ +public: + + ImagePannelWidgetPriv() + { + imageRegionWidget = 0; + imagePanIconWidget = 0; + mainLayout = 0; + separateView = 0; + progressBar = 0; + settingsSideBar = 0; + splitter = 0; + settingsLayout = 0; + settings = 0; + previewWidget = 0; + zoomBar = 0; + } + + TQGridLayout *mainLayout; + + TQHButtonGroup *separateView; + + TQString settingsSection; + + TQWidget *settings; + TQWidget *previewWidget; + + TQVBoxLayout *settingsLayout; + + TQSplitter *splitter; + + KProgress *progressBar; + + ImageRegionWidget *imageRegionWidget; + ImagePanIconWidget *imagePanIconWidget; + + Sidebar *settingsSideBar; + + StatusZoomBar *zoomBar; +}; + +ImagePannelWidget::ImagePannelWidget(uint w, uint h, const TQString& settingsSection, + TQWidget *parent, int separateViewMode) + : TQHBox(parent, 0, TQt::WDestructiveClose) +{ + d = new ImagePannelWidgetPriv; + d->settingsSection = settingsSection; + d->splitter = new TQSplitter(this); + d->previewWidget = new TQWidget(d->splitter); + d->mainLayout = new TQGridLayout( d->previewWidget, 2, 3, 0, KDialog::spacingHint()); + + d->splitter->setFrameStyle( TQFrame::NoFrame ); + d->splitter->setFrameShadow( TQFrame::Plain ); + d->splitter->setFrameShape( TQFrame::NoFrame ); + d->splitter->setOpaqueResize(false); + + // ------------------------------------------------------------- + + TQFrame *preview = new TQFrame(d->previewWidget); + TQVBoxLayout* l1 = new TQVBoxLayout(preview, 5, 0); + d->imageRegionWidget = new ImageRegionWidget(w, h, preview, false); + d->imageRegionWidget->setFrameStyle(TQFrame::NoFrame); + preview->setFrameStyle(TQFrame::Panel|TQFrame::Sunken); + TQWhatsThis::add( d->imageRegionWidget, i18n("<p>Here you can see the original clip image " + "which will be used for the preview computation." + "<p>Click and drag the mouse cursor in the " + "image to change the clip focus.")); + l1->addWidget(d->imageRegionWidget, 0); + + TQSizePolicy rightSzPolicy(TQSizePolicy::Preferred, TQSizePolicy::Expanding, 2, 1); + d->previewWidget->setSizePolicy(rightSzPolicy); + + // ------------------------------------------------------------- + + d->zoomBar = new StatusZoomBar(d->previewWidget); + TQWhatsThis::add( d->zoomBar, i18n("<p>Here set the zoom factor of the preview area.") ); + + // ------------------------------------------------------------- + + TQString directory; + d->separateView = new TQHButtonGroup(d->previewWidget); + d->separateView->setExclusive(true); + d->separateView->setInsideMargin( 0 ); + d->separateView->setFrameShape(TQFrame::NoFrame); + + if (separateViewMode == SeparateViewDuplicate || + separateViewMode == SeparateViewAll) + { + TQPushButton *duplicateHorButton = new TQPushButton( d->separateView ); + d->separateView->insert(duplicateHorButton, ImageRegionWidget::SeparateViewDuplicateHorz); + TDEGlobal::dirs()->addResourceType("duplicatebothhorz", TDEGlobal::dirs()->kde_default("data") + "digikam/data"); + directory = TDEGlobal::dirs()->findResourceDir("duplicatebothhorz", "duplicatebothhorz.png"); + duplicateHorButton->setPixmap( TQPixmap( directory + "duplicatebothhorz.png" ) ); + duplicateHorButton->setToggleButton(true); + TQWhatsThis::add( duplicateHorButton, i18n("<p>If you enable this option, you will separate the preview area " + "horizontally, displaying the original and target image " + "at the same time. The target is duplicated from the original " + "below the red dashed line." ) ); + + TQPushButton *duplicateVerButton = new TQPushButton( d->separateView ); + d->separateView->insert(duplicateVerButton, ImageRegionWidget::SeparateViewDuplicateVert); + TDEGlobal::dirs()->addResourceType("duplicatebothvert", TDEGlobal::dirs()->kde_default("data") + "digikam/data"); + directory = TDEGlobal::dirs()->findResourceDir("duplicatebothvert", "duplicatebothvert.png"); + duplicateVerButton->setPixmap( TQPixmap( directory + "duplicatebothvert.png" ) ); + duplicateVerButton->setToggleButton(true); + TQWhatsThis::add( duplicateVerButton, i18n("<p>If you enable this option, you will separate the preview area " + "vertically, displaying the original and target image " + "at the same time. The target is duplicated from the original to " + "the right of the red dashed line." ) ); + } + + if (separateViewMode == SeparateViewNormal || + separateViewMode == SeparateViewAll) + { + TQPushButton *separateHorButton = new TQPushButton( d->separateView ); + d->separateView->insert(separateHorButton, ImageRegionWidget::SeparateViewHorizontal); + TDEGlobal::dirs()->addResourceType("bothhorz", TDEGlobal::dirs()->kde_default("data") + "digikam/data"); + directory = TDEGlobal::dirs()->findResourceDir("bothhorz", "bothhorz.png"); + separateHorButton->setPixmap( TQPixmap( directory + "bothhorz.png" ) ); + separateHorButton->setToggleButton(true); + TQWhatsThis::add( separateHorButton, i18n( "<p>If you enable this option, you will separate the preview area " + "horizontally, displaying the original and target image " + "at the same time. The original is above the " + "red dashed line, the target below it." ) ); + + TQPushButton *separateVerButton = new TQPushButton( d->separateView ); + d->separateView->insert(separateVerButton, ImageRegionWidget::SeparateViewVertical); + TDEGlobal::dirs()->addResourceType("bothvert", TDEGlobal::dirs()->kde_default("data") + "digikam/data"); + directory = TDEGlobal::dirs()->findResourceDir("bothvert", "bothvert.png"); + separateVerButton->setPixmap( TQPixmap( directory + "bothvert.png" ) ); + separateVerButton->setToggleButton(true); + TQWhatsThis::add( separateVerButton, i18n( "<p>If you enable this option, you will separate the preview area " + "vertically, displaying the original and target image " + "at the same time. The original is to the left of the " + "red dashed line, the target to the right of it." ) ); + } + + TQPushButton *noSeparateButton = new TQPushButton( d->separateView ); + d->separateView->insert(noSeparateButton, ImageRegionWidget::SeparateViewNone); + TDEGlobal::dirs()->addResourceType("target", TDEGlobal::dirs()->kde_default("data") + "digikam/data"); + directory = TDEGlobal::dirs()->findResourceDir("target", "target.png"); + noSeparateButton->setPixmap( TQPixmap( directory + "target.png" ) ); + noSeparateButton->setToggleButton(true); + TQWhatsThis::add( noSeparateButton, i18n( "<p>If you enable this option, the preview area will not " + "be separated." ) ); + + // ------------------------------------------------------------- + + d->progressBar = new KProgress(100, d->previewWidget); + TQWhatsThis::add(d->progressBar ,i18n("<p>This is the percentage of the task which has been completed up to this point.")); + d->progressBar->setProgress(0); + d->progressBar->setMaximumHeight( fontMetrics().height() ); + + // ------------------------------------------------------------- + + d->mainLayout->addMultiCellWidget(preview, 0, 1, 0, 3); + d->mainLayout->addMultiCellWidget(d->zoomBar, 2, 2, 0, 0); + d->mainLayout->addMultiCellWidget(d->progressBar, 2, 2, 2, 2); + d->mainLayout->addMultiCellWidget(d->separateView, 2, 2, 3, 3); + + d->mainLayout->setRowStretch(1, 10); + d->mainLayout->setColStretch(1, 10); + + // ------------------------------------------------------------- + + TQString sbName(d->settingsSection + TQString(" Image Plugin Sidebar")); + d->settingsSideBar = new Sidebar(this, sbName.ascii(), Sidebar::Right); + d->settingsSideBar->setSplitter(d->splitter); + + d->settings = new TQWidget(d->settingsSideBar); + d->settingsLayout = new TQVBoxLayout(d->settings); + + TQFrame *frame3 = new TQFrame(d->settings); + frame3->setFrameStyle(TQFrame::Panel|TQFrame::Sunken); + TQVBoxLayout* l3 = new TQVBoxLayout(frame3, 5, 0); + d->imagePanIconWidget = new ImagePanIconWidget(360, 240, frame3); + TQWhatsThis::add( d->imagePanIconWidget, i18n("<p>Here you can see the original image panel " + "which can help you to select the clip preview." + "<p>Click and drag the mouse cursor in the " + "red rectangle to change the clip focus.")); + l3->addWidget(d->imagePanIconWidget, 0, TQt::AlignCenter); + + d->settingsLayout->addWidget(frame3, 0, TQt::AlignHCenter); + d->settingsLayout->addSpacing(KDialog::spacingHint()); + + d->settingsSideBar->appendTab(d->settings, SmallIcon("configure"), i18n("Settings")); + d->settingsSideBar->loadViewState(); + + // ------------------------------------------------------------- + + setProgressVisible(false); + TQTimer::singleShot(0, this, TQ_SLOT(slotInitGui())); + + // ------------------------------------------------------------- + + connect(d->imageRegionWidget, TQ_SIGNAL(signalContentsMovedEvent(bool)), + this, TQ_SLOT(slotOriginalImageRegionChanged(bool))); + + connect(d->imagePanIconWidget, TQ_SIGNAL(signalSelectionMoved(const TQRect&, bool)), + this, TQ_SLOT(slotSetImageRegionPosition(const TQRect&, bool))); + + connect(d->imagePanIconWidget, TQ_SIGNAL(signalSelectionTakeFocus()), + this, TQ_SLOT(slotPanIconTakeFocus())); + + connect(d->separateView, TQ_SIGNAL(released(int)), + d->imageRegionWidget, TQ_SLOT(slotSeparateViewToggled(int))); + + connect(d->separateView, TQ_SIGNAL(released(int)), + d->imagePanIconWidget, TQ_SLOT(slotSeparateViewToggled(int))); + + connect(d->zoomBar, TQ_SIGNAL(signalZoomMinusClicked()), + d->imageRegionWidget, TQ_SLOT(slotDecreaseZoom())); + + connect(d->zoomBar, TQ_SIGNAL(signalZoomPlusClicked()), + d->imageRegionWidget, TQ_SLOT(slotIncreaseZoom())); + + connect(d->zoomBar, TQ_SIGNAL(signalZoomSliderReleased(int)), + this, TQ_SLOT(slotZoomSliderChanged(int))); +} + +ImagePannelWidget::~ImagePannelWidget() +{ + writeSettings(); + delete d->settingsSideBar; + delete d; +} + +void ImagePannelWidget::readSettings() +{ + TDEConfig *config = kapp->config(); + config->setGroup(d->settingsSection); + int mode = config->readNumEntry("Separate View", ImageRegionWidget::SeparateViewDuplicateVert); + mode = TQMAX(ImageRegionWidget::SeparateViewHorizontal, mode); + mode = TQMIN(ImageRegionWidget::SeparateViewDuplicateHorz, mode); + + d->imageRegionWidget->blockSignals(true); + d->imagePanIconWidget->blockSignals(true); + d->separateView->blockSignals(true); + d->imageRegionWidget->slotSeparateViewToggled( mode ); + d->imagePanIconWidget->slotSeparateViewToggled( mode ); + d->separateView->setButton( mode ); + d->imageRegionWidget->blockSignals(false); + d->imagePanIconWidget->blockSignals(false); + d->separateView->blockSignals(false); +} + +void ImagePannelWidget::writeSettings() +{ + TDEConfig *config = kapp->config(); + config->setGroup(d->settingsSection); + config->writeEntry( "Separate View", d->separateView->selectedId() ); + config->sync(); +} + +void ImagePannelWidget::slotOriginalImageRegionChanged(bool target) +{ + slotZoomFactorChanged(d->imageRegionWidget->zoomFactor()); + TQRect rect = getOriginalImageRegion(); + d->imagePanIconWidget->setRegionSelection(rect); + updateSelectionInfo(rect); + + if (target) + { + d->imageRegionWidget->backupPixmapRegion(); + emit signalOriginalClipFocusChanged(); + } +} + +void ImagePannelWidget::slotZoomFactorChanged(double zoom) +{ + double h = (double)ThumbnailSize::Huge; + double s = (double)ThumbnailSize::Small; + double zmin = d->imageRegionWidget->zoomMin(); + double zmax = d->imageRegionWidget->zoomMax(); + double b = (zmin-(zmax*s/h))/(1-s/h); + double a = (zmax-b)/h; + int size = (int)((zoom - b) /a); + + d->zoomBar->setZoomSliderValue(size); + d->zoomBar->setZoomTrackerText(i18n("zoom: %1%").arg((int)(zoom*100.0))); + + d->zoomBar->setEnableZoomPlus(true); + d->zoomBar->setEnableZoomMinus(true); + + if (d->imageRegionWidget->maxZoom()) + d->zoomBar->setEnableZoomPlus(false); + + if (d->imageRegionWidget->minZoom()) + d->zoomBar->setEnableZoomMinus(false); + + d->imagePanIconWidget->slotZoomFactorChanged(zoom); +} + +void ImagePannelWidget::slotZoomSliderChanged(int size) +{ + double h = (double)ThumbnailSize::Huge; + double s = (double)ThumbnailSize::Small; + double zmin = d->imageRegionWidget->zoomMin(); + double zmax = d->imageRegionWidget->zoomMax(); + double b = (zmin-(zmax*s/h))/(1-s/h); + double a = (zmax-b)/h; + double z = a*size+b; + + d->imageRegionWidget->setZoomFactorSnapped(z); +} + +KProgress *ImagePannelWidget::progressBar() +{ + return d->progressBar; +} + +void ImagePannelWidget::resizeEvent(TQResizeEvent *) +{ + emit signalResized(); +} + +void ImagePannelWidget::slotInitGui() +{ + readSettings(); + setCenterImageRegionPosition(); + slotOriginalImageRegionChanged(true); +} + +void ImagePannelWidget::setPanIconHighLightPoints(const TQPointArray& pt) +{ + d->imageRegionWidget->setHighLightPoints(pt); + d->imagePanIconWidget->setHighLightPoints(pt); +} + +void ImagePannelWidget::slotPanIconTakeFocus() +{ + d->imageRegionWidget->restorePixmapRegion(); +} + +void ImagePannelWidget::setUserAreaWidget(TQWidget *w) +{ + w->reparent( d->settings, TQPoint(0, 0) ); + d->settingsLayout->addSpacing(KDialog::spacingHint()); + d->settingsLayout->addWidget(w); + d->settingsLayout->addStretch(); +} + +void ImagePannelWidget::setEnable(bool b) +{ + d->imageRegionWidget->setEnabled(b); + d->imagePanIconWidget->setEnabled(b); + d->separateView->setEnabled(b); + d->zoomBar->setEnabled(b); +} + +void ImagePannelWidget::setProgress(int val) +{ + d->progressBar->setValue(val); +} + +void ImagePannelWidget::setProgressVisible(bool b) +{ + if (b) d->progressBar->show(); + else d->progressBar->hide(); +} + +void ImagePannelWidget::setProgressWhatsThis(const TQString& desc) +{ + TQWhatsThis::add( d->progressBar, desc); +} + +void ImagePannelWidget::setPreviewImageWaitCursor(bool enable) +{ + if ( enable ) + d->imageRegionWidget->setCursor( KCursor::waitCursor() ); + else + d->imageRegionWidget->unsetCursor(); +} + +TQRect ImagePannelWidget::getOriginalImageRegion() +{ + return ( d->imageRegionWidget->getImageRegion() ); +} + +TQRect ImagePannelWidget::getOriginalImageRegionToRender() +{ + return ( d->imageRegionWidget->getImageRegionToRender() ); +} + +DImg ImagePannelWidget::getOriginalRegionImage() +{ + return ( d->imageRegionWidget->getImageRegionImage() ); +} + +void ImagePannelWidget::setPreviewImage(DImg img) +{ + d->imageRegionWidget->updatePreviewImage(&img); +} + +void ImagePannelWidget::setCenterImageRegionPosition() +{ + d->imageRegionWidget->setCenterContentsPosition(); +} + +void ImagePannelWidget::slotSetImageRegionPosition(const TQRect& rect, bool targetDone) +{ + d->imageRegionWidget->setContentsPosition(rect.x(), rect.y(), targetDone); +} + +void ImagePannelWidget::updateSelectionInfo(const TQRect& rect) +{ + TQToolTip::add( d->imagePanIconWidget, + i18n("<nobr>(%1,%2)(%3x%4)</nobr>") + .arg(rect.left()).arg(rect.top()) + .arg(rect.width()).arg(rect.height())); +} + +} // NameSpace Digikam diff --git a/src/libs/widgets/imageplugins/imagepannelwidget.h b/src/libs/widgets/imageplugins/imagepannelwidget.h new file mode 100644 index 00000000..a3429887 --- /dev/null +++ b/src/libs/widgets/imageplugins/imagepannelwidget.h @@ -0,0 +1,123 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-07-01 + * Description : a widget to draw a control pannel image tool. + * + * Copyright (C) 2005-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. + * + * ============================================================ */ + +#ifndef IMAGEPANNELWIDGET_H +#define IMAGEPANNELWIDGET_H + +// TQt includes. + +#include <tqhbox.h> +#include <tqimage.h> +#include <tqrect.h> +#include <tqstring.h> + +// Local includes + +#include "dimg.h" +#include "digikam_export.h" + +class KProgress; + +namespace Digikam +{ + +class ImagePannelWidgetPriv; +class ImageRegionWidget; + +class DIGIKAM_EXPORT ImagePannelWidget : public TQHBox +{ +TQ_OBJECT + + +public: + + enum SeparateViewOptions + { + SeparateViewNormal=0, + SeparateViewDuplicate, + SeparateViewAll + }; + +public: + + ImagePannelWidget(uint w, uint h, const TQString& settingsSection, TQWidget *parent=0, + int separateViewMode=SeparateViewAll); + ~ImagePannelWidget(); + + TQRect getOriginalImageRegion(); + TQRect getOriginalImageRegionToRender(); + DImg getOriginalRegionImage(); + void setPreviewImage(DImg img); + void setPreviewImageWaitCursor(bool enable); + void setCenterImageRegionPosition(); + + void setEnable(bool b); + + void setProgress(int val); + void setProgressVisible(bool b); + void setProgressWhatsThis(const TQString& desc); + + void setUserAreaWidget(TQWidget *w); + + void setPanIconHighLightPoints(const TQPointArray& pt); + + KProgress *progressBar(); + +signals: + + void signalOriginalClipFocusChanged(); + void signalResized(); + +public slots: + + // Set the top/Left conner clip position. + void slotSetImageRegionPosition(const TQRect& rect, bool targetDone); + + // Slot used when the original image clip focus is changed by the user. + void slotOriginalImageRegionChanged(bool target); + +protected: + + void resizeEvent(TQResizeEvent *e); + +private slots: + + void slotPanIconTakeFocus(); + void slotInitGui(); + void slotZoomSliderChanged(int); + void slotZoomFactorChanged(double); + +private: + + void updateSelectionInfo(const TQRect& rect); + void readSettings(); + void writeSettings(); + +private: + + ImagePannelWidgetPriv* d; +}; + +} // NameSpace Digikam + +#endif /* IMAGEPANNELWIDGET_H */ 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 diff --git a/src/libs/widgets/imageplugins/imageregionwidget.h b/src/libs/widgets/imageplugins/imageregionwidget.h new file mode 100644 index 00000000..8555703d --- /dev/null +++ b/src/libs/widgets/imageplugins/imageregionwidget.h @@ -0,0 +1,115 @@ +/* ============================================================ + * + * 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. + * + * ============================================================ */ + +#ifndef IMAGEREGIONWIDGET_H +#define IMAGEREGIONWIDGET_H + +// TQt includes. + +#include <tqrect.h> + +// Local includes. + +#include "previewwidget.h" +#include "dimg.h" +#include "digikam_export.h" + +namespace Digikam +{ + +class ImageRegionWidgetPriv; + +class DIGIKAM_EXPORT ImageRegionWidget : public PreviewWidget +{ +TQ_OBJECT + + +public: + + enum SeparateViewMode + { + SeparateViewHorizontal=0, + SeparateViewVertical, + SeparateViewNone, + SeparateViewDuplicateVert, + SeparateViewDuplicateHorz + }; + +public: + + ImageRegionWidget(int wp, int hp, TQWidget *parent=0, bool scrollBar=true); + ~ImageRegionWidget(); + + void setContentsPosition(int x, int y, bool targetDone); + void setCenterContentsPosition(); + + /** To get image region including original or/and target area depending of separate view mode. + The region is given using not scaled image unit.*/ + TQRect getImageRegion(); + + /** To get target image region area to render */ + TQRect getImageRegionToRender(); + + /** To get target image region image to use for render operations */ + DImg getImageRegionImage(); + + void updatePreviewImage(DImg *img); + + void backupPixmapRegion(); + void restorePixmapRegion(); + + void setHighLightPoints(const TQPointArray& pointsList); + void drawSeparateView(); + +public slots: + + void slotSeparateViewToggled(int mode); + +private slots: + + void slotZoomFactorChanged(); + +private: + + void updatePixmap(DImg& img); + TQRect getLocalTargetImageRegion(); + TQRect getLocalImageRegionToRender(); + void viewportPaintExtraData(); + int previewWidth(); + int previewHeight(); + bool previewIsNull(); + void resetPreview(); + void setContentsSize(); + void resizeEvent(TQResizeEvent *); + void contentsWheelEvent(TQWheelEvent *); + + inline void paintPreview(TQPixmap *pix, int sx, int sy, int sw, int sh); + +private: + + ImageRegionWidgetPriv* d; +}; + +} // NameSpace Digikam + +#endif /* IMAGEREGIONWIDGET_H */ diff --git a/src/libs/widgets/imageplugins/imagewidget.cpp b/src/libs/widgets/imageplugins/imagewidget.cpp new file mode 100644 index 00000000..ab73bbf7 --- /dev/null +++ b/src/libs/widgets/imageplugins/imagewidget.cpp @@ -0,0 +1,347 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2006-02-01 + * Description : a widget to display an image preview with some + * modes to compare effect results. + * + * Copyright (C) 2006-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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqwhatsthis.h> +#include <tqlayout.h> +#include <tqframe.h> +#include <tqhbuttongroup.h> +#include <tqpushbutton.h> + +// KDE includes. + +#include <ksqueezedtextlabel.h> +#include <kdialog.h> +#include <tdeapplication.h> +#include <tdelocale.h> +#include <kiconloader.h> +#include <tdeconfig.h> +#include <kstandarddirs.h> + +// Local includes. + +#include "ddebug.h" +#include "imagewidget.h" +#include "imagewidget.moc" + +namespace Digikam +{ + +class ImageWidgetPriv +{ +public: + + ImageWidgetPriv() + { + spotInfoLabel = 0; + previewButtons = 0; + underExposureButton = 0; + overExposureButton = 0; + previewWidget = 0; + } + + TQString settingsSection; + + TQHButtonGroup *previewButtons; + + TQPushButton *underExposureButton; + TQPushButton *overExposureButton; + + KSqueezedTextLabel *spotInfoLabel; + + ImageGuideWidget *previewWidget; +}; + +ImageWidget::ImageWidget(const TQString& settingsSection, TQWidget *parent, + const TQString& previewWhatsThis, bool prevModeOptions, + int guideMode, bool guideVisible, bool useImageSelection) + : TQWidget(parent) +{ + d = new ImageWidgetPriv; + d->settingsSection = settingsSection; + + // ------------------------------------------------------------- + + TQGridLayout* grid = new TQGridLayout(this, 2, 3); + + d->spotInfoLabel = new KSqueezedTextLabel(this); + d->spotInfoLabel->setAlignment(TQt::AlignRight); + + // ------------------------------------------------------------- + + d->previewButtons = new TQHButtonGroup(this); + d->previewButtons->setExclusive(true); + d->previewButtons->setInsideMargin(0); + d->previewButtons->setFrameShape(TQFrame::NoFrame); + + TQPushButton *previewOriginalButton = new TQPushButton( d->previewButtons ); + d->previewButtons->insert(previewOriginalButton, ImageGuideWidget::PreviewOriginalImage); + TDEGlobal::dirs()->addResourceType("original", TDEGlobal::dirs()->kde_default("data") + "digikam/data"); + TQString directory = TDEGlobal::dirs()->findResourceDir("original", "original.png"); + previewOriginalButton->setPixmap( TQPixmap( directory + "original.png" ) ); + previewOriginalButton->setToggleButton(true); + TQWhatsThis::add( previewOriginalButton, i18n( "<p>If you enable this option, you will see " + "the original image." ) ); + + TQPushButton *previewBothButtonVert = new TQPushButton( d->previewButtons ); + d->previewButtons->insert(previewBothButtonVert, ImageGuideWidget::PreviewBothImagesVertCont); + TDEGlobal::dirs()->addResourceType("bothvert", TDEGlobal::dirs()->kde_default("data") + "digikam/data"); + directory = TDEGlobal::dirs()->findResourceDir("bothvert", "bothvert.png"); + previewBothButtonVert->setPixmap( TQPixmap( directory + "bothvert.png" ) ); + previewBothButtonVert->setToggleButton(true); + TQWhatsThis::add( previewBothButtonVert, i18n( "<p>If you enable this option, the preview area will " + "split vertically. " + "A contiguous area of the image will be shown, " + "with one half from the original image, " + "the other half from the target image.") ); + + TQPushButton *previewBothButtonHorz = new TQPushButton( d->previewButtons ); + d->previewButtons->insert(previewBothButtonHorz, ImageGuideWidget::PreviewBothImagesHorzCont); + TDEGlobal::dirs()->addResourceType("bothhorz", TDEGlobal::dirs()->kde_default("data") + "digikam/data"); + directory = TDEGlobal::dirs()->findResourceDir("bothhorz", "bothhorz.png"); + previewBothButtonHorz->setPixmap( TQPixmap( directory + "bothhorz.png" ) ); + previewBothButtonHorz->setToggleButton(true); + TQWhatsThis::add( previewBothButtonHorz, i18n( "<p>If you enable this option, the preview area will " + "split horizontally. " + "A contiguous area of the image will be shown, " + "with one half from the original image, " + "the other half from the target image.") ); + + TQPushButton *previewDuplicateBothButtonVert = new TQPushButton( d->previewButtons ); + d->previewButtons->insert(previewDuplicateBothButtonVert, ImageGuideWidget::PreviewBothImagesVert); + TDEGlobal::dirs()->addResourceType("duplicatebothvert", TDEGlobal::dirs()->kde_default("data") + "digikam/data"); + directory = TDEGlobal::dirs()->findResourceDir("duplicatebothvert", "duplicatebothvert.png"); + previewDuplicateBothButtonVert->setPixmap( TQPixmap( directory + "duplicatebothvert.png" ) ); + previewDuplicateBothButtonVert->setToggleButton(true); + TQWhatsThis::add( previewDuplicateBothButtonVert, i18n( "<p>If you enable this option, the preview area will " + "split vertically. " + "The same part of the original and the target image " + "will be shown side by side.") ); + + TQPushButton *previewDupplicateBothButtonHorz = new TQPushButton( d->previewButtons ); + d->previewButtons->insert(previewDupplicateBothButtonHorz, ImageGuideWidget::PreviewBothImagesHorz); + TDEGlobal::dirs()->addResourceType("duplicatebothhorz", TDEGlobal::dirs()->kde_default("data") + "digikam/data"); + directory = TDEGlobal::dirs()->findResourceDir("duplicatebothhorz", "duplicatebothhorz.png"); + previewDupplicateBothButtonHorz->setPixmap( TQPixmap( directory + "duplicatebothhorz.png" ) ); + previewDupplicateBothButtonHorz->setToggleButton(true); + TQWhatsThis::add( previewDupplicateBothButtonHorz, i18n( "<p>If you enable this option, the preview area will " + "split horizontally. " + "The same part of the original and the target image " + "will be shown side by side.") ); + + TQPushButton *previewtargetButton = new TQPushButton( d->previewButtons ); + d->previewButtons->insert(previewtargetButton, ImageGuideWidget::PreviewTargetImage); + TDEGlobal::dirs()->addResourceType("target", TDEGlobal::dirs()->kde_default("data") + "digikam/data"); + directory = TDEGlobal::dirs()->findResourceDir("target", "target.png"); + previewtargetButton->setPixmap( TQPixmap( directory + "target.png" ) ); + previewtargetButton->setToggleButton(true); + TQWhatsThis::add( previewtargetButton, i18n( "<p>If you enable this option, you will see " + "the target image." ) ); + + TQPushButton *previewToggleMouseOverButton = new TQPushButton( d->previewButtons ); + d->previewButtons->insert(previewToggleMouseOverButton, ImageGuideWidget::PreviewToggleOnMouseOver); + TDEGlobal::dirs()->addResourceType("togglemouseover", TDEGlobal::dirs()->kde_default("data") + "digikam/data"); + directory = TDEGlobal::dirs()->findResourceDir("togglemouseover", "togglemouseover.png"); + previewToggleMouseOverButton->setPixmap( TQPixmap( directory + "togglemouseover.png" ) ); + previewToggleMouseOverButton->setToggleButton(true); + TQWhatsThis::add( previewToggleMouseOverButton, i18n( "<p>If you enable this option, you will see " + "the original image when the mouse is over image area, " + "else the target image." ) ); + + // ------------------------------------------------------------- + + TQHButtonGroup *exposureButtons = new TQHButtonGroup(this); + exposureButtons->setInsideMargin(0); + exposureButtons->setFrameShape(TQFrame::NoFrame); + + d->underExposureButton = new TQPushButton(exposureButtons); + exposureButtons->insert(d->underExposureButton, UnderExposure); + d->underExposureButton->setPixmap(SmallIcon("underexposure")); + d->underExposureButton->setToggleButton(true); + TQWhatsThis::add(d->underExposureButton, i18n("<p>Set this option to display black " + "overlaid on the preview. This will help you to avoid " + "under-exposing the image." ) ); + + d->overExposureButton = new TQPushButton(exposureButtons); + exposureButtons->insert(d->overExposureButton, OverExposure); + d->overExposureButton->setPixmap(SmallIcon("overexposure")); + d->overExposureButton->setToggleButton(true); + TQWhatsThis::add(d->overExposureButton, i18n("<p>Set this option on display white " + "overlaid on the preview. This will help you to avoid " + "over-exposing the image." ) ); + + // ------------------------------------------------------------- + + TQFrame *frame = new TQFrame(this); + frame->setFrameStyle(TQFrame::Panel|TQFrame::Sunken); + TQVBoxLayout* l = new TQVBoxLayout(frame, 5, 0); + d->previewWidget = new ImageGuideWidget(480, 320, frame, guideVisible, + guideMode, TQt::red, 1, false, + useImageSelection); + TQWhatsThis::add( d->previewWidget, previewWhatsThis); + l->addWidget(d->previewWidget, 0); + + // ------------------------------------------------------------- + + grid->addMultiCellWidget(d->previewButtons, 1, 1, 0, 0); + grid->addMultiCellWidget(d->spotInfoLabel, 1, 1, 1, 1); + grid->addMultiCellWidget(exposureButtons, 1, 1, 2, 2); + grid->addMultiCellWidget(frame, 3, 3, 0, 2); + grid->setColSpacing(1, KDialog::spacingHint()); + grid->setRowSpacing(0, KDialog::spacingHint()); + grid->setRowSpacing(2, KDialog::spacingHint()); + grid->setRowStretch(3, 10); + grid->setColStretch(1, 10); + + // ------------------------------------------------------------- + + connect(d->previewWidget, TQ_SIGNAL(signalResized()), + this, TQ_SIGNAL(signalResized())); + + connect(d->previewWidget, TQ_SIGNAL(spotPositionChangedFromOriginal( const Digikam::DColor &, const TQPoint & )), + this, TQ_SIGNAL(spotPositionChangedFromOriginal( const Digikam::DColor &, const TQPoint & ))); + + connect(d->previewWidget, TQ_SIGNAL(spotPositionChangedFromOriginal( const Digikam::DColor &, const TQPoint & )), + this, TQ_SLOT(slotUpdateSpotInfo( const Digikam::DColor &, const TQPoint & ))); + + connect(d->previewWidget, TQ_SIGNAL(spotPositionChangedFromTarget( const Digikam::DColor &, const TQPoint & )), + this, TQ_SIGNAL(spotPositionChangedFromTarget( const Digikam::DColor &, const TQPoint & ))); + + connect(d->previewWidget, TQ_SIGNAL(spotPositionChangedFromTarget( const Digikam::DColor &, const TQPoint & )), + this, TQ_SLOT(slotUpdateSpotInfo( const Digikam::DColor &, const TQPoint & ))); + + connect(d->previewButtons, TQ_SIGNAL(released(int)), + d->previewWidget, TQ_SLOT(slotChangeRenderingPreviewMode(int))); + + connect(d->underExposureButton, TQ_SIGNAL(toggled(bool)), + d->previewWidget, TQ_SLOT(slotToggleUnderExposure(bool))); + + connect(d->overExposureButton, TQ_SIGNAL(toggled(bool)), + d->previewWidget, TQ_SLOT(slotToggleOverExposure(bool))); + + // ------------------------------------------------------------- + + if (prevModeOptions) + readSettings(); + else + { + setRenderingPreviewMode(ImageGuideWidget::NoPreviewMode); + d->spotInfoLabel->hide(); + d->previewButtons->hide(); + exposureButtons->hide(); + } +} + +ImageWidget::~ImageWidget() +{ + writeSettings(); + delete d; +} + +ImageIface* ImageWidget::imageIface() +{ + return d->previewWidget->imageIface(); +} + +void ImageWidget::updatePreview() +{ + d->previewWidget->updatePreview(); +} + +void ImageWidget::slotChangeGuideColor(const TQColor &color) +{ + d->previewWidget->slotChangeGuideColor(color); +} + +void ImageWidget::slotChangeGuideSize(int size) +{ + d->previewWidget->slotChangeGuideSize(size); +} + +void ImageWidget::resetSpotPosition() +{ + d->previewWidget->resetSpotPosition(); +} + +TQPoint ImageWidget::getSpotPosition() +{ + return ( d->previewWidget->getSpotPosition() ); +} + +DColor ImageWidget::getSpotColor(int getColorFrom) +{ + return ( d->previewWidget->getSpotColor(getColorFrom) ); +} + +void ImageWidget::setSpotVisible(bool spotVisible, bool blink) +{ + d->previewWidget->setSpotVisible(spotVisible, blink); +} + +int ImageWidget::getRenderingPreviewMode() +{ + return ( d->previewWidget->getRenderingPreviewMode() ); +} + +void ImageWidget::setRenderingPreviewMode(int mode) +{ + d->previewButtons->setButton(mode); + d->previewWidget->slotChangeRenderingPreviewMode(mode); +} + +void ImageWidget::slotUpdateSpotInfo(const Digikam::DColor &col, const TQPoint &point) +{ + DColor color = col; + d->spotInfoLabel->setText(i18n("(%1,%2) RGBA:%3,%4,%5,%6") + .arg(point.x()).arg(point.y()) + .arg(color.red()).arg(color.green()) + .arg(color.blue()).arg(color.alpha()) ); +} + +void ImageWidget::readSettings() +{ + TDEConfig *config = kapp->config(); + config->setGroup(d->settingsSection); + + d->underExposureButton->setOn(config->readBoolEntry("Under Exposure Indicator", false)); + d->overExposureButton->setOn(config->readBoolEntry("Over Exposure Indicator", false)); + + int mode = config->readNumEntry("Separate View", ImageGuideWidget::PreviewBothImagesVertCont); + mode = TQMAX(ImageGuideWidget::PreviewOriginalImage, mode); + mode = TQMIN(ImageGuideWidget::NoPreviewMode, mode); + setRenderingPreviewMode(mode); +} + +void ImageWidget::writeSettings() +{ + TDEConfig *config = kapp->config(); + config->setGroup(d->settingsSection); + config->writeEntry("Separate View", getRenderingPreviewMode()); + config->writeEntry("Under Exposure Indicator", d->underExposureButton->isOn()); + config->writeEntry("Over Exposure Indicator", d->overExposureButton->isOn()); + config->sync(); +} + +} // namespace Digikam diff --git a/src/libs/widgets/imageplugins/imagewidget.h b/src/libs/widgets/imageplugins/imagewidget.h new file mode 100644 index 00000000..ebdf92e9 --- /dev/null +++ b/src/libs/widgets/imageplugins/imagewidget.h @@ -0,0 +1,106 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2006-02-01 + * Description : a widget to display an image preview with some + * modes to compare effect results. + * + * Copyright (C) 2006-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. + * + * ============================================================ */ + +#ifndef IMAGEWIDGET_H +#define IMAGEWIDGET_H + +// TQt includes. + +#include <tqwidget.h> +#include <tqpoint.h> +#include <tqcolor.h> +#include <tqstring.h> + +// Local includes. + +#include "dcolor.h" +#include "imageguidewidget.h" +#include "digikam_export.h" + +namespace Digikam +{ + +class ImageIface; +class ImageWidgetPriv; + +class DIGIKAM_EXPORT ImageWidget : public TQWidget +{ +TQ_OBJECT + + +public: + + enum ExposureIndicator + { + UnderExposure=0, + OverExposure + }; + +public: + + ImageWidget(const TQString& settingsSection, TQWidget *parent=0, + const TQString& previewWhatsThis=TQString(), bool prevModeOptions=true, + int guideMode=ImageGuideWidget::PickColorMode, + bool guideVisible=true, bool useImageSelection=false); + ~ImageWidget(); + + ImageIface* imageIface(); + + TQPoint getSpotPosition(); + DColor getSpotColor(int getColorFrom); + void setSpotVisible(bool spotVisible, bool blink=false); + int getRenderingPreviewMode(); + void resetSpotPosition(); + void updatePreview(); + void writeSettings(); + + void setRenderingPreviewMode(int mode); + +public slots: + + void slotChangeGuideColor(const TQColor &color); + void slotChangeGuideSize(int size); + +signals: + + void spotPositionChangedFromOriginal( const Digikam::DColor &color, const TQPoint &position ); + void spotPositionChangedFromTarget( const Digikam::DColor &color, const TQPoint &position ); + void signalResized(); + +private slots: + + void slotUpdateSpotInfo(const Digikam::DColor &col, const TQPoint &point); + +private: + + void readSettings(); + +private: + + ImageWidgetPriv* d; +}; + +} // namespace Digikam + +#endif /* IMAGEWIDGET_H */ diff --git a/src/libs/widgets/imageplugins/listboxpreviewitem.cpp b/src/libs/widgets/imageplugins/listboxpreviewitem.cpp new file mode 100644 index 00000000..8ba63a61 --- /dev/null +++ b/src/libs/widgets/imageplugins/listboxpreviewitem.cpp @@ -0,0 +1,62 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2006-10-05 + * Description : a TQListBoxItem which can display an image preview + * as a thumbnail and a customized qwhatsthis class + * for listbox items + * + * Copyright (C) 2006-2007 by Guillaume Laurent <[email protected]> + * + * 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. + * + * ============================================================ */ + +// Local includes. + +#include "listboxpreviewitem.h" + +namespace Digikam +{ + +int ListBoxPreviewItem::height(const TQListBox *lb) const +{ + int height = TQListBoxPixmap::height(lb); + return TQMAX(height, pixmap()->height() + 5); +} + +int ListBoxPreviewItem::width(const TQListBox *lb) const +{ + int width = TQListBoxPixmap::width(lb); + return TQMAX(width, pixmap()->width() + 5); +} + +// ------------------------------------------------------------------- + +TQString ListBoxWhatsThis::text(const TQPoint &p) +{ + TQListBoxItem* item = m_listBox->itemAt(p); + + if (item != 0) + return m_itemWhatsThisMap[item]; + + return TQString(); +} + +void ListBoxWhatsThis::add(TQListBoxItem* item, const TQString& text) +{ + m_itemWhatsThisMap[item] = text; +} + +} // namespace Digikam diff --git a/src/libs/widgets/imageplugins/listboxpreviewitem.h b/src/libs/widgets/imageplugins/listboxpreviewitem.h new file mode 100644 index 00000000..50b769c6 --- /dev/null +++ b/src/libs/widgets/imageplugins/listboxpreviewitem.h @@ -0,0 +1,80 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2006-10-05 + * Description : a TQListBoxItem which can display an image preview + * as a thumbnail and a customized qwhatsthis class + * for listbox items + * + * Copyright (C) 2006-2007 by Guillaume Laurent <[email protected]> + * + * 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. + * + * ============================================================ */ + +#ifndef LISTBOXPREVIEWITEM_H +#define LISTBOXPREVIEWITEM_H + +// TQt includes. + +#include <tqmap.h> +#include <tqlistbox.h> +#include <tqwhatsthis.h> +#include <tqpixmap.h> + +// Local includes. + +#include "digikam_export.h" + +namespace Digikam +{ + +class DIGIKAM_EXPORT ListBoxPreviewItem : public TQListBoxPixmap +{ + +public: + + ListBoxPreviewItem(TQListBox *listbox, const TQPixmap &pix, const TQString &text) + : TQListBoxPixmap(listbox, pix, text) {}; + + ListBoxPreviewItem(const TQPixmap &pix, const TQString &text) + : TQListBoxPixmap(pix, text) {}; + + virtual int height ( const TQListBox * lb ) const; + virtual int width ( const TQListBox * lb ) const; +}; + +/** + * A qwhatthis class which can be pointed to a specific item + * in a TQListBox rather than the TQListBox itself + * + */ +class DIGIKAM_EXPORT ListBoxWhatsThis : public TQWhatsThis +{ + +public: + + ListBoxWhatsThis(TQListBox* w) : TQWhatsThis(w), m_listBox(w) {} + virtual TQString text (const TQPoint &); + void add(TQListBoxItem*, const TQString& text); + +protected: + + TQMap<TQListBoxItem*, TQString> m_itemWhatsThisMap; + TQListBox *m_listBox; +}; + +} // namespace Digikam + +#endif // LISTBOXPREVIEWITEM_H diff --git a/src/libs/widgets/metadata/Makefile.am b/src/libs/widgets/metadata/Makefile.am new file mode 100644 index 00000000..4fe62356 --- /dev/null +++ b/src/libs/widgets/metadata/Makefile.am @@ -0,0 +1,17 @@ +METASOURCES = AUTO + +noinst_LTLIBRARIES = libmetadatawidgets.la + +libmetadatawidgets_la_SOURCES = metadatalistview.cpp metadatalistviewitem.cpp metadatawidget.cpp \ + iptcwidget.cpp exifwidget.cpp mdkeylistviewitem.cpp \ + makernotewidget.cpp gpswidget.cpp worldmapwidget.cpp + +libmetadatawidgets_la_LDFLAGS = $(all_libraries) $(KDE_RPATH) $(LIB_TQT) -lDCOP $(LIB_TDECORE) $(LIB_TDEUI) -ltdefx $(LIB_TDEIO) -ltdetexteditor + +INCLUDES = -I$(top_srcdir)/src/libs/dmetadata \ + -I$(top_srcdir)/src/libs/dimg \ + -I$(top_srcdir)/src/libs/themeengine \ + -I$(top_srcdir)/src/libs/widgets/common \ + -I$(top_srcdir)/src/digikam \ + $(LIBKEXIV2_CFLAGS) $(LIBKDCRAW_CFLAGS) \ + $(all_includes) diff --git a/src/libs/widgets/metadata/exifwidget.cpp b/src/libs/widgets/metadata/exifwidget.cpp new file mode 100644 index 00000000..7761c250 --- /dev/null +++ b/src/libs/widgets/metadata/exifwidget.cpp @@ -0,0 +1,185 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2006-02-20 + * Description : a widget to display Standard Exif metadata + * + * Copyright (C) 2006-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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqmap.h> +#include <tqfile.h> + +// KDE includes. + +#include <tdelocale.h> + +// Local includes. + +#include "ddebug.h" +#include "dmetadata.h" +#include "metadatalistview.h" +#include "exifwidget.h" +#include "exifwidget.moc" + +namespace Digikam +{ + +static const char* ExifHumanList[] = +{ + "Make", + "Model", + "DateTime", + "ImageDescription", + "Copyright", + "ShutterSpeedValue", + "ApertureValue", + "ExposureProgram", + "ExposureMode", + "ExposureBiasValue", + "ExposureTime", + "WhiteBalance", + "ISOSpeedRatings", + "FocalLength", + "SubjectDistance", + "MeteringMode", + "Contrast", + "Saturation", + "Sharpness", + "LightSource", + "Flash", + "FNumber", + "-1" +}; + +// Standard Exif Entry list from to less important to the most important for photograph. +// This will not including GPS information because they are displayed on another tab. +static const char* StandardExifEntryList[] = +{ + "Iop", + "Thumbnail", + "SubImage1", + "SubImage2", + "Image", + "Photo", + "-1" +}; + +ExifWidget::ExifWidget(TQWidget* parent, const char* name) + : MetadataWidget(parent, name) +{ + view()->setSortColumn(-1); + + for (int i=0 ; TQString(StandardExifEntryList[i]) != TQString("-1") ; i++) + m_keysFilter << StandardExifEntryList[i]; + + for (int i=0 ; TQString(ExifHumanList[i]) != TQString("-1") ; i++) + m_tagsfilter << ExifHumanList[i]; +} + +ExifWidget::~ExifWidget() +{ +} + +TQString ExifWidget::getMetadataTitle() +{ + return i18n("Standard EXIF Tags"); +} + +bool ExifWidget::loadFromURL(const KURL& url) +{ + setFileName(url.path()); + + if (url.isEmpty()) + { + setMetadata(); + return false; + } + else + { + DMetadata metadata(url.path()); + TQByteArray exifData = metadata.getExif(); + + if (exifData.isEmpty()) + { + setMetadata(); + return false; + } + else + setMetadata(exifData); + } + + return true; +} + +bool ExifWidget::decodeMetadata() +{ + DMetadata metaData; + if (!metaData.setExif(getMetadata())) + return false; + + // Update all metadata contents. + setMetadataMap(metaData.getExifTagsDataList(m_keysFilter)); + return true; +} + +void ExifWidget::buildView() +{ + if (getMode() == SIMPLE) + { + setIfdList(getMetadataMap(), m_keysFilter, m_tagsfilter); + } + else + { + setIfdList(getMetadataMap(), m_keysFilter, TQStringList()); + } + + MetadataWidget::buildView(); +} + +TQString ExifWidget::getTagTitle(const TQString& key) +{ + DMetadata meta; + TQString title = meta.getExifTagTitle(key.ascii()); + + if (title.isEmpty()) + return key.section('.', -1); + + return title; +} + +TQString ExifWidget::getTagDescription(const TQString& key) +{ + DMetadata meta; + TQString desc = meta.getExifTagDescription(key.ascii()); + + if (desc.isEmpty()) + return i18n("No description available"); + + return desc; +} + +void ExifWidget::slotSaveMetadataToFile() +{ + KURL url = saveMetadataToFile(i18n("EXIF File to Save"), + TQString("*.exif|"+i18n("EXIF binary Files (*.exif)"))); + storeMetadataToFile(url); +} + +} // namespace Digikam diff --git a/src/libs/widgets/metadata/exifwidget.h b/src/libs/widgets/metadata/exifwidget.h new file mode 100644 index 00000000..ba66d085 --- /dev/null +++ b/src/libs/widgets/metadata/exifwidget.h @@ -0,0 +1,73 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2006-02-20 + * Description : a widget to display Standard Exif metadata + * + * Copyright (C) 2006-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. + * + * ============================================================ */ + +#ifndef EXIFWIDGET_H +#define EXIFWIDGET_H + +// TQt includes. + +#include <tqstring.h> + +// Local includes. + +#include "metadatawidget.h" +#include "digikam_export.h" + +namespace Digikam +{ + +class DIGIKAM_EXPORT ExifWidget : public MetadataWidget +{ + TQ_OBJECT + + +public: + + ExifWidget(TQWidget* parent, const char* name=0); + ~ExifWidget(); + + bool loadFromURL(const KURL& url); + + TQString getTagDescription(const TQString& key); + TQString getTagTitle(const TQString& key); + + TQString getMetadataTitle(); + +protected slots: + + virtual void slotSaveMetadataToFile(); + +private: + + bool decodeMetadata(); + void buildView(); + +private: + + TQStringList m_tagsfilter; + TQStringList m_keysFilter; +}; + +} // namespace Digikam + +#endif /* EXIFWIDGET_H */ diff --git a/src/libs/widgets/metadata/gpswidget.cpp b/src/libs/widgets/metadata/gpswidget.cpp new file mode 100644 index 00000000..033423e9 --- /dev/null +++ b/src/libs/widgets/metadata/gpswidget.cpp @@ -0,0 +1,340 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2006-02-22 + * Description : a tab widget to display GPS info + * + * Copyright (C) 2006-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. + * + * ============================================================ */ + +/* +Any good explainations about GPS (in French) can be found at this url : +http://www.gpspassion.com/forumsen/topic.asp?TOPIC_ID=16593 +*/ + +// TQt includes. + +#include <tqlayout.h> +#include <tqpushbutton.h> +#include <tqmap.h> +#include <tqhbox.h> +#include <tqfile.h> +#include <tqcombobox.h> +#include <tqgroupbox.h> + +// KDE includes. + +#include <kdialogbase.h> +#include <tdelocale.h> +#include <tdeapplication.h> + +// Local includes. + +#include "ddebug.h" +#include "dmetadata.h" +#include "metadatalistview.h" +#include "worldmapwidget.h" +#include "gpswidget.h" +#include "gpswidget.moc" + +namespace Digikam +{ + +static const char* ExifGPSHumanList[] = +{ + "GPSLatitude", + "GPSLongitude", + "GPSAltitude", + "-1" +}; + +// Standard Exif Entry list from to less important to the most important for photograph. +static const char* StandardExifGPSEntryList[] = +{ + "GPSInfo", + "-1" +}; + +class GPSWidgetPriv +{ + +public: + + GPSWidgetPriv() + { + detailsButton = 0; + detailsCombo = 0; + map = 0; + } + + TQStringList tagsfilter; + TQStringList keysFilter; + + TQPushButton *detailsButton; + + TQComboBox *detailsCombo; + + WorldMapWidget *map; +}; + +GPSWidget::GPSWidget(TQWidget* parent, const char* name) + : MetadataWidget(parent, name) +{ + d = new GPSWidgetPriv; + + for (int i=0 ; TQString(StandardExifGPSEntryList[i]) != TQString("-1") ; i++) + d->keysFilter << StandardExifGPSEntryList[i]; + + for (int i=0 ; TQString(ExifGPSHumanList[i]) != TQString("-1") ; i++) + d->tagsfilter << ExifGPSHumanList[i]; + + // -------------------------------------------------------- + + TQWidget *gpsInfo = new TQWidget(this); + TQGridLayout *layout = new TQGridLayout(gpsInfo, 3, 2); + d->map = new WorldMapWidget(256, 256, gpsInfo); + + // -------------------------------------------------------- + + TQGroupBox* box2 = new TQGroupBox( 0, TQt::Vertical, gpsInfo ); + box2->setInsideMargin(0); + box2->setInsideSpacing(0); + box2->setFrameStyle( TQFrame::NoFrame ); + TQGridLayout* box2Layout = new TQGridLayout( box2->layout(), 0, 2, KDialog::spacingHint() ); + + d->detailsCombo = new TQComboBox( false, box2 ); + d->detailsButton = new TQPushButton(i18n("More Info..."), box2); + d->detailsCombo->insertItem(TQString("MapQuest"), MapQuest); + d->detailsCombo->insertItem(TQString("Google Maps"), GoogleMaps); + d->detailsCombo->insertItem(TQString("MSN Maps"), MsnMaps); + d->detailsCombo->insertItem(TQString("MultiMap"), MultiMap); + + box2Layout->addMultiCellWidget( d->detailsCombo, 0, 0, 0, 0 ); + box2Layout->addMultiCellWidget( d->detailsButton, 0, 0, 1, 1 ); + box2Layout->setColStretch(2, 10); + + // -------------------------------------------------------- + + layout->addMultiCellWidget(d->map, 0, 0, 0, 2); + layout->addMultiCell(new TQSpacerItem(KDialog::spacingHint(), KDialog::spacingHint(), + TQSizePolicy::Minimum, TQSizePolicy::MinimumExpanding), 1, 1, 0, 2); + layout->addMultiCellWidget(box2, 2, 2, 0, 0); + layout->setColStretch(2, 10); + layout->setRowStretch(3, 10); + + // -------------------------------------------------------- + + connect(d->detailsButton, TQ_SIGNAL(clicked()), + this, TQ_SLOT(slotGPSDetails())); + + setUserAreaWidget(gpsInfo); + decodeMetadata(); +} + +GPSWidget::~GPSWidget() +{ + delete d; +} + +int GPSWidget::getWebGPSLocator() +{ + return ( d->detailsCombo->currentItem() ); +} + +void GPSWidget::setWebGPSLocator(int locator) +{ + d->detailsCombo->setCurrentItem(locator); +} + +void GPSWidget::slotGPSDetails() +{ + TQString val, url; + + switch( getWebGPSLocator() ) + { + case MapQuest: + { + url.append("http://www.mapquest.com/maps/map.adp?searchtype=address" + "&formtype=address&latlongtype=decimal"); + url.append("&latitude="); + url.append(val.setNum(d->map->getLatitude(), 'g', 12)); + url.append("&longitude="); + url.append(val.setNum(d->map->getLongitude(), 'g', 12)); + break; + } + + case GoogleMaps: + { + url.append("http://maps.google.com/?q="); + url.append(val.setNum(d->map->getLatitude(), 'g', 12)); + url.append(","); + url.append(val.setNum(d->map->getLongitude(), 'g', 12)); + url.append("&spn=0.05,0.05&t=h&om=1&hl=en"); + break; + } + + case MsnMaps: + { + url.append("http://maps.msn.com/map.aspx?"); + url.append("&lats1="); + url.append(val.setNum(d->map->getLatitude(), 'g', 12)); + url.append("&lons1="); + url.append(val.setNum(d->map->getLongitude(), 'g', 12)); + url.append("&name=HERE"); + url.append("&alts1=7"); + break; + } + + case MultiMap: + { + url.append("http://www.multimap.com/map/browse.cgi?"); + url.append("lat="); + url.append(val.setNum(d->map->getLatitude(), 'g', 12)); + url.append("&lon="); + url.append(val.setNum(d->map->getLongitude(), 'g', 12)); + url.append("&scale=10000"); + url.append("&icon=x"); + break; + } + } + + TDEApplication::kApplication()->invokeBrowser(url); +} + +TQString GPSWidget::getMetadataTitle() +{ + return i18n("Global Positioning System Information"); +} + +bool GPSWidget::loadFromURL(const KURL& url) +{ + setFileName(url.path()); + + if (url.isEmpty()) + { + setMetadata(); + return false; + } + else + { + DMetadata metadata(url.path()); + TQByteArray exifData = metadata.getExif(); + + if (exifData.isEmpty()) + { + setMetadata(); + return false; + } + else + setMetadata(exifData); + } + + return true; +} + +bool GPSWidget::decodeMetadata() +{ + DMetadata metaData; + if (!metaData.setExif(getMetadata())) + { + setMetadataEmpty(); + return false; + } + + // Update all metadata contents. + setMetadataMap(metaData.getExifTagsDataList(d->keysFilter)); + + bool ret = decodeGPSPosition(); + if (!ret) + { + setMetadataEmpty(); + return false; + } + + d->map->setEnabled(true); + d->detailsButton->setEnabled(true); + d->detailsCombo->setEnabled(true); + return true; +} + +void GPSWidget::setMetadataEmpty() +{ + MetadataWidget::setMetadataEmpty(); + d->map->setEnabled(false); + d->detailsButton->setEnabled(false); + d->detailsCombo->setEnabled(false); +} + +void GPSWidget::buildView() +{ + if (getMode() == SIMPLE) + { + setIfdList(getMetadataMap(), d->keysFilter, d->tagsfilter); + } + else + { + setIfdList(getMetadataMap(), d->keysFilter, TQStringList()); + } + + MetadataWidget::buildView(); +} + +TQString GPSWidget::getTagTitle(const TQString& key) +{ + DMetadata meta; + TQString title = meta.getExifTagTitle(key.ascii()); + + if (title.isEmpty()) + return key.section('.', -1); + + return title; +} + +TQString GPSWidget::getTagDescription(const TQString& key) +{ + DMetadata meta; + TQString desc = meta.getExifTagDescription(key.ascii()); + + if (desc.isEmpty()) + return i18n("No description available"); + + return desc; +} + +bool GPSWidget::decodeGPSPosition() +{ + double latitude=0.0, longitude=0.0, altitude=0.0; + + DMetadata meta; + meta.setExif(getMetadata()); + + if (meta.getGPSInfo(altitude, latitude, longitude)) + d->map->setGPSPosition(latitude, longitude); + else + return false; + + return true; +} + +void GPSWidget::slotSaveMetadataToFile() +{ + KURL url = saveMetadataToFile(i18n("EXIF File to Save"), + TQString("*.exif|"+i18n("EXIF binary Files (*.exif)"))); + storeMetadataToFile(url); +} + +} // namespace Digikam diff --git a/src/libs/widgets/metadata/gpswidget.h b/src/libs/widgets/metadata/gpswidget.h new file mode 100644 index 00000000..fd787d67 --- /dev/null +++ b/src/libs/widgets/metadata/gpswidget.h @@ -0,0 +1,95 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2006-02-22 + * Description : a tab widget to display GPS info + * + * Copyright (C) 2006-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. + * + * ============================================================ */ + +#ifndef GPSWIDGET_H +#define GPSWIDGET_H + +// TQt includes. + +#include <tqwidget.h> +#include <tqstring.h> + +// Local includes. + +#include "metadatawidget.h" +#include "digikam_export.h" + +namespace Digikam +{ + +class GPSWidgetPriv; +class WorldMapWidget; + +class DIGIKAM_EXPORT GPSWidget : public MetadataWidget +{ + TQ_OBJECT + + +public: + + enum WebGPSLocator + { + MapQuest = 0, + GoogleMaps, + MsnMaps, + MultiMap + }; + +public: + + GPSWidget(TQWidget* parent, const char* name=0); + ~GPSWidget(); + + bool loadFromURL(const KURL& url); + + TQString getTagDescription(const TQString& key); + TQString getTagTitle(const TQString& key); + + TQString getMetadataTitle(); + + int getWebGPSLocator(); + void setWebGPSLocator(int locator); + +protected slots: + + virtual void slotSaveMetadataToFile(); + +private slots: + + void slotGPSDetails(); + +private: + + bool decodeMetadata(); + void buildView(); + bool decodeGPSPosition(); + virtual void setMetadataEmpty(); + +private: + + GPSWidgetPriv *d; +}; + +} // namespace Digikam + +#endif /* GPSWIDGET_H */ diff --git a/src/libs/widgets/metadata/iptcwidget.cpp b/src/libs/widgets/metadata/iptcwidget.cpp new file mode 100644 index 00000000..b0bcb009 --- /dev/null +++ b/src/libs/widgets/metadata/iptcwidget.cpp @@ -0,0 +1,167 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2006-02-20 + * Description : A widget to display IPTC metadata + * + * Copyright (C) 2006-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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqmap.h> +#include <tqfile.h> + +// KDE includes. + +#include <tdelocale.h> + +// Local includes. + +#include "ddebug.h" +#include "dmetadata.h" +#include "iptcwidget.h" +#include "iptcwidget.moc" + +namespace Digikam +{ + +static const char* IptcHumanList[] = +{ + "Caption", + "City", + "Contact", + "Copyright", + "Credit", + "DateCreated", + "Headline", + "Keywords", + "ProvinceState", + "Source", + "Urgency", + "Writer", + "-1" +}; + +static const char* StandardIptcEntryList[] = +{ + "Envelope", + "Application2", + "-1" +}; + +IptcWidget::IptcWidget(TQWidget* parent, const char* name) + : MetadataWidget(parent, name) +{ + for (int i=0 ; TQString(StandardIptcEntryList[i]) != TQString("-1") ; i++) + m_keysFilter << StandardIptcEntryList[i]; + + for (int i=0 ; TQString(IptcHumanList[i]) != TQString("-1") ; i++) + m_tagsfilter << IptcHumanList[i]; +} + +IptcWidget::~IptcWidget() +{ +} + +TQString IptcWidget::getMetadataTitle() +{ + return i18n("IPTC Records"); +} + +bool IptcWidget::loadFromURL(const KURL& url) +{ + setFileName(url.filename()); + + if (url.isEmpty()) + { + setMetadata(); + return false; + } + else + { + DMetadata metadata(url.path()); + TQByteArray iptcData = metadata.getIptc(); + + if (iptcData.isEmpty()) + { + setMetadata(); + return false; + } + else + setMetadata(iptcData); + } + + return true; +} + +bool IptcWidget::decodeMetadata() +{ + DMetadata metaData; + if (!metaData.setIptc(getMetadata())) + return false; + + // Update all metadata contents. + setMetadataMap(metaData.getIptcTagsDataList(m_keysFilter)); + return true; +} + +void IptcWidget::buildView() +{ + if (getMode() == SIMPLE) + { + setIfdList(getMetadataMap(), m_tagsfilter); + } + else + { + setIfdList(getMetadataMap()); + } + + MetadataWidget::buildView(); +} + +TQString IptcWidget::getTagTitle(const TQString& key) +{ + DMetadata meta; + TQString title = meta.getIptcTagTitle(key.ascii()); + + if (title.isEmpty()) + return key.section('.', -1); + + return title; +} + +TQString IptcWidget::getTagDescription(const TQString& key) +{ + DMetadata meta; + TQString desc = meta.getIptcTagDescription(key.ascii()); + + if (desc.isEmpty()) + return i18n("No description available"); + + return desc; +} + +void IptcWidget::slotSaveMetadataToFile() +{ + KURL url = saveMetadataToFile(i18n("IPTC File to Save"), + TQString("*.iptc|"+i18n("IPTC binary Files (*.iptc)"))); + storeMetadataToFile(url); +} + +} // namespace Digikam + diff --git a/src/libs/widgets/metadata/iptcwidget.h b/src/libs/widgets/metadata/iptcwidget.h new file mode 100644 index 00000000..58f1449e --- /dev/null +++ b/src/libs/widgets/metadata/iptcwidget.h @@ -0,0 +1,69 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2006-02-20 + * Description : A widget to display IPTC metadata + * + * Copyright (C) 2006-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. + * + * ============================================================ */ + +#ifndef IPTCWIDGET_H +#define IPTCWIDGET_H + +// Local includes. + +#include "metadatawidget.h" +#include "digikam_export.h" + +namespace Digikam +{ + +class DIGIKAM_EXPORT IptcWidget : public MetadataWidget +{ + TQ_OBJECT + + +public: + + IptcWidget(TQWidget* parent, const char* name=0); + ~IptcWidget(); + + bool loadFromURL(const KURL& url); + + TQString getTagDescription(const TQString& key); + TQString getTagTitle(const TQString& key); + + TQString getMetadataTitle(); + +protected slots: + + virtual void slotSaveMetadataToFile(); + +private: + + bool decodeMetadata(); + void buildView(); + +private: + + TQStringList m_tagsfilter; + TQStringList m_keysFilter; +}; + +} // namespace Digikam + +#endif /* IPTCWIDGET_H */ diff --git a/src/libs/widgets/metadata/makernotewidget.cpp b/src/libs/widgets/metadata/makernotewidget.cpp new file mode 100644 index 00000000..ddd1fe3c --- /dev/null +++ b/src/libs/widgets/metadata/makernotewidget.cpp @@ -0,0 +1,210 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2006-02-20 + * Description : a widget to display non standard Exif metadata + * used by camera makers + * + * Copyright (C) 2006-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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqmap.h> +#include <tqfile.h> + +// KDE includes. + +#include <tdelocale.h> + +// Local includes. + +#include "ddebug.h" +#include "dmetadata.h" +#include "makernotewidget.h" +#include "makernotewidget.moc" + +namespace Digikam +{ + +// This list mix differents tags name used by camera makers. +static const char* MakerNoteHumanList[] = +{ + "AFFocusPos", + "AFMode", + "AFPoint", + "AutofocusMode", + "ColorMode", + "ColorTemperature", + "Contrast", + "DigitalZoom", + "ExposureMode", + "ExposureProgram", + "ExposureCompensation", + "ExposureManualBias", + "Flash", + "FlashBias", + "FlashMode", + "FlashType", + "FlashDevice", + "FNumber", + "Focus" + "FocusDistance", + "FocusMode", + "FocusSetting", + "FocusType", + "Hue", + "HueAdjustment", + "ImageStabilizer", + "ImageStabilization", + "InternalFlash", + "ISOSelection", + "ISOSpeed", + "Lens", + "LensType", + "LensRange", + "Macro", + "MacroFocus", + "MeteringMode", + "NoiseReduction", + "OwnerName", + "Quality", + "Tone", + "ToneComp", + "Saturation", + "Sharpness", + "ShootingMode", + "ShutterSpeedValue", + "SpotMode", + "SubjectDistance", + "WhiteBalance", + "WhiteBalanceBias", + "-1" +}; + +static const char* ExifEntryListToIgnore[] = +{ + "GPSInfo", + "Iop", + "Thumbnail", + "SubImage1", + "SubImage2", + "Image", + "Photo", + "-1" +}; + +MakerNoteWidget::MakerNoteWidget(TQWidget* parent, const char* name) + : MetadataWidget(parent, name) +{ + for (int i=0 ; TQString(ExifEntryListToIgnore[i]) != TQString("-1") ; i++) + m_keysFilter << ExifEntryListToIgnore[i]; + + for (int i=0 ; TQString(MakerNoteHumanList[i]) != TQString("-1") ; i++) + m_tagsfilter << MakerNoteHumanList[i]; +} + +MakerNoteWidget::~MakerNoteWidget() +{ +} + +TQString MakerNoteWidget::getMetadataTitle() +{ + return i18n("MakerNote EXIF Tags"); +} + +bool MakerNoteWidget::loadFromURL(const KURL& url) +{ + setFileName(url.path()); + + if (url.isEmpty()) + { + setMetadata(); + return false; + } + else + { + DMetadata metadata(url.path()); + TQByteArray exifData = metadata.getExif(); + + if (exifData.isEmpty()) + { + setMetadata(); + return false; + } + else + setMetadata(exifData); + } + + return true; +} + +bool MakerNoteWidget::decodeMetadata() +{ + DMetadata metaData; + if (!metaData.setExif(getMetadata())) + return false; + + // Update all metadata contents. + setMetadataMap(metaData.getExifTagsDataList(m_keysFilter, true)); + return true; +} + +void MakerNoteWidget::buildView() +{ + if (getMode() == SIMPLE) + { + setIfdList(getMetadataMap(), m_tagsfilter); + } + else + { + setIfdList(getMetadataMap()); + } + + MetadataWidget::buildView(); +} + +TQString MakerNoteWidget::getTagTitle(const TQString& key) +{ + DMetadata meta; + TQString title = meta.getExifTagTitle(key.ascii()); + + if (title.isEmpty()) + return key.section('.', -1); + + return title; +} + +TQString MakerNoteWidget::getTagDescription(const TQString& key) +{ + DMetadata meta; + TQString desc = meta.getExifTagDescription(key.ascii()); + + if (desc.isEmpty()) + return i18n("No description available"); + + return desc; +} + +void MakerNoteWidget::slotSaveMetadataToFile() +{ + KURL url = saveMetadataToFile(i18n("EXIF File to Save"), + TQString("*.exif|"+i18n("EXIF binary Files (*.exif)"))); + storeMetadataToFile(url); +} + +} // namespace Digikam diff --git a/src/libs/widgets/metadata/makernotewidget.h b/src/libs/widgets/metadata/makernotewidget.h new file mode 100644 index 00000000..f6549591 --- /dev/null +++ b/src/libs/widgets/metadata/makernotewidget.h @@ -0,0 +1,70 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2006-02-20 + * Description : a widget to display non standard Exif metadata + * used by camera makers + * + * Copyright (C) 2006-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. + * + * ============================================================ */ + +#ifndef MARKERNOTEWIDGET_H +#define MARKERNOTEWIDGET_H + +// Local includes. + +#include "metadatawidget.h" +#include "digikam_export.h" + +namespace Digikam +{ + +class DIGIKAM_EXPORT MakerNoteWidget : public MetadataWidget +{ + TQ_OBJECT + + +public: + + MakerNoteWidget(TQWidget* parent, const char* name=0); + ~MakerNoteWidget(); + + bool loadFromURL(const KURL& url); + + TQString getTagDescription(const TQString& key); + TQString getTagTitle(const TQString& key); + + TQString getMetadataTitle(); + +protected slots: + + virtual void slotSaveMetadataToFile(); + +private: + + bool decodeMetadata(); + void buildView(); + +private: + + TQStringList m_tagsfilter; + TQStringList m_keysFilter; +}; + +} // namespace Digikam + +#endif /* MARKERNOTEWIDGET_H */ diff --git a/src/libs/widgets/metadata/mdkeylistviewitem.cpp b/src/libs/widgets/metadata/mdkeylistviewitem.cpp new file mode 100644 index 00000000..27963eaf --- /dev/null +++ b/src/libs/widgets/metadata/mdkeylistviewitem.cpp @@ -0,0 +1,94 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2006-02-21 + * Description : a generic list view item widget to + * display metadata key like a title + * + * Copyright (C) 2006-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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqpalette.h> +#include <tqfont.h> +#include <tqpainter.h> + +// KDE includes. + +#include <tdelocale.h> + +// Local includes. + +#include "themeengine.h" +#include "ddebug.h" +#include "mdkeylistviewitem.h" + +namespace Digikam +{ + +MdKeyListViewItem::MdKeyListViewItem(TQListView *parent, const TQString& key) + : TQListViewItem(parent) +{ + m_decryptedKey = key; + + // Standard Exif key descriptions. + if (key == "Iop") m_decryptedKey = i18n("Interoperability"); + else if (key == "Image") m_decryptedKey = i18n("Image Information"); + else if (key == "Photo") m_decryptedKey = i18n("Photograph Information"); + else if (key == "GPSInfo") m_decryptedKey = i18n("Global Positioning System"); + else if (key == "Thumbnail") m_decryptedKey = i18n("Embedded Thumbnail"); + + // Standard IPTC key descriptions. + else if (key == "Envelope") m_decryptedKey = i18n("IIM Envelope"); + else if (key == "Application2") m_decryptedKey = i18n("IIM Application 2"); + + setOpen(true); + setSelected(false); + setSelectable(false); +} + +MdKeyListViewItem::~MdKeyListViewItem() +{ +} + +TQString MdKeyListViewItem::getMdKey() +{ + return m_decryptedKey; +} + +void MdKeyListViewItem::paintCell(TQPainter* p, const TQColorGroup&, + int column, int, int) +{ + p->save(); + TQFont fn(p->font()); + fn.setBold(true); + fn.setItalic(false); + p->setFont(fn); + p->setPen(ThemeEngine::instance()->textSelColor()); + int width = listView()->contentsWidth(); + TQRect rect(0, 0, width, fn.weight()); + + if (column == 1) + rect.moveLeft(-width/2); + + p->fillRect(rect, ThemeEngine::instance()->thumbSelColor()); + p->drawText(rect, TQt::AlignHCenter, m_decryptedKey); + p->restore(); +} + +} // namespace Digikam diff --git a/src/libs/widgets/metadata/mdkeylistviewitem.h b/src/libs/widgets/metadata/mdkeylistviewitem.h new file mode 100644 index 00000000..aeaf7e4c --- /dev/null +++ b/src/libs/widgets/metadata/mdkeylistviewitem.h @@ -0,0 +1,63 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2006-02-21 + * Description : a generic list view item widget to + * display metadata key like a title + * + * Copyright (C) 2006-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. + * + * ============================================================ */ + +#ifndef MDKEYLISTVIEWITEM_H +#define MDKEYLISTVIEWITEM_H + +// TQt includes. + +#include <tqstring.h> +#include <tqlistview.h> + +// Local includes. + +#include "digikam_export.h" + +class TQPainter; + +namespace Digikam +{ + +class DIGIKAM_EXPORT MdKeyListViewItem : public TQListViewItem +{ + +public: + + MdKeyListViewItem(TQListView *parent, const TQString& key); + ~MdKeyListViewItem(); + + TQString getMdKey(); + +protected: + + void paintCell(TQPainter*, const TQColorGroup &, int, int, int); + +private: + + TQString m_decryptedKey; +}; + +} // namespace Digikam + +#endif /* MDKEYLISTVIEWITEM_H */ diff --git a/src/libs/widgets/metadata/metadatalistview.cpp b/src/libs/widgets/metadata/metadatalistview.cpp new file mode 100644 index 00000000..612eed1e --- /dev/null +++ b/src/libs/widgets/metadata/metadatalistview.cpp @@ -0,0 +1,283 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2006-02-21 + * Description : a generic list view widget to + * display metadata + * + * Copyright (c) 2006-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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqtimer.h> +#include <tqptrlist.h> +#include <tqpalette.h> +#include <tqheader.h> +#include <tqwhatsthis.h> + +// KDE includes. + +#include <tdelocale.h> + +// Local includes. + +#include "mdkeylistviewitem.h" +#include "metadatalistviewitem.h" +#include "metadatalistview.h" +#include "metadatalistview.moc" + +namespace Digikam +{ + +MetadataListView::MetadataListView(TQWidget* parent) + : TQListView(parent) +{ + header()->hide(); + addColumn("Name"); // No need i18n here. + addColumn("Value"); // No need i18n here. + setItemMargin(0); + setAllColumnsShowFocus(true); + setResizeMode(TQListView::AllColumns); + // Vertical scroll bar is always disable to give more + // free space to metadata content + setVScrollBarMode(TQScrollView::AlwaysOff); + + m_parent = dynamic_cast<MetadataWidget *>(parent); + + connect(this, TQ_SIGNAL(selectionChanged(TQListViewItem*)), + this, TQ_SLOT(slotSelectionChanged(TQListViewItem*))); +} + +MetadataListView::~MetadataListView() +{ +} + +TQString MetadataListView::getCurrentItemKey() +{ + if (currentItem()) + { + if (currentItem()->isSelectable()) + { + MetadataListViewItem *item = static_cast<MetadataListViewItem *>(currentItem()); + return item->getKey(); + } + } + + return TQString(); +} + +void MetadataListView::setCurrentItemByKey(TQString itemKey) +{ + if (itemKey.isNull()) + return; + + TQListViewItemIterator it(this); + while ( it.current() ) + { + if ( it.current()->isSelectable() ) + { + MetadataListViewItem *item = dynamic_cast<MetadataListViewItem *>(it.current()); + + if (item->getKey() == itemKey) + { + setSelected(item, true); + ensureItemVisible(item); + m_selectedItemKey = itemKey; + return; + } + } + + ++it; + } +} + +void MetadataListView::slotSelectionChanged(TQListViewItem *item) +{ + if (!item) + return; + + MetadataListViewItem* viewItem = static_cast<MetadataListViewItem *>(item); + m_selectedItemKey = viewItem->getKey(); + TQString tagValue = viewItem->getValue().simplifyWhiteSpace(); + TQString tagTitle = m_parent->getTagTitle(m_selectedItemKey); + TQString tagDesc = m_parent->getTagDescription(m_selectedItemKey); + if (tagValue.length() > 128) + { + tagValue.truncate(128); + tagValue.append("..."); + } + + TQWhatsThis::add(this, i18n("<b>Title: </b><p>%1<p>" + "<b>Value: </b><p>%2<p>" + "<b>Description: </b><p>%3") + .arg(tagTitle) + .arg(tagValue) + .arg(tagDesc)); +} + +void MetadataListView::setIfdList(const DMetadata::MetaDataMap& ifds, const TQStringList& tagsfilter) +{ + clear(); + + uint subItems = 0; + TQString ifDItemName; + MdKeyListViewItem *parentifDItem = 0; + + for (DMetadata::MetaDataMap::const_iterator it = ifds.begin(); it != ifds.end(); ++it) + { + // We checking if we have changed of ifDName + TQString currentIfDName = it.key().section('.', 1, 1); + + if ( currentIfDName != ifDItemName ) + { + ifDItemName = currentIfDName; + + // Check if the current IfD have any items. If no remove it before to toggle to the next IfD. + if ( subItems == 0 && parentifDItem) + delete parentifDItem; + + parentifDItem = new MdKeyListViewItem(this, currentIfDName); + subItems = 0; + } + + // We ignore all unknown tags if necessary. + if (!it.key().section('.', 2, 2).startsWith("0x")) + { + if (!tagsfilter.isEmpty()) + { + // We using the filter to make a more user friendly output (Simple Mode) + + if (tagsfilter.contains(it.key().section('.', 2, 2))) + { + TQString tagTitle = m_parent->getTagTitle(it.key()); + new MetadataListViewItem(parentifDItem, it.key(), tagTitle, it.data()); + subItems++; + } + } + else + { + // We don't filter the output (Complete Mode) + + TQString tagTitle = m_parent->getTagTitle(it.key()); + new MetadataListViewItem(parentifDItem, it.key(), tagTitle, it.data()); + subItems++; + } + } + } + + // To check if the last IfD have any items... + if ( subItems == 0 && parentifDItem) + delete parentifDItem; + + setCurrentItemByKey(m_selectedItemKey); + TQTimer::singleShot( 0, this, TQ_SLOT( triggerUpdate() ) ); +} + +void MetadataListView::setIfdList(const DMetadata::MetaDataMap& ifds, const TQStringList& keysFilter, + const TQStringList& tagsFilter) +{ + clear(); + + uint subItems = 0; + MdKeyListViewItem *parentifDItem = 0; + + for (TQStringList::const_iterator itKeysFilter = keysFilter.begin(); + itKeysFilter != keysFilter.end(); + ++itKeysFilter) + { + subItems = 0; + parentifDItem = new MdKeyListViewItem(this, *itKeysFilter); + + DMetadata::MetaDataMap::const_iterator it = ifds.end(); + + while(1) + { + if ( *itKeysFilter == it.key().section('.', 1, 1) ) + { + // We ignore all unknown tags if necessary. + if (!it.key().section('.', 2, 2).startsWith("0x")) + { + if (!tagsFilter.isEmpty()) + { + // We using the filter to make a more user friendly output (Simple Mode) + + if (tagsFilter.contains(it.key().section('.', 2, 2))) + { + TQString tagTitle = m_parent->getTagTitle(it.key()); + new MetadataListViewItem(parentifDItem, it.key(), tagTitle, it.data()); + subItems++; + } + } + else + { + // We don't filter the output (Complete Mode) + + TQString tagTitle = m_parent->getTagTitle(it.key()); + new MetadataListViewItem(parentifDItem, it.key(), tagTitle, it.data()); + subItems++; + } + } + } + + if (it == ifds.begin()) break; + --it; + } + + // We checking if the last IfD have any items. If no, we remove it. + if ( subItems == 0 && parentifDItem) + delete parentifDItem; + } + + setCurrentItemByKey(m_selectedItemKey); + TQTimer::singleShot( 0, this, TQ_SLOT( triggerUpdate() ) ); +} + +void MetadataListView::viewportResizeEvent(TQResizeEvent* e) +{ + TQListView::viewportResizeEvent(e); + TQTimer::singleShot( 0, this, TQ_SLOT( triggerUpdate() ) ); +} + +void MetadataListView::slotSearchTextChanged(const TQString& filter) +{ + bool query = false; + TQString search = filter.lower(); + + TQListViewItemIterator it(this); + for ( ; it.current(); ++it ) + { + MetadataListViewItem *item = dynamic_cast<MetadataListViewItem*>(it.current()); + if (item) + { + if (item->text(0).lower().contains(search) || + item->text(1).lower().contains(search)) + { + query = true; + item->setVisible(true); + } + else + { + item->setVisible(false); + } + } + } + + emit signalTextFilterMatch(query); +} + +} // namespace Digikam diff --git a/src/libs/widgets/metadata/metadatalistview.h b/src/libs/widgets/metadata/metadatalistview.h new file mode 100644 index 00000000..aefe6498 --- /dev/null +++ b/src/libs/widgets/metadata/metadatalistview.h @@ -0,0 +1,85 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2006-02-21 + * Description : a generic list view widget to + * display metadata + * + * Copyright (C) 2006-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. + * + * ============================================================ */ + +#ifndef METADATALISTVIEW_H +#define METADATALISTVIEW_H + +// TQt includes. + +#include <tqstring.h> +#include <tqptrlist.h> +#include <tqmap.h> +#include <tqlistview.h> + +// Local includes. + +#include "metadatawidget.h" +#include "digikam_export.h" + +namespace Digikam +{ + +class DIGIKAM_EXPORT MetadataListView : public TQListView +{ + TQ_OBJECT + + +public: + + MetadataListView(TQWidget* parent); + ~MetadataListView(); + + TQString getCurrentItemKey(); + void setCurrentItemByKey(TQString itemKey); + + void setIfdList(const DMetadata::MetaDataMap& ifds, const TQStringList& tagsfilter); + void setIfdList(const DMetadata::MetaDataMap& ifds, const TQStringList& keysFilter, + const TQStringList& tagsFilter); + +signals: + + void signalTextFilterMatch(bool); + +public slots: + + void slotSearchTextChanged(const TQString&); + +protected: + + void viewportResizeEvent(TQResizeEvent*); + +private slots: + + void slotSelectionChanged(TQListViewItem *item); + +private: + + TQString m_selectedItemKey; + + MetadataWidget *m_parent; +}; + +} // namespace Digikam + +#endif // METADATALISTVIEW_H diff --git a/src/libs/widgets/metadata/metadatalistviewitem.cpp b/src/libs/widgets/metadata/metadatalistviewitem.cpp new file mode 100644 index 00000000..f18056b5 --- /dev/null +++ b/src/libs/widgets/metadata/metadatalistviewitem.cpp @@ -0,0 +1,75 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2006-02-21 + * Description : a generic list view item widget to + * display metadata + * + * Copyright (C) 2006-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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqpalette.h> +#include <tqfont.h> +#include <tqpainter.h> + +// Local includes. + +#include "metadatalistviewitem.h" + +namespace Digikam +{ + +MetadataListViewItem::MetadataListViewItem(TQListViewItem *parent, const TQString& key, + const TQString& title, const TQString& value) + : TQListViewItem(parent) +{ + m_key = key; + + setSelectable(true); + setText(0, title); + + TQString tagVal = value.simplifyWhiteSpace(); + if (tagVal.length() > 128) + { + tagVal.truncate(128); + tagVal.append("..."); + } + setText(1, tagVal); +} + +MetadataListViewItem::~MetadataListViewItem() +{ +} + +TQString MetadataListViewItem::getKey() +{ + return m_key; +} + +TQString MetadataListViewItem::getTitle() +{ + return text(0); +} + +TQString MetadataListViewItem::getValue() +{ + return text(1); +} + +} // namespace Digikam diff --git a/src/libs/widgets/metadata/metadatalistviewitem.h b/src/libs/widgets/metadata/metadatalistviewitem.h new file mode 100644 index 00000000..4a860d5b --- /dev/null +++ b/src/libs/widgets/metadata/metadatalistviewitem.h @@ -0,0 +1,59 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2006-02-21 + * Description : a generic list view item widget to + * display metadata + * + * Copyright (C) 2006-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. + * + * ============================================================ */ + +#ifndef METADATALISTVIEWITEM_H +#define METADATALISTVIEWITEM_H + +// TQt includes. + +#include <tqstring.h> +#include <tqlistview.h> + +// Local includes. + +#include "digikam_export.h" + +namespace Digikam +{ + +class DIGIKAM_EXPORT MetadataListViewItem : public TQListViewItem +{ +public: + + MetadataListViewItem(TQListViewItem *parent, const TQString& key, + const TQString& title, const TQString& value); + ~MetadataListViewItem(); + + TQString getKey(); + TQString getTitle(); + TQString getValue(); + +private: + + TQString m_key; +}; + +} // namespace Digikam + +#endif /* METADATALISTVIEWITEM_H */ diff --git a/src/libs/widgets/metadata/metadatawidget.cpp b/src/libs/widgets/metadata/metadatawidget.cpp new file mode 100644 index 00000000..d0bd5b19 --- /dev/null +++ b/src/libs/widgets/metadata/metadatawidget.cpp @@ -0,0 +1,454 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2006-02-22 + * Description : a generic widget to display metadata + * + * Copyright (C) 2006-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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqlayout.h> +#include <tqmap.h> +#include <tqfile.h> +#include <tqmime.h> +#include <tqheader.h> +#include <tqwhatsthis.h> +#include <tqpainter.h> +#include <tqhbuttongroup.h> +#include <tqpushbutton.h> +#include <tqlabel.h> +#include <tqdragobject.h> +#include <tqclipboard.h> +#include <tqsimplerichtext.h> +#include <tqpaintdevicemetrics.h> +#include <tqstylesheet.h> +#include <tqlistview.h> +#include <tqtooltip.h> + +// KDE includes. + +#include <kdialogbase.h> +#include <tdelocale.h> +#include <tdefiledialog.h> +#include <tdeglobalsettings.h> +#include <kprinter.h> +#include <tdeglobal.h> +#include <kiconloader.h> +#include <tdeapplication.h> + +// Local includes. + +#include "ddebug.h" +#include "metadatalistview.h" +#include "mdkeylistviewitem.h" +#include "searchtextbar.h" +#include "metadatawidget.h" +#include "metadatawidget.moc" + +namespace Digikam +{ + +class MetadataWidgetPriv +{ + +public: + + MetadataWidgetPriv() + { + toolButtons = 0; + levelButtons = 0; + view = 0; + mainLayout = 0; + searchBar = 0; + } + + TQGridLayout *mainLayout; + + TQHButtonGroup *toolButtons; + TQHButtonGroup *levelButtons; + + TQByteArray metadata; + + TQString fileName; + + MetadataListView *view; + + SearchTextBar *searchBar; + + DMetadata::MetaDataMap metaDataMap; +}; + +MetadataWidget::MetadataWidget(TQWidget* parent, const char* name) + : TQWidget(parent, name) +{ + d = new MetadataWidgetPriv; + + d->mainLayout = new TQGridLayout(this, 3, 4, KDialog::spacingHint(), KDialog::spacingHint()); + TDEIconLoader *iconLoader = TDEApplication::kApplication()->iconLoader(); + + d->levelButtons = new TQHButtonGroup(this); + d->levelButtons->setInsideMargin( 0 ); + d->levelButtons->setExclusive(true); + d->levelButtons->setFrameShape(TQFrame::NoFrame); + + TQPushButton *simpleLevel = new TQPushButton( d->levelButtons ); + simpleLevel->setPixmap( iconLoader->loadIcon( "text-vnd.tde.ascii", (TDEIcon::Group)TDEIcon::Toolbar ) ); + simpleLevel->setToggleButton(true); + TQWhatsThis::add( simpleLevel, i18n( "Switch the tags view to a simple human-readable list" ) ); + TQToolTip::add( simpleLevel, i18n( "Simple list" )); + d->levelButtons->insert(simpleLevel, SIMPLE); + + TQPushButton *fullLevel = new TQPushButton( d->levelButtons ); + fullLevel->setPixmap( iconLoader->loadIcon( "text-x-generic", (TDEIcon::Group)TDEIcon::Toolbar ) ); + fullLevel->setToggleButton(true); + TQWhatsThis::add( fullLevel, i18n( "Switch the tags view to a full list" ) ); + TQToolTip::add( fullLevel, i18n( "Full list" )); + d->levelButtons->insert(fullLevel, FULL); + + d->toolButtons = new TQHButtonGroup(this); + d->toolButtons->setInsideMargin( 0 ); + d->toolButtons->setFrameShape(TQFrame::NoFrame); + + TQPushButton *saveMetadata = new TQPushButton( d->toolButtons ); + saveMetadata->setPixmap( iconLoader->loadIcon( "document-save", (TDEIcon::Group)TDEIcon::Toolbar ) ); + TQWhatsThis::add( saveMetadata, i18n( "Save metadata to a binary file" ) ); + TQToolTip::add( saveMetadata, i18n( "Save metadata" )); + d->toolButtons->insert(saveMetadata); + + TQPushButton *printMetadata = new TQPushButton( d->toolButtons ); + printMetadata->setPixmap( iconLoader->loadIcon( "document-print", (TDEIcon::Group)TDEIcon::Toolbar ) ); + TQWhatsThis::add( printMetadata, i18n( "Print metadata to printer" ) ); + TQToolTip::add( printMetadata, i18n( "Print metadata" )); + d->toolButtons->insert(printMetadata); + + TQPushButton *copy2ClipBoard = new TQPushButton( d->toolButtons ); + copy2ClipBoard->setPixmap( iconLoader->loadIcon( "edit-copy", (TDEIcon::Group)TDEIcon::Toolbar ) ); + TQWhatsThis::add( copy2ClipBoard, i18n( "Copy metadata to clipboard" ) ); + TQToolTip::add( copy2ClipBoard, i18n( "Copy metadata to clipboard" )); + d->toolButtons->insert(copy2ClipBoard); + + d->view = new MetadataListView(this); + TQString barName = TQString(name) + "SearchBar"; + d->searchBar = new SearchTextBar(this, barName.ascii()); + + // ----------------------------------------------------------------- + + d->mainLayout->addMultiCellWidget(d->levelButtons, 0, 0, 0, 1); + d->mainLayout->addMultiCellWidget(d->toolButtons, 0, 0, 4, 4); + d->mainLayout->addMultiCellWidget(d->view, 1, 1, 0, 4); + d->mainLayout->addMultiCellWidget(d->searchBar, 2, 2, 0, 4); + d->mainLayout->setRowStretch(1, 10); + d->mainLayout->setColStretch(3, 10); + + // ----------------------------------------------------------------- + + connect(d->levelButtons, TQ_SIGNAL(released(int)), + this, TQ_SLOT(slotModeChanged(int))); + + connect(copy2ClipBoard, TQ_SIGNAL(clicked()), + this, TQ_SLOT(slotCopy2Clipboard())); + + connect(printMetadata, TQ_SIGNAL(clicked()), + this, TQ_SLOT(slotPrintMetadata())); + + connect(saveMetadata, TQ_SIGNAL(clicked()), + this, TQ_SLOT(slotSaveMetadataToFile())); + + connect(d->searchBar, TQ_SIGNAL(signalTextChanged(const TQString&)), + d->view, TQ_SLOT(slotSearchTextChanged(const TQString&))); + + connect(d->view, TQ_SIGNAL(signalTextFilterMatch(bool)), + d->searchBar, TQ_SLOT(slotSearchResult(bool))); +} + +MetadataWidget::~MetadataWidget() +{ + delete d; +} + +MetadataListView* MetadataWidget::view() +{ + return d->view; +} + +void MetadataWidget::enabledToolButtons(bool b) +{ + d->toolButtons->setEnabled(b); +} + +bool MetadataWidget::setMetadata(const TQByteArray& data) +{ + d->metadata = data; + + // Cleanup all metadata contents. + setMetadataMap(); + + if (d->metadata.isEmpty()) + { + setMetadataEmpty(); + return false; + } + + // Try to decode current metadata. + if (decodeMetadata()) + enabledToolButtons(true); + else + enabledToolButtons(false); + + // Refresh view using decoded metadata. + buildView(); + + return true; +} + +void MetadataWidget::setMetadataEmpty() +{ + d->view->clear(); + enabledToolButtons(false); +} + +const TQByteArray& MetadataWidget::getMetadata() +{ + return d->metadata; +} + +bool MetadataWidget::storeMetadataToFile(const KURL& url) +{ + if( url.isEmpty() ) + return false; + + TQFile file(url.path()); + if ( !file.open(IO_WriteOnly) ) + return false; + + TQDataStream stream( &file ); + stream.writeRawBytes(d->metadata.data(), d->metadata.size()); + file.close(); + return true; +} + +void MetadataWidget::setMetadataMap(const DMetadata::MetaDataMap& data) +{ + d->metaDataMap = data; +} + +const DMetadata::MetaDataMap& MetadataWidget::getMetadataMap() +{ + return d->metaDataMap; +} + +void MetadataWidget::setIfdList(const DMetadata::MetaDataMap &ifds, const TQStringList& tagsFilter) +{ + d->view->setIfdList(ifds, tagsFilter); +} + +void MetadataWidget::setIfdList(const DMetadata::MetaDataMap &ifds, const TQStringList& keysFilter, + const TQStringList& tagsFilter) +{ + d->view->setIfdList(ifds, keysFilter, tagsFilter); +} + +void MetadataWidget::slotModeChanged(int) +{ + buildView(); +} + +void MetadataWidget::slotCopy2Clipboard() +{ + TQString textmetadata = i18n("File name: %1 (%2)").arg(d->fileName).arg(getMetadataTitle()); + TQListViewItemIterator it( d->view ); + + while ( it.current() ) + { + if ( !it.current()->isSelectable() ) + { + MdKeyListViewItem *item = dynamic_cast<MdKeyListViewItem *>(it.current()); + textmetadata.append("\n\n>>> "); + textmetadata.append(item->getMdKey()); + textmetadata.append(" <<<\n\n"); + } + else + { + TQListViewItem *item = it.current(); + textmetadata.append(item->text(0)); + textmetadata.append(" : "); + textmetadata.append(item->text(1)); + textmetadata.append("\n"); + } + + ++it; + } + + TQApplication::clipboard()->setData(new TQTextDrag(textmetadata), TQClipboard::Clipboard); +} + +void MetadataWidget::slotPrintMetadata() +{ + TQString textmetadata = i18n("<p><big><big><b>File name: %1 (%2)</b></big></big>") + .arg(d->fileName) + .arg(getMetadataTitle()); + TQListViewItemIterator it( d->view ); + + while ( it.current() ) + { + if ( !it.current()->isSelectable() ) + { + MdKeyListViewItem *item = dynamic_cast<MdKeyListViewItem *>(it.current()); + textmetadata.append("<br><br><b>"); + textmetadata.append(item->getMdKey()); + textmetadata.append("</b><br><br>"); + } + else + { + TQListViewItem *item = it.current(); + textmetadata.append(item->text(0)); + textmetadata.append(" : <i>"); + textmetadata.append(item->text(1)); + textmetadata.append("</i><br>"); + } + + ++it; + } + + textmetadata.append("</p>"); + + KPrinter printer; + printer.setFullPage( true ); + + if ( printer.setup( this ) ) + { + TQPainter p( &printer ); + + if ( !p.device() ) + return; + + TQPaintDeviceMetrics metrics(p.device()); + int dpiy = metrics.logicalDpiY(); + int margin = (int) ( (2/2.54)*dpiy ); // 2 cm margins + TQRect view( margin, margin, metrics.width() - 2*margin, metrics.height() - 2*margin ); + TQFont font(TDEApplication::font()); + font.setPointSize( 10 ); // we define 10pt to be a nice base size for printing + TQSimpleRichText richText( textmetadata, font, + TQString(), + TQStyleSheet::defaultSheet(), + TQMimeSourceFactory::defaultFactory(), + view.height() ); + richText.setWidth( &p, view.width() ); + int page = 1; + + do + { + richText.draw( &p, margin, margin, view, colorGroup() ); + view.moveBy( 0, view.height() ); + p.translate( 0 , -view.height() ); + p.setFont( font ); + p.drawText( view.right() - p.fontMetrics().width( TQString::number( page ) ), + view.bottom() + p.fontMetrics().ascent() + 5, TQString::number( page ) ); + + if ( view.top() - margin >= richText.height() ) + break; + + printer.newPage(); + page++; + } + while (true); + } +} + +KURL MetadataWidget::saveMetadataToFile(const TQString& caption, const TQString& fileFilter) +{ + KFileDialog fileSaveDialog(TDEGlobalSettings::documentPath(), + TQString(), + this, + "MetadataFileSaveDialog", + false); + + fileSaveDialog.setOperationMode(KFileDialog::Saving); + fileSaveDialog.setMode(KFile::File); + fileSaveDialog.setSelection(d->fileName); + fileSaveDialog.setCaption(caption); + fileSaveDialog.setFilter(fileFilter); + + // Check for cancel. + if ( fileSaveDialog.exec() == KFileDialog::Accepted ) + return fileSaveDialog.selectedURL().path(); + + return KURL(); +} + +void MetadataWidget::setMode(int mode) +{ + if (d->levelButtons->selectedId() == mode) + return; + + d->levelButtons->setButton(mode); + buildView(); +} + +int MetadataWidget::getMode() +{ + int level = d->levelButtons->selectedId(); + return level; +} + +TQString MetadataWidget::getCurrentItemKey() const +{ + return d->view->getCurrentItemKey(); +} + +void MetadataWidget::setCurrentItemByKey(const TQString& itemKey) +{ + d->view->setCurrentItemByKey(itemKey); +} + +bool MetadataWidget::loadFromData(const TQString& fileName, const TQByteArray& data) +{ + setFileName(fileName); + return(setMetadata(data)); +} + +TQString MetadataWidget::getTagTitle(const TQString&) +{ + return TQString(); +} + +TQString MetadataWidget::getTagDescription(const TQString&) +{ + return TQString(); +} + +void MetadataWidget::setFileName(const TQString& fileName) +{ + d->fileName = fileName; +} + +void MetadataWidget::setUserAreaWidget(TQWidget *w) +{ + TQVBoxLayout *vLayout = new TQVBoxLayout( KDialog::spacingHint() ); + vLayout->addWidget(w); + vLayout->addStretch(); + d->mainLayout->addMultiCellLayout(vLayout, 3, 3, 0, 4); +} + +void MetadataWidget::buildView() +{ + d->view->slotSearchTextChanged(d->searchBar->text()); +} + +} // namespace Digikam diff --git a/src/libs/widgets/metadata/metadatawidget.h b/src/libs/widgets/metadata/metadatawidget.h new file mode 100644 index 00000000..5d2feb64 --- /dev/null +++ b/src/libs/widgets/metadata/metadatawidget.h @@ -0,0 +1,120 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2006-02-22 + * Description : a generic widget to display metadata + * + * Copyright (C) 2006-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. + * + * ============================================================ */ + +#ifndef METADATAWIDGET_H +#define METADATAWIDGET_H + +// TQt includes. + +#include <tqwidget.h> +#include <tqstring.h> + +// KDE includes. + +#include <kurl.h> + +// Local includes. + +#include "dmetadata.h" +#include "digikam_export.h" + +namespace Digikam +{ + +class MetadataListView; +class MetadataWidgetPriv; + +class DIGIKAM_EXPORT MetadataWidget : public TQWidget +{ + TQ_OBJECT + + +public: + + enum Mode + { + SIMPLE=0, + FULL + }; + +public: + + MetadataWidget(TQWidget* parent, const char* name=0); + ~MetadataWidget(); + + int getMode(); + void setMode(int mode); + + TQString getCurrentItemKey() const; + void setCurrentItemByKey(const TQString& itemKey); + + void setUserAreaWidget(TQWidget *w); + + virtual TQString getTagTitle(const TQString& key); + virtual TQString getTagDescription(const TQString& key); + + virtual bool loadFromData(const TQString &fileName, const TQByteArray& data=TQByteArray()); + virtual bool loadFromURL(const KURL& url)=0; + +private slots: + + void slotModeChanged(int); + void slotCopy2Clipboard(); + void slotPrintMetadata(); + +protected slots: + + virtual void slotSaveMetadataToFile()=0; + +protected: + + void enabledToolButtons(bool); + void setFileName(const TQString& fileName); + MetadataListView* view(); + + bool setMetadata(const TQByteArray& data=TQByteArray()); + const TQByteArray& getMetadata(); + + void setMetadataMap(const DMetadata::MetaDataMap& data=DMetadata::MetaDataMap()); + const DMetadata::MetaDataMap& getMetadataMap(); + + void setIfdList(const DMetadata::MetaDataMap &ifds, const TQStringList& tagsFilter=TQStringList()); + void setIfdList(const DMetadata::MetaDataMap &ifds, const TQStringList& keysFilter, + const TQStringList& tagsFilter); + + KURL saveMetadataToFile(const TQString& caption, const TQString& fileFilter); + bool storeMetadataToFile(const KURL& url); + + virtual void buildView(); + virtual bool decodeMetadata()=0; + virtual TQString getMetadataTitle()=0; + virtual void setMetadataEmpty(); + +private: + + MetadataWidgetPriv* d; +}; + +} // namespace Digikam + +#endif /* METADATAWIDGET_H */ diff --git a/src/libs/widgets/metadata/worldmapwidget.cpp b/src/libs/widgets/metadata/worldmapwidget.cpp new file mode 100644 index 00000000..811e9148 --- /dev/null +++ b/src/libs/widgets/metadata/worldmapwidget.cpp @@ -0,0 +1,211 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2006-02-20 + * Description : a widget to display GPS info on a world map + * + * Copyright (C) 2006-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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqpainter.h> +#include <tqstring.h> +#include <tqpixmap.h> +#include <tqlabel.h> + +// KDE includes. + +#include <kstandarddirs.h> +#include <kcursor.h> +#include <tdelocale.h> +#include <kstaticdeleter.h> + +// Local includes. + +#include "ddebug.h" +#include "worldmapwidget.h" +#include "worldmapwidget.moc" + +namespace Digikam +{ + +class WorldMapWidgetPriv +{ + +public: + + WorldMapWidgetPriv() + { + latitude = 0; + longitude = 0; + latLonPos = 0; + } + + int xPos; + int yPos; + int xMousePos; + int yMousePos; + + double latitude; + double longitude; + + TQLabel *latLonPos; + + static TQPixmap *worldMap; +}; + +static KStaticDeleter<TQPixmap> pixmapDeleter; + +TQPixmap *WorldMapWidgetPriv::worldMap = 0; + +WorldMapWidget::WorldMapWidget(int w, int h, TQWidget *parent) + : TQScrollView(parent, 0, TQt::WDestructiveClose) +{ + d = new WorldMapWidgetPriv; + + setVScrollBarMode(TQScrollView::AlwaysOff); + setHScrollBarMode(TQScrollView::AlwaysOff); + viewport()->setMouseTracking(true); + viewport()->setPaletteBackgroundColor(colorGroup().background()); + setMinimumWidth(w); + setMaximumHeight(h); + resizeContents(worldMapPixmap().width(), worldMapPixmap().height()); + + d->latLonPos = new TQLabel(viewport()); + d->latLonPos->setMaximumHeight(fontMetrics().height()); + d->latLonPos->setAlignment(TQt::AlignHCenter | TQt::AlignVCenter); + d->latLonPos->setFrameStyle(TQFrame::Panel | TQFrame::Sunken); + addChild(d->latLonPos); +} + +WorldMapWidget::~WorldMapWidget() +{ + delete d; +} + +TQPixmap &WorldMapWidget::worldMapPixmap() +{ + if (!d->worldMap) + { + TDEGlobal::dirs()->addResourceType("worldmap", TDEGlobal::dirs()->kde_default("data") + "digikam/data"); + TQString directory = TDEGlobal::dirs()->findResourceDir("worldmap", "worldmap.jpg"); + pixmapDeleter.setObject(d->worldMap, new TQPixmap(directory + "worldmap.jpg")); + } + return *d->worldMap; +} + +double WorldMapWidget::getLatitude() +{ + return d->latitude; +} + +double WorldMapWidget::getLongitude() +{ + return d->longitude; +} + +void WorldMapWidget::setEnabled(bool b) +{ + if (!b) + d->latLonPos->hide(); + else + d->latLonPos->show(); + + TQScrollView::setEnabled(b); +} + +void WorldMapWidget::setGPSPosition(double lat, double lng) +{ + d->latitude = lat; + d->longitude = lng; + + double latMid = contentsHeight() / 2.0; + double longMid = contentsWidth() / 2.0; + + double latOffset = ( d->latitude * latMid ) / 90.0; + double longOffset = ( d->longitude * longMid ) / 180.0; + + d->xPos = (int)(longMid + longOffset); + d->yPos = (int)(latMid - latOffset); + + repaintContents(false); + center(d->xPos, d->yPos); + + TQString la, lo; + d->latLonPos->setText(TQString("(%1, %2)").arg(la.setNum(d->latitude, 'f', 2)) + .arg(lo.setNum(d->longitude, 'f', 2))); + + moveChild(d->latLonPos, contentsX()+10, contentsY()+10); +} + +void WorldMapWidget::drawContents(TQPainter *p, int x, int y, int w, int h) +{ + if (isEnabled()) + { + p->drawPixmap(x, y, worldMapPixmap(), x, y, w, h); + p->setPen(TQPen(TQt::white, 0, TQt::SolidLine)); + p->drawLine(d->xPos, 0, d->xPos, contentsHeight()); + p->drawLine(0, d->yPos, contentsWidth(), d->yPos); + p->setPen(TQPen(TQt::red, 0, TQt::DotLine)); + p->drawLine(d->xPos, 0, d->xPos, contentsHeight()); + p->drawLine(0, d->yPos, contentsWidth(), d->yPos); + p->setPen( TQt::red ); + p->setBrush( TQt::red ); + p->drawEllipse( d->xPos-2, d->yPos-2, 4, 4 ); + } + else + { + p->fillRect(x, y, w, h, palette().disabled().background()); + } +} + +void WorldMapWidget::contentsMousePressEvent ( TQMouseEvent * e ) +{ + if ( e->button() == TQt::LeftButton ) + { + d->xMousePos = e->x(); + d->yMousePos = e->y(); + setCursor( KCursor::sizeAllCursor() ); + } +} + +void WorldMapWidget::contentsMouseReleaseEvent ( TQMouseEvent * ) +{ + unsetCursor(); +} + +void WorldMapWidget::contentsMouseMoveEvent( TQMouseEvent * e ) +{ + if ( e->state() == TQt::LeftButton ) + { + uint newxpos = e->x(); + uint newypos = e->y(); + + scrollBy (-(newxpos - d->xMousePos), -(newypos - d->yMousePos)); + repaintContents(false); + + d->xMousePos = newxpos - (newxpos-d->xMousePos); + d->yMousePos = newypos - (newypos-d->yMousePos); + return; + } + + setCursor( KCursor::handCursor() ); +} + +} // namespace Digikam + diff --git a/src/libs/widgets/metadata/worldmapwidget.h b/src/libs/widgets/metadata/worldmapwidget.h new file mode 100644 index 00000000..bfb8ad8f --- /dev/null +++ b/src/libs/widgets/metadata/worldmapwidget.h @@ -0,0 +1,73 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2006-02-20 + * Description : a widget to display GPS info on a world map + * + * Copyright (C) 2006-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. + * + * ============================================================ */ + +#ifndef WORLDMAPWIDGET_H +#define WORLDMAPWIDGET_H + +// TQt includes. + +#include <tqscrollview.h> + +// Local includes. + +#include "digikam_export.h" + +namespace Digikam +{ + +class WorldMapWidgetPriv; + +class DIGIKAM_EXPORT WorldMapWidget : public TQScrollView +{ +TQ_OBJECT + + +public: + + WorldMapWidget(int w, int h, TQWidget *parent); + ~WorldMapWidget(); + + void setGPSPosition(double lat, double lng); + + double getLatitude(); + double getLongitude(); + void setEnabled(bool); + +private: + + void drawContents(TQPainter *p, int x, int y, int w, int h); + void contentsMousePressEvent ( TQMouseEvent * e ); + void contentsMouseReleaseEvent ( TQMouseEvent * e ); + void contentsMouseMoveEvent( TQMouseEvent * e ); + + TQPixmap &worldMapPixmap(); + +private: + + WorldMapWidgetPriv *d; + +}; + +} // namespace Digikam + +#endif /* WORLDMAPWIDGET_H */ |