1 /*
2  */
3 
4 /*
5 
6     Copyright (C) 2014 Ferrero Andrea
7 
8     This program is free software: you can redistribute it and/or modify
9     it under the terms of the GNU General Public License as published by
10     the Free Software Foundation, either version 3 of the License, or
11     (at your option) any later version.
12 
13     This program is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16     GNU General Public License for more details.
17 
18     You should have received a copy of the GNU General Public License
19     along with this program. If not, see <http://www.gnu.org/licenses/>.
20 
21 
22  */
23 
24 /*
25 
26     These files are distributed with PhotoFlow - http://aferrero2707.github.io/PhotoFlow/
27 
28  */
29 
30 #ifndef IMAGE_EDITOR_H
31 #define IMAGE_EDITOR_H
32 
33 #include <string>
34 
35 #include <gtkmm.h>
36 
37 #include "../base/photoflow.hh"
38 
39 #include "imagearea.hh"
40 #include "histogram.hh"
41 #include "sampler.hh"
42 #include "image_info.hh"
43 #include "snapshotswidget.hh"
44 #include "layerwidget.hh"
45 #include "tablabelwidget.hh"
46 #include "softproofdialog.hh"
47 #include "widgets/statusindicator.hh"
48 
49 
50 namespace PF {
51 
52 
53 class PreviewScrolledWindow: public Gtk::ScrolledWindow
54 {
55 public:
56   void on_map();
57   bool on_configure_event(GdkEventConfigure*event);
58 };
59 
60 
61 
62 // The image_size_updater is a special pipeline sink that stores
63 // the dimensions of the full-res image which corresponds to
64 // the output being displayed in the preview area.
65 // It is used to compute the correct scaling factor when
66 // the preview image is shown in zoom-to-fit mode.
67 class ImageSizeUpdater: public PipelineSink
68 {
69   int sticky_layer_id;
70 
71   VipsImage* image;
72   int image_width, image_height;
73 public:
74   ImageSizeUpdater( Pipeline* p );
75 
get_sticky_layer()76   int get_sticky_layer() { return sticky_layer_id; }
set_sticky_layer(int id)77   void set_sticky_layer( int id ) { sticky_layer_id = id; }
78 
get_image()79   VipsImage* get_image() { return image; }
get_image_width()80   int get_image_width() { return image_width; }
get_image_height()81   int get_image_height() { return image_height; }
82 
83   void update( VipsRect* area );
84 };
85 
86 
87 class MainWindow;
88 
89 
90 class ImageEditor: public Gtk::HBox
91 {
92   std::string filename;
93   Image* image;
94   bool image_opened;
95 
96   Layer* sticky_layer;
97   Layer* edited_layer;
98   int selected_layer_id;
99   std::list<PF::Layer*> edited_layer_children;
100 
101   ImageSizeUpdater* image_size_updater;
102 
103   Gtk::VBox imageBox;
104   ImageArea* imageArea;
105   Gtk::EventBox imageArea_eventBox;
106 
107 
108   Histogram* histogram;
109   SamplerGroup* samplers;
110   ImageInfo* image_info;
111   SnapshotsWidget* snapshots;
112 
113 
114   // Boxes for aligning the image area inside the scrolled window.
115   // The image area gets inserted into an HBox which in turn
116   // is inserted into a VBox, in both cases with PACK_EXPAND_PADDING.
117   // The VBox is the inserted into an EventBox which provides
118   // the black background.
119   Gtk::VBox imageArea_vbox;
120   Gtk::HBox imageArea_hbox;
121   Gtk::EventBox imageArea_eventBox2;
122   PreviewScrolledWindow imageArea_scrolledWindow;
123 
124   Gtk::VBox imageArea_scrolledWindow_box;
125   //Gtk::HPaned main_panel;
126   Gtk::HBox* main_panel;
127   LayerWidget layersWidget;
128   Gtk::VBox layersWidget_box;
129   Gtk::Widget* aux_controls;
130   Gtk::VBox aux_controlsBox;
131   Gtk::HBox controlsBox;
132   Gtk::VBox controlsBox2;
133 
134   Gtk::Frame soft_proof_frame;
135   Gtk::VBox soft_proof_box;
136   Gtk::CheckButton soft_proof_enable_button;
137   SoftProofDialog* softproof_dialog;
138 
139   StatusIndicatorWidget status_indicator;
140   Gtk::Image  img_zoom_in, img_zoom_out, img_zoom_fit;
141   Gtk::Button buttonZoomIn, buttonZoomOut, buttonZoom100, buttonZoomFit;
142   Gtk::Image img_shadows_warning, img_highlights_warning;
143   Gtk::ToggleButton button_shadows_warning, button_highlights_warning;
144   Gtk::VBox radioBox;
145   Gtk::RadioButton buttonShowMerged, buttonShowActive;
146   Gtk::VBox controls_group_vbox;
147   Gtk::ScrolledWindow controls_group_scrolled_window;
148   Gtk::HBox image_controls_box, image_controls_box2;
149 
150   HTabLabelWidget* tab_label_widget;
151 
152   Gtk::HBox file_buttons_box;
153 
154   Glib::ustring last_exported_file;
155 
156 
157   bool fit_image;
158   bool fit_image_needed;
159 
160   bool hide_background_layer;
161 
162   int preview_drag_start_x, preview_drag_start_y, adjustment_drag_start_x, adjustment_drag_start_y;
163 
164   Glib::Dispatcher signal_image_modified, signal_image_updated;
165 
166   void expand_layer( PF::Layer* layer, std::list<PF::Layer*>& list );
167   void get_child_layers( Layer* layer, std::list<PF::Layer*>& container,
168       std::list<Layer*>& children );
169   void get_child_layers();
170 
171 public:
172   ImageEditor( std::string filename );
173   ~ImageEditor();
174 
175   void dispose();
176 
get_image()177   Image* get_image() { return image; }
get_image_area()178   ImageArea* get_image_area() { return imageArea; }
179 
get_layer_widget()180   LayerWidget& get_layer_widget() { return layersWidget; }
181 
set_tab_label_widget(HTabLabelWidget * l)182   void set_tab_label_widget( HTabLabelWidget* l ) { tab_label_widget = l; }
183 
184   void update_controls();
185   void set_aux_controls( Gtk::Widget* aux );
get_aux_controls()186   Gtk::Widget* get_aux_controls() { return aux_controls; }
187 
get_file_buttons_box()188   Gtk::HBox& get_file_buttons_box() { return file_buttons_box; }
189 
get_edited_layer()190   int get_edited_layer() {
191     //std::cout<<"ImageEditor::get_edited_layer(): edited_layer="<<edited_layer;
192     //if(edited_layer) std::cout<<"(\""<<edited_layer->get_name()<<"\", "<<edited_layer->get_id()<<")"<<std::endl;
193     return( (edited_layer) ? edited_layer->get_id() : -1 );
194   }
195   void set_edited_layer( int id );
get_sticky_layer()196   int get_sticky_layer() { return (sticky_layer) ? sticky_layer->get_id() : -1; }
197   void set_sticky_layer( int id );
198   void set_selected_layer( int id );
get_selected_layer()199   int get_selected_layer() { return selected_layer_id; }
200 
201   void set_display_mask( bool val );
202 
203 
set_hide_background_layer(bool flag)204   void set_hide_background_layer( bool flag ) { hide_background_layer = flag; }
get_hide_background_layer()205   bool get_hide_background_layer() { return hide_background_layer; }
206 
207   void open_image();
208   void build_image();
209 
210   void on_image_modified();
211   void on_image_modified_async();
212 
213   void on_image_updated();
214   void on_image_updated_async();
215 
216   void on_map();
217   void on_realize();
218 
set_status(std::string label,int status)219   void set_status( std::string label, int status )
220   {
221     //std::cout<<"ImageEditor::set_status("<<label<<", "<<status<<") called"<<std::endl;
222     status_indicator.set_status( label, status );
223   }
set_status_ready()224   void set_status_ready() { set_status(_("ready"), 0); }
set_status_caching()225   void set_status_caching() { set_status(_("caching"), 1); }
set_status_processing()226   void set_status_processing() { set_status(_("processing"), 2); }
set_status_updating()227   void set_status_updating() { set_status(_("updating"), 3); }
set_status_exporting()228   void set_status_exporting() { set_status(_("exporting"), 2); }
229 
230   // Handlers for the mouse events inside the image area
231   bool my_button_press_event( GdkEventButton* button );
232   bool my_button_release_event( GdkEventButton* button );
233   bool my_motion_notify_event( GdkEventMotion* button );
234   bool on_key_press_event(GdkEventKey* event);
235 
236   // Handler for the widget size change
237   //bool on_preview_configure_event( GdkEventConfigure* event );
238   void on_my_size_allocate(Gtk::Allocation& allocation);
239 
get_zoom_factor()240   float get_zoom_factor()
241   {
242     PF::Pipeline* pipeline = image->get_pipeline(1);
243     if( !pipeline ) return 1.0f;
244     unsigned int level = pipeline->get_level();
245     float fact = 1.0f;
246     for( unsigned int i = 0; i < level; i++ )
247       fact /= 2.0f;
248 #ifndef NDEBUG
249     std::cout<<"get_zoom_factor(): level="<<level<<"  fact="<<fact<<std::endl;
250 #endif
251     return fact;
252   }
253 
254   void screen2image( gdouble& x, gdouble& y, gdouble& w, gdouble& h );
255   void image2layer( gdouble& x, gdouble& y, gdouble& w, gdouble& h );
screen2layer(gdouble & x,gdouble & y,gdouble & w,gdouble & h)256   void screen2layer( gdouble& x, gdouble& y, gdouble& w, gdouble& h )
257   {
258     screen2image( x, y, w, h );
259     image2layer( x, y, w, h );
260   }
261 
262   void image2screen( gdouble& x, gdouble& y, gdouble& w, gdouble& h );
263   void layer2image( gdouble& x, gdouble& y, gdouble& w, gdouble& h );
layer2screen(gdouble & x,gdouble & y,gdouble & w,gdouble & h)264   void layer2screen( gdouble& x, gdouble& y, gdouble& w, gdouble& h )
265   {
266     layer2image( x, y, w, h );
267     image2screen( x, y, w, h );
268   }
269 
270   void toggle_highlights_warning();
271   void toggle_shadows_warning();
272 
273   void on_soft_proof_toggled();
soft_proof_disable()274   void soft_proof_disable()
275   {
276     soft_proof_enable_button.set_active(false);
277   }
278 
279   void zoom_in();
280   void zoom_out();
281   bool zoom_fit();
282   void zoom_actual_size();
283 
284   // Functions called when switching in and out of the current editor in the
285   // main window's notebook
286   void enter();
287   void exit();
288 
get_last_exported_file()289   Glib::ustring get_last_exported_file() { return last_exported_file; }
set_last_exported_file(Glib::ustring name)290   void set_last_exported_file( Glib::ustring name ) { last_exported_file = name; }
291 };
292 
293 }
294 
295 #endif
296