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
231 KisGenericRGBHistogramProducerFactory f;
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"
TQString name() const
User-friendly name for this channel for presentation purposes in the gui.
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.
Chalk has a large number of extensible resources.
Definition kis_id.h:57