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