1 /* -*- C++ -*-
2  *
3  *  This file is part of RawTherapee.
4  *
5  *  Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
6  *
7  *  RawTherapee is free software: you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation, either version 3 of the License, or
10  *  (at your option) any later version.
11  *
12  *  RawTherapee is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with RawTherapee.  If not, see <https://www.gnu.org/licenses/>.
19  */
20 #pragma once
21 
22 #include <vector>
23 
24 #include <gtkmm.h>
25 #include <glibmm.h>
26 #include <cairomm/cairomm.h>
27 
28 #include "guiutils.h"
29 #include "options.h"
30 #include "pointermotionlistener.h"
31 #include "../rtengine/array2D.h"
32 #include "../rtengine/LUT.h"
33 #include "../rtengine/noncopyable.h"
34 
35 using rtengine::array2D;
36 class HistogramArea;
37 
38 struct HistogramAreaIdleHelper {
39     HistogramArea* harea;
40     bool destroyed;
41     int pending;
42 };
43 
44 class HistogramRGBArea;
45 struct HistogramRGBAreaIdleHelper {
46     HistogramRGBArea* harea;
47     bool destroyed;
48     int pending;
49 };
50 
51 class HistogramScaling
52 {
53 public:
54     double factor;
55     HistogramScaling();
56     double log (double vsize, double val);
57 };
58 
59 class HistogramRGBArea : public Gtk::DrawingArea, public BackBuffer, protected HistogramScaling, public rtengine::NonCopyable
60 {
61 private:
62     typedef const double (*TMatrix)[3];
63 
64     IdleRegister idle_register;
65 
66 protected:
67     int val;
68     int r;
69     int g;
70     int b;
71 
72     bool valid;
73 
74     bool needRed;
75     bool needGreen;
76     bool needBlue;
77     bool needLuma;
78     bool needChroma;
79     bool showMode;
80     bool barDisplayed;
81 
82     Gtk::Grid* parent;
83 
84     //double padding = 0.0;//5.0;
85 
86     HistogramRGBAreaIdleHelper* harih;
87 
88     /** Draw an indicator bar for the value. */
89     virtual void drawBar(Cairo::RefPtr<Cairo::Context> cc, double value, double max_value, int winw, int winh, double scale) = 0;
90 
91     void getPreferredThickness(int& min_thickness, int& natural_length) const;
92     void getPreferredLength(int& min_length, int& natural_length) const;
93     void getPreferredThicknessForLength(int length, int& min_thickness, int& natural_length) const;
94     void getPreferredLengthForThickness(int thickness, int& min_length, int& natural_length) const;
95 
96 public:
97     HistogramRGBArea();
98     ~HistogramRGBArea() override;
99 
100     void updateBackBuffer (int r, int g, int b, const Glib::ustring &profile = "", const Glib::ustring &profileW = "");
101     bool getShow ();
102     void setShow(bool show);
setParent(Gtk::Grid * p)103     void setParent (Gtk::Grid* p)
104     {
105         parent = p;
106     };
107 
108     void update (int val, int rh, int gh, int bh);
109     void updateOptions (bool r, bool g, bool b, bool l, bool c, bool show);
110 
111     void on_realize() override;
112     bool on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr) override;
113     bool on_button_press_event (GdkEventButton* event) override;
114     void factorChanged (double newFactor);
115 
116 };
117 
118 class HistogramRGBAreaHori final : public HistogramRGBArea
119 {
120 private:
121     void drawBar(Cairo::RefPtr<Cairo::Context> cc, double value, double max_value, int winw, int winh, double scale) override;
122 
123     Gtk::SizeRequestMode get_request_mode_vfunc () const override;
124     void get_preferred_height_vfunc (int& minimum_height, int& natural_height) const override;
125     void get_preferred_width_vfunc (int &minimum_width, int &natural_width) const override;
126     void get_preferred_height_for_width_vfunc (int width, int &minimum_height, int &natural_height) const override;
127     void get_preferred_width_for_height_vfunc (int h, int &minimum_width, int &natural_width) const override;
128 };
129 
130 class HistogramRGBAreaVert final : public HistogramRGBArea
131 {
132 private:
133     void drawBar(Cairo::RefPtr<Cairo::Context> cc, double value, double max_value, int winw, int winh, double scale) override;
134 
135     Gtk::SizeRequestMode get_request_mode_vfunc () const override;
136     void get_preferred_height_vfunc (int& minimum_height, int& natural_height) const override;
137     void get_preferred_width_vfunc (int &minimum_width, int &natural_width) const override;
138     void get_preferred_height_for_width_vfunc (int width, int &minimum_height, int &natural_height) const override;
139     void get_preferred_width_for_height_vfunc (int h, int &minimum_width, int &natural_width) const override;
140 };
141 
142 class DrawModeListener
143 {
144 public:
145     virtual ~DrawModeListener() = default;
146     virtual void toggleButtonMode() = 0;
147 };
148 
149 class HistogramArea final : public Gtk::DrawingArea, public BackBuffer, private HistogramScaling, public rtengine::NonCopyable
150 {
151 public:
152     typedef sigc::signal<void, double> type_signal_factor_changed;
153     typedef sigc::signal<void, float> SignalBrightnessChanged;
154 
155     static constexpr float MIN_BRIGHT = 0.1;
156     static constexpr float MAX_BRIGHT = 3;
157 private:
158     IdleRegister idle_register;
159     type_signal_factor_changed sigFactorChanged;
160 
161 protected:
162     LUTu rhist, ghist, bhist, lhist, chist;
163     LUTu rhistRaw, ghistRaw, bhistRaw, lhistRaw; //lhistRaw is unused?
164     int vectorscope_scale;
165     array2D<int> vect_hc, vect_hs;
166     std::vector<unsigned char> vect_hc_buffer, vect_hs_buffer;
167     bool vect_hc_buffer_dirty, vect_hs_buffer_dirty;
168     int waveform_scale;
169     array2D<int> rwave, gwave, bwave, lwave;
170     std::vector<unsigned char> parade_buffer_r;
171     std::vector<unsigned char> parade_buffer_g;
172     std::vector<unsigned char> parade_buffer_b;
173     bool parade_buffer_r_dirty, parade_buffer_g_dirty, parade_buffer_b_dirty;
174     std::vector<unsigned char> wave_buffer;
175     std::vector<unsigned char> wave_buffer_luma;
176     bool wave_buffer_dirty, wave_buffer_luma_dirty;
177 
178     bool valid;
179     int drawMode;
180     DrawModeListener *myDrawModeListener;
181     Options::ScopeType scopeType;
182     int oldwidth, oldheight;
183     /// Intensity of waveform and vectorscope trace.
184     float trace_brightness;
185 
186     bool needRed, needGreen, needBlue, needLuma, needChroma;
187     bool isPressed;
188     double movingPosition;
189     bool needPointer;
190 
191     double padding = 0.0;
192 
193     HistogramAreaIdleHelper* haih;
194 
195     int pointer_red, pointer_green, pointer_blue;
196     float pointer_a, pointer_b;
197 
198     SignalBrightnessChanged signal_brightness_changed;
199 
200     bool is_main_;
201 
202 public:
203     explicit HistogramArea(DrawModeListener *fml=nullptr, bool is_main=true);
204     ~HistogramArea() override;
205 
206     void updateBackBuffer(int custom_w=-1, int custom_h=-1);
207     /// Update pointer values. Returns true if widget needs redrawing.
208     bool updatePointer(int r, int g, int b, const Glib::ustring &profile = "", const Glib::ustring &profileW = "");
209     void update(
210         const LUTu& histRed,
211         const LUTu& histGreen,
212         const LUTu& histBlue,
213         const LUTu& histLuma,
214         const LUTu& histChroma,
215         const LUTu& histRedRaw,
216         const LUTu& histGreenRaw,
217         const LUTu& histBlueRaw,
218         int vectorscopeScale,
219         const array2D<int>& vectorscopeHC,
220         const array2D<int>& vectorscopeHS,
221         int waveformScale,
222         const array2D<int>& waveformRed,
223         const array2D<int>& waveformGreen,
224         const array2D<int>& waveformBlue,
225         const array2D<int>& waveformLuma
226     );
227     void updateOptions (bool r, bool g, bool b, bool l, bool c, int mode, Options::ScopeType type, bool pointer);
228     bool updatePending();
229     void on_realize() override;
230     bool on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr) override;
231     bool on_button_press_event (GdkEventButton* event) override;
232     bool on_button_release_event (GdkEventButton* event) override;
233     bool on_motion_notify_event (GdkEventMotion* event) override;
234     float getBrightness(void);
235     /** Set the trace brightness, with 1 being normal. */
236     void setBrightness(float brightness);
237     SignalBrightnessChanged getBrighnessChangedSignal(void);
238     type_signal_factor_changed signal_factor_changed();
239 
240 private:
241     void drawCurve(Cairo::RefPtr<Cairo::Context> &cr, const LUTu & data, double scale, int hsize, int vsize);
242     void drawMarks(Cairo::RefPtr<Cairo::Context> &cr, const LUTu & data, double scale, int hsize, int & ui, int & oi);
243     void drawParade(Cairo::RefPtr<Cairo::Context> &cr, int hsize, int vsize);
244     void drawVectorscope(Cairo::RefPtr<Cairo::Context> &cr, int hsize, int vsize);
245     void drawWaveform(Cairo::RefPtr<Cairo::Context> &cr, int hsize, int vsize);
246     Gtk::SizeRequestMode get_request_mode_vfunc () const override;
247     void get_preferred_height_vfunc (int& minimum_height, int& natural_height) const override;
248     void get_preferred_width_vfunc (int &minimum_width, int &natural_width) const override;
249     void get_preferred_height_for_width_vfunc (int width, int &minimum_height, int &natural_height) const override;
250     void get_preferred_width_for_height_vfunc (int height, int &minimum_width, int &natural_width) const override;
251 
252     void updateRaw(Cairo::RefPtr<Cairo::Context> cr);
253     void updateNonRaw(Cairo::RefPtr<Cairo::Context> cr);
254     void drawRawCurve(Cairo::RefPtr<Cairo::Context> &cr, LUTu &data, unsigned int ub, double scale, int hsize, int vsize);
255 };
256 
257 class HistogramPanelListener
258 {
259 public:
260     virtual void scopeTypeChanged(Options::ScopeType new_type) = 0;
261 };
262 
263 class HistogramPanel final : public Gtk::Grid, public PointerMotionListener, public DrawModeListener, public rtengine::NonCopyable
264 {
265 protected:
266 
267     Gtk::Grid* gfxGrid;
268     Gtk::Grid* buttonGrid;
269     Gtk::Box* persistentButtons;
270     Gtk::Box* optionButtons;
271     HistogramArea* histogramArea;
272     HistogramRGBArea* histogramRGBArea;
273     std::unique_ptr<HistogramRGBAreaHori> histogramRGBAreaHori;
274     std::unique_ptr<HistogramRGBAreaVert> histogramRGBAreaVert;
275     Gtk::ToggleButton* showRed;
276     Gtk::ToggleButton* showGreen;
277     Gtk::ToggleButton* showBlue;
278     Gtk::ToggleButton* showValue;
279     Gtk::ToggleButton* showBAR;
280     Gtk::ToggleButton* showChro;
281     Gtk::Button* showMode;
282     Gtk::ToggleButton* scopeOptions;
283     Gtk::Scale* brightnessWidget;
284 
285     Gtk::RadioButton* scopeHistBtn;
286     Gtk::RadioButton* scopeHistRawBtn;
287     Gtk::RadioButton* scopeParadeBtn;
288     Gtk::RadioButton* scopeWaveBtn;
289     Gtk::RadioButton* scopeVectHcBtn;
290     Gtk::RadioButton* scopeVectHsBtn;
291 
292     Gtk::Image *redImage;
293     Gtk::Image *greenImage;
294     Gtk::Image *blueImage;
295     Gtk::Image *valueImage;
296     Gtk::Image *barImage;
297     Gtk::Image *chroImage;
298 
299     Gtk::Image *redImage_g;
300     Gtk::Image *greenImage_g;
301     Gtk::Image *blueImage_g;
302     Gtk::Image *valueImage_g;
303     Gtk::Image *barImage_g;
304     Gtk::Image *chroImage_g;
305 
306     Gtk::Image *mode_images_[3];
307     Glib::ustring mode_tips_[3];
308 
309     HistogramPanelListener* panel_listener;
310 
311     sigc::connection brightness_changed_connection;
312     sigc::connection rconn;
313     void setHistInvalid ();
314     void showRGBBar();
315     void updateHistAreaOptions();
316     void updateHistRGBAreaOptions();
317 
318 public:
319 
320     HistogramPanel ();
321     ~HistogramPanel () override;
322 
histogramChanged(const LUTu & histRed,const LUTu & histGreen,const LUTu & histBlue,const LUTu & histLuma,const LUTu & histChroma,const LUTu & histRedRaw,const LUTu & histGreenRaw,const LUTu & histBlueRaw,int vectorscopeScale,const array2D<int> & vectorscopeHC,const array2D<int> & vectorscopeHS,int waveformScale,const array2D<int> & waveformRed,const array2D<int> & waveformGreen,const array2D<int> & waveformBlue,const array2D<int> & waveformLuma)323     void histogramChanged(
324         const LUTu& histRed,
325         const LUTu& histGreen,
326         const LUTu& histBlue,
327         const LUTu& histLuma,
328         const LUTu& histChroma,
329         const LUTu& histRedRaw,
330         const LUTu& histGreenRaw,
331         const LUTu& histBlueRaw,
332         int vectorscopeScale,
333         const array2D<int>& vectorscopeHC,
334         const array2D<int>& vectorscopeHS,
335         int waveformScale,
336         const array2D<int>& waveformRed,
337         const array2D<int>& waveformGreen,
338         const array2D<int>& waveformBlue,
339         const array2D<int>& waveformLuma
340     )
341     {
342         histogramArea->update(histRed, histGreen, histBlue, histLuma, histChroma, histRedRaw, histGreenRaw, histBlueRaw, vectorscopeScale, vectorscopeHC, vectorscopeHS, waveformScale, waveformRed, waveformGreen, waveformBlue, waveformLuma);
343     }
344     // pointermotionlistener interface
345     void pointerMoved (bool validPos, const Glib::ustring &profile, const Glib::ustring &profileW, int x, int y, int r, int g, int b, bool isRaw = false) override;
346 
347     // TODO should be protected
348     void setHistRGBInvalid ();
349 
350     void reorder (Gtk::PositionType position);
351     void red_toggled ();
352     void green_toggled ();
353     void blue_toggled ();
354     void value_toggled ();
355     void chro_toggled ();
356     void bar_toggled ();
357     void mode_released ();
358     void brightnessWidgetValueChanged();
359     void brightnessUpdated(float brightness);
360     void scopeOptionsToggled();
361     void type_selected(Gtk::RadioButton* button);
362     void type_changed ();
363     void rgbv_toggled ();
364     void resized (Gtk::Allocation& req);
365 
366     // drawModeListener interface
367     void toggleButtonMode () override;
368 
369     void setPanelListener(HistogramPanelListener* listener);
370 };
371