diff options
Diffstat (limited to 'src/libs/widgets/common/histogramwidget.cpp')
-rw-r--r-- | src/libs/widgets/common/histogramwidget.cpp | 1089 |
1 files changed, 1089 insertions, 0 deletions
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 |