diff options
Diffstat (limited to 'chalk/ui/kis_histogram_view.cc')
-rw-r--r-- | chalk/ui/kis_histogram_view.cc | 354 |
1 files changed, 354 insertions, 0 deletions
diff --git a/chalk/ui/kis_histogram_view.cc b/chalk/ui/kis_histogram_view.cc new file mode 100644 index 00000000..cc4fe59c --- /dev/null +++ b/chalk/ui/kis_histogram_view.cc @@ -0,0 +1,354 @@ +/* + * Copyright (c) 2005 Bart Coppens <kde@bartcoppens.be> + * + * 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 of the License, 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <math.h> + +#include <tqpainter.h> +#include <tqpixmap.h> +#include <tqlabel.h> +#include <tqcombobox.h> +#include <tqbuttongroup.h> +#include <tqpushbutton.h> +#include <tqscrollbar.h> + +#include <kdebug.h> + +#include "kis_channelinfo.h" +#include "kis_histogram.h" +#include "kis_global.h" +#include "kis_types.h" +#include "kis_layer.h" +#include "kis_colorspace.h" +#include "kis_histogram_view.h" +#include "kis_basic_histogram_producers.h" +#include "kis_paint_device.h" + +KisHistogramView::KisHistogramView(TQWidget *tqparent, const char *name, WFlags f) + : TQLabel(tqparent, name, f) +{ + // This is needed until we can computationally scale it well. Until then, this is needed + // And when we have it, it won't hurt to have it around + setScaledContents(true); + setFrameShape(TQFrame::Box); // Draw a box around ourselves +} + +KisHistogramView::~KisHistogramView() +{ +} + +void KisHistogramView::setPaintDevice(KisPaintDeviceSP dev) +{ + m_cs = dev->colorSpace(); + + setChannels(); // Sets m_currentProducer to the first in the list + + if (!m_currentProducer) + return; + + m_from = m_currentProducer->viewFrom(); + m_width = m_currentProducer->viewWidth(); + + m_histogram = new KisHistogram(dev, m_currentProducer, LINEAR); + + updateHistogram(); +} + +void KisHistogramView::setHistogram(KisHistogramSP histogram) +{ + m_cs = 0; + m_histogram = histogram; + m_currentProducer = m_histogram->producer(); + m_from = m_currentProducer->viewFrom(); + m_width = m_currentProducer->viewWidth(); + + m_comboInfo.clear(); + m_channelStrings.clear(); + m_channels.clear(); + m_channelToOffset.clear(); + + addProducerChannels(m_currentProducer); + + // Set the currently viewed channel: + m_color = false; + m_channels.append(m_comboInfo.at(1).channel); + m_channelToOffset.append(0); + + updateHistogram(); +} + +void KisHistogramView::setView(double from, double size) +{ + m_from = from; + m_width = size; + if (m_from + m_width > 1.0) + m_from = 1.0 - m_width; + m_histogram->producer()->setView(m_from, m_width); + + m_histogram->updateHistogram(); + updateHistogram(); +} + +KisHistogramProducerSP KisHistogramView::currentProducer() +{ + return m_currentProducer; +} + +TQStringList KisHistogramView::channelStrings() +{ + return m_channelStrings; +} + +KisIDList KisHistogramView::listProducers() +{ + if (m_cs) + return KisHistogramProducerFactoryRegistry::instance()->listKeysCompatibleWith(m_cs); + return KisIDList(); +} + +void KisHistogramView::setCurrentChannels(const KisID& producerID, TQValueVector<KisChannelInfo *> channels) +{ + setCurrentChannels( + KisHistogramProducerFactoryRegistry::instance()->get(producerID)->generate(), + channels); +} + +void KisHistogramView::setCurrentChannels(KisHistogramProducerSP producer, TQValueVector<KisChannelInfo *> channels) +{ + m_currentProducer = producer; + m_currentProducer->setView(m_from, m_width); + m_histogram->setProducer(m_currentProducer); + m_histogram->updateHistogram(); + m_histogram->setChannel(0); // Set a default channel, just being nice + + m_channels.clear(); + m_channelToOffset.clear(); + + if (channels.count() == 0) { + updateHistogram(); + return; + } + + TQValueVector<KisChannelInfo *> producerChannels = m_currentProducer->channels(); + + for (uint i = 0; i < channels.count(); i++) { + // Also makes sure the channel is actually in the producer's list + for (uint j = 0; j < producerChannels.count(); j++) { + if (channels.at(i)->name() == producerChannels.at(j)->name()) { + m_channelToOffset.append(m_channels.count()); // The first we append maps to 0 + m_channels.append(channels.at(i)); + } + } + } + + updateHistogram(); +} + +bool KisHistogramView::hasColor() +{ + return m_color; +} + +void KisHistogramView::setColor(bool set) +{ + if (set != m_color) { + m_color = set; + updateHistogram(); + } +} + +void KisHistogramView::setActiveChannel(int channel) +{ + ComboboxInfo info = m_comboInfo.at(channel); + if (info.producer.data() != m_currentProducer.data()) { + m_currentProducer = info.producer; + m_currentProducer->setView(m_from, m_width); + m_histogram->setProducer(m_currentProducer); + m_histogram->updateHistogram(); + } + + m_channels.clear(); + m_channelToOffset.clear(); + + if (!m_currentProducer) { + updateHistogram(); + return; + } + + if (info.isProducer) { + m_color = true; + m_channels = m_currentProducer->channels(); + for (uint i = 0; i < m_channels.count(); i++) + m_channelToOffset.append(i); + m_histogram->setChannel(0); // Set a default channel, just being nice + } else { + m_color = false; + TQValueVector<KisChannelInfo *> channels = m_currentProducer->channels(); + for (uint i = 0; i < channels.count(); i++) { + KisChannelInfo* channel = channels.at(i); + if (channel->name() == info.channel->name()) { + m_channels.append(channel); + m_channelToOffset.append(i); + break; + } + } + } + + updateHistogram(); +} + +void KisHistogramView::setHistogramType(enumHistogramType type) +{ + m_histogram->setHistogramType(type); + updateHistogram(); +} + +void KisHistogramView::setChannels() +{ + m_comboInfo.clear(); + m_channelStrings.clear(); + m_channels.clear(); + m_channelToOffset.clear(); + + KisIDList list = KisHistogramProducerFactoryRegistry::instance()->listKeysCompatibleWith(m_cs); + + if (list.count() == 0) { + // XXX: No native histogram for this colorspace. Using converted RGB. We should have a warning + KisGenericRGBHistogramProducerFactory f; + addProducerChannels(f.generate()); + } else { + for (uint i = 0; i < list.count(); i++) { + KisID id(*(list.at(i))); + addProducerChannels( KisHistogramProducerFactoryRegistry::instance()->get(id)->generate() ); + } + } + + m_currentProducer = m_comboInfo.at(0).producer; + m_color = false; + // The currently displayed channel and its offset + m_channels.append(m_comboInfo.at(1).channel); + m_channelToOffset.append(0); +} + +void KisHistogramView::addProducerChannels(KisHistogramProducerSP producer) { + ComboboxInfo info; + info.isProducer = true; + info.producer = producer; + // channel not used for a producer + TQValueVector<KisChannelInfo *> channels = info.producer->channels(); + int count = channels.count(); + m_comboInfo.append(info); + m_channelStrings.append(producer->id() . name()); + for (int j = 0; j < count; j++) { + info.isProducer = false; + info.channel = channels.at(j); + m_comboInfo.append(info); + m_channelStrings.append(TQString(" ").append(info.channel->name())); + } +} + +void KisHistogramView::updateHistogram() +{ + TQ_UINT32 height = this->height(); + int selFrom, selTo; // from - to in bins + + if (!m_currentProducer) { // Something's very wrong: no producer for this colorspace to update histogram with! + return; + } + + TQ_INT32 bins = m_histogram->producer()->numberOfBins(); + m_pix = TQPixmap(bins, height); + m_pix.fill(); + TQPainter p(&m_pix); + p.setBrush(TQt::black); + + // Draw the box of the selection, if any + if (m_histogram->hasSelection()) { + double width = m_histogram->selectionTo() - m_histogram->selectionFrom(); + double factor = static_cast<double>(bins) / m_histogram->producer()->viewWidth(); + selFrom = static_cast<int>(m_histogram->selectionFrom() * factor); + selTo = selFrom + static_cast<int>(width * factor); + p.drawRect(selFrom, 0, selTo - selFrom, height); + } else { + // We don't want the drawing to think we're in a selected area + selFrom = -1; + selTo = 2; + } + + TQ_INT32 i = 0; + double highest = 0; + bool blackOnBlack = false; + + // First we iterate once, so that we have the overall maximum. This is a bit inefficient, + // but not too much since the histogram caches the calculations + for (uint chan = 0; chan < m_channels.count(); chan++) { + m_histogram->setChannel(m_channelToOffset.at(chan)); + if ((double)m_histogram->calculations().getHighest() > highest) + highest = (double)m_histogram->calculations().getHighest(); + } + + for (uint chan = 0; chan < m_channels.count(); chan++) { + TQColor color; + m_histogram->setChannel(m_channelToOffset.at(chan)); + + if (m_color) { + color = m_channels.at(chan)->color(); + p.setPen(color); + } else { + color = TQt::black; + } + blackOnBlack = (color == TQt::black); + + if (m_histogram->getHistogramType() == LINEAR) { + double factor = (double)height / highest; + for( i=0; i<bins; ++i ) { + // So that we get a good view even with a selection box with + // black colors on background of black selection + if (i >= selFrom && i < selTo && blackOnBlack) { + p.setPen(TQt::white); + } else { + p.setPen(color); + } + p.drawLine(i, height, i, height - int(m_histogram->getValue(i) * factor)); + } + } else { + double factor = (double)height / (double)log(highest); + for( i = 0; i < bins; ++i ) { + // Same as above + if (i >= selFrom && i < selTo && blackOnBlack) { + p.setPen(TQt::white); + } else { + p.setPen(color); + } + p.drawLine(i, height, i, + height - int(log((double)m_histogram->getValue(i)) * factor)); + } + } + } + + setPixmap(m_pix); +} + +void KisHistogramView::mousePressEvent(TQMouseEvent * e) { + if (e->button() == Qt::RightButton) + emit rightClicked(e->globalPos()); + else + TQLabel::mousePressEvent(e); +} + + +#include "kis_histogram_view.moc" |