4 * Copyright (C) 1997-2012 Adam Williams <broadcast at earthling dot net>
5 * Copyright (C) 2003-2016 Cinelerra CV contributors
7 * This program 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 2 of the License, or
10 * (at your option) any later version.
12 * This program 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.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include "cwindowgui.h"
29 #include "edlsession.h"
30 #include "formatpresets.h"
32 #include "levelwindow.h"
33 #include "levelwindowgui.h"
34 #include "mainerror.h"
38 #include "mwindowgui.h"
40 #include "preferences.h"
41 #include "rotateframe.h"
42 #include "setformat.h"
46 #include "vwindowgui.h"
50 SetFormat::SetFormat(MWindow *mwindow)
51 : BC_MenuItem(_("Format..."), _("Shift-F"), 'F')
54 this->mwindow = mwindow;
55 thread = new SetFormatThread(mwindow);
58 SetFormat::~SetFormat()
63 int SetFormat::handle_event()
65 if(!thread->running())
71 // window_lock has to be locked but window can't be locked until after
72 // it is known to exist, so we neglect window_lock for now
75 thread->window_lock->lock("SetFormat::handle_event");
76 thread->window->lock_window("SetFormat::handle_event");
77 thread->window->raise_window();
78 thread->window->unlock_window();
79 thread->window_lock->unlock();
85 SetFormatThread::SetFormatThread(MWindow *mwindow)
88 this->mwindow = mwindow;
89 window_lock = new Mutex("SetFormatThread::window_lock");
93 SetFormatThread::~SetFormatThread()
103 void SetFormatThread::run()
105 orig_dimension[0] = dimension[0] = mwindow->edl->session->output_w;
106 orig_dimension[1] = dimension[1] = mwindow->edl->session->output_h;
107 auto_aspect = mwindow->defaults->get("AUTOASPECT", 0);
109 ratio[0] = ratio[1] = 1;
111 new_settings = new EDL;
112 new_settings->create_objects();
113 new_settings->copy_session(mwindow->edl);
115 // This locks mwindow, so it must be done outside window_lock
116 int x = mwindow->gui->get_abs_cursor_x(1) - mwindow->theme->setformat_w / 2;
117 int y = mwindow->gui->get_abs_cursor_y(1) - mwindow->theme->setformat_h / 2;
119 window_lock->lock("SetFormatThread::run 1");
120 window = new SetFormatWindow(mwindow, this, x, y);
121 window->create_objects();
122 window_lock->unlock();
124 int result = window->run_window();
127 window_lock->lock("SetFormatThread::run 2");
130 window_lock->unlock();
138 mwindow->defaults->update("AUTOASPECT", auto_aspect);
139 new_settings->Garbage::remove_user();
142 void SetFormatThread::apply_changes()
144 double new_samplerate = new_settings->session->sample_rate;
145 double old_samplerate = mwindow->edl->session->sample_rate;
146 double new_framerate = new_settings->session->frame_rate;
147 double old_framerate = mwindow->edl->session->frame_rate;
148 int new_channels = new_settings->session->audio_channels;
149 CLAMP(new_channels, 1, MAXCHANNELS);
153 mwindow->undo->update_undo_before();
155 memcpy(&mwindow->preferences->channel_positions[new_channels - 1],
156 new_settings->session->achannel_positions,
157 sizeof(mwindow->preferences->channel_positions[new_channels - 1]));
160 mwindow->edl->copy_session(new_settings, 1);
161 mwindow->edl->session->output_w = dimension[0];
162 mwindow->edl->session->output_h = dimension[1];
163 mwindow->edl->retrack();
164 mwindow->edl->rechannel();
165 mwindow->edl->resample(old_samplerate, new_samplerate, TRACK_AUDIO);
166 mwindow->edl->resample(old_framerate, new_framerate, TRACK_VIDEO);
167 mwindow->save_backup();
168 mwindow->undo->update_undo_after(_("set format"), LOAD_ALL);
170 mwindow->resync_guis();
173 void SetFormatThread::update()
175 window->sample_rate->update(new_settings->session->sample_rate);
176 window->channels->update((int64_t)new_settings->session->audio_channels);
177 window->frame_rate->update((float)new_settings->session->frame_rate);
180 window->auto_aspect->update(0);
183 dimension[0] = new_settings->session->output_w;
184 window->dimension[0]->update((int64_t)dimension[0]);
185 dimension[1] = new_settings->session->output_h;
186 window->dimension[1]->update((int64_t)dimension[1]);
188 ratio[0] = (float)dimension[0] / orig_dimension[0];
189 window->ratio[0]->update(ratio[0]);
190 ratio[1] = (float)dimension[1] / orig_dimension[1];
191 window->ratio[1]->update(ratio[1]);
193 window->aspect_w->update(new_settings->session->aspect_w);
194 window->aspect_h->update(new_settings->session->aspect_h);
195 window->interlace_pulldown->update(new_settings->session->interlace_mode);
196 window->color_model->update_value(new_settings->session->color_model);
198 window->canvas->draw();
201 void SetFormatThread::update_window()
203 int i, result, modified_item = 0, dimension_modified = 0, ratio_modified = 0;
205 for(i = 0, result = 0; i < 2 && !result; i++)
212 dimension_modified = 1;
225 if(dimension_modified)
226 ratio[modified_item] = (float)dimension[modified_item] / orig_dimension[modified_item];
228 if(ratio_modified && !constrain_ratio)
230 dimension[modified_item] = (int)(orig_dimension[modified_item] * ratio[modified_item]);
231 window->dimension[modified_item]->update((int64_t)dimension[modified_item]);
234 for(i = 0; i < 2; i++)
236 if(dimension_modified ||
237 (i != modified_item && ratio_modified))
239 if(constrain_ratio) ratio[i] = ratio[modified_item];
240 window->ratio[i]->update(ratio[i]);
244 (i != modified_item && dimension_modified))
248 dimension[i] = (int)(orig_dimension[i] * ratio[modified_item]);
249 window->dimension[i]->update((int64_t)dimension[i]);
258 void SetFormatThread::update_aspect()
262 char string[BCTEXTLEN];
263 MWindow::create_aspect_ratio(new_settings->session->aspect_w,
264 new_settings->session->aspect_h,
267 sprintf(string, "%.02f", new_settings->session->aspect_w);
268 window->aspect_w->update(string);
269 sprintf(string, "%.02f", new_settings->session->aspect_h);
270 window->aspect_h->update(string);
275 SetFormatWindow::SetFormatWindow(MWindow *mwindow,
276 SetFormatThread *thread, int x, int y)
277 : BC_Window(_(PROGRAM_NAME ": Set Format"), x, y,
278 mwindow->theme->setformat_w, mwindow->theme->setformat_h,
281 this->mwindow = mwindow;
282 this->thread = thread;
284 // *** CONTEXT_HELP ***
285 context_help_set_keyword("Project and Media Attributes");
287 SetFormatWindow::~SetFormatWindow()
293 Sets the ratio of the new canvas size (W, H) to the old (previous) canvas size (W, H).
294 The new canvas size is recalculated based upon a certain factor in the W Ratio,
295 H Ratio fields. A practical use-case: The current resolution is 640x480, and for some reason
296 you want it to be 1.33 times wider. You don't have to calculate what 640x1.33 is;
297 you type 1.33 into the "W" input instead, and Cinelerra calculates it for you. */
299 void SetFormatWindow::create_objects()
301 lock_window("SetFormatWindow::create_objects");
302 int x = xS(10), y = mwindow->theme->setformat_y1;
305 mwindow->theme->draw_setformat_bg(this);
307 presets = new SetFormatPresets(mwindow, this, x, y);
308 presets->create_objects();
309 x = presets->x; // y = presets->y;
310 y = mwindow->theme->setformat_y2;
312 add_subwindow(new BC_Title(mwindow->theme->setformat_x1, y,
313 _("Audio"), LARGEFONT));
314 y = mwindow->theme->setformat_y3;
316 add_subwindow(new BC_Title(mwindow->theme->setformat_x1, y,
318 add_subwindow(sample_rate = new SetSampleRateTextBox(thread,
319 mwindow->theme->setformat_x2,
321 add_subwindow(new SampleRatePulldown(mwindow, sample_rate,
322 mwindow->theme->setformat_x2 + sample_rate->get_w(), y));
324 y += mwindow->theme->setformat_margin;
325 add_subwindow(new BC_Title(mwindow->theme->setformat_x1, y,
327 add_subwindow(channels = new SetChannelsTextBox(thread,
328 mwindow->theme->setformat_x2, y));
329 add_subwindow(new BC_ITumbler(channels, 0, MAXCHANNELS,
330 mwindow->theme->setformat_x2 + channels->get_w(), y));
332 y += mwindow->theme->setformat_margin;
333 add_subwindow(new BC_Title(mwindow->theme->setformat_x1, y,
334 _("Channel positions:")));
335 y += mwindow->theme->setformat_margin;
336 add_subwindow(channels_reset = new SetChannelsReset(thread,
337 mwindow->theme->setformat_x1, y,
339 add_subwindow(canvas = new SetChannelsCanvas(mwindow,
341 mwindow->theme->setformat_channels_x,
342 mwindow->theme->setformat_channels_y,
343 mwindow->theme->setformat_channels_w,
344 mwindow->theme->setformat_channels_h));
349 y = mwindow->theme->setformat_y2;
350 add_subwindow(new BC_Title(mwindow->theme->setformat_x3,
355 y = mwindow->theme->setformat_y3;
356 add_subwindow(new BC_Title(mwindow->theme->setformat_x3,
359 add_subwindow(frame_rate = new SetFrameRateTextBox(thread,
360 mwindow->theme->setformat_x4,
362 add_subwindow(new FrameRatePulldown(mwindow,
364 mwindow->theme->setformat_x4 + frame_rate->get_w(),
367 y += mwindow->theme->setformat_margin;
368 add_subwindow(new BC_Title(mwindow->theme->setformat_x3,
372 y += mwindow->theme->setformat_margin;
373 add_subwindow(title = new BC_Title(mwindow->theme->setformat_x3, y, _("Width:")));
374 add_subwindow(dimension[0] = new ScaleSizeText(mwindow->theme->setformat_x4,
377 &(thread->dimension[0])));
379 y += mwindow->theme->setformat_margin;
380 add_subwindow(new BC_Title(mwindow->theme->setformat_x3, y, _("Height:")));
381 add_subwindow(dimension[1] = new ScaleSizeText(mwindow->theme->setformat_x4,
384 &(thread->dimension[1])));
386 x = mwindow->theme->setformat_x4 + dimension[0]->get_w();
387 FrameSizePulldown *pulldown;
388 add_subwindow(pulldown = new FrameSizePulldown(mwindow->theme,
392 y - mwindow->theme->setformat_margin));
394 add_subwindow(new FormatSwapExtents(mwindow,
397 x + pulldown->get_w() + 5,
398 y - mwindow->theme->setformat_margin));
400 y += mwindow->theme->setformat_margin;
401 add_subwindow(new BC_Title(mwindow->theme->setformat_x3,
404 add_subwindow(ratio[0] = new ScaleRatioText(mwindow->theme->setformat_x4,
407 &(thread->ratio[0])));
409 y += mwindow->theme->setformat_margin;
410 add_subwindow(new BC_Title(mwindow->theme->setformat_x3,
413 add_subwindow(ratio[1] = new ScaleRatioText(mwindow->theme->setformat_x4,
416 &(thread->ratio[1])));
418 y += mwindow->theme->setformat_margin;
419 add_subwindow(new BC_Title(mwindow->theme->setformat_x3,
422 x = mwindow->theme->setformat_x4;
423 add_subwindow(textbox = new BC_TextBox(x, y, xS(100), 1, ""));
424 x += textbox->get_w();
425 add_subwindow(color_model = new ColormodelPulldown(mwindow, textbox,
426 &thread->new_settings->session->color_model, x, y));
428 y += mwindow->theme->setformat_margin;
429 add_subwindow(new BC_Title(mwindow->theme->setformat_x3,
431 _("Display Aspect ratio:")));
432 y += mwindow->theme->setformat_margin;
433 x = mwindow->theme->setformat_x3;
434 add_subwindow(aspect_w = new ScaleAspectText(x, y, thread,
435 &(thread->new_settings->session->aspect_w)));
436 x += aspect_w->get_w() + xS(5);
437 add_subwindow(new BC_Title(x, y, ":"));
439 add_subwindow(aspect_h = new ScaleAspectText(x,
442 &(thread->new_settings->session->aspect_h)));
443 x += aspect_h->get_w();
444 add_subwindow(new AspectPulldown(mwindow,
450 add_subwindow(auto_aspect = new ScaleAspectAuto(x, y, thread));
451 y += mwindow->theme->setformat_margin;
453 // --------------------
454 add_subwindow(new BC_Title(mwindow->theme->setformat_x3,
456 _("Interlace mode:")));
457 add_subwindow(textbox = new BC_TextBox(mwindow->theme->setformat_x4, y,
459 add_subwindow(interlace_pulldown = new InterlacemodePulldown(mwindow,
460 textbox, &(thread->new_settings->session->interlace_mode),
461 (ArrayList<BC_ListBoxItem*>*)&mwindow->interlace_project_modes,
462 mwindow->theme->setformat_x4 + textbox->get_w(), y));
463 y += mwindow->theme->setformat_margin;
465 add_subwindow(new BC_Title(mwindow->theme->setformat_x3,
467 _("Note: W/H ratio fields means multipliers \nrelative to previous canvas size \n")));
470 BC_CancelTextButton *cancel;
471 add_subwindow(ok = new BC_OKTextButton(this));
472 add_subwindow(cancel = new BC_CancelTextButton(this));
473 add_subwindow(new SetFormatApply((ok->get_x() + cancel->get_x()) / 2,
474 ok->get_y(), thread));
480 const char* SetFormatWindow::get_preset_text()
486 SetFormatPresets::SetFormatPresets(MWindow *mwindow,
487 SetFormatWindow *gui,
490 : FormatPresets(mwindow, 0, gui, x, y)
495 SetFormatPresets::~SetFormatPresets()
499 int SetFormatPresets::handle_event()
501 format_gui->thread->update();
502 return format_gui->channels_reset->handle_event();
505 EDL* SetFormatPresets::get_edl()
507 return format_gui->thread->new_settings;
512 SetSampleRateTextBox::SetSampleRateTextBox(SetFormatThread *thread, int x, int y)
513 : BC_TextBox(x, y, xS(100), 1, (int64_t)thread->new_settings->session->sample_rate)
515 this->thread = thread;
517 int SetSampleRateTextBox::handle_event()
519 thread->new_settings->session->sample_rate = CLIP(atol(get_text()), 1, 1000000);
523 SetChannelsTextBox::SetChannelsTextBox(SetFormatThread *thread, int x, int y)
524 : BC_TextBox(x, y, xS(100), 1, thread->new_settings->session->audio_channels)
526 this->thread = thread;
528 int SetChannelsTextBox::handle_event()
530 int new_channels = CLIP(atoi(get_text()), 0, MAXCHANNELS);
531 thread->new_settings->session->audio_channels = new_channels;
532 if(new_channels > 0) {
533 memcpy(thread->new_settings->session->achannel_positions,
534 &thread->mwindow->preferences->channel_positions[new_channels - 1],
535 sizeof(thread->new_settings->session->achannel_positions));
538 thread->window->canvas->draw();
542 SetChannelsReset::SetChannelsReset(SetFormatThread *thread, int x, int y, const char *text)
543 : BC_GenericButton(x, y, text)
545 this->thread = thread;
548 int SetChannelsReset::handle_event()
550 int channels = thread->new_settings->session->audio_channels;
551 int *achannels = thread->new_settings->session->achannel_positions;
552 for( int i=0; i<MAX_CHANNELS; ++i )
553 achannels[i] = default_audio_channel_position(i, channels);
554 thread->window->canvas->draw();
558 SetChannelsCanvas::SetChannelsCanvas(MWindow *mwindow,
559 SetFormatThread *thread, int x, int y, int w, int h)
560 : BC_SubWindow(x, y, w, h)
562 this->thread = thread;
563 this->mwindow = mwindow;
565 box_r = mwindow->theme->channel_position_data->get_w() / 2;
566 temp_picon = new VFrame(
567 mwindow->theme->channel_position_data->get_w(),
568 mwindow->theme->channel_position_data->get_h(),
569 mwindow->theme->channel_position_data->get_color_model(),
571 rotater = new RotateFrame(mwindow->preferences->processors,
572 mwindow->theme->channel_position_data->get_w(),
573 mwindow->theme->channel_position_data->get_h());
575 SetChannelsCanvas::~SetChannelsCanvas()
581 int SetChannelsCanvas::draw(int angle)
584 //int real_w = get_w() - box_r * 2;
585 //int real_h = get_h() - box_r * 2;
586 //int real_x = box_r;
587 //int real_y = box_r;
589 draw_top_background(get_top_level(), 0, 0, get_w(), get_h());
590 // draw_vframe(mwindow->theme->channel_bg_data, 0, 0);
597 set_color(mwindow->theme->channel_position_color);
598 for(int i = 0; i < thread->new_settings->session->audio_channels; i++)
600 get_dimensions(thread->new_settings->session->achannel_positions[i],
602 double rotate_angle = thread->new_settings->session->achannel_positions[i];
603 rotate_angle = -rotate_angle;
604 while(rotate_angle < 0) rotate_angle += 360;
605 rotater->rotate(temp_picon,
606 mwindow->theme->channel_position_data,
610 BC_Pixmap temp_pixmap(this,
614 draw_pixmap(&temp_pixmap, x, y);
615 sprintf(string, "%d", i + 1);
616 draw_text(x + 2, y + box_r * 2 - 2, string);
621 sprintf(string, _("%d degrees"), angle);
622 draw_text(this->get_w() / 2 - 40, this->get_h() / 2, string);
629 int SetChannelsCanvas::get_dimensions(int channel_position,
630 int &x, int &y, int &w, int &h)
632 int xs10 = xS(10), ys10 = yS(10);
633 int real_w = this->get_w() - box_r * 2 - xs10;
634 int real_h = this->get_h() - box_r * 2 - ys10;
635 float corrected_position = channel_position;
636 if(corrected_position < 0) corrected_position += 360;
637 Units::polar_to_xy((float)corrected_position, real_w / 2, x, y);
638 x += real_w / 2 + xs10 / 2;
639 y += real_h / 2 + ys10 / 2;
645 int SetChannelsCanvas::button_press_event()
647 if(!cursor_inside()) return 0;
648 // get active channel
649 for( int i = 0; i < thread->new_settings->session->audio_channels; i++ ) {
651 get_dimensions(thread->new_settings->session->achannel_positions[i], x, y, w, h);
652 if( get_cursor_x() > x && get_cursor_y() > y &&
653 get_cursor_x() < x + w && get_cursor_y() < y + h ) {
655 degree_offset = (int)Units::xy_to_polar(get_cursor_x() - this->get_w() / 2, get_cursor_y() - this->get_h() / 2);
657 if(degree_offset >= 360) degree_offset -= 360;
658 degree_offset -= thread->new_settings->session->achannel_positions[i];
659 draw(thread->new_settings->session->achannel_positions[i]);
666 int SetChannelsCanvas::button_release_event()
668 if(active_channel >= 0)
677 int SetChannelsCanvas::cursor_motion_event()
679 if(active_channel >= 0)
681 // get degrees of new channel
683 new_d = (int)Units::xy_to_polar(get_cursor_x() - this->get_w() / 2, get_cursor_y() - this->get_h() / 2);
685 new_d -= degree_offset;
687 while(new_d >= 360) new_d -= 360;
688 while(new_d < 0) new_d += 360;
690 if(thread->new_settings->session->achannel_positions[active_channel] != new_d)
692 thread->new_settings->session->achannel_positions[active_channel] = new_d;
693 int new_channels = thread->new_settings->session->audio_channels;
694 memcpy(&thread->mwindow->preferences->channel_positions[new_channels - 1],
695 thread->new_settings->session->achannel_positions,
696 sizeof(thread->mwindow->preferences->channel_positions[new_channels - 1]));
697 draw(thread->new_settings->session->achannel_positions[active_channel]);
705 SetFrameRateTextBox::SetFrameRateTextBox(SetFormatThread *thread, int x, int y)
706 : BC_TextBox(x, y, xS(100), 1, (float)thread->new_settings->session->frame_rate)
708 this->thread = thread;
711 int SetFrameRateTextBox::handle_event()
713 thread->new_settings->session->frame_rate = Units::atoframerate(get_text());
719 // SetVChannels::SetVChannels(SetFormatThread *thread, int x, int y)
720 // : BC_TextBox(x, y, xS(100), 1, thread->channels)
722 // this->thread = thread;
724 // int SetVChannels::handle_event()
726 // thread->channels = atol(get_text());
733 ScaleSizeText::ScaleSizeText(int x, int y, SetFormatThread *thread, int *output)
734 : BC_TextBox(x, y, xS(100), 1, *output)
736 this->thread = thread;
737 this->output = output;
739 ScaleSizeText::~ScaleSizeText()
742 int ScaleSizeText::handle_event()
744 *output = atol(get_text());
745 *output /= 2; *output *= 2;
746 if(*output <= 0) *output = 2;
747 if(*output > 10000) *output = 10000;
749 thread->update_window();
755 ScaleRatioText::ScaleRatioText(int x,
757 SetFormatThread *thread,
759 : BC_TextBox(x, y, xS(100), 1, *output)
761 this->thread = thread;
762 this->output = output;
764 ScaleRatioText::~ScaleRatioText()
767 int ScaleRatioText::handle_event()
769 *output = atof(get_text());
770 //if(*output <= 0) *output = 1;
771 if(*output > 10000) *output = 10000;
772 if(*output < -10000) *output = -10000;
774 thread->update_window();
779 ScaleAspectAuto::ScaleAspectAuto(int x, int y, SetFormatThread *thread)
780 : BC_CheckBox(x, y, thread->auto_aspect, _("Auto"))
782 this->thread = thread;
785 ScaleAspectAuto::~ScaleAspectAuto()
789 int ScaleAspectAuto::handle_event()
791 thread->auto_aspect = get_value();
792 thread->update_aspect();
796 ScaleAspectText::ScaleAspectText(int x, int y, SetFormatThread *thread, float *output)
797 : BC_TextBox(x, y, xS(70), 1, *output)
799 this->output = output;
800 this->thread = thread;
802 ScaleAspectText::~ScaleAspectText()
806 int ScaleAspectText::handle_event()
808 *output = atof(get_text());
813 SetFormatApply::SetFormatApply(int x, int y, SetFormatThread *thread)
814 : BC_GenericButton(x, y, _("Apply"))
816 this->thread = thread;
819 int SetFormatApply::handle_event()
821 thread->apply_changes();
826 FormatSwapExtents::FormatSwapExtents(MWindow *mwindow,
827 SetFormatThread *thread,
828 SetFormatWindow *gui,
831 : BC_Button(x, y, mwindow->theme->get_image_set("swap_extents"))
833 this->mwindow = mwindow;
834 this->thread = thread;
836 set_tooltip(_("Swap dimensions"));
839 int FormatSwapExtents::handle_event()
841 int w = thread->dimension[0];
842 int h = thread->dimension[1];
843 thread->dimension[0] = -h;
844 gui->dimension[0]->update((int64_t)h);
845 gui->dimension[1]->update((int64_t)w);
846 thread->update_window();
847 thread->dimension[1] = -w;
848 thread->update_window();