chalk

kis_histogram_view.cpp
1/*
2 * Copyright (c) 2005 Bart Coppens <kde@bartcoppens.be>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19#include <math.h>
20
21#include <tqpainter.h>
22#include <tqpixmap.h>
23#include <tqlabel.h>
24#include <tqcombobox.h>
25#include <tqbuttongroup.h>
26#include <tqpushbutton.h>
27#include <tqscrollbar.h>
28
29#include <kdebug.h>
30
31#include "kis_channelinfo.h"
32#include "kis_histogram.h"
33#include "kis_global.h"
34#include "kis_types.h"
35#include "kis_layer.h"
36#include "kis_colorspace.h"
37#include "kis_histogram_view.h"
38#include "kis_basic_histogram_producers.h"
39#include "kis_paint_device.h"
40
41KisHistogramView::KisHistogramView(TQWidget *parent, const char *name, WFlags f)
42 : TQLabel(parent, name, f)
43{
44 // This is needed until we can computationally scale it well. Until then, this is needed
45 // And when we have it, it won't hurt to have it around
46 setScaledContents(true);
47 setFrameShape(TQFrame::Box); // Draw a box around ourselves
48}
49
50KisHistogramView::~KisHistogramView()
51{
52}
53
54void KisHistogramView::setPaintDevice(KisPaintDeviceSP dev)
55{
56 m_cs = dev->colorSpace();
57
58 setChannels(); // Sets m_currentProducer to the first in the list
59
60 if (!m_currentProducer)
61 return;
62
63 m_from = m_currentProducer->viewFrom();
64 m_width = m_currentProducer->viewWidth();
65
66 m_histogram = new KisHistogram(dev, m_currentProducer, LINEAR);
67
68 updateHistogram();
69}
70
71void KisHistogramView::setHistogram(KisHistogramSP histogram)
72{
73 m_cs = 0;
74 m_histogram = histogram;
75 m_currentProducer = m_histogram->producer();
76 m_from = m_currentProducer->viewFrom();
77 m_width = m_currentProducer->viewWidth();
78
79 m_comboInfo.clear();
80 m_channelStrings.clear();
81 m_channels.clear();
82 m_channelToOffset.clear();
83
84 addProducerChannels(m_currentProducer);
85
86 // Set the currently viewed channel:
87 m_color = false;
88 m_channels.append(m_comboInfo.at(1).channel);
89 m_channelToOffset.append(0);
90
91 updateHistogram();
92}
93
94void KisHistogramView::setView(double from, double size)
95{
96 m_from = from;
97 m_width = size;
98 if (m_from + m_width > 1.0)
99 m_from = 1.0 - m_width;
100 m_histogram->producer()->setView(m_from, m_width);
101
102 m_histogram->updateHistogram();
103 updateHistogram();
104}
105
106KisHistogramProducerSP KisHistogramView::currentProducer()
107{
108 return m_currentProducer;
109}
110
111TQStringList KisHistogramView::channelStrings()
112{
113 return m_channelStrings;
114}
115
117{
118 if (m_cs)
119 return KisHistogramProducerFactoryRegistry::instance()->listKeysCompatibleWith(m_cs);
120 return KisIDList();
121}
122
123void KisHistogramView::setCurrentChannels(const KisID& producerID, TQValueVector<KisChannelInfo *> channels)
124{
126 KisHistogramProducerFactoryRegistry::instance()->get(producerID)->generate(),
127 channels);
128}
129
130void KisHistogramView::setCurrentChannels(KisHistogramProducerSP producer, TQValueVector<KisChannelInfo *> channels)
131{
132 m_currentProducer = producer;
133 m_currentProducer->setView(m_from, m_width);
134 m_histogram->setProducer(m_currentProducer);
135 m_histogram->updateHistogram();
136 m_histogram->setChannel(0); // Set a default channel, just being nice
137
138 m_channels.clear();
139 m_channelToOffset.clear();
140
141 if (channels.count() == 0) {
142 updateHistogram();
143 return;
144 }
145
146 TQValueVector<KisChannelInfo *> producerChannels = m_currentProducer->channels();
147
148 for (uint i = 0; i < channels.count(); i++) {
149 // Also makes sure the channel is actually in the producer's list
150 for (uint j = 0; j < producerChannels.count(); j++) {
151 if (channels.at(i)->name() == producerChannels.at(j)->name()) {
152 m_channelToOffset.append(m_channels.count()); // The first we append maps to 0
153 m_channels.append(channels.at(i));
154 }
155 }
156 }
157
158 updateHistogram();
159}
160
161bool KisHistogramView::hasColor()
162{
163 return m_color;
164}
165
166void KisHistogramView::setColor(bool set)
167{
168 if (set != m_color) {
169 m_color = set;
170 updateHistogram();
171 }
172}
173
174void KisHistogramView::setActiveChannel(int channel)
175{
176 ComboboxInfo info = m_comboInfo.at(channel);
177 if (info.producer.data() != m_currentProducer.data()) {
178 m_currentProducer = info.producer;
179 m_currentProducer->setView(m_from, m_width);
180 m_histogram->setProducer(m_currentProducer);
181 m_histogram->updateHistogram();
182 }
183
184 m_channels.clear();
185 m_channelToOffset.clear();
186
187 if (!m_currentProducer) {
188 updateHistogram();
189 return;
190 }
191
192 if (info.isProducer) {
193 m_color = true;
194 m_channels = m_currentProducer->channels();
195 for (uint i = 0; i < m_channels.count(); i++)
196 m_channelToOffset.append(i);
197 m_histogram->setChannel(0); // Set a default channel, just being nice
198 } else {
199 m_color = false;
200 TQValueVector<KisChannelInfo *> channels = m_currentProducer->channels();
201 for (uint i = 0; i < channels.count(); i++) {
202 KisChannelInfo* channel = channels.at(i);
203 if (channel->name() == info.channel->name()) {
204 m_channels.append(channel);
205 m_channelToOffset.append(i);
206 break;
207 }
208 }
209 }
210
211 updateHistogram();
212}
213
214void KisHistogramView::setHistogramType(enumHistogramType type)
215{
216 m_histogram->setHistogramType(type);
217 updateHistogram();
218}
219
220void KisHistogramView::setChannels()
221{
222 m_comboInfo.clear();
223 m_channelStrings.clear();
224 m_channels.clear();
225 m_channelToOffset.clear();
226
227 KisIDList list = KisHistogramProducerFactoryRegistry::instance()->listKeysCompatibleWith(m_cs);
228
229 if (list.count() == 0) {
230 // XXX: No native histogram for this colorspace. Using converted RGB. We should have a warning
232 addProducerChannels(f.generate());
233 } else {
234 for (uint i = 0; i < list.count(); i++) {
235 KisID id(*(list.at(i)));
236 addProducerChannels( KisHistogramProducerFactoryRegistry::instance()->get(id)->generate() );
237 }
238 }
239
240 m_currentProducer = m_comboInfo.at(0).producer;
241 m_color = false;
242 // The currently displayed channel and its offset
243 m_channels.append(m_comboInfo.at(1).channel);
244 m_channelToOffset.append(0);
245}
246
247void KisHistogramView::addProducerChannels(KisHistogramProducerSP producer) {
248 ComboboxInfo info;
249 info.isProducer = true;
250 info.producer = producer;
251 // channel not used for a producer
252 TQValueVector<KisChannelInfo *> channels = info.producer->channels();
253 int count = channels.count();
254 m_comboInfo.append(info);
255 m_channelStrings.append(producer->id() . name());
256 for (int j = 0; j < count; j++) {
257 info.isProducer = false;
258 info.channel = channels.at(j);
259 m_comboInfo.append(info);
260 m_channelStrings.append(TQString(" ").append(info.channel->name()));
261 }
262}
263
264void KisHistogramView::updateHistogram()
265{
266 TQ_UINT32 height = this->height();
267 int selFrom, selTo; // from - to in bins
268
269 if (!m_currentProducer) { // Something's very wrong: no producer for this colorspace to update histogram with!
270 return;
271 }
272
273 TQ_INT32 bins = m_histogram->producer()->numberOfBins();
274 m_pix = TQPixmap(bins, height);
275 m_pix.fill();
276 TQPainter p(&m_pix);
277 p.setBrush(TQt::black);
278
279 // Draw the box of the selection, if any
280 if (m_histogram->hasSelection()) {
281 double width = m_histogram->selectionTo() - m_histogram->selectionFrom();
282 double factor = static_cast<double>(bins) / m_histogram->producer()->viewWidth();
283 selFrom = static_cast<int>(m_histogram->selectionFrom() * factor);
284 selTo = selFrom + static_cast<int>(width * factor);
285 p.drawRect(selFrom, 0, selTo - selFrom, height);
286 } else {
287 // We don't want the drawing to think we're in a selected area
288 selFrom = -1;
289 selTo = 2;
290 }
291
292 TQ_INT32 i = 0;
293 double highest = 0;
294 bool blackOnBlack = false;
295
296 // First we iterate once, so that we have the overall maximum. This is a bit inefficient,
297 // but not too much since the histogram caches the calculations
298 for (uint chan = 0; chan < m_channels.count(); chan++) {
299 m_histogram->setChannel(m_channelToOffset.at(chan));
300 if ((double)m_histogram->calculations().getHighest() > highest)
301 highest = (double)m_histogram->calculations().getHighest();
302 }
303
304 for (uint chan = 0; chan < m_channels.count(); chan++) {
305 TQColor color;
306 m_histogram->setChannel(m_channelToOffset.at(chan));
307
308 if (m_color) {
309 color = m_channels.at(chan)->color();
310 p.setPen(color);
311 } else {
312 color = TQt::black;
313 }
314 blackOnBlack = (color == TQt::black);
315
316 if (m_histogram->getHistogramType() == LINEAR) {
317 double factor = (double)height / highest;
318 for( i=0; i<bins; ++i ) {
319 // So that we get a good view even with a selection box with
320 // black colors on background of black selection
321 if (i >= selFrom && i < selTo && blackOnBlack) {
322 p.setPen(TQt::white);
323 } else {
324 p.setPen(color);
325 }
326 p.drawLine(i, height, i, height - int(m_histogram->getValue(i) * factor));
327 }
328 } else {
329 double factor = (double)height / (double)log(highest);
330 for( i = 0; i < bins; ++i ) {
331 // Same as above
332 if (i >= selFrom && i < selTo && blackOnBlack) {
333 p.setPen(TQt::white);
334 } else {
335 p.setPen(color);
336 }
337 p.drawLine(i, height, i,
338 height - int(log((double)m_histogram->getValue(i)) * factor));
339 }
340 }
341 }
342
343 setPixmap(m_pix);
344}
345
346void KisHistogramView::mousePressEvent(TQMouseEvent * e) {
347 if (e->button() == TQt::RightButton)
348 emit rightClicked(e->globalPos());
349 else
350 TQLabel::mousePressEvent(e);
351}
352
353
354#include "kis_histogram_view.moc"
This class gives some basic information about a channel, that is, one of the components that makes up...
TQString name() const
User-friendly name for this channel for presentation purposes in the gui.
KisGenericRGBHistogramProducer his special Factory that isCompatibleWith everything.
KisIDList listProducers()
Lists all producers currently available.
void setCurrentChannels(const KisID &producerID, TQValueVector< KisChannelInfo * > channels)
Sets the currently displayed channels to channels of the producer with producerID as ID.
The histogram class computes the histogram data from the specified layer for the specified channel,...
Chalk has a large number of extensible resources.
Definition kis_id.h:57