4 * Copyright (C) 1997-2011 Adam Williams <broadcast at earthling dot net>
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.
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.
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
26 #include "awindowgui.h"
27 #include "batchrender.h"
28 #include "bcprogressbox.h"
29 #include "bcsignals.h"
32 #include "compresspopup.h"
33 #include "condition.h"
34 #include "confirmsave.h"
35 #include "cwindowgui.h"
40 #include "edlsession.h"
43 #include "filesystem.h"
45 #include "formatcheck.h"
46 #include "formatpopup.h"
47 #include "formattools.h"
48 #include "indexable.h"
52 #include "localsession.h"
53 #include "mainprogress.h"
54 #include "mainsession.h"
58 #include "mwindowgui.h"
60 #include "packagedispatcher.h"
61 #include "packagerenderer.h"
63 #include "playabletracks.h"
64 #include "preferences.h"
65 #include "preferencesthread.h"
66 #include "renderfarm.h"
68 #include "renderprofiles.h"
69 #include "statusbar.h"
73 #include "transportque.h"
76 #include "videoconfig.h"
84 RenderItem::RenderItem(MWindow *mwindow)
85 : BC_MenuItem(_("Render..."), _("Shift-R"), 'R')
87 this->mwindow = mwindow;
91 int RenderItem::handle_event()
93 mwindow->gui->unlock_window();
94 mwindow->render->start_interactive();
95 mwindow->gui->lock_window("RenderItem::handle_event");
108 RenderProgress::RenderProgress(MWindow *mwindow, Render *render)
111 this->mwindow = mwindow;
112 this->render = render;
114 Thread::set_synchronous(1);
117 RenderProgress::~RenderProgress()
124 void RenderProgress::run()
126 Thread::disable_cancel();
129 if(render->total_rendered != last_value)
131 render->progress->update(render->total_rendered);
132 last_value = render->total_rendered;
134 if(mwindow) mwindow->preferences_thread->update_rates();
137 Thread::enable_cancel();
139 Thread::disable_cancel();
145 MainPackageRenderer::MainPackageRenderer(Render *render)
148 this->render = render;
153 MainPackageRenderer::~MainPackageRenderer()
158 int MainPackageRenderer::get_master()
163 int MainPackageRenderer::get_result()
165 return render->result;
168 void MainPackageRenderer::set_result(int value)
171 render->result = value;
177 void MainPackageRenderer::set_progress(int64_t value)
179 render->counter_lock->lock("MainPackageRenderer::set_progress");
180 // Increase total rendered for all nodes
181 render->total_rendered += value;
183 // Update frames per second for master node
184 render->preferences->set_rate(frames_per_second, -1);
186 //printf("MainPackageRenderer::set_progress %d %ld %f\n", __LINE__, (long)value, frames_per_second);
188 // If non interactive, print progress out
189 if(!render->progress)
191 int64_t current_eta = render->progress_timer->get_scaled_difference(1000);
192 if(current_eta - render->last_eta > 1000)
197 if(render->total_rendered)
201 render->progress_max /
202 render->total_rendered -
207 char string[BCTEXTLEN];
208 Units::totext(string,
212 printf(_("\r%d%% ETA: %s "), (int)(100 *
213 (float)render->total_rendered /
214 render->progress_max),
217 render->last_eta = current_eta;
221 render->counter_lock->unlock();
223 // This locks the preferences
224 if(mwindow) mwindow->preferences->copy_rates_from(preferences);
227 int MainPackageRenderer::progress_cancelled()
229 return (render->progress && render->progress->is_cancelled()) ||
230 render->batch_cancelled;
234 Render::Render(MWindow *mwindow)
237 this->mwindow = mwindow;
242 package_lock = new Mutex("Render::package_lock");
243 counter_lock = new Mutex("Render::counter_lock");
244 completion = new Condition(0, "Render::completion");
245 progress_timer = new Timer;
246 range_type = RANGE_BACKCOMPAT;
247 thread = new RenderThread(mwindow, this);
259 // May be owned by someone else. This is owned by mwindow, so we don't care
261 // delete preferences;
262 delete progress_timer;
263 if( asset ) asset->Garbage::remove_user();
267 void Render::start_interactive()
269 if( !thread->running() ) {
270 mode = Render::INTERACTIVE;
271 BC_DialogThread::start();
273 else if( in_progress ) {
274 ErrorBox error_box(_(PROGRAM_NAME ": Error"),
275 mwindow->gui->get_abs_cursor_x(1),
276 mwindow->gui->get_abs_cursor_y(1));
277 error_box.create_objects(_("Already rendering"));
278 error_box.raise_window();
279 error_box.run_window();
281 else if( render_window ) {
282 render_window->raise_window();
287 void Render::start_batches(ArrayList<BatchRenderJob*> *jobs)
289 if(!thread->running())
291 mode = Render::BATCH;
297 else if( in_progress ) {
298 ErrorBox error_box(PROGRAM_NAME ": Error",
299 mwindow->gui->get_abs_cursor_x(1),
300 mwindow->gui->get_abs_cursor_y(1));
301 error_box.create_objects("Already rendering");
302 error_box.raise_window();
303 error_box.run_window();
305 // raise the window if rendering hasn't started yet
306 else if( render_window ) {
307 render_window->raise_window();
311 void Render::start_batches(ArrayList<BatchRenderJob*> *jobs,
312 BC_Hash *boot_defaults,
313 Preferences *preferences)
315 mode = Render::BATCH;
318 this->preferences = preferences;
324 this->preferences = 0;
328 BC_Window* Render::new_gui()
336 if(mode == Render::INTERACTIVE) {
337 // Fix the asset for rendering
338 if(!asset) asset = new Asset;
339 load_defaults(asset);
340 check_asset(mwindow->edl, *asset);
342 // Get format from user
343 render_window = new RenderWindow(mwindow,
346 mwindow->gui->get_abs_cursor_x(1),
347 mwindow->gui->get_abs_cursor_y(1));
348 render_window->create_objects();
351 return render_window;
354 void Render::handle_done_event(int result)
357 // add to recentlist only on OK
358 render_window->format_tools->path_recent->
359 add_item(File::formattostr(asset->format), asset->path);
364 void Render::handle_close_event(int result)
366 int format_error = 0;
370 // Check the asset format for errors.
371 FormatCheck format_check(asset);
372 format_error = format_check.check_format();
377 save_defaults(asset);
379 mwindow->save_defaults();
382 if(!format_error && !result)
384 if(debug) printf("Render::handle_close_event %d\n", __LINE__);
385 if(!result) start_render();
386 if(debug) printf("Render::handle_close_event %d\n", __LINE__);
393 void Render::stop_operation()
395 if(thread->Thread::running())
398 // Wait for completion
399 completion->lock("Render::stop_operation");
406 int Render::check_asset(EDL *edl, Asset &asset)
408 if(asset.video_data &&
409 edl->tracks->playable_video_tracks() &&
410 File::supports_video(asset.format))
412 asset.video_data = 1;
414 asset.width = edl->session->output_w;
415 asset.height = edl->session->output_h;
416 asset.interlace_mode = edl->session->interlace_mode;
417 asset.tcstart = (int64_t) (edl->session->get_frame_offset() +
418 edl->local_session->get_selectionstart() *
419 edl->session->frame_rate);
420 asset.tcend = (int64_t) (edl->session->get_frame_offset() +
421 edl->local_session->get_selectionend() *
422 edl->session->frame_rate);
426 asset.video_data = 0;
432 if(asset.audio_data &&
433 edl->tracks->playable_audio_tracks() &&
434 File::supports_audio(asset.format))
436 asset.audio_data = 1;
437 asset.channels = edl->session->audio_channels;
438 asset.tcstart = (int64_t) (edl->session->get_frame_offset() +
439 edl->local_session->get_selectionstart() *
440 edl->session->sample_rate);
441 asset.tcend = (int64_t) (edl->session->get_frame_offset() +
442 edl->local_session->get_selectionend() *
443 edl->session->sample_rate);
447 asset.audio_data = 0;
453 if(!asset.audio_data &&
461 int Render::fix_strategy(int strategy, int use_renderfarm)
465 if(strategy == FILE_PER_LABEL)
466 strategy = FILE_PER_LABEL_FARM;
468 if(strategy == SINGLE_PASS)
469 strategy = SINGLE_PASS_FARM;
473 if(strategy == FILE_PER_LABEL_FARM)
474 strategy = FILE_PER_LABEL;
476 if(strategy == SINGLE_PASS_FARM)
477 strategy = SINGLE_PASS;
482 void Render::start_progress()
484 char filename[BCTEXTLEN];
485 char string[BCTEXTLEN];
488 progress_max = packages->get_progress_max();
490 progress_timer->update();
494 // Generate the progress box
495 fs.extract_name(filename, default_asset->path);
496 sprintf(string, _("Rendering %s..."), filename);
498 // Don't bother with the filename since renderfarm defeats the meaning
499 progress = mwindow->mainprogress->start_progress(_("Rendering..."),
501 render_progress = new RenderProgress(mwindow, this);
502 render_progress->start();
506 void Render::stop_progress()
510 char string[BCTEXTLEN], string2[BCTEXTLEN];
511 delete render_progress;
512 progress->get_time(string);
513 elapsed_time = progress->get_time();
514 progress->stop_progress();
517 sprintf(string2, _("Rendering took %s"), string);
518 mwindow->gui->lock_window("");
519 mwindow->gui->show_message(string2);
520 mwindow->gui->stop_hourglass();
521 mwindow->gui->unlock_window();
528 void Render::start_render()
537 void Render::create_filename(char *path,
544 int len = strlen(default_path);
545 char printf_string[BCTEXTLEN];
547 for(i = 0, j = 0; i < number_start; i++, j++)
549 printf_string[j] = default_path[i];
553 sprintf(&printf_string[j], "%%0%dd", total_digits);
554 j = strlen(printf_string);
557 // Copy remainder of string
558 for( ; i < len; i++, j++)
560 printf_string[j] = default_path[i];
562 printf_string[j] = 0;
563 // Print the printf argument to the path
564 sprintf(path, printf_string, current_number);
567 void Render::get_starting_number(char *path,
573 int len = strlen(path);
574 char number_text[BCTEXTLEN];
582 ptr2 = strrchr(path, '/');
584 // Search for first 0 after last /.
586 ptr = strchr(ptr2, '0');
588 if(ptr && isdigit(*ptr))
590 number_start = ptr - path;
592 // Store the first number
593 char *ptr2 = number_text;
597 current_number = atol(number_text);
598 total_digits = strlen(number_text);
602 // No number found or number not long enough
603 if(total_digits < min_digits)
607 total_digits = min_digits;
612 int Render::load_defaults(Asset *asset)
614 strategy = mwindow->defaults->get("RENDER_STRATEGY", SINGLE_PASS);
615 load_mode = mwindow->defaults->get("RENDER_LOADMODE", LOADMODE_NEW_TRACKS);
616 range_type = mwindow->defaults->get("RENDER_RANGE_TYPE", RANGE_PROJECT);
618 // some defaults which work
619 asset->video_data = 1;
620 asset->audio_data = 1;
621 asset->format = FILE_FFMPEG;
622 strcpy(asset->acodec, "mp4.qt");
623 strcpy(asset->vcodec, "mp4.qt");
625 asset->load_defaults(mwindow->defaults,
626 "RENDER_", 1, 1, 1, 1, 1);
630 int Render::load_profile(int profile_slot, Asset *asset)
632 char string_name[100];
633 sprintf(string_name, "RENDER_%i_STRATEGY", profile_slot);
634 strategy = mwindow->defaults->get(string_name, SINGLE_PASS);
635 // Load mode is not part of the profile
636 // printf(string_name, "RENDER_%i_LOADMODE", profile_slot);
637 // load_mode = mwindow->defaults->get(string_name, LOADMODE_NEW_TRACKS);
638 sprintf(string_name, "RENDER_%i_RANGE_TYPE", profile_slot);
639 range_type = mwindow->defaults->get(string_name, RANGE_PROJECT);
641 sprintf(string_name, "RENDER_%i_", profile_slot);
642 asset->load_defaults(mwindow->defaults,
643 string_name, 1, 1, 1, 1, 1);
648 int Render::save_defaults(Asset *asset)
650 mwindow->defaults->update("RENDER_STRATEGY", strategy);
651 mwindow->defaults->update("RENDER_LOADMODE", load_mode);
652 mwindow->defaults->update("RENDER_RANGE_TYPE", range_type);
654 asset->save_defaults(mwindow->defaults,
655 "RENDER_", 1, 1, 1, 1, 1);
660 static void run_script(const char *script, const char *arg)
662 char *const argv[] = { (char*)script, (char*)arg, 0 };
663 execvp(script ,&argv[0]);
664 perror("execvp script failed");
668 RenderThread::RenderThread(MWindow *mwindow, Render *render)
671 this->mwindow = mwindow;
672 this->render = render;
675 RenderThread::~RenderThread()
680 void RenderThread::render_single(int test_overwrite,
686 // Total length in seconds
688 RenderFarmServer *farm_server = 0;
693 render->in_progress = 1;
696 render->default_asset = asset;
697 render->progress = 0;
702 if(!render->preferences)
703 render->preferences = new Preferences;
705 render->preferences->copy_from(mwindow->preferences);
709 // Create rendering command
710 TransportCommand *command = new TransportCommand;
711 command->command = NORMAL_FWD;
712 command->get_edl()->copy_all(edl);
713 command->change_type = CHANGE_ALL;
715 if (range_type == RANGE_BACKCOMPAT) {
716 // Get highlighted playback range
717 command->set_playback_range();
718 // Adjust playback range with in/out points
719 command->playback_range_adjust_inout();
721 else if (range_type == RANGE_PROJECT) {
722 command->playback_range_project();
724 else if (range_type == RANGE_SELECTION) {
725 command->set_playback_range();
727 else if (range_type == RANGE_INOUT) {
728 command->playback_range_inout();
731 render->packages = new PackageDispatcher;
734 CICache *audio_cache = new CICache(render->preferences);
735 CICache *video_cache = new CICache(render->preferences);
737 render->default_asset->frame_rate = command->get_edl()->session->frame_rate;
738 render->default_asset->sample_rate = command->get_edl()->session->sample_rate;
740 // Conform asset to EDL. Find out if any tracks are playable.
741 render->result = render->check_asset(command->get_edl(),
742 *render->default_asset);
746 // Get total range to render
747 render->total_start = command->start_position;
748 render->total_end = command->end_position;
749 total_length = render->total_end - render->total_start;
752 if(EQUIV(total_length, 0))
761 // Stop background rendering
762 if(mwindow) mwindow->stop_brender();
764 fs.complete_path(render->default_asset->path);
765 strategy = Render::fix_strategy(strategy, render->preferences->use_renderfarm);
767 render->result = render->packages->create_packages(mwindow,
771 render->default_asset,
778 render->total_rendered = 0;
782 // Start dispatching external jobs
785 mwindow->gui->lock_window("Render::render 1");
786 mwindow->gui->show_message(_("Starting render farm"));
787 mwindow->gui->start_hourglass();
788 mwindow->gui->unlock_window();
792 printf("Render::render: starting render farm\n");
795 if(strategy == SINGLE_PASS_FARM || strategy == FILE_PER_LABEL_FARM)
797 farm_server = new RenderFarmServer(mwindow,
802 &render->total_rendered,
803 render->counter_lock,
804 render->default_asset,
807 render->result = farm_server->start_clients();
813 mwindow->gui->lock_window("Render::render 2");
814 mwindow->gui->show_message(_("Failed to start render farm"),
815 mwindow->theme->message_error);
816 mwindow->gui->stop_hourglass();
817 mwindow->gui->unlock_window();
821 printf("Render::render: Failed to start render farm\n");
827 // Perform local rendering
832 render->start_progress();
837 MainPackageRenderer package_renderer(render);
838 render->result = package_renderer.initialize(mwindow,
839 command->get_edl(), // Copy of master EDL
841 render->default_asset);
849 while(!render->result)
851 // Get unfinished job
852 RenderPackage *package;
854 if(strategy == SINGLE_PASS_FARM)
856 package = render->packages->get_package(
857 package_renderer.frames_per_second,
863 package = render->packages->get_package(0, -1, 1);
878 if(package_renderer.render_package(package))
886 printf("Render::render_single: Session finished.\n");
892 if(strategy == SINGLE_PASS_FARM || strategy == FILE_PER_LABEL_FARM)
894 farm_server->wait_clients();
895 render->result |= render->packages->packages_are_done();
898 if(debug) printf("Render::render %d\n", __LINE__);
902 (!render->progress || !render->progress->is_cancelled()) &&
903 !render->batch_cancelled)
905 if(debug) printf("Render::render %d\n", __LINE__);
908 if(debug) printf("Render::render %d\n", __LINE__);
909 ErrorBox error_box(_(PROGRAM_NAME ": Error"),
910 mwindow->gui->get_abs_cursor_x(1),
911 mwindow->gui->get_abs_cursor_y(1));
912 error_box.create_objects(_("Error rendering data."));
913 error_box.raise_window();
914 error_box.run_window();
915 if(debug) printf("Render::render %d\n", __LINE__);
919 printf("Render::render: Error rendering data\n");
922 if(debug) printf("Render::render %d\n", __LINE__);
924 // Delete the progress box
925 render->stop_progress();
927 if(debug) printf("Render::render %d\n", __LINE__);
931 // Paste all packages into timeline if desired
933 if(!render->result &&
934 render->load_mode != LOADMODE_NOTHING &&
936 render->mode != Render::BATCH)
938 if(debug) printf("Render::render %d\n", __LINE__);
939 mwindow->gui->lock_window("Render::render 3");
940 if(debug) printf("Render::render %d\n", __LINE__);
942 mwindow->undo->update_undo_before();
944 if(debug) printf("Render::render %d\n", __LINE__);
947 ArrayList<Indexable*> *assets = render->packages->get_asset_list();
948 if(debug) printf("Render::render %d\n", __LINE__);
949 if(render->load_mode == LOADMODE_PASTE)
951 if(debug) printf("Render::render %d\n", __LINE__);
952 mwindow->load_assets(assets,
957 mwindow->edl->session->labels_follow_edits,
958 mwindow->edl->session->plugins_follow_edits,
959 mwindow->edl->session->autos_follow_edits,
961 if(debug) printf("Render::render %d\n", __LINE__);
962 for(int i = 0; i < assets->size(); i++)
963 assets->get(i)->Garbage::remove_user();
965 if(debug) printf("Render::render %d\n", __LINE__);
968 mwindow->save_backup();
969 if(debug) printf("Render::render %d\n", __LINE__);
970 mwindow->undo->update_undo_after(_("render"), LOAD_ALL);
971 if(debug) printf("Render::render %d\n", __LINE__);
972 mwindow->update_plugin_guis();
973 if(debug) printf("Render::render %d\n", __LINE__);
974 mwindow->gui->update(1,
981 if(debug) printf("Render::render %d\n", __LINE__);
982 mwindow->sync_parameters(CHANGE_ALL);
983 if(debug) printf("Render::render %d\n", __LINE__);
984 mwindow->gui->unlock_window();
987 mwindow->awindow->gui->async_update_assets();
989 if(debug) printf("Render::render %d\n", __LINE__);
992 if(debug) printf("Render::render %d\n", __LINE__);
997 mwindow->gui->lock_window("Render::render 3");
998 mwindow->gui->stop_hourglass();
999 mwindow->gui->unlock_window();
1002 //printf("Render::render 110\n");
1003 // Need to restart because brender always stops before render.
1005 mwindow->restart_brender();
1006 if(farm_server) delete farm_server;
1010 // Must delete packages after server
1011 delete render->packages;
1013 render->packages = 0;
1014 render->in_progress = 0;
1015 render->completion->unlock();
1016 if(debug) printf("Render::render %d\n", __LINE__);
1019 void RenderThread::run()
1021 if(render->mode == Render::INTERACTIVE)
1023 render_single(1, render->asset, mwindow->edl, render->strategy, render->range_type);
1026 if(render->mode == Render::BATCH)
1029 // printf("RenderThread::run %d %d %d\n",
1031 // render->jobs->total,
1033 for(int i = 0; i < render->jobs->total && !render->result; i++)
1036 BatchRenderJob *job = render->jobs->values[i];
1040 if( *job->edl_path == '@' )
1042 run_script(job->edl_path+1, job->asset->path);
1047 mwindow->batch_render->update_active(i);
1051 printf("Render::run: %s\n", job->edl_path);
1056 FileXML *file = new FileXML;
1058 edl->create_objects();
1059 file->read_from_file(job->edl_path);
1060 edl->load_xml(file, LOAD_ALL);
1063 render_single(0, job->asset, edl, job->strategy, RANGE_BACKCOMPAT);
1066 edl->Garbage::remove_user();
1071 mwindow->batch_render->update_done(i, 1, render->elapsed_time);
1074 char string[BCTEXTLEN];
1075 render->elapsed_time =
1076 (double)render->progress_timer->get_scaled_difference(1);
1077 Units::totext(string,
1078 render->elapsed_time,
1080 printf("Render::run: done in %s\n", string);
1086 mwindow->batch_render->update_active(-1);
1088 printf("Render::run: failed\n");
1096 mwindow->batch_render->update_active(-1);
1097 mwindow->batch_render->update_done(-1, 0, 0);
1107 RenderWindow::RenderWindow(MWindow *mwindow,
1112 : BC_Window(_(PROGRAM_NAME ": Render"),
1113 x - WIDTH / 2, y - HEIGHT / 2,
1114 WIDTH, HEIGHT, WIDTH, HEIGHT,
1117 this->mwindow = mwindow;
1118 this->render = render;
1119 this->asset = asset;
1122 RenderWindow::~RenderWindow()
1125 lock_window("RenderWindow::~RenderWindow");
1127 delete format_tools;
1136 void RenderWindow::load_profile(int profile_slot)
1138 render->load_profile(profile_slot, asset);
1139 update_range_type(render->range_type);
1140 format_tools->update(asset, &render->strategy);
1144 void RenderWindow::create_objects()
1147 lock_window("RenderWindow::create_objects");
1148 add_subwindow(new BC_Title(x,
1150 (char*)((render->strategy == FILE_PER_LABEL ||
1151 render->strategy == FILE_PER_LABEL_FARM) ?
1152 _("Select the first file to render to:") :
1153 _("Select a file to render to:"))));
1156 format_tools = new FormatTools(mwindow, this, asset);
1157 format_tools->create_objects(x, y,
1158 1, 1, 1, 1, 0, 1, 0, 0, &render->strategy, 0);
1160 add_subwindow(new BC_Title(x, y, _("Render range:")));
1163 add_subwindow(rangeproject = new RenderRangeProject(this,
1164 render->range_type == RANGE_PROJECT, x, y));
1166 add_subwindow(rangeselection = new RenderRangeSelection(this,
1167 render->range_type == RANGE_SELECTION, x, y));
1169 add_subwindow(rangeinout = new RenderRangeInOut(this,
1170 render->range_type == RANGE_INOUT, x, y));
1174 renderprofile = new RenderProfile(mwindow, this, x, y, 1);
1175 renderprofile->create_objects();
1178 loadmode = new LoadMode(mwindow, this, x, y, &render->load_mode, 1);
1179 loadmode->create_objects();
1181 add_subwindow(new BC_OKButton(this));
1182 add_subwindow(new BC_CancelButton(this));
1187 void RenderWindow::update_range_type(int range_type)
1189 render->range_type = range_type;
1190 rangeproject->update(range_type == RANGE_PROJECT);
1191 rangeselection->update(range_type == RANGE_SELECTION);
1192 rangeinout->update(range_type == RANGE_INOUT);
1196 RenderRangeProject::RenderRangeProject(RenderWindow *rwindow, int value, int x, int y)
1197 : BC_Radial(x, y, value, _("Project"))
1199 this->rwindow = rwindow;
1201 int RenderRangeProject::handle_event()
1203 rwindow->update_range_type(RANGE_PROJECT);
1207 RenderRangeSelection::RenderRangeSelection(RenderWindow *rwindow, int value, int x, int y)
1208 : BC_Radial(x, y, value, _("Selection"))
1210 this->rwindow = rwindow;
1212 int RenderRangeSelection::handle_event()
1214 rwindow->update_range_type(RANGE_SELECTION);
1219 RenderRangeInOut::RenderRangeInOut(RenderWindow *rwindow, int value, int x, int y)
1220 : BC_Radial(x, y, value, _("In/Out Points"))
1222 this->rwindow = rwindow;
1224 int RenderRangeInOut::handle_event()
1226 rwindow->update_range_type(RANGE_INOUT);