add missing GPL information in guicast program files
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / scale.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program 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 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program 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.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include "bchash.h"
23 #include "mainundo.h"
24 #include "mwindow.h"
25 #include "scale.h"
26 #include "mainsession.h"
27 #include "tracks.h"
28 #include "videowindow.h"
29
30 #include <libintl.h>
31 #define _(String) gettext(String)
32 #define gettext_noop(String) String
33 #define N_(String) gettext_noop (String)
34
35 Scale::Scale(MWindow *mwindow)
36  : BC_MenuItem(_("Resize..."))
37 {
38         this->mwindow = mwindow;
39         thread = new ScaleThread(mwindow);
40 }
41
42 Scale::~Scale()
43 {
44         delete thread;
45 }
46
47 int Scale::handle_event()
48 {
49         thread->start();
50 return 0;
51 }
52
53 ScaleThread::ScaleThread(MWindow *mwindow)
54  : Thread()
55 {
56         this->mwindow = mwindow;
57         already_running = 0;
58 }
59
60 ScaleThread::~ScaleThread() {}
61
62 void ScaleThread::run()
63 {
64         if(already_running) return;
65         already_running = 1;
66         constrain_ratio = mwindow->defaults->get("SCALECONSTRAIN", 0);
67         scale_data = mwindow->defaults->get("SCALEDATA", 0);
68         auto_aspect = mwindow->defaults->get("AUTOASPECT", 0);
69         offsets[0] = offsets[1] = offsets[2] = offsets[3] = 0;
70
71         orig_dimension[0] = dimension[0] = mwindow->session->track_w;
72         orig_dimension[1] = dimension[1] = mwindow->session->track_h;
73         orig_dimension[2] = dimension[2] = mwindow->session->output_w;
74         orig_dimension[3] = dimension[3] = mwindow->session->output_h;
75         ratio[0] = ratio[1] = ratio[2] = ratio[3] = 1;
76         aspect_w = mwindow->session->aspect_w;
77         aspect_h = mwindow->session->aspect_h;
78
79         window = new ScaleWindow(this);
80         window->create_objects();
81         int result = window->run_window();
82         if(!result)
83         {
84                 int dummy_offsets[4];
85                 dummy_offsets[0] = dummy_offsets[1] = dummy_offsets[2] = dummy_offsets[3] = 0;
86 // Fake the offsets if data is scaled.
87
88 // fix tracks
89                 //mwindow->stop_playback(1);
90 // save the before undo
91                 mwindow->undo->update_undo_edits(_("Resize"), 0);
92                 mwindow->tracks->scale_video(dimension, scale_data ? dummy_offsets : offsets, scale_data);
93                 mwindow->session->track_w = dimension[0];
94                 mwindow->session->track_h = dimension[1];
95                 mwindow->session->output_w = dimension[2];
96                 mwindow->session->output_h = dimension[3];
97                 mwindow->session->aspect_w = aspect_w;
98                 mwindow->session->aspect_h = aspect_h;
99                 mwindow->video_window->resize_window();
100                 mwindow->draw();
101                 mwindow->undo->update_undo_edits();
102                 mwindow->session->changes_made = 1;
103                 mwindow->defaults->update("ASPECTW", aspect_w);
104                 mwindow->defaults->update("ASPECTH", aspect_h);
105                 mwindow->defaults->update("AUTOASPECT", auto_aspect);
106         }
107         delete window;
108
109         mwindow->defaults->update("SCALECONSTRAIN", constrain_ratio);
110         mwindow->defaults->update("SCALEDATA", scale_data);
111         already_running = 0;
112 }
113
114 int ScaleThread::update_window(int offset_updated)
115 {
116         int pair_start = 0;
117         int i, result, modified_item, dimension_modified = 0, ratio_modified = 0;
118
119         for(i = 0, result = 0; i < 4 && !result; i++)
120         {
121                 if(i == 2) pair_start = 2;
122                 if(dimension[i] < 0)
123                 {
124                         dimension[i] *= -1;
125                         result = 1;
126                         modified_item = i;
127                         dimension_modified = 1;
128                 }
129                 if(ratio[i] < 0)
130                 {
131                         ratio[i] *= -1;
132                         result = 1;
133                         modified_item = i;
134                         ratio_modified = 1;
135                 }
136         }
137
138         if(result)
139         {
140                 if(dimension_modified)
141                         ratio[modified_item] = (float)dimension[modified_item] / orig_dimension[modified_item];
142
143                 if(ratio_modified && !constrain_ratio)
144                 {
145                         dimension[modified_item] = (int)(orig_dimension[modified_item] * ratio[modified_item]);
146                         window->dimension[modified_item]->update((long)dimension[modified_item]);
147                 }
148
149                 for(i = pair_start; i < pair_start + 2 && constrain_ratio; i++)
150                 {
151                         if(dimension_modified ||
152                                 (i != modified_item && ratio_modified))
153                         {
154                                 ratio[i] = ratio[modified_item];
155                                 window->ratio[i]->update(ratio[i]);
156                         }
157
158                         if(ratio_modified ||
159                                 (i != modified_item && dimension_modified))
160                         {
161                                 dimension[i] = (int)(orig_dimension[i] * ratio[modified_item]);
162                                 window->dimension[i]->update((long)dimension[i]);
163                         }
164                 }
165         }
166
167 //      window->position1->draw();
168 //      window->position2->draw();
169 //printf("%d\n", offsets[0]);
170 //      if(!offset_updated)
171 //      {
172 //              window->offsets[0]->update(offsets[0]);
173 //              window->offsets[1]->update(offsets[1]);
174 //              window->offsets[2]->update(offsets[2]);
175 //              window->offsets[3]->update(offsets[3]);
176 //      }
177
178         update_aspect(window);
179         return 0;
180 }
181
182 int ScaleThread::update_aspect(ScaleWindow *window)
183 {
184         if(auto_aspect)
185         {
186                 char string[1024];
187                 mwindow->create_aspect_ratio(aspect_w, aspect_h, dimension[2], dimension[3]);
188                 sprintf(string, "%.0f", aspect_w);
189                 window->aspect_w->update(string);
190                 sprintf(string, "%.0f", aspect_h);
191                 window->aspect_h->update(string);
192         }
193 return 0;
194 }
195
196
197
198 ScaleWindow::ScaleWindow(ScaleThread *thread)
199  : BC_Window(_(PROGRAM_NAME ": Scale"), xS(370), yS(260), 0, 0)
200 { this->thread = thread; }
201
202 ScaleWindow::~ScaleWindow()
203 {
204 }
205
206 void ScaleWindow::create_objects()
207 {
208         int xs5 = xS(5), xs10 = xS(10), xs20 = xS(20), xs30 = xS(30), xs200 = xS(200);
209         int ys5 = yS(5), ys10 = yS(10), ys20 = yS(20), ys30 = yS(30);
210         lock_window("ScaleWindow::create_objects");
211         int x = xs10, y = ys10;
212         int x0 = x, x1 = x + xS(70), x2 = x1 = xS(110), x3 = x = xS(70);
213         add_subwindow(new BC_Title(x, y, _("New camera size:")));
214         add_subwindow(new BC_Title(x + xs200, y, _("New projector size:")));
215         y += ys30;
216         add_subwindow(new BC_Title(x0, y, _("Width:")));
217         add_subwindow(dimension[0] = new ScaleSizeText(x1, y, thread, &(thread->dimension[0])));
218         add_subwindow(new BC_Title(x2, y, _("Width:")));
219         add_subwindow(dimension[2] = new ScaleSizeText(x3, y, thread, &(thread->dimension[2])));
220
221         y += ys30;
222         add_subwindow(new BC_Title(x0, y, _("Height:")));
223         add_subwindow(dimension[1] = new ScaleSizeText(x1, y, thread, &(thread->dimension[1])));
224         add_subwindow(new BC_Title(x2, y, _("Height:")));
225         add_subwindow(dimension[3] = new ScaleSizeText(x3, y, thread, &(thread->dimension[3])));
226
227         y += ys30;
228         add_subwindow(new BC_Title(x0, y, _("W Ratio:")));
229         add_subwindow(ratio[0] = new ScaleRatioText(x1, y, thread, &(thread->ratio[0])));
230         add_subwindow(new BC_Title(x2, y, _("W Ratio:")));
231         add_subwindow(ratio[2] = new ScaleRatioText(x3, y, thread, &(thread->ratio[2])));
232
233         y += ys30;
234         add_subwindow(new BC_Title(x0, y, _("H Ratio:")));
235         add_subwindow(ratio[1] = new ScaleRatioText(x1, y, thread, &(thread->ratio[1])));
236         add_subwindow(new BC_Title(x2, y, _("H Ratio:")));
237         add_subwindow(ratio[3] = new ScaleRatioText(x3, y, thread, &(thread->ratio[3])));
238
239 //      y += ys30;
240 //      add_subwindow(new BC_Title(x0, y, "X Offset:"));
241 //      add_subwindow(offsets[0] = new ScaleOffsetText(x1, y, thread, &(thread->offsets[0])));
242 //      add_subwindow(new BC_Title(x2, y, "X Offset:"));
243 //      add_subwindow(offsets[2] = new ScaleOffsetText(x3, y, thread, &(thread->offsets[2])));
244 //
245 //      y += ys30;
246 //      add_subwindow(new BC_Title(x0, y, "Y Offset:"));
247 //      add_subwindow(offsets[1] = new ScaleOffsetText(x1, y, thread, &(thread->offsets[1])));
248 //      add_subwindow(new BC_Title(x2, y, "Y Offset:"));
249 //      add_subwindow(offsets[3] = new ScaleOffsetText(x3, y, thread, &(thread->offsets[3])));
250
251         y += ys30;
252         add_subwindow(new BC_Title(x, y, _("Aspect ratio:")));
253         x += xS(100);
254         char string[1024];
255         sprintf(string, "%.0f", thread->aspect_w);
256         add_subwindow(aspect_w = new ScaleAspectW(x, y, thread, &(thread->aspect_w), string));
257         x += xS(55);
258         add_subwindow(new BC_Title(x, y, ":"));
259         x += xs10;
260         sprintf(string, "%.0f", thread->aspect_h);
261         add_subwindow(aspect_h = new ScaleAspectH(x, y, thread, &(thread->aspect_h), string));
262         x += xS(60);
263         add_subwindow(new ScaleAspectAuto(x, y + 5, thread));
264
265         y += ys30;
266 //      x = xS(40);
267 //      add_subwindow(new BC_Title(x, y, _("Camera position:")));
268 //      x += xs200;
269 //      add_subwindow(new BC_Title(x, y, _("Projector position:")));
270
271 //      ScalePosition *position;
272 //      x = xS(60);
273 //      y += yS(25);
274 //      add_subwindow(position1 = new ScalePosition(x, y, thread, this,
275 //              &(thread->orig_dimension[0]), &(thread->dimension[0]), &(thread->offsets[0])));
276 //      position1->draw();
277
278 //      x += xs200;
279 //      add_subwindow(position2 = new ScalePosition(x, y, thread, this,
280 //              &(thread->orig_dimension[2]), &(thread->dimension[2]), &(thread->offsets[2])));
281 //      position2->draw();
282
283 //      y += yS(110);
284         x = xs10;
285         add_subwindow(new ScaleConstrain(x, y, thread));
286         x += xs200;
287         add_subwindow(new ScaleData(x, y, thread));
288
289         y += ys30;
290         x = xS(50);
291         add_subwindow(new BC_OKButton(x, y));
292         x += xs200;
293         add_subwindow(new BC_CancelButton(x, y));
294         unlock_window();
295 }
296
297 ScaleSizeText::ScaleSizeText(int x, int y, ScaleThread *thread, int *output)
298  : BC_TextBox(x, y, xS(100), 1, *output)
299 {
300         this->thread = thread;
301         this->output = output;
302 }
303 ScaleSizeText::~ScaleSizeText() {}
304 int ScaleSizeText::handle_event()
305 {
306         *output = atol(get_text());
307         *output /= 2;  *output *= 2;
308         if(*output <= 0) *output = 2;
309         if(*output > 10000) *output = 10000;
310         *output *= -1;
311         thread->update_window();
312 return 0;
313 }
314
315 ScaleOffsetText::ScaleOffsetText(int x, int y, ScaleThread *thread, int *output)
316  : BC_TextBox(x, y, xs(100), 1, *output)
317 { this->thread = thread; this->output = output; }
318 ScaleOffsetText::~ScaleOffsetText() {}
319 int ScaleOffsetText::handle_event()
320 {
321         *output = atol(get_text());
322         //if(*output <= 0) *output = 0;
323         if(*output > 10000) *output = 10000;
324         if(*output < -10000) *output = -10000;
325         thread->update_window(1);
326 return 0;
327 }
328
329 ScaleRatioText::ScaleRatioText(int x, int y, ScaleThread *thread, float *output)
330  : BC_TextBox(x, y, xS(100), 1, *output)
331 { this->thread = thread; this->output = output; }
332 ScaleRatioText::~ScaleRatioText() {}
333 int ScaleRatioText::handle_event()
334 {
335         *output = atof(get_text());
336         //if(*output <= 0) *output = 1;
337         if(*output > 10000) *output = 10000;
338         if(*output < -10000) *output = -10000;
339         *output *= -1;
340         thread->update_window();
341 return 0;
342 }
343
344
345
346
347 ScaleConstrain::ScaleConstrain(int x, int y, ScaleThread *thread)
348  : BC_CheckBox(x, y, thread->constrain_ratio, _("Constrain ratio"))
349 { this->thread = thread; }
350 ScaleConstrain::~ScaleConstrain() {}
351 int ScaleConstrain::handle_event()
352 {
353         thread->constrain_ratio = get_value();
354 return 0;
355 }
356
357 ScaleData::ScaleData(int x, int y, ScaleThread *thread)
358  : BC_CheckBox(x, y, thread->scale_data, _("Scale data"))
359 { this->thread = thread; }
360 ScaleData::~ScaleData() {}
361 int ScaleData::handle_event()
362 {
363         thread->scale_data = get_value();
364         thread->update_window();
365 return 0;
366 }
367
368
369 ScaleAspectAuto::ScaleAspectAuto(int x, int y, ScaleThread *thread)
370  : BC_CheckBox(x, y, thread->auto_aspect, _("Auto"))
371 { this->thread = thread; }
372
373 ScaleAspectAuto::~ScaleAspectAuto()
374 {
375 }
376
377 int ScaleAspectAuto::handle_event()
378 {
379         thread->auto_aspect = get_value();
380         thread->update_aspect(thread->window);
381 return 0;
382 }
383
384
385
386
387 ScaleAspectW::ScaleAspectW(int x, int y, ScaleThread *thread, float *output, char *string)
388  : BC_TextBox(x, y, xS(50), 1, string)
389 {
390         this->output = output;
391         this->thread = thread;
392 }
393 ScaleAspectW::~ScaleAspectW()
394 {
395 }
396
397 int ScaleAspectW::handle_event()
398 {
399         *output = atof(get_text());
400 return 0;
401 }
402
403
404 ScaleAspectH::ScaleAspectH(int x, int y, ScaleThread *thread, float *output, char *string)
405  : BC_TextBox(x, y, xS(50), 1, string)
406 {
407         this->output = output;
408         this->thread = thread;
409 }
410 ScaleAspectH::~ScaleAspectH()
411 {
412 }
413
414 int ScaleAspectH::handle_event()
415 {
416         *output = atof(get_text());
417 return 0;
418 }
419
420