Proper check for rawzor libraries.
[rawtherapee-fixes.git] / rtgui / histogrampanel.cc
blobc319d043f1b743c9bba8d8c1d9fb7c80d2543ecc
1 /*
2 * This file is part of RawTherapee.
4 * Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
6 * RawTherapee is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * RawTherapee is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with RawTherapee. If not, see <http://www.gnu.org/licenses/>.
19 #include <histogrampanel.h>
20 #include <multilangmgr.h>
22 HistogramPanel::HistogramPanel () {
24 histogramArea = Gtk::manage (new HistogramArea ());
25 showRed = Gtk::manage (new Gtk::ToggleButton ("R"));
26 showGreen = Gtk::manage (new Gtk::ToggleButton ("G"));
27 showBlue = Gtk::manage (new Gtk::ToggleButton ("B"));
28 showValue = Gtk::manage (new Gtk::ToggleButton ("L"));
29 Gtk::VBox* vbox = Gtk::manage (new Gtk::VBox (false, 0));
31 showRed->set_active (true);
32 showGreen->set_active (true);
33 showBlue->set_active (true);
34 showValue->set_active (true);
35 vbox->pack_start (*showRed, Gtk::PACK_SHRINK, 2);
36 vbox->pack_start (*showGreen, Gtk::PACK_SHRINK, 2);
37 vbox->pack_start (*showBlue, Gtk::PACK_SHRINK, 2);
38 vbox->pack_start (*showValue, Gtk::PACK_SHRINK, 2);
39 pack_start (*histogramArea);
40 pack_end (*vbox, Gtk::PACK_SHRINK, 2);
42 showRed->signal_toggled().connect( sigc::mem_fun(*this, &HistogramPanel::rgbv_toggled) );
43 showGreen->signal_toggled().connect( sigc::mem_fun(*this, &HistogramPanel::rgbv_toggled) );
44 showBlue->signal_toggled().connect( sigc::mem_fun(*this, &HistogramPanel::rgbv_toggled) );
45 showValue->signal_toggled().connect( sigc::mem_fun(*this, &HistogramPanel::rgbv_toggled) );
47 show_all ();
49 showRed->set_tooltip_text (M("HISTOGRAM_TOOLTIP_R"));
50 showGreen->set_tooltip_text (M("HISTOGRAM_TOOLTIP_G"));
51 showBlue->set_tooltip_text (M("HISTOGRAM_TOOLTIP_B"));
52 showValue->set_tooltip_text (M("HISTOGRAM_TOOLTIP_L"));
54 rconn = signal_size_allocate().connect( sigc::mem_fun(*this, &HistogramPanel::resized) );
57 void HistogramPanel::resized (Gtk::Allocation& req) {
59 rconn.block (true);
61 if (req.get_width()/2>150)
62 set_size_request (req.get_width(), 150);
63 else
64 set_size_request (req.get_width(), req.get_width()/2);
65 rconn.block (false);
66 histogramArea->renderHistogram ();
67 histogramArea->queue_draw ();
70 void HistogramPanel::rgbv_toggled () {
72 histogramArea->updateOptions (showRed->get_active(), showGreen->get_active(), showBlue->get_active(), showValue->get_active());
73 histogramArea->queue_draw ();
76 HistogramArea::HistogramArea () :
77 needVal(true), needRed(true), needGreen(true), needBlue(true), oldwidth(-1), valid(false), showFull(true) {
79 haih = new HistogramAreaIdleHelper;
80 haih->harea = this;
81 haih->destroyed = false;
82 haih->pending = 0;
84 signal_style_changed().connect( sigc::mem_fun(*this, &HistogramArea::styleChanged) );
87 HistogramArea::~HistogramArea () {
89 if (haih->pending)
90 haih->destroyed = true;
91 else
92 delete haih;
95 void HistogramArea::updateOptions (bool r, bool g, bool b, bool v) {
97 needRed = r;
98 needGreen = g;
99 needBlue = b;
100 needVal = v;
102 renderHistogram ();
105 int histupdate (void* data) {
107 gdk_threads_enter ();
109 HistogramAreaIdleHelper* haih = (HistogramAreaIdleHelper*)data;
111 if (haih->destroyed) {
112 if (haih->pending == 1)
113 delete haih;
114 else
115 haih->pending--;
116 gdk_threads_leave ();
117 return 0;
120 haih->harea->renderHistogram ();
121 haih->harea->queue_draw ();
123 haih->pending--;
124 gdk_threads_leave ();
125 return 0;
128 void HistogramArea::update (unsigned int* rh, unsigned int* gh, unsigned int* bh, unsigned int* lh) {
130 if (rh!=NULL) {
131 memcpy (lhist, lh, 256*sizeof(unsigned int));
132 memcpy (rhist, rh, 256*sizeof(unsigned int));
133 memcpy (ghist, gh, 256*sizeof(unsigned int));
134 memcpy (bhist, bh, 256*sizeof(unsigned int));
135 valid = true;
137 else
138 valid = false;
140 haih->pending++;
141 g_idle_add (histupdate, haih);
144 void HistogramArea::renderHistogram () {
146 if (!is_realized ())
147 return;
149 Glib::RefPtr<Gdk::Window> window = get_window();
150 int winx, winy, winw, winh, wind;
151 window->get_geometry(winx, winy, winw, winh, wind);
153 backBuffer = Gdk::Pixmap::create (window, winw, winh, -1);
155 Glib::RefPtr<Gdk::GC> bgc = Gdk::GC::create(backBuffer);
157 bgc->set_foreground (white);
158 backBuffer->draw_rectangle (bgc, true, 0, 0, winw, winh);
160 if (valid) {
162 // compute height of the full histogram (realheight) and
164 int fullhistheight = 0;
165 for (int i=0; i<256; i++) {
166 if (needVal && lhist[i]>fullhistheight)
167 fullhistheight = lhist[i];
168 if (needRed && rhist[i]>fullhistheight)
169 fullhistheight = rhist[i];
170 if (needGreen && ghist[i]>fullhistheight)
171 fullhistheight = ghist[i];
172 if (needBlue && bhist[i]>fullhistheight)
173 fullhistheight = bhist[i];
176 // compute two hights, one for the magnified view and one for the threshold
177 int realhistheight = fullhistheight;
179 if (!showFull) {
180 int area1thres = 0;
181 int area2thres = 0;
182 int area = 0;
183 for (int i=0; i<fullhistheight; i++) {
184 for (int j=0; j<256; j++)
185 if ((needVal && lhist[j]>i) || (needRed && rhist[j]>i) || (needGreen && ghist[j]>i) || (needBlue && bhist[j]>i))
186 area++;
187 if (area1thres==0 && (double)area / (256*(i+1)) < 0.3)
188 area1thres = i;
189 if (area2thres==0 && (double)area / (256*(i+1)) < 0.3)
190 area2thres = i;
191 if (area1thres && area2thres)
192 break;
194 if (area1thres>0 && area2thres>0 && area1thres<fullhistheight)
195 realhistheight = area2thres;
198 if (realhistheight<winh-2)
199 realhistheight = winh-2;
201 Cairo::RefPtr<Cairo::Context> cr = backBuffer->create_cairo_context();
202 cr->set_antialias (Cairo::ANTIALIAS_SUBPIXEL);
203 cr->set_line_width (1.0);
204 double stepSize = (winw-1) / 256.0;
205 if (needVal) {
206 cr->move_to (0, winh-1);
207 cr->set_source_rgb (0.75, 0.75, 0.75);
208 for (int i=0; i<256; i++) {
209 double val = lhist[i] * (double)(winh-2) / realhistheight;
210 if (val>winh-1)
211 val = winh-1;
212 if (i>0)
213 cr->line_to (i*stepSize, winh-1-val);
215 cr->save ();
216 cr->line_to (winw-1, winh-1); cr->fill_preserve ();
217 cr->restore ();
218 cr->set_source_rgb (0.5, 0.5, 0.5);
219 cr->stroke ();
221 if (needRed) {
222 cr->move_to (0, winh-1);
223 cr->set_source_rgb (1.0, 0.0, 0.0);
224 for (int i=0; i<256; i++) {
225 double val = rhist[i] * (double)(winh-2) / realhistheight;
226 if (val>winh-1)
227 val = winh-1;
228 if (i>0)
229 cr->line_to (i*stepSize, winh-1-val);
231 cr->stroke ();
233 if (needGreen) { cr->move_to (0, winh-1);
234 cr->set_source_rgb (0.0, 1.0, 0.0);
235 for (int i=0; i<256; i++) {
236 double val = ghist[i] * (double)(winh-2) / realhistheight;
237 if (val>winh-1)
238 val = winh-1;
239 if (i>0)
240 cr->line_to (i*stepSize, winh-1-val);
242 cr->stroke ();
244 if (needBlue) {
245 cr->move_to (0, winh-1);
246 cr->set_source_rgb (0.0, 0.0, 1.0);
247 for (int i=0; i<256; i++) {
248 int val = bhist[i] * (double)(winh-2) / realhistheight;
249 if (val>winh-1)
250 val = winh-1;
251 if (i>0)
252 cr->line_to (i*stepSize, winh-1-val);
254 cr->stroke ();
260 // scale histogram to width winw-1
262 int* vval = new int[winw-1];
263 int* vred = new int[winw-1];
264 int* vgreen = new int[winw-1];
265 int* vblue = new int[winw-1];
267 memset (vval, 0, sizeof(int)*(winw-1));
268 memset (vred, 0, sizeof(int)*(winw-1));
269 memset (vgreen, 0, sizeof(int)*(winw-1));
270 memset (vblue, 0, sizeof(int)*(winw-1));
272 int index = 0;
273 double scale = 256.0 / (winw-2);
274 for (int i=0; i<=winw-2; i++) {
275 int samples = 0;
276 while (index < 256 && (int)(index/scale) == i) {
277 vval[i] += lhist[index];
278 vred[i] += rhist[index];
279 vgreen[i] += ghist[index];
280 vblue[i] += bhist[index];
281 index++;
282 samples++;
284 if (samples>0) {
285 vval[i] /= samples;
286 vred[i] /= samples;
287 vgreen[i] /= samples;
288 vblue[i] /= samples;
292 // compute height of the full histogram (realheight) and
294 int fullhistheight = 0;
295 for (int i=0; i<=winw-2; i++) {
296 if (needVal && vval[i]>fullhistheight)
297 fullhistheight = vval[i];
298 if (needRed && vred[i]>fullhistheight)
299 fullhistheight = vred[i];
300 if (needGreen && vgreen[i]>fullhistheight)
301 fullhistheight = vgreen[i];
302 if (needBlue && vblue[i]>fullhistheight)
303 fullhistheight = vblue[i];
306 // compute two hights, one for the magnified view and one for the threshold
308 int realhistheight = fullhistheight;
310 if (!showFull) {
311 int area1thres = 0;
312 int area2thres = 0;
313 int area = 0;
314 for (int i=0; i<fullhistheight; i++) {
315 for (int j=0; j<winw-1; j++)
316 if ((needVal && vval[j]>i) || (needRed && vred[j]>i) || (needGreen && vgreen[j]>i) || (needBlue && vblue[j]>i))
317 area++;
318 if (area1thres==0 && (double)area / ((winw-1)*(i+1)) < 0.3)
319 area1thres = i;
320 if (area2thres==0 && (double)area / ((winw-1)*(i+1)) < 0.3)
321 area2thres = i;
322 if (area1thres && area2thres)
323 break;
325 if (area1thres>0 && area2thres>0 && area1thres<fullhistheight)
326 realhistheight = area2thres;
329 if (realhistheight<winh-2)
330 realhistheight = winh-2;
332 Cairo::RefPtr<Cairo::Context> cr = backBuffer->create_cairo_context();
333 cr->set_antialias (Cairo::ANTIALIAS_SUBPIXEL);
334 cr->set_line_width (1.0);
335 if (needVal) {
336 cr->move_to (0, winh-1);
337 cr->set_source_rgb (0.75, 0.75, 0.75);
338 for (int i=0; i<=winw-2; i++) {
339 int val = (int)(vval[i] * (double)(winh-2) / realhistheight);
340 if (val>winh-1)
341 val = winh-1;
342 if (i>0)
343 cr->line_to (i+1, winh-1-val);
345 cr->fill_preserve ();
346 cr->set_source_rgb (0.5, 0.5, 0.5);
347 cr->stroke ();
349 if (needRed) {
350 cr->move_to (0, winh-1);
351 cr->set_source_rgb (1.0, 0.0, 0.0);
352 for (int i=0; i<=winw-2; i++) {
353 int val = (int)(vred[i] * (double)(winh-2) / realhistheight);
354 if (val>winh-1)
355 val = winh-1;
356 if (i>0)
357 cr->line_to (i+1, winh-1-val);
359 cr->stroke ();
361 if (needGreen) {
362 cr->move_to (0, winh-1);
363 cr->set_source_rgb (0.0, 1.0, 0.0);
364 for (int i=0; i<=winw-2; i++) {
365 int val = (int)(vgreen[i] * (double)(winh-2) / realhistheight);
366 if (val>winh-1)
367 val = winh-1;
368 if (i>0)
369 cr->line_to (i+1, winh-1-val);
371 cr->stroke ();
373 if (needBlue) {
374 cr->move_to (0, winh-1);
375 cr->set_source_rgb (0.0, 0.0, 1.0);
376 for (int i=0; i<=winw-2; i++) {
377 int val = (int)(vblue[i] * (double)(winh-2) / realhistheight);
378 if (val>winh-1)
379 val = winh-1;
380 if (i>0)
381 cr->line_to (i+1, winh-1-val);
383 cr->stroke ();
386 delete [] vval;
387 delete [] vred;
388 delete [] vgreen;
389 delete [] vblue;
392 bgc->set_foreground (mgray);
393 backBuffer->draw_rectangle (bgc, false, 0, 0, winw-1, winh-1);
395 bgc->set_line_attributes (1, Gdk::LINE_ON_OFF_DASH, Gdk::CAP_NOT_LAST, Gdk::JOIN_MITER);
397 backBuffer->draw_line (bgc, winw/3, 0, winw/3, winh-1);
398 backBuffer->draw_line (bgc, 2*winw/3, 0, 2*winw/3, winh-1);
399 backBuffer->draw_line (bgc, 0, winh/3, winw-1, winh/3);
400 backBuffer->draw_line (bgc, 0, 2*winh/3, winw-1, 2*winh/3);
402 bgc->set_line_attributes (1, Gdk::LINE_SOLID, Gdk::CAP_NOT_LAST, Gdk::JOIN_MITER);
404 oldwidth = winw;
405 oldheight = winh;
408 void HistogramArea::on_realize () {
410 Gtk::DrawingArea::on_realize();
411 Glib::RefPtr<Gdk::Window> window = get_window();
412 gc_ = Gdk::GC::create(window);
413 add_events(Gdk::EXPOSURE_MASK | Gdk::BUTTON_PRESS_MASK);
414 Glib::RefPtr<Gdk::Colormap> colormap = get_default_colormap();
416 black = Gdk::Color ("black");
417 red = Gdk::Color ("red");
418 green = Gdk::Color ("green");
419 blue = Gdk::Color ("blue");
420 lgray = Gdk::Color ("gray75");
421 mgray = Gdk::Color ("gray50");
422 dgray = Gdk::Color ("gray25");
423 colormap->alloc_color(black);
424 colormap->alloc_color(white);
425 colormap->alloc_color(red);
426 colormap->alloc_color(green);
427 colormap->alloc_color(blue);
428 colormap->alloc_color(lgray);
429 colormap->alloc_color(mgray);
430 colormap->alloc_color(dgray);
434 void HistogramArea::styleChanged (const Glib::RefPtr<Gtk::Style>& style) {
436 white = get_style()->get_base(Gtk::STATE_NORMAL);
437 queue_draw ();
440 bool HistogramArea::on_expose_event(GdkEventExpose* event) {
442 Glib::RefPtr<Gdk::Window> window = get_window();
444 int winx, winy, winw, winh, wind;
445 window->get_geometry(winx, winy, winw, winh, wind);
447 if (winw!=oldwidth && winh!=oldheight)
448 renderHistogram ();
449 window->draw_drawable (gc_, backBuffer, 0, 0, 0, 0, -1, -1);
451 return true;
455 bool HistogramArea::on_button_press_event (GdkEventButton* event) {
457 if (event->type==GDK_2BUTTON_PRESS && event->button==1) {
458 showFull = !showFull;
459 renderHistogram ();
460 queue_draw ();