Move things round a bit.
[dcpomatic.git] / src / tools / alignomatic.cc
1 /*
2     Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
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., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include <gtkmm.h>
21 #include "lib/util.h"
22 #include "lib/config.h"
23 #include "lib/screen.h"
24 #include "lib/format.h"
25 #include "gtk/gtk_util.h"
26 #include "gtk/alignment.h"
27
28 using namespace std;
29 using namespace boost;
30
31 static Alignment* alignment = 0;
32 static Gtk::ComboBoxText* format_combo = 0;
33 static Format const * format = 0;
34 static Gtk::ComboBoxText* screen_combo = 0;
35 static shared_ptr<Screen> screen;
36 static Gtk::Button* add_screen = 0;
37 static Gtk::Entry* screen_name = 0;
38 static Gtk::SpinButton* x_position = 0;
39 static Gtk::SpinButton* y_position = 0;
40 static Gtk::SpinButton* width = 0;
41 static Gtk::Button* calculate_width = 0;
42 static Gtk::SpinButton* height = 0;
43 static Gtk::Button* calculate_height = 0;
44 static Gtk::Button* save = 0;
45 static bool screen_dirty = false;
46
47 enum GeometryPart {
48         GEOMETRY_PART_X,
49         GEOMETRY_PART_Y,
50         GEOMETRY_PART_WIDTH,
51         GEOMETRY_PART_HEIGHT
52 };
53
54 void
55 update_sensitivity ()
56 {
57         bool const dims = format && screen;
58
59         x_position->set_sensitive (dims);
60         y_position->set_sensitive (dims);
61         width->set_sensitive (dims);
62         calculate_width->set_sensitive (dims);
63         height->set_sensitive (dims);
64         calculate_height->set_sensitive (dims);
65
66         screen_name->set_sensitive (screen);
67         save->set_sensitive (screen_dirty);
68 }
69
70 void
71 update_alignment ()
72 {
73         if (!screen || !format) {
74                 return;
75         }
76
77         delete alignment;
78         alignment = new Alignment (screen->position (format), screen->size (format));
79         alignment->set_text_line (0, screen->name ());
80         alignment->set_text_line (1, format->name ());
81 }
82
83 void
84 update_entries ()
85 {
86         if (!screen || !format) {
87                 return;
88         }
89         
90         Position p = screen->position (format);
91         x_position->set_value (p.x);
92         y_position->set_value (p.y);
93         Size s = screen->size (format);
94         width->set_value (s.width);
95         height->set_value (s.height);
96
97         update_sensitivity ();
98 }
99
100 void
101 screen_changed ()
102 {
103         if (screen_combo->get_active_row_number() < 0) {
104                 return;
105         }
106
107         vector<shared_ptr<Screen> > screens = Config::instance()->screens ();
108         
109         if (screens[screen_combo->get_active_row_number()] == screen) {
110                 return;
111         }
112         
113         screen = screens[screen_combo->get_active_row_number()];
114
115         update_entries ();
116         update_alignment ();
117
118         screen_name->set_text (screen->name ());
119
120         screen_dirty = false;
121         update_sensitivity ();
122 }
123
124 void
125 format_changed ()
126 {
127         vector<Format const *> formats = Format::all ();
128         
129         if (formats[format_combo->get_active_row_number()] == format) {
130                 return;
131         }
132         
133         format = formats[format_combo->get_active_row_number()];
134         
135         update_entries ();
136         update_alignment ();
137         update_sensitivity ();
138 }
139
140 void
141 geometry_changed (GeometryPart p)
142 {
143         if (p == GEOMETRY_PART_X && screen->position(format).x == x_position->get_value_as_int()) {
144                 return;
145         }
146
147         if (p == GEOMETRY_PART_Y && screen->position(format).y == y_position->get_value_as_int()) {
148                 return;
149         }
150
151         if (p == GEOMETRY_PART_WIDTH && screen->size(format).width == width->get_value_as_int()) {
152                 return;
153         }
154
155         if (p == GEOMETRY_PART_HEIGHT && screen->size(format).height == height->get_value_as_int()) {
156                 return;
157         }
158         
159         screen->set_geometry (
160                 format,
161                 Position (x_position->get_value_as_int(), y_position->get_value_as_int()),
162                 Size (width->get_value_as_int(), height->get_value_as_int())
163                 );
164
165         update_alignment ();
166
167         screen_dirty = true;
168         update_sensitivity ();
169 }
170
171 void
172 save_clicked ()
173 {
174         Config::instance()->write ();
175         screen_dirty = false;
176         update_sensitivity ();
177 }
178
179 void
180 calculate_width_clicked ()
181 {
182         width->set_value (height->get_value_as_int() * format->ratio_as_float ());
183 }
184
185 void
186 calculate_height_clicked ()
187 {
188         height->set_value (width->get_value_as_int() / format->ratio_as_float ());
189 }
190
191 void
192 update_screen_combo ()
193 {
194         screen_combo->clear ();
195         
196         vector<shared_ptr<Screen> > screens = Config::instance()->screens ();
197         for (vector<shared_ptr<Screen> >::iterator i = screens.begin(); i != screens.end(); ++i) {
198                 screen_combo->append_text ((*i)->name ());
199         }
200 }
201
202 void
203 screen_name_changed ()
204 {
205         screen->set_name (screen_name->get_text ());
206
207         int const r = screen_combo->get_active_row_number ();
208         update_screen_combo ();
209         screen_combo->set_active (r);
210
211         screen_dirty = true;
212         update_sensitivity ();
213 }
214
215 void
216 add_screen_clicked ()
217 {
218         shared_ptr<Screen> s (new Screen ("New Screen"));
219         vector<shared_ptr<Screen> > screens = Config::instance()->screens ();
220         screens.push_back (s);
221         Config::instance()->set_screens (screens);
222         update_screen_combo ();
223         screen_combo->set_active (screens.size() - 1);
224 }
225
226 int
227 main (int argc, char* argv[])
228 {
229         dvdomatic_setup ();
230         
231         Gtk::Main kit (argc, argv);
232         
233         Gtk::Dialog dialog ("Align-o-matic");
234
235         screen_combo = Gtk::manage (new Gtk::ComboBoxText);
236         update_screen_combo ();
237         screen_combo->signal_changed().connect (sigc::ptr_fun (&screen_changed));
238
239         add_screen = Gtk::manage (new Gtk::Button ("Add"));
240         add_screen->signal_clicked().connect (sigc::ptr_fun (&add_screen_clicked));
241         
242         screen_name = Gtk::manage (new Gtk::Entry ());
243         screen_name->signal_changed().connect (sigc::ptr_fun (&screen_name_changed));
244         
245         format_combo = Gtk::manage (new Gtk::ComboBoxText);
246         vector<Format const *> formats = Format::all ();
247         for (vector<Format const *>::iterator i = formats.begin(); i != formats.end(); ++i) {
248                 format_combo->append_text ((*i)->name ());
249         }
250
251         format_combo->signal_changed().connect (sigc::ptr_fun (&format_changed));
252
253         save = Gtk::manage (new Gtk::Button ("Save"));
254         save->signal_clicked().connect (sigc::ptr_fun (&save_clicked));
255
256         x_position = Gtk::manage (new Gtk::SpinButton ());
257         x_position->signal_value_changed().connect (sigc::bind (ptr_fun (&geometry_changed), GEOMETRY_PART_X));
258         x_position->set_range (0, 2048);
259         x_position->set_increments (1, 16);
260         y_position = Gtk::manage (new Gtk::SpinButton ());
261         y_position->signal_value_changed().connect (sigc::bind (sigc::ptr_fun (&geometry_changed), GEOMETRY_PART_Y));
262         y_position->set_range (0, 1080);
263         y_position->set_increments (1, 16);
264         width = Gtk::manage (new Gtk::SpinButton ());
265         width->signal_value_changed().connect (sigc::bind (sigc::ptr_fun (&geometry_changed), GEOMETRY_PART_WIDTH));
266         width->set_range (0, 2048);
267         width->set_increments (1, 16);
268         height = Gtk::manage (new Gtk::SpinButton ());
269         height->signal_value_changed().connect (sigc::bind (sigc::ptr_fun (&geometry_changed), GEOMETRY_PART_HEIGHT));
270         height->set_range (0, 1080);
271         height->set_increments (1, 16);
272
273         calculate_width = Gtk::manage (new Gtk::Button ("Calculate"));
274         calculate_width->signal_clicked().connect (sigc::ptr_fun (&calculate_width_clicked));
275         calculate_height = Gtk::manage (new Gtk::Button ("Calculate"));
276         calculate_height->signal_clicked().connect (sigc::ptr_fun (&calculate_height_clicked));
277
278         Gtk::Table table;
279         table.set_row_spacings (12);
280         table.set_col_spacings (12);
281         table.set_border_width (12);
282         
283         int n = 0;
284         table.attach (left_aligned_label ("Screen"), 0, 1, n, n + 1);
285         table.attach (*screen_combo, 1, 2, n, n + 1);
286         table.attach (*add_screen, 2, 3, n, n + 1);
287         ++n;
288         table.attach (left_aligned_label ("Screen Name"), 0, 1, n, n + 1);
289         table.attach (*screen_name, 1, 2, n, n + 1);
290         ++n;
291         table.attach (left_aligned_label ("Format"), 0, 1, n, n + 1);
292         table.attach (*format_combo, 1, 2, n, n + 1);
293         ++n;
294         table.attach (left_aligned_label ("x"), 0, 1, n, n + 1);
295         table.attach (*x_position, 1, 2, n, n + 1);
296         ++n;
297         table.attach (left_aligned_label ("y"), 0, 1, n, n + 1);
298         table.attach (*y_position, 1, 2, n, n + 1);
299         ++n;
300         table.attach (left_aligned_label ("Width"), 0, 1, n, n + 1);
301         table.attach (*width, 1, 2, n, n + 1);
302         table.attach (*calculate_width, 2, 3, n, n + 1);
303         ++n;
304         table.attach (left_aligned_label ("Height"), 0, 1, n, n + 1);
305         table.attach (*height, 1, 2, n, n + 1);
306         table.attach (*calculate_height, 2, 3, n, n + 1);
307         ++n;
308
309         dialog.get_vbox()->pack_start (table, false, false);
310         dialog.add_action_widget (*save, 0);
311         update_sensitivity ();
312         dialog.show_all ();
313
314         Gtk::Main::run (dialog);
315
316         return 0;
317 }