/* ============================================================ * * 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 * * 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 // TQt includes. #include #include #include #include #include #include #include #include #include #include #include // KDE includes. #include #include // 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 *tqparent, bool selectMode, bool showProgress, bool statisticsVisible) : TQWidget(tqparent, 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 *tqparent, bool selectMode, bool showProgress, bool statisticsVisible) : TQWidget(tqparent, 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, TQT_TQOBJECT(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 *tqparent, bool selectMode, bool showProgress, bool statisticsVisible) : TQWidget(tqparent, 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, TQT_TQOBJECT(this)); m_selectionHistogram = new ImageHistogram(s_data, s_w, s_h, i_sixteenBits, TQT_TQOBJECT(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, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotBlinkTimerDone()) ); } void HistogramWidget::setHistogramGuideByColor(const DColor& color) { d->guideVisible = true; d->colorGuide = color; tqrepaint(false); } void HistogramWidget::reset() { d->guideVisible = false; tqrepaint(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 tqrepaint wait, tqrepaint 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 tqrepaint, we can tqrepaint immediately tqrepaint(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 tqrepaint once afterwards. setUpdatesEnabled(false); notifyValuesChanged(); emit signalHistogramComputationDone(d->sixteenBits); setUpdatesEnabled(true); tqrepaint(false); } else { d->clearFlag = HistogramWidgetPriv::HistogramFailed; d->blinkTimer->stop(); d->inInitialRepaintWait = false; tqrepaint(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 tqrepaint wait, tqrepaint 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; tqrepaint(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, TQT_TQOBJECT(this)); if (s_data && s_w && s_h) m_selectionHistogram = new ImageHistogram(s_data, s_w, s_h, i_sixteenBits, TQT_TQOBJECT(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, TQT_TQOBJECT(this)); } void HistogramWidget::slotBlinkTimerDone() { d->inInitialRepaintWait = false; tqrepaint(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.tqbegin(TQT_TQPAINTDEVICE(&pm), TQT_TQOBJECT(this)); p1.fillRect(0, 0, size().width(), size().height(), tqpalette().disabled().background()); p1.setPen(TQPen(tqpalette().active().foreground(), 1, TQt::SolidLine)); p1.drawRect(0, 0, width(), height()); p1.setPen(TQPen(tqpalette().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.tqbegin(TQT_TQPAINTDEVICE(&anim), TQT_TQOBJECT(this)); p2.fillRect(0, 0, asize, asize, tqpalette().active().background()); p2.translate(asize/2, asize/2); d->pos = (d->pos + 10) % 360; p2.setPen(TQPen(tqpalette().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.tqbegin(TQT_TQPAINTDEVICE(&pm), TQT_TQOBJECT(this)); p1.fillRect(0, 0, width(), height(), tqpalette().active().background()); p1.setPen(TQPen(tqpalette().active().foreground(), 1, TQt::SolidLine)); p1.drawRect(0, 0, width(), height()); p1.drawPixmap(width()/2 - asize /2, asize, anim); p1.setPen(TQPen(tqpalette().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.tqbegin(TQT_TQPAINTDEVICE(&pm), TQT_TQOBJECT(this)); p1.fillRect(0, 0, width(), height(), tqpalette().active().background()); p1.setPen(TQPen(tqpalette().active().foreground(), 1, TQt::SolidLine)); p1.drawRect(0, 0, width(), height()); p1.setPen(TQPen(tqpalette().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.tqbegin(TQT_TQPAINTDEVICE(&pm), TQT_TQOBJECT(this)); p1.fillRect(0, 0, width(), height(), tqpalette().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(tqpalette().active().foreground(), 1, TQt::SolidLine)); p1.drawLine(x, wHeight, x, 0); p1.setPen(TQPen(tqpalette().active().background(), 1, TQt::SolidLine)); p1.drawLine(x, wHeight, x, wHeight - y); } else { p1.setPen(TQPen(tqpalette().active().foreground(), 1, TQt::SolidLine)); p1.drawLine(x, wHeight, x, wHeight - y); p1.setPen(TQPen(tqpalette().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(tqpalette().active().base(), 1, TQt::SolidLine)); p1.drawLine(x, wHeight, x, 0); } } } else { p1.setPen(TQPen(tqpalette().active().foreground(), 1, TQt::SolidLine)); p1.drawLine(x, wHeight, x, wHeight - y); p1.setPen(TQPen(tqpalette().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(tqpalette().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(tqpalette().active().foreground(), 1, TQt::SolidLine)); p1.drawLine(x, wHeight, x, 0); p1.setPen(TQPen(tqpalette().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(tqpalette().active().background(), 1, TQt::SolidLine)); p1.drawLine(x, wHeight - TQMAX(TQMAX(yr, yg), yb), x, 0); p1.setPen(TQPen(tqpalette().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(tqpalette().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(tqpalette().active().background(), 1, TQt::SolidLine)); p1.drawLine(x, wHeight - TQMAX(TQMAX(yr, yg), yb), x, 0); p1.setPen(TQPen(tqpalette().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(tqpalette().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(tqpalette().active().background(), 1, TQt::SolidLine)); p1.drawLine(x, wHeight - TQMAX(TQMAX(yr, yg), yb), x, 0); p1.setPen(TQPen(tqpalette().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(tqpalette().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(tqpalette().active().background(), 1, TQt::SolidLine)); p1.drawLine(x, wHeight - TQMAX(TQMAX(yr, yg), yb), x, 0); p1.setPen(TQPen(tqpalette().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(tqpalette().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(tqpalette().active().background(), 1, TQt::SolidLine)); p1.drawLine(x, wHeight - TQMAX(TQMAX(yr, yg), yb), x, 0); p1.setPen(TQPen(tqpalette().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(tqpalette().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(tqpalette().active().background(), 1, TQt::SolidLine)); p1.drawLine(x, wHeight - TQMAX(TQMAX(yr, yg), yb), x, 0); p1.setPen(TQPen(tqpalette().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(tqpalette().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").tqarg(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(""); TQString cellMid(""); TQString cellEnd(""); tipText = ""; 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 += "
"; TQToolTip::add( this, tipText); } p1.setPen(TQPen(tqpalette().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; tqrepaint(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(); tqrepaint(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) ); tqrepaint(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; } tqrepaint(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; } tqrepaint(false); } } } // namespace Digikam