/* ============================================================
 *
 * 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 <klocale.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, 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 *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, 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;
    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, 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;
    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(TQT_TQPAINTDEVICE(&pm), TQT_TQOBJECT(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(TQT_TQPAINTDEVICE(&anim), TQT_TQOBJECT(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(TQT_TQPAINTDEVICE(&pm), TQT_TQOBJECT(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(TQT_TQPAINTDEVICE(&pm), TQT_TQOBJECT(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(TQT_TQPAINTDEVICE(&pm), TQT_TQOBJECT(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
