diff options
Diffstat (limited to 'src/libs/widgets/common')
35 files changed, 7063 insertions, 0 deletions
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 <markey@web.de> + * 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 <markey@web.de> + * 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 <joern.ahrens@kdemail.net> + * 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 <joern.ahrens@kdemail.net> + * 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 <renchi@pooh.tam.uiuc.edu> + * 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 <renchi@pooh.tam.uiuc.edu> + * 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 <tomalbers@kde.nl> + * 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 <tomalbers@kde.nl> + * 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 */ |