You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
digikam/digikam/libs/widgets/common/histogramwidget.cpp

1090 lines
37 KiB

/* ============================================================
*
* 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