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()
292 void SetFormatWindow::create_objects()
294 lock_window("SetFormatWindow::create_objects");
295 int x = xS(10), y = mwindow->theme->setformat_y1;
298 mwindow->theme->draw_setformat_bg(this);
300 presets = new SetFormatPresets(mwindow, this, x, y);
301 presets->create_objects();
302 x = presets->x; // y = presets->y;
303 y = mwindow->theme->setformat_y2;
305 add_subwindow(new BC_Title(mwindow->theme->setformat_x1, y,
306 _("Audio"), LARGEFONT));
307 y = mwindow->theme->setformat_y3;
309 add_subwindow(new BC_Title(mwindow->theme->setformat_x1, y,
311 add_subwindow(sample_rate = new SetSampleRateTextBox(thread,
312 mwindow->theme->setformat_x2,
314 add_subwindow(new SampleRatePulldown(mwindow, sample_rate,
315 mwindow->theme->setformat_x2 + sample_rate->get_w(), y));
317 y += mwindow->theme->setformat_margin;
318 add_subwindow(new BC_Title(mwindow->theme->setformat_x1, y,
320 add_subwindow(channels = new SetChannelsTextBox(thread,
321 mwindow->theme->setformat_x2, y));
322 add_subwindow(new BC_ITumbler(channels, 0, MAXCHANNELS,
323 mwindow->theme->setformat_x2 + channels->get_w(), y));
325 y += mwindow->theme->setformat_margin;
326 add_subwindow(new BC_Title(mwindow->theme->setformat_x1, y,
327 _("Channel positions:")));
328 y += mwindow->theme->setformat_margin;
329 add_subwindow(channels_reset = new SetChannelsReset(thread,
330 mwindow->theme->setformat_x1, y,
332 add_subwindow(canvas = new SetChannelsCanvas(mwindow,
334 mwindow->theme->setformat_channels_x,
335 mwindow->theme->setformat_channels_y,
336 mwindow->theme->setformat_channels_w,
337 mwindow->theme->setformat_channels_h));
342 y = mwindow->theme->setformat_y2;
343 add_subwindow(new BC_Title(mwindow->theme->setformat_x3,
348 y = mwindow->theme->setformat_y3;
349 add_subwindow(new BC_Title(mwindow->theme->setformat_x3,
352 add_subwindow(frame_rate = new SetFrameRateTextBox(thread,
353 mwindow->theme->setformat_x4,
355 add_subwindow(new FrameRatePulldown(mwindow,
357 mwindow->theme->setformat_x4 + frame_rate->get_w(),
360 y += mwindow->theme->setformat_margin;
361 add_subwindow(new BC_Title(mwindow->theme->setformat_x3,
365 y += mwindow->theme->setformat_margin;
366 add_subwindow(title = new BC_Title(mwindow->theme->setformat_x3, y, _("Width:")));
367 add_subwindow(dimension[0] = new ScaleSizeText(mwindow->theme->setformat_x4,
370 &(thread->dimension[0])));
372 y += mwindow->theme->setformat_margin;
373 add_subwindow(new BC_Title(mwindow->theme->setformat_x3, y, _("Height:")));
374 add_subwindow(dimension[1] = new ScaleSizeText(mwindow->theme->setformat_x4,
377 &(thread->dimension[1])));
379 x = mwindow->theme->setformat_x4 + dimension[0]->get_w();
380 FrameSizePulldown *pulldown;
381 add_subwindow(pulldown = new FrameSizePulldown(mwindow->theme,
385 y - mwindow->theme->setformat_margin));
387 add_subwindow(new FormatSwapExtents(mwindow,
390 x + pulldown->get_w() + 5,
391 y - mwindow->theme->setformat_margin));
393 y += mwindow->theme->setformat_margin;
394 add_subwindow(new BC_Title(mwindow->theme->setformat_x3,
397 add_subwindow(ratio[0] = new ScaleRatioText(mwindow->theme->setformat_x4,
400 &(thread->ratio[0])));
402 y += mwindow->theme->setformat_margin;
403 add_subwindow(new BC_Title(mwindow->theme->setformat_x3,
406 add_subwindow(ratio[1] = new ScaleRatioText(mwindow->theme->setformat_x4,
409 &(thread->ratio[1])));
411 y += mwindow->theme->setformat_margin;
412 add_subwindow(new BC_Title(mwindow->theme->setformat_x3,
415 x = mwindow->theme->setformat_x4;
416 add_subwindow(textbox = new BC_TextBox(x, y, xS(100), 1, ""));
417 x += textbox->get_w();
418 add_subwindow(color_model = new ColormodelPulldown(mwindow, textbox,
419 &thread->new_settings->session->color_model, x, y));
421 y += mwindow->theme->setformat_margin;
422 add_subwindow(new BC_Title(mwindow->theme->setformat_x3,
424 _("Aspect ratio:")));
425 y += mwindow->theme->setformat_margin;
426 x = mwindow->theme->setformat_x3;
427 add_subwindow(aspect_w = new ScaleAspectText(x, y, thread,
428 &(thread->new_settings->session->aspect_w)));
429 x += aspect_w->get_w() + xS(5);
430 add_subwindow(new BC_Title(x, y, ":"));
432 add_subwindow(aspect_h = new ScaleAspectText(x,
435 &(thread->new_settings->session->aspect_h)));
436 x += aspect_h->get_w();
437 add_subwindow(new AspectPulldown(mwindow,
443 add_subwindow(auto_aspect = new ScaleAspectAuto(x, y, thread));
444 y += mwindow->theme->setformat_margin;
446 // --------------------
447 add_subwindow(new BC_Title(mwindow->theme->setformat_x3,
449 _("Interlace mode:")));
450 add_subwindow(textbox = new BC_TextBox(mwindow->theme->setformat_x4, y,
452 add_subwindow(interlace_pulldown = new InterlacemodePulldown(mwindow,
453 textbox, &(thread->new_settings->session->interlace_mode),
454 (ArrayList<BC_ListBoxItem*>*)&mwindow->interlace_project_modes,
455 mwindow->theme->setformat_x4 + textbox->get_w(), y));
456 y += mwindow->theme->setformat_margin;
459 BC_CancelTextButton *cancel;
460 add_subwindow(ok = new BC_OKTextButton(this));
461 add_subwindow(cancel = new BC_CancelTextButton(this));
462 add_subwindow(new SetFormatApply((ok->get_x() + cancel->get_x()) / 2,
463 ok->get_y(), thread));
469 const char* SetFormatWindow::get_preset_text()
475 SetFormatPresets::SetFormatPresets(MWindow *mwindow,
476 SetFormatWindow *gui,
479 : FormatPresets(mwindow, 0, gui, x, y)
484 SetFormatPresets::~SetFormatPresets()
488 int SetFormatPresets::handle_event()
490 format_gui->thread->update();
491 return format_gui->channels_reset->handle_event();
494 EDL* SetFormatPresets::get_edl()
496 return format_gui->thread->new_settings;
501 SetSampleRateTextBox::SetSampleRateTextBox(SetFormatThread *thread, int x, int y)
502 : BC_TextBox(x, y, xS(100), 1, (int64_t)thread->new_settings->session->sample_rate)
504 this->thread = thread;
506 int SetSampleRateTextBox::handle_event()
508 thread->new_settings->session->sample_rate = CLIP(atol(get_text()), 1, 1000000);
512 SetChannelsTextBox::SetChannelsTextBox(SetFormatThread *thread, int x, int y)
513 : BC_TextBox(x, y, xS(100), 1, thread->new_settings->session->audio_channels)
515 this->thread = thread;
517 int SetChannelsTextBox::handle_event()
519 int new_channels = CLIP(atoi(get_text()), 0, MAXCHANNELS);
520 thread->new_settings->session->audio_channels = new_channels;
521 if(new_channels > 0) {
522 memcpy(thread->new_settings->session->achannel_positions,
523 &thread->mwindow->preferences->channel_positions[new_channels - 1],
524 sizeof(thread->new_settings->session->achannel_positions));
527 thread->window->canvas->draw();
531 SetChannelsReset::SetChannelsReset(SetFormatThread *thread, int x, int y, const char *text)
532 : BC_GenericButton(x, y, text)
534 this->thread = thread;
537 int SetChannelsReset::handle_event()
539 int channels = thread->new_settings->session->audio_channels;
540 int *achannels = thread->new_settings->session->achannel_positions;
541 for( int i=0; i<MAX_CHANNELS; ++i )
542 achannels[i] = default_audio_channel_position(i, channels);
543 thread->window->canvas->draw();
547 SetChannelsCanvas::SetChannelsCanvas(MWindow *mwindow,
548 SetFormatThread *thread, int x, int y, int w, int h)
549 : BC_SubWindow(x, y, w, h)
551 this->thread = thread;
552 this->mwindow = mwindow;
554 box_r = mwindow->theme->channel_position_data->get_w() / 2;
555 temp_picon = new VFrame(
556 mwindow->theme->channel_position_data->get_w(),
557 mwindow->theme->channel_position_data->get_h(),
558 mwindow->theme->channel_position_data->get_color_model(),
560 rotater = new RotateFrame(mwindow->preferences->processors,
561 mwindow->theme->channel_position_data->get_w(),
562 mwindow->theme->channel_position_data->get_h());
564 SetChannelsCanvas::~SetChannelsCanvas()
570 int SetChannelsCanvas::draw(int angle)
573 //int real_w = get_w() - box_r * 2;
574 //int real_h = get_h() - box_r * 2;
575 //int real_x = box_r;
576 //int real_y = box_r;
578 draw_top_background(get_top_level(), 0, 0, get_w(), get_h());
579 // draw_vframe(mwindow->theme->channel_bg_data, 0, 0);
586 set_color(mwindow->theme->channel_position_color);
587 for(int i = 0; i < thread->new_settings->session->audio_channels; i++)
589 get_dimensions(thread->new_settings->session->achannel_positions[i],
591 double rotate_angle = thread->new_settings->session->achannel_positions[i];
592 rotate_angle = -rotate_angle;
593 while(rotate_angle < 0) rotate_angle += 360;
594 rotater->rotate(temp_picon,
595 mwindow->theme->channel_position_data,
599 BC_Pixmap temp_pixmap(this,
603 draw_pixmap(&temp_pixmap, x, y);
604 sprintf(string, "%d", i + 1);
605 draw_text(x + 2, y + box_r * 2 - 2, string);
610 sprintf(string, _("%d degrees"), angle);
611 draw_text(this->get_w() / 2 - 40, this->get_h() / 2, string);
618 int SetChannelsCanvas::get_dimensions(int channel_position,
619 int &x, int &y, int &w, int &h)
621 int xs10 = xS(10), ys10 = yS(10);
622 int real_w = this->get_w() - box_r * 2 - xs10;
623 int real_h = this->get_h() - box_r * 2 - ys10;
624 float corrected_position = channel_position;
625 if(corrected_position < 0) corrected_position += 360;
626 Units::polar_to_xy((float)corrected_position, real_w / 2, x, y);
627 x += real_w / 2 + xs10 / 2;
628 y += real_h / 2 + ys10 / 2;
634 int SetChannelsCanvas::button_press_event()
636 if(!cursor_inside()) return 0;
637 // get active channel
638 for( int i = 0; i < thread->new_settings->session->audio_channels; i++ ) {
640 get_dimensions(thread->new_settings->session->achannel_positions[i], x, y, w, h);
641 if( get_cursor_x() > x && get_cursor_y() > y &&
642 get_cursor_x() < x + w && get_cursor_y() < y + h ) {
644 degree_offset = (int)Units::xy_to_polar(get_cursor_x() - this->get_w() / 2, get_cursor_y() - this->get_h() / 2);
646 if(degree_offset >= 360) degree_offset -= 360;
647 degree_offset -= thread->new_settings->session->achannel_positions[i];
648 draw(thread->new_settings->session->achannel_positions[i]);
655 int SetChannelsCanvas::button_release_event()
657 if(active_channel >= 0)
666 int SetChannelsCanvas::cursor_motion_event()
668 if(active_channel >= 0)
670 // get degrees of new channel
672 new_d = (int)Units::xy_to_polar(get_cursor_x() - this->get_w() / 2, get_cursor_y() - this->get_h() / 2);
674 new_d -= degree_offset;
676 while(new_d >= 360) new_d -= 360;
677 while(new_d < 0) new_d += 360;
679 if(thread->new_settings->session->achannel_positions[active_channel] != new_d)
681 thread->new_settings->session->achannel_positions[active_channel] = new_d;
682 int new_channels = thread->new_settings->session->audio_channels;
683 memcpy(&thread->mwindow->preferences->channel_positions[new_channels - 1],
684 thread->new_settings->session->achannel_positions,
685 sizeof(thread->mwindow->preferences->channel_positions[new_channels - 1]));
686 draw(thread->new_settings->session->achannel_positions[active_channel]);
694 SetFrameRateTextBox::SetFrameRateTextBox(SetFormatThread *thread, int x, int y)
695 : BC_TextBox(x, y, xS(100), 1, (float)thread->new_settings->session->frame_rate)
697 this->thread = thread;
700 int SetFrameRateTextBox::handle_event()
702 thread->new_settings->session->frame_rate = Units::atoframerate(get_text());
708 // SetVChannels::SetVChannels(SetFormatThread *thread, int x, int y)
709 // : BC_TextBox(x, y, xS(100), 1, thread->channels)
711 // this->thread = thread;
713 // int SetVChannels::handle_event()
715 // thread->channels = atol(get_text());
722 ScaleSizeText::ScaleSizeText(int x, int y, SetFormatThread *thread, int *output)
723 : BC_TextBox(x, y, xS(100), 1, *output)
725 this->thread = thread;
726 this->output = output;
728 ScaleSizeText::~ScaleSizeText()
731 int ScaleSizeText::handle_event()
733 *output = atol(get_text());
734 *output /= 2; *output *= 2;
735 if(*output <= 0) *output = 2;
736 if(*output > 10000) *output = 10000;
738 thread->update_window();
744 ScaleRatioText::ScaleRatioText(int x,
746 SetFormatThread *thread,
748 : BC_TextBox(x, y, xS(100), 1, *output)
750 this->thread = thread;
751 this->output = output;
753 ScaleRatioText::~ScaleRatioText()
756 int ScaleRatioText::handle_event()
758 *output = atof(get_text());
759 //if(*output <= 0) *output = 1;
760 if(*output > 10000) *output = 10000;
761 if(*output < -10000) *output = -10000;
763 thread->update_window();
768 ScaleAspectAuto::ScaleAspectAuto(int x, int y, SetFormatThread *thread)
769 : BC_CheckBox(x, y, thread->auto_aspect, _("Auto"))
771 this->thread = thread;
774 ScaleAspectAuto::~ScaleAspectAuto()
778 int ScaleAspectAuto::handle_event()
780 thread->auto_aspect = get_value();
781 thread->update_aspect();
785 ScaleAspectText::ScaleAspectText(int x, int y, SetFormatThread *thread, float *output)
786 : BC_TextBox(x, y, xS(70), 1, *output)
788 this->output = output;
789 this->thread = thread;
791 ScaleAspectText::~ScaleAspectText()
795 int ScaleAspectText::handle_event()
797 *output = atof(get_text());
802 SetFormatApply::SetFormatApply(int x, int y, SetFormatThread *thread)
803 : BC_GenericButton(x, y, _("Apply"))
805 this->thread = thread;
808 int SetFormatApply::handle_event()
810 thread->apply_changes();
815 FormatSwapExtents::FormatSwapExtents(MWindow *mwindow,
816 SetFormatThread *thread,
817 SetFormatWindow *gui,
820 : BC_Button(x, y, mwindow->theme->get_image_set("swap_extents"))
822 this->mwindow = mwindow;
823 this->thread = thread;
825 set_tooltip(_("Swap dimensions"));
828 int FormatSwapExtents::handle_event()
830 int w = thread->dimension[0];
831 int h = thread->dimension[1];
832 thread->dimension[0] = -h;
833 gui->dimension[0]->update((int64_t)h);
834 gui->dimension[1]->update((int64_t)w);
835 thread->update_window();
836 thread->dimension[1] = -w;
837 thread->update_window();