r851: Merge 2.1:
[cinelerra_cv/ct.git] / cinelerra / cwindowgui.C
blobca602ffb6987f6c9156daf91be11021c8738ddf2
1 #include "automation.h"
2 #include "autos.h"
3 #include "bcsignals.h"
4 #include "canvas.h"
5 #include "clip.h"
6 #include "cpanel.h"
7 #include "cplayback.h"
8 #include "ctimebar.h"
9 #include "cursors.h"
10 #include "cwindowgui.h"
11 #include "cwindow.h"
12 #include "cwindowtool.h"
13 #include "editpanel.h"
14 #include "edl.h"
15 #include "edlsession.h"
16 #include "floatauto.h"
17 #include "floatautos.h"
18 #include "keys.h"
19 #include "language.h"
20 #include "localsession.h"
21 #include "mainclock.h"
22 #include "mainmenu.h"
23 #include "mainundo.h"
24 #include "mainsession.h"
25 #include "maskauto.h"
26 #include "maskautos.h"
27 #include "meterpanel.h"
28 #include "mwindowgui.h"
29 #include "mwindow.h"
30 #include "mwindow.h"
31 #include "playtransport.h"
32 #include "theme.h"
33 #include "trackcanvas.h"
34 #include "tracks.h"
35 #include "transportque.h"
36 #include "vtrack.h"
39 static double my_zoom_table[] = 
41         0.25,
42         0.33,
43         0.50,
44         0.75,
45         1.0,
46         1.5,
47         2.0,
48         3.0,
49         4.0
52 static int total_zooms = sizeof(my_zoom_table) / sizeof(double);
55 CWindowGUI::CWindowGUI(MWindow *mwindow, CWindow *cwindow)
56  : BC_Window(PROGRAM_NAME ": Compositor",
57         mwindow->session->cwindow_x, 
58     mwindow->session->cwindow_y, 
59     mwindow->session->cwindow_w, 
60     mwindow->session->cwindow_h,
61     100,
62     100,
63     1,
64     1,
65     1,
66         BC_WindowBase::get_resources()->bg_color,
67         mwindow->edl->session->get_cwindow_display())
69         this->mwindow = mwindow;
70     this->cwindow = cwindow;
71         affected_track = 0;
72         affected_x = 0;
73         affected_y = 0;
74         affected_z = 0;
75         affected_keyframe = 0;
76         affected_point = 0;
77         x_offset = 0;
78         y_offset = 0;
79         x_origin = 0;
80         y_origin = 0;
81         current_operation = CWINDOW_NONE;
82         tool_panel = 0;
83         translating_zoom = 0;
84         active = 0;
85         inactive = 0;
86         crop_translate = 0;
89 CWindowGUI::~CWindowGUI()
91         if(tool_panel) delete tool_panel;
92         delete meters;
93         delete composite_panel;
94         delete canvas;
95         delete transport;
96         delete edit_panel;
97         delete zoom_panel;
98         delete active;
99         delete inactive;
102 int CWindowGUI::create_objects()
104         set_icon(mwindow->theme->get_image("cwindow_icon"));
106         active = new BC_Pixmap(this, mwindow->theme->get_image("cwindow_active"));
107         inactive = new BC_Pixmap(this, mwindow->theme->get_image("cwindow_inactive"));
109         mwindow->theme->get_cwindow_sizes(this, mwindow->session->cwindow_controls);
110         mwindow->theme->draw_cwindow_bg(this);
111         flash();
113 // Meters required by composite panel
114         meters = new CWindowMeters(mwindow, 
115                 this,
116                 mwindow->theme->cmeter_x,
117                 mwindow->theme->cmeter_y,
118                 mwindow->theme->cmeter_h);
119         meters->create_objects();
122         composite_panel = new CPanel(mwindow, 
123                 this, 
124                 mwindow->theme->ccomposite_x,
125                 mwindow->theme->ccomposite_y,
126                 mwindow->theme->ccomposite_w,
127                 mwindow->theme->ccomposite_h);
128         composite_panel->create_objects();
130         canvas = new CWindowCanvas(mwindow, this);
131         canvas->create_objects(mwindow->edl);
134         add_subwindow(timebar = new CTimeBar(mwindow,
135                 this,
136                 mwindow->theme->ctimebar_x,
137                 mwindow->theme->ctimebar_y,
138                 mwindow->theme->ctimebar_w, 
139                 mwindow->theme->ctimebar_h));
140         timebar->create_objects();
142         add_subwindow(slider = new CWindowSlider(mwindow, 
143                 cwindow, 
144                 mwindow->theme->cslider_x,
145                 mwindow->theme->cslider_y, 
146                 mwindow->theme->cslider_w));
148         transport = new CWindowTransport(mwindow, 
149                 this, 
150                 mwindow->theme->ctransport_x, 
151                 mwindow->theme->ctransport_y);
152         transport->create_objects();
153         transport->set_slider(slider);
155         edit_panel = new CWindowEditing(mwindow, cwindow);
156         edit_panel->set_meters(meters);
157         edit_panel->create_objects();
159 //      add_subwindow(clock = new MainClock(mwindow, 
160 //              mwindow->theme->ctime_x, 
161 //              mwindow->theme->ctime_y));
163         zoom_panel = new CWindowZoom(mwindow, 
164                 this, 
165                 mwindow->theme->czoom_x, 
166                 mwindow->theme->czoom_y);
167         zoom_panel->create_objects();
168         zoom_panel->zoom_text->add_item(new BC_MenuItem(AUTO_ZOOM));
169         if(!mwindow->edl->session->cwindow_scrollbars) zoom_panel->set_text(AUTO_ZOOM);
171 //      destination = new CWindowDestination(mwindow, 
172 //              this, 
173 //              mwindow->theme->cdest_x,
174 //              mwindow->theme->cdest_y);
175 //      destination->create_objects();
177 // Must create after meter panel
178         tool_panel = new CWindowTool(mwindow, this);
179         tool_panel->Thread::start();
180         
181         set_operation(mwindow->edl->session->cwindow_operation);
184         canvas->draw_refresh();
186         draw_status();
188         return 0;
191 int CWindowGUI::translation_event()
193         mwindow->session->cwindow_x = get_x();
194         mwindow->session->cwindow_y = get_y();
195         return 0;
198 int CWindowGUI::resize_event(int w, int h)
200         mwindow->session->cwindow_x = get_x();
201         mwindow->session->cwindow_y = get_y();
202         mwindow->session->cwindow_w = w;
203         mwindow->session->cwindow_h = h;
205         mwindow->theme->get_cwindow_sizes(this, mwindow->session->cwindow_controls);
206         mwindow->theme->draw_cwindow_bg(this);
207         flash();
209         composite_panel->reposition_buttons(mwindow->theme->ccomposite_x,
210                 mwindow->theme->ccomposite_y);
212         canvas->reposition_window(mwindow->edl,
213                 mwindow->theme->ccanvas_x,
214                 mwindow->theme->ccanvas_y,
215                 mwindow->theme->ccanvas_w,
216                 mwindow->theme->ccanvas_h);
218         timebar->resize_event();
220         slider->reposition_window(mwindow->theme->cslider_x,
221                 mwindow->theme->cslider_y, 
222                 mwindow->theme->cslider_w);
223 // Recalibrate pointer motion range
224         slider->set_position();
226         transport->reposition_buttons(mwindow->theme->ctransport_x, 
227                 mwindow->theme->ctransport_y);
229         edit_panel->reposition_buttons(mwindow->theme->cedit_x, 
230                 mwindow->theme->cedit_y);
232 //      clock->reposition_window(mwindow->theme->ctime_x, 
233 //              mwindow->theme->ctime_y);
235         zoom_panel->reposition_window(mwindow->theme->czoom_x, 
236                 mwindow->theme->czoom_y);
238 //      destination->reposition_window(mwindow->theme->cdest_x,
239 //              mwindow->theme->cdest_y);
241         meters->reposition_window(mwindow->theme->cmeter_x,
242                 mwindow->theme->cmeter_y,
243                 mwindow->theme->cmeter_h);
245         draw_status();
247         BC_WindowBase::resize_event(w, h);
248         return 1;
251 int CWindowGUI::button_press_event()
253         if(canvas->get_canvas())
254                 return canvas->button_press_event_base(canvas->get_canvas());
255         return 0;
258 int CWindowGUI::cursor_leave_event()
260         if(canvas->get_canvas())
261                 return canvas->cursor_leave_event_base(canvas->get_canvas());
262         return 0;
265 int CWindowGUI::cursor_enter_event()
267         if(canvas->get_canvas())
268                 return canvas->cursor_enter_event_base(canvas->get_canvas());
269         return 0;
272 int CWindowGUI::button_release_event()
274         if(canvas->get_canvas())
275                 return canvas->button_release_event();
276         return 0;
279 int CWindowGUI::cursor_motion_event()
281         if(canvas->get_canvas())
282         {
283                 canvas->get_canvas()->unhide_cursor();
284                 return canvas->cursor_motion_event();
285         }
286         return 0;
295 void CWindowGUI::draw_status()
297         if(canvas->get_canvas() && 
298                 canvas->get_canvas()->get_video_on() ||
299                 canvas->is_processing)
300         {
301                 draw_pixmap(active, 
302                         mwindow->theme->cstatus_x, 
303                         mwindow->theme->cstatus_y);
304         }
305         else
306         {
307                 draw_pixmap(inactive, 
308                         mwindow->theme->cstatus_x, 
309                         mwindow->theme->cstatus_y);
310         }
311         
312         flash(mwindow->theme->cstatus_x,
313                 mwindow->theme->cstatus_y,
314                 active->get_w(),
315                 active->get_h());
319 void CWindowGUI::zoom_canvas(int do_auto, double value, int update_menu)
321         if(do_auto)
322                 mwindow->edl->session->cwindow_scrollbars = 0;
323         else
324                 mwindow->edl->session->cwindow_scrollbars = 1;
326         float old_zoom = mwindow->edl->session->cwindow_zoom;
327         float new_zoom = value;
328         float x = canvas->w / 2;
329         float y = canvas->h / 2;
330         canvas->canvas_to_output(mwindow->edl, 
331                                 0, 
332                                 x, 
333                                 y);
334         x -= canvas->w_visible / 2 * old_zoom / new_zoom;
335         y -= canvas->h_visible / 2 * old_zoom / new_zoom;
337         canvas->update_zoom((int)x, 
338                 (int)y, 
339                 new_zoom);
340         canvas->reposition_window(mwindow->edl, 
341                 mwindow->theme->ccanvas_x,
342                 mwindow->theme->ccanvas_y,
343                 mwindow->theme->ccanvas_w,
344                 mwindow->theme->ccanvas_h);
345         canvas->draw_refresh();
349 // TODO
350 // Don't refresh the canvas in a load file operation which is going to
351 // refresh it anyway.
352 void CWindowGUI::set_operation(int value)
354         mwindow->edl->session->cwindow_operation = value;
356         composite_panel->set_operation(value);
357         edit_panel->update();
359         tool_panel->start_tool(value);
360         canvas->draw_refresh();
363 void CWindowGUI::update_tool()
365         tool_panel->update_values();
368 int CWindowGUI::close_event()
370         cwindow->hide_window();
371         return 1;
375 int CWindowGUI::keypress_event()
377         int result = 0;
379         switch(get_keypress())
380         {
381                 case 'w':
382                 case 'W':
383                         close_event();
384                         result = 1;
385                         break;
386                 case '+':
387                 case '=':
388                         keyboard_zoomin();
389                         result = 1;
390                         break;
391                 case '-':
392                         keyboard_zoomout();
393                         result = 1;
394                         break;
395                 case 'f':
396                         unlock_window();
397                         if(mwindow->session->cwindow_fullscreen)
398                                 canvas->stop_fullscreen();
399                         else
400                                 canvas->start_fullscreen();
401                         lock_window("CWindowGUI::keypress_event 1");
402                         break;
403                 case ESC:
404                         unlock_window();
405                         if(mwindow->session->cwindow_fullscreen)
406                                 canvas->stop_fullscreen();
407                         lock_window("CWindowGUI::keypress_event 2");
408                         break;
409         }
411         if(!result) result = transport->keypress_event();
413         return result;
417 void CWindowGUI::reset_affected()
419         affected_x = 0;
420         affected_y = 0;
421         affected_z = 0;
424 void CWindowGUI::keyboard_zoomin()
426 //      if(mwindow->edl->session->cwindow_scrollbars)
427 //      {
428                 zoom_panel->zoom_tumbler->handle_up_event();
429 //      }
430 //      else
431 //      {
432 //      }
435 void CWindowGUI::keyboard_zoomout()
437 //      if(mwindow->edl->session->cwindow_scrollbars)
438 //      {
439                 zoom_panel->zoom_tumbler->handle_down_event();
440 //      }
441 //      else
442 //      {
443 //      }
447 void CWindowGUI::drag_motion()
449         if(get_hidden()) return;
451         if(mwindow->session->current_operation == DRAG_ASSET ||
452                 mwindow->session->current_operation == DRAG_VTRANSITION ||
453                 mwindow->session->current_operation == DRAG_VEFFECT)
454         {
455                 int old_status = mwindow->session->ccanvas_highlighted;
456                 int cursor_x = get_relative_cursor_x();
457                 int cursor_y = get_relative_cursor_y();
459                 mwindow->session->ccanvas_highlighted = get_cursor_over_window() &&
460                         cursor_x >= canvas->x &&
461                         cursor_x < canvas->x + canvas->w &&
462                         cursor_y >= canvas->y &&
463                         cursor_y < canvas->y + canvas->h;
466                 if(old_status != mwindow->session->ccanvas_highlighted)
467                         canvas->draw_refresh();
468         }
471 int CWindowGUI::drag_stop()
473         int result = 0;
474         if(get_hidden()) return 0;
476         if((mwindow->session->current_operation == DRAG_ASSET ||
477                 mwindow->session->current_operation == DRAG_VTRANSITION ||
478                 mwindow->session->current_operation == DRAG_VEFFECT) &&
479                 mwindow->session->ccanvas_highlighted)
480         {
481 // Hide highlighting
482                 mwindow->session->ccanvas_highlighted = 0;
483                 canvas->draw_refresh();
484                 result = 1;
485         }
486         else
487                 return 0;
489         if(mwindow->session->current_operation == DRAG_ASSET)
490         {
491                 if(mwindow->session->drag_assets->total)
492                 {
493                         mwindow->gui->lock_window("CWindowGUI::drag_stop 1");
494                         mwindow->clear(0);
495                         mwindow->load_assets(mwindow->session->drag_assets, 
496                                 mwindow->edl->local_session->get_selectionstart(), 
497                                 LOAD_PASTE,
498                                 mwindow->session->track_highlighted,
499                                 0,
500                                 mwindow->edl->session->labels_follow_edits, 
501                                 mwindow->edl->session->plugins_follow_edits);
502                 }
504                 if(mwindow->session->drag_clips->total)
505                 {
506                         mwindow->gui->lock_window("CWindowGUI::drag_stop 2");
507                         mwindow->clear(0);
508                         mwindow->paste_edls(mwindow->session->drag_clips, 
509                                 LOAD_PASTE, 
510                                 mwindow->session->track_highlighted,
511                                 mwindow->edl->local_session->get_selectionstart(),
512                                 mwindow->edl->session->labels_follow_edits, 
513                                 mwindow->edl->session->plugins_follow_edits);
514                 }
516                 if(mwindow->session->drag_assets->total ||
517                         mwindow->session->drag_clips->total)
518                 {
519                         mwindow->save_backup();
520                         mwindow->restart_brender();
521                         mwindow->gui->update(1, 1, 1, 1, 0, 1, 0);
522                         mwindow->undo->update_undo(_("insert assets"), LOAD_ALL);
523                         mwindow->gui->unlock_window();
524                         mwindow->sync_parameters(LOAD_ALL);
525                 }
526         }
528         if(mwindow->session->current_operation == DRAG_VEFFECT)
529         {
530 //printf("CWindowGUI::drag_stop 1\n");
531                 Track *affected_track = cwindow->calculate_affected_track();
532 //printf("CWindowGUI::drag_stop 2\n");
534                 mwindow->gui->lock_window("CWindowGUI::drag_stop 3");
535                 mwindow->insert_effects_cwindow(affected_track);
536                 mwindow->session->current_operation = NO_OPERATION;
537                 mwindow->gui->unlock_window();
538         }
540         if(mwindow->session->current_operation == DRAG_VTRANSITION)
541         {
542                 Track *affected_track = cwindow->calculate_affected_track();
543                 mwindow->gui->lock_window("CWindowGUI::drag_stop 4");
544                 mwindow->paste_transition_cwindow(affected_track);
545                 mwindow->session->current_operation = NO_OPERATION;
546                 mwindow->gui->unlock_window();
547         }
549         return result;
553 CWindowEditing::CWindowEditing(MWindow *mwindow, CWindow *cwindow)
554  : EditPanel(mwindow, 
555                 cwindow->gui, 
556                 mwindow->theme->cedit_x, 
557                 mwindow->theme->cedit_y,
558                 mwindow->edl->session->editing_mode, 
559                 0,
560                 1,
561                 0, 
562                 0,
563                 1,
564                 1,
565                 1,
566                 1,
567                 1,
568                 0,
569                 1,
570                 1,
571                 1,
572                 0,
573                 1)
575         this->mwindow = mwindow;
576         this->cwindow = cwindow;
579 void CWindowEditing::set_inpoint()
581         mwindow->set_inpoint(0);
584 void CWindowEditing::set_outpoint()
586         mwindow->set_outpoint(0);
593 CWindowMeters::CWindowMeters(MWindow *mwindow, CWindowGUI *gui, int x, int y, int h)
594  : MeterPanel(mwindow, 
595                 gui,
596                 x,
597                 y,
598                 h,
599                 mwindow->edl->session->audio_channels,
600                 mwindow->edl->session->cwindow_meter)
602         this->mwindow = mwindow;
603         this->gui = gui;
606 CWindowMeters::~CWindowMeters()
610 int CWindowMeters::change_status_event()
612         mwindow->edl->session->cwindow_meter = use_meters;
613         mwindow->theme->get_cwindow_sizes(gui, mwindow->session->cwindow_controls);
614         gui->resize_event(gui->get_w(), gui->get_h());
615         return 1;
621 CWindowZoom::CWindowZoom(MWindow *mwindow, CWindowGUI *gui, int x, int y)
622  : ZoomPanel(mwindow, 
623         gui, 
624         (double)mwindow->edl->session->cwindow_zoom, 
625         x, 
626         y,
627         80, 
628         my_zoom_table, 
629         total_zooms, 
630         ZOOM_PERCENTAGE)
632         this->mwindow = mwindow;
633         this->gui = gui;
636 CWindowZoom::~CWindowZoom()
640 int CWindowZoom::handle_event()
642         if(!strcasecmp(AUTO_ZOOM, get_text()))
643         {
644                 gui->zoom_canvas(1, get_value(), 0);
645         }
646         else
647         {
648                 gui->zoom_canvas(0, get_value(), 0);
649         }
651         return 1;
656 CWindowSlider::CWindowSlider(MWindow *mwindow, CWindow *cwindow, int x, int y, int pixels)
657  : BC_PercentageSlider(x, 
658                         y,
659                         0,
660                         pixels, 
661                         pixels, 
662                         0, 
663                         1, 
664                         0)
666         this->mwindow = mwindow;
667         this->cwindow = cwindow;
668         set_precision(0.00001);
671 CWindowSlider::~CWindowSlider()
675 int CWindowSlider::handle_event()
677         unlock_window();
678         cwindow->playback_engine->interrupt_playback(1);
679         lock_window("CWindowSlider::handle_event 1");
680         
681         mwindow->gui->lock_window("CWindowSlider::handle_event 2");
682         mwindow->select_point((double)get_value());
683         mwindow->gui->unlock_window();
684         return 1;
687 void CWindowSlider::set_position()
689         double new_length = mwindow->edl->tracks->total_playable_length();
690         if(mwindow->edl->local_session->preview_end <= 0 ||
691                 mwindow->edl->local_session->preview_end > new_length)
692                 mwindow->edl->local_session->preview_end = new_length;
693         if(mwindow->edl->local_session->preview_start > 
694                 mwindow->edl->local_session->preview_end)
695                 mwindow->edl->local_session->preview_start = 0;
699         update(mwindow->theme->cslider_w, 
700                 mwindow->edl->local_session->get_selectionstart(1), 
701                 mwindow->edl->local_session->preview_start, 
702                 mwindow->edl->local_session->preview_end);
706 int CWindowSlider::increase_value()
708         unlock_window();
709         cwindow->gui->transport->handle_transport(SINGLE_FRAME_FWD);
710         lock_window("CWindowSlider::increase_value");
711         return 1;
714 int CWindowSlider::decrease_value()
716         unlock_window();
717         cwindow->gui->transport->handle_transport(SINGLE_FRAME_REWIND);
718         lock_window("CWindowSlider::decrease_value");
719         return 1;
723 // CWindowDestination::CWindowDestination(MWindow *mwindow, CWindowGUI *cwindow, int x, int y)
724 //  : BC_PopupTextBox(cwindow, 
725 //      &cwindow->destinations, 
726 //      cwindow->destinations.values[cwindow->cwindow->destination]->get_text(),
727 //      x, 
728 //      y, 
729 //      70, 
730 //      200)
731 // {
732 //      this->mwindow = mwindow;
733 //      this->cwindow = cwindow;
734 // }
735 // 
736 // CWindowDestination::~CWindowDestination()
737 // {
738 // }
739 // 
740 // int CWindowDestination::handle_event()
741 // {
742 //      return 1;
743 // }
746 CWindowTransport::CWindowTransport(MWindow *mwindow, 
747         CWindowGUI *gui, 
748         int x, 
749         int y)
750  : PlayTransport(mwindow, 
751         gui, 
752         x, 
753         y)
755         this->gui = gui;
758 EDL* CWindowTransport::get_edl()
760         return mwindow->edl;
763 void CWindowTransport::goto_start()
765         gui->unlock_window();
766         handle_transport(REWIND, 1);
768         mwindow->gui->lock_window("CWindowTransport::goto_start 1");
769         mwindow->goto_start();
770         mwindow->gui->unlock_window();
772         gui->lock_window("CWindowTransport::goto_start 2");
775 void CWindowTransport::goto_end()
777         gui->unlock_window();
778         handle_transport(GOTO_END, 1);
780         mwindow->gui->lock_window("CWindowTransport::goto_end 1");
781         mwindow->goto_end();
782         mwindow->gui->unlock_window();
784         gui->lock_window("CWindowTransport::goto_end 2");
789 CWindowCanvas::CWindowCanvas(MWindow *mwindow, CWindowGUI *gui)
790  : Canvas(mwindow,
791         gui,
792         mwindow->theme->ccanvas_x,
793         mwindow->theme->ccanvas_y,
794         mwindow->theme->ccanvas_w,
795         mwindow->theme->ccanvas_h,
796         0,
797         0,
798         mwindow->edl->session->cwindow_scrollbars,
799         1)
801         this->mwindow = mwindow;
802         this->gui = gui;
805 void CWindowCanvas::status_event()
807         gui->draw_status();
810 int CWindowCanvas::get_fullscreen()
812         return mwindow->session->cwindow_fullscreen;
815 void CWindowCanvas::set_fullscreen(int value)
817         mwindow->session->cwindow_fullscreen = value;
821 void CWindowCanvas::update_zoom(int x, int y, float zoom)
823         use_scrollbars = mwindow->edl->session->cwindow_scrollbars;
825         mwindow->edl->session->cwindow_xscroll = x;
826         mwindow->edl->session->cwindow_yscroll = y;
827         mwindow->edl->session->cwindow_zoom = zoom;
830 int CWindowCanvas::get_xscroll()
832         return mwindow->edl->session->cwindow_xscroll;
835 int CWindowCanvas::get_yscroll()
837         return mwindow->edl->session->cwindow_yscroll;
841 float CWindowCanvas::get_zoom()
843         return mwindow->edl->session->cwindow_zoom;
846 void CWindowCanvas::draw_refresh()
848         if(get_canvas() && !get_canvas()->get_video_on())
849         {
850                 get_canvas()->clear_box(0, 0, get_canvas()->get_w(), get_canvas()->get_h());
852                 if(refresh_frame)
853                 {
854                         int in_x, in_y, in_w, in_h, out_x, out_y, out_w, out_h;
855                         get_transfers(mwindow->edl, 
856                                 in_x, 
857                                 in_y, 
858                                 in_w, 
859                                 in_h, 
860                                 out_x, 
861                                 out_y, 
862                                 out_w, 
863                                 out_h);
865 // printf("CWindowCanvas::draw_refresh %d %d %d %d -> %d %d %d %d\n", 
866 // in_x, in_y, in_w, in_h, out_x, out_y, out_w, out_h);
869                         if(out_w > 0 && out_h > 0 && in_w > 0 && in_h > 0)
870                                 get_canvas()->draw_vframe(refresh_frame,
871                                                 out_x, 
872                                                 out_y, 
873                                                 out_w, 
874                                                 out_h,
875                                                 in_x, 
876                                                 in_y, 
877                                                 in_w, 
878                                                 in_h,
879                                                 0);
880                 }
881                 else
882                 {
883                         get_canvas()->clear_box(0, 0, get_canvas()->get_w(), get_canvas()->get_h());
884                 }
886                 draw_overlays();
887                 get_canvas()->flash();
888         }
889 //printf("CWindowCanvas::draw_refresh 10\n");
892 #define CROPHANDLE_W 10
893 #define CROPHANDLE_H 10
895 void CWindowCanvas::draw_crophandle(int x, int y)
897         get_canvas()->draw_box(x, y, CROPHANDLE_W, CROPHANDLE_H);
900 #define CONTROL_W 10
901 #define CONTROL_H 10
902 #define FIRST_CONTROL_W 20
903 #define FIRST_CONTROL_H 20
904 #undef BC_INFINITY
905 #define BC_INFINITY 65536
906 #ifndef SQR
907 #define SQR(x) ((x) * (x))
908 #endif
910 int CWindowCanvas::do_mask(int &redraw, 
911                 int &rerender, 
912                 int button_press, 
913                 int cursor_motion,
914                 int draw)
916 // Retrieve points from top recordable track
917 //printf("CWindowCanvas::do_mask 1\n");
918         Track *track = gui->cwindow->calculate_affected_track();
919 //printf("CWindowCanvas::do_mask 2\n");
921         if(!track) return 0;
922 //printf("CWindowCanvas::do_mask 3\n");
924         MaskAutos *mask_autos = (MaskAutos*)track->automation->autos[AUTOMATION_MASK];
925         int64_t position = track->to_units(
926                 mwindow->edl->local_session->get_selectionstart(1),
927                 0);
928         ArrayList<MaskPoint*> points;
929         mask_autos->get_points(&points, mwindow->edl->session->cwindow_mask,
930                 position, 
931                 PLAY_FORWARD);
932 //printf("CWindowCanvas::do_mask 4\n");
934 // Projector zooms relative to the center of the track output.
935         float half_track_w = (float)track->track_w / 2;
936         float half_track_h = (float)track->track_h / 2;
937 // Translate mask to projection
938         float projector_x, projector_y, projector_z;
939         track->automation->get_projector(&projector_x,
940                 &projector_y,
941                 &projector_z,
942                 position,
943                 PLAY_FORWARD);
946 // Get position of cursor relative to mask
947         float mask_cursor_x = get_cursor_x();
948         float mask_cursor_y = get_cursor_y();
949         canvas_to_output(mwindow->edl, 0, mask_cursor_x, mask_cursor_y);
951         projector_x += mwindow->edl->session->output_w / 2;
952         projector_y += mwindow->edl->session->output_h / 2;
954         mask_cursor_x -= projector_x;
955         mask_cursor_y -= projector_y;
956         mask_cursor_x = mask_cursor_x / projector_z + half_track_w;
957         mask_cursor_y = mask_cursor_y / projector_z + half_track_h;
959 // Fix cursor origin
960         if(button_press)
961         {
962                 gui->x_origin = mask_cursor_x;
963                 gui->y_origin = mask_cursor_y;
964         }
966         int result = 0;
967 // Points of closest line
968         int shortest_point1 = -1;
969         int shortest_point2 = -1;
970 // Closest point
971         int shortest_point = -1;
972 // Distance to closest line
973         float shortest_line_distance = BC_INFINITY;
974 // Distance to closest point
975         float shortest_point_distance = BC_INFINITY;
976         int selected_point = -1;
977         int selected_control_point = -1;
978         float selected_control_point_distance = BC_INFINITY;
979         ArrayList<int> x_points;
980         ArrayList<int> y_points;
982         if(!cursor_motion)
983         {
984                 if(draw)
985                 {
986                         get_canvas()->set_color(WHITE);
987                         get_canvas()->set_inverse();
988                 }
989 //printf("CWindowCanvas::do_mask 1 %d\n", points.total);
991 // Never draw closed polygon and a closed
992 // polygon is harder to add points to.
993                 for(int i = 0; i < points.total && !result; i++)
994                 {
995                         MaskPoint *point1 = points.values[i];
996                         MaskPoint *point2 = (i >= points.total - 1) ? 
997                                 points.values[0] : 
998                                 points.values[i + 1];
999                         float x0, x1, x2, x3;
1000                         float y0, y1, y2, y3;
1001                         float old_x, old_y, x, y;
1002                         int segments = (int)(sqrt(SQR(point1->x - point2->x) + SQR(point1->y - point2->y)));
1004 //printf("CWindowCanvas::do_mask 1 %f, %f -> %f, %f projectorz=%f\n",
1005 //point1->x, point1->y, point2->x, point2->y, projector_z);
1006                         for(int j = 0; j <= segments && !result; j++)
1007                         {
1008 //printf("CWindowCanvas::do_mask 1 %f, %f -> %f, %f\n", x0, y0, x3, y3);
1009                                 x0 = point1->x;
1010                                 y0 = point1->y;
1011                                 x1 = point1->x + point1->control_x2;
1012                                 y1 = point1->y + point1->control_y2;
1013                                 x2 = point2->x + point2->control_x1;
1014                                 y2 = point2->y + point2->control_y1;
1015                                 x3 = point2->x;
1016                                 y3 = point2->y;
1018                                 float t = (float)j / segments;
1019                                 float tpow2 = t * t;
1020                                 float tpow3 = t * t * t;
1021                                 float invt = 1 - t;
1022                                 float invtpow2 = invt * invt;
1023                                 float invtpow3 = invt * invt * invt;
1025                                 x = (        invtpow3 * x0
1026                                         + 3 * t     * invtpow2 * x1
1027                                         + 3 * tpow2 * invt     * x2 
1028                                         +     tpow3            * x3);
1029                                 y = (        invtpow3 * y0 
1030                                         + 3 * t     * invtpow2 * y1
1031                                         + 3 * tpow2 * invt     * y2 
1032                                         +     tpow3            * y3);
1034                                 x = (x - half_track_w) * projector_z + projector_x;
1035                                 y = (y - half_track_h) * projector_z + projector_y;
1038 // Test new point addition
1039                                 if(button_press)
1040                                 {
1041                                         float line_distance = 
1042                                                 sqrt(SQR(x - mask_cursor_x) + SQR(y - mask_cursor_y));
1044 //printf("CWindowCanvas::do_mask 1 x=%f mask_cursor_x=%f y=%f mask_cursor_y=%f %f %f %d, %d\n", 
1045 //x, mask_cursor_x, y, mask_cursor_y, line_distance, shortest_line_distance, shortest_point1, shortest_point2);
1046                                         if(line_distance < shortest_line_distance || 
1047                                                 shortest_point1 < 0)
1048                                         {
1049                                                 shortest_line_distance = line_distance;
1050                                                 shortest_point1 = i;
1051                                                 shortest_point2 = (i >= points.total - 1) ? 0 : (i + 1);
1052 //printf("CWindowCanvas::do_mask 2 %f %f %d, %d\n", line_distance, shortest_line_distance, shortest_point1, shortest_point2);
1053                                         }
1056                                         float point_distance1 = 
1057                                                 sqrt(SQR(point1->x - mask_cursor_x) + SQR(point1->y - mask_cursor_y));
1058                                         float point_distance2 = 
1059                                                 sqrt(SQR(point2->x - mask_cursor_x) + SQR(point2->y - mask_cursor_y));
1061                                         if(point_distance1 < shortest_point_distance || 
1062                                                 shortest_point < 0)
1063                                         {
1064                                                 shortest_point_distance = point_distance1;
1065                                                 shortest_point = i;
1066                                         }
1068                                         if(point_distance2 < shortest_point_distance || 
1069                                                 shortest_point < 0)
1070                                         {
1071                                                 shortest_point_distance = point_distance2;
1072                                                 shortest_point = (i >= points.total - 1) ? 0 : (i + 1);
1073                                         }
1074                                 }
1076                                 output_to_canvas(mwindow->edl, 0, x, y);
1079 #define TEST_BOX(cursor_x, cursor_y, target_x, target_y) \
1080         (cursor_x >= target_x - CONTROL_W / 2 && \
1081         cursor_x < target_x + CONTROL_W / 2 && \
1082         cursor_y >= target_y - CONTROL_H / 2 && \
1083         cursor_y < target_y + CONTROL_H / 2)
1085 // Test existing point selection
1086                                 if(button_press)
1087                                 {
1088                                         float canvas_x = (x0 - half_track_w) * projector_z + projector_x;
1089                                         float canvas_y = (y0 - half_track_h) * projector_z + projector_y;
1090                                         int cursor_x = get_cursor_x();
1091                                         int cursor_y = get_cursor_y();
1093 // Test first point
1094                                         if(gui->shift_down())
1095                                         {
1096                                                 float control_x = (x1 - half_track_w) * projector_z + projector_x;
1097                                                 float control_y = (y1 - half_track_h) * projector_z + projector_y;
1098                                                 output_to_canvas(mwindow->edl, 0, control_x, control_y);
1100                                                 float distance = 
1101                                                         sqrt(SQR(control_x - cursor_x) + SQR(control_y - cursor_y));
1103                                                 if(distance < selected_control_point_distance)
1104                                                 {
1105                                                         selected_point = i;
1106                                                         selected_control_point = 1;
1107                                                         selected_control_point_distance = distance;
1108                                                 }
1109                                         }
1110                                         else
1111                                         {
1112                                                 output_to_canvas(mwindow->edl, 0, canvas_x, canvas_y);
1113                                                 if(!gui->ctrl_down())
1114                                                 {
1115                                                         if(TEST_BOX(cursor_x, cursor_y, canvas_x, canvas_y))
1116                                                         {
1117                                                                 selected_point = i;
1118                                                         }
1119                                                 }
1120                                                 else
1121                                                 {
1122                                                         selected_point = shortest_point;
1123                                                 }
1124                                         }
1126 // Test second point
1127                                         canvas_x = (x3 - half_track_w) * projector_z + projector_x;
1128                                         canvas_y = (y3 - half_track_h) * projector_z + projector_y;
1129                                         if(gui->shift_down())
1130                                         {
1131                                                 float control_x = (x2 - half_track_w) * projector_z + projector_x;
1132                                                 float control_y = (y2 - half_track_h) * projector_z + projector_y;
1133                                                 output_to_canvas(mwindow->edl, 0, control_x, control_y);
1135                                                 float distance = 
1136                                                         sqrt(SQR(control_x - cursor_x) + SQR(control_y - cursor_y));
1138 //printf("CWindowCanvas::do_mask %d %f %f\n", i, distance, selected_control_point_distance);
1139                                                 if(distance < selected_control_point_distance)
1140                                                 {
1141                                                         selected_point = (i < points.total - 1 ? i + 1 : 0);
1142                                                         selected_control_point = 0;
1143                                                         selected_control_point_distance = distance;
1144                                                 }
1145                                         }
1146                                         else
1147                                         if(i < points.total - 1)
1148                                         {
1149                                                 output_to_canvas(mwindow->edl, 0, canvas_x, canvas_y);
1150                                                 if(!gui->ctrl_down())
1151                                                 {
1152                                                         if(TEST_BOX(cursor_x, cursor_y, canvas_x, canvas_y))
1153                                                         {
1154                                                                 selected_point = (i < points.total - 1 ? i + 1 : 0);
1155                                                         }
1156                                                 }
1157                                                 else
1158                                                 {
1159                                                         selected_point = shortest_point;
1160                                                 }
1161                                         }
1162                                 }
1166                                 if(j > 0)
1167                                 {
1168 // Draw joining line
1169                                         if(draw)
1170                                         {
1171                                                 x_points.append((int)x);
1172                                                 y_points.append((int)y);
1173                                         }
1175                                         if(j == segments)
1176                                         {
1181                                                 if(draw)
1182                                                 {
1183 // Draw second anchor
1184                                                         if(i < points.total - 1)
1185                                                         {
1186                                                                 if(i == gui->affected_point - 1)
1187                                                                         get_canvas()->draw_disc((int)x - CONTROL_W / 2, 
1188                                                                                 (int)y - CONTROL_W / 2, 
1189                                                                                 CONTROL_W, 
1190                                                                                 CONTROL_W);
1191                                                                 else
1192                                                                         get_canvas()->draw_circle((int)x - CONTROL_W / 2, 
1193                                                                                 (int)y - CONTROL_W / 2, 
1194                                                                                 CONTROL_W, 
1195                                                                                 CONTROL_W);
1196 // char string[BCTEXTLEN];
1197 // sprintf(string, "%d", (i < points.total - 1 ? i + 1 : 0));
1198 // canvas->draw_text((int)x + CONTROL_W, (int)y + CONTROL_W, string);
1199                                                         }
1201 // Draw second control point.  Discard x2 and y2 after this.
1202                                                         x2 = (x2 - half_track_w) * projector_z + projector_x;
1203                                                         y2 = (y2 - half_track_h) * projector_z + projector_y;
1204                                                         output_to_canvas(mwindow->edl, 0, x2, y2);
1205                                                         get_canvas()->draw_line((int)x, (int)y, (int)x2, (int)y2);
1206                                                         get_canvas()->draw_rectangle((int)x2 - CONTROL_W / 2,
1207                                                                 (int)y2 - CONTROL_H / 2,
1208                                                                 CONTROL_W,
1209                                                                 CONTROL_H);
1210                                                 }
1211                                         }
1212                                 }
1213                                 else
1214                                 {
1217 // Draw first anchor
1218                                         if(i == 0 && draw)
1219                                         {
1220                                                 get_canvas()->draw_disc((int)x - FIRST_CONTROL_W / 2, 
1221                                                         (int)y - FIRST_CONTROL_H / 2, 
1222                                                         FIRST_CONTROL_W, 
1223                                                         FIRST_CONTROL_H);
1224                                         }
1226 // Draw first control point.  Discard x1 and y1 after this.
1227                                         if(draw)
1228                                         {
1229                                                 x1 = (x1 - half_track_w) * projector_z + projector_x;
1230                                                 y1 = (y1 - half_track_h) * projector_z + projector_y;
1231                                                 output_to_canvas(mwindow->edl, 0, x1, y1);
1232                                                 get_canvas()->draw_line((int)x, (int)y, (int)x1, (int)y1);
1233                                                 get_canvas()->draw_rectangle((int)x1 - CONTROL_W / 2,
1234                                                         (int)y1 - CONTROL_H / 2,
1235                                                         CONTROL_W,
1236                                                         CONTROL_H);
1237                                         
1238                                                 x_points.append((int)x);
1239                                                 y_points.append((int)y);
1240                                         }
1241                                 }
1242 //printf("CWindowCanvas::do_mask 1\n");
1244                                 old_x = x;
1245                                 old_y = y;
1246                         }
1247                 }
1248 //printf("CWindowCanvas::do_mask 1\n");
1250                 if(draw)
1251                 {
1252                         get_canvas()->draw_polygon(&x_points, &y_points);
1253                         get_canvas()->set_opaque();
1254                 }
1255 //printf("CWindowCanvas::do_mask 1\n");
1256         }
1264         if(button_press && !result)
1265         {
1266                 gui->affected_track = gui->cwindow->calculate_affected_track();
1267 // Get current keyframe
1268                 if(gui->affected_track)
1269                         gui->affected_keyframe = 
1270                                 gui->cwindow->calculate_affected_auto(
1271                                         gui->affected_track->automation->autos[AUTOMATION_MASK],
1272                                         1);
1274                 MaskAuto *keyframe = (MaskAuto*)gui->affected_keyframe;
1275                 SubMask *mask = keyframe->get_submask(mwindow->edl->session->cwindow_mask);
1278 // Translate entire keyframe
1279                 if(gui->alt_down() && mask->points.total)
1280                 {
1281                         gui->current_operation = CWINDOW_MASK_TRANSLATE;
1282                         gui->affected_point = 0;
1283                 }
1284                 else
1285 // Existing point or control point was selected
1286                 if(selected_point >= 0)
1287                 {
1288                         gui->affected_point = selected_point;
1290                         if(selected_control_point == 0)
1291                                 gui->current_operation = CWINDOW_MASK_CONTROL_IN;
1292                         else
1293                         if(selected_control_point == 1)
1294                                 gui->current_operation = CWINDOW_MASK_CONTROL_OUT;
1295                         else
1296                                 gui->current_operation = mwindow->edl->session->cwindow_operation;
1297                 }
1298                 else
1299 // No existing point or control point was selected so create a new one
1300                 if(!gui->shift_down() && !gui->alt_down())
1301                 {
1302 // Create the template
1303                         MaskPoint *point = new MaskPoint;
1304                         point->x = mask_cursor_x;
1305                         point->y = mask_cursor_y;
1306                         point->control_x1 = 0;
1307                         point->control_y1 = 0;
1308                         point->control_x2 = 0;
1309                         point->control_y2 = 0;
1312                         if(shortest_point2 < shortest_point1)
1313                         {
1314                                 shortest_point2 ^= shortest_point1;
1315                                 shortest_point1 ^= shortest_point2;
1316                                 shortest_point2 ^= shortest_point1;
1317                         }
1321 // printf("CWindowGUI::do_mask 40\n");
1322 // mwindow->edl->dump();
1323 // printf("CWindowGUI::do_mask 50\n");
1327 //printf("CWindowCanvas::do_mask 1 %f %f %d %d\n", 
1328 //      shortest_line_distance, shortest_point_distance, shortest_point1, shortest_point2);
1329 //printf("CWindowCanvas::do_mask %d %d\n", shortest_point1, shortest_point2);
1331 // Append to end of list
1332                         if(labs(shortest_point1 - shortest_point2) > 1)
1333                         {
1334 // Need to apply the new point to every keyframe
1335                                 for(MaskAuto *current = (MaskAuto*)mask_autos->default_auto;
1336                                         current; )
1337                                 {
1338                                         SubMask *submask = current->get_submask(mwindow->edl->session->cwindow_mask);
1339                                         MaskPoint *new_point = new MaskPoint;
1340                                         submask->points.append(new_point);
1341                                         *new_point = *point;
1342                                         if(current == (MaskAuto*)mask_autos->default_auto)
1343                                                 current = (MaskAuto*)mask_autos->first;
1344                                         else
1345                                                 current = (MaskAuto*)NEXT;
1346                                 }
1348                                 gui->affected_point = mask->points.total - 1;
1349                                 result = 1;
1350                         }
1351                         else
1352 // Insert between 2 points, shifting back point 2
1353                         if(shortest_point1 >= 0 && shortest_point2 >= 0)
1354                         {
1355                                 for(MaskAuto *current = (MaskAuto*)mask_autos->default_auto;
1356                                         current; )
1357                                 {
1358                                         SubMask *submask = current->get_submask(mwindow->edl->session->cwindow_mask);
1359 // In case the keyframe point count isn't synchronized with the rest of the keyframes,
1360 // avoid a crash.
1361                                         if(submask->points.total >= shortest_point2)
1362                                         {
1363                                                 MaskPoint *new_point = new MaskPoint;
1364                                                 submask->points.append(0);
1365                                                 for(int i = submask->points.total - 1; 
1366                                                         i > shortest_point2; 
1367                                                         i--)
1368                                                         submask->points.values[i] = submask->points.values[i - 1];
1369                                                 submask->points.values[shortest_point2] = new_point;
1371                                                 *new_point = *point;
1372                                         }
1374                                         if(current == (MaskAuto*)mask_autos->default_auto)
1375                                                 current = (MaskAuto*)mask_autos->first;
1376                                         else
1377                                                 current = (MaskAuto*)NEXT;
1378                                 }
1381                                 gui->affected_point = shortest_point2;
1382                                 result = 1;
1383                         }
1386 // printf("CWindowGUI::do_mask 20\n");
1387 // mwindow->edl->dump();
1388 // printf("CWindowGUI::do_mask 30\n");
1393 // Create the first point.
1394                         if(!result)
1395                         {
1396 //printf("CWindowCanvas::do_mask 1\n");
1397                                 for(MaskAuto *current = (MaskAuto*)mask_autos->default_auto;
1398                                         current; )
1399                                 {
1400                                         SubMask *submask = current->get_submask(mwindow->edl->session->cwindow_mask);
1401                                         MaskPoint *new_point = new MaskPoint;
1402                                         submask->points.append(new_point);
1403                                         *new_point = *point;
1404                                         if(current == (MaskAuto*)mask_autos->default_auto)
1405                                                 current = (MaskAuto*)mask_autos->first;
1406                                         else
1407                                                 current = (MaskAuto*)NEXT;
1408                                 }
1410 //printf("CWindowCanvas::do_mask 2\n");
1411 // Create a second point if none existed before
1412                                 if(mask->points.total < 2)
1413                                 {
1414                                         for(MaskAuto *current = (MaskAuto*)mask_autos->default_auto;
1415                                                 current; )
1416                                         {
1417                                                 SubMask *submask = current->get_submask(mwindow->edl->session->cwindow_mask);
1418                                                 MaskPoint *new_point = new MaskPoint;
1419                                                 submask->points.append(new_point);
1420                                                 *new_point = *point;
1421                                                 if(current == (MaskAuto*)mask_autos->default_auto)
1422                                                         current = (MaskAuto*)mask_autos->first;
1423                                                 else
1424                                                         current = (MaskAuto*)NEXT;
1425                                         }
1426                                 }
1427                                 gui->affected_point = mask->points.total - 1;
1428 //printf("CWindowCanvas::do_mask 3 %d\n", mask->points.total);
1429                         }
1433                         gui->current_operation = mwindow->edl->session->cwindow_operation;
1434 // Delete the template
1435                         delete point;
1436 //printf("CWindowGUI::do_mask 1\n");
1437                         mwindow->undo->update_undo(_("mask point"), LOAD_AUTOMATION);
1438 //printf("CWindowGUI::do_mask 10\n");
1440                 }
1442                 result = 1;
1443                 rerender = 1;
1444                 redraw = 1;
1445         }
1447         if(button_press && result)
1448         {
1449                 MaskAuto *keyframe = (MaskAuto*)gui->affected_keyframe;
1450                 SubMask *mask = keyframe->get_submask(mwindow->edl->session->cwindow_mask);
1451                 MaskPoint *point = mask->points.values[gui->affected_point];
1452                 gui->center_x = point->x;
1453                 gui->center_y = point->y;
1454                 gui->control_in_x = point->control_x1;
1455                 gui->control_in_y = point->control_y1;
1456                 gui->control_out_x = point->control_x2;
1457                 gui->control_out_y = point->control_y2;
1458         }
1460 //printf("CWindowCanvas::do_mask 8\n");
1461         if(cursor_motion)
1462         {
1463                 MaskAuto *keyframe = (MaskAuto*)gui->affected_keyframe;
1464                 SubMask *mask = keyframe->get_submask(mwindow->edl->session->cwindow_mask);
1465                 if(gui->affected_point < mask->points.total)
1466                 {
1467                         MaskPoint *point = mask->points.values[gui->affected_point];
1468 //                      float cursor_x = get_cursor_x();
1469 //                      float cursor_y = get_cursor_y();
1470 //                      canvas_to_output(mwindow->edl, 0, cursor_x, cursor_y);
1471                         float cursor_x = mask_cursor_x;
1472                         float cursor_y = mask_cursor_y;
1473 //printf("CWindowCanvas::do_mask 9 %d %d\n", mask->points.total, gui->affected_point);
1475                         float last_x = point->x;
1476                         float last_y = point->y;
1477                         float last_control_x1 = point->control_x1;
1478                         float last_control_y1 = point->control_y1;
1479                         float last_control_x2 = point->control_x2;
1480                         float last_control_y2 = point->control_y2;
1483                         switch(gui->current_operation)
1484                         {
1485                                 case CWINDOW_MASK:
1486                                         point->x = cursor_x - gui->x_origin + gui->center_x;
1487                                         point->y = cursor_y - gui->y_origin + gui->center_y;
1488                                         break;
1490                                 case CWINDOW_MASK_CONTROL_IN:
1491                                         point->control_x1 = cursor_x - gui->x_origin + gui->control_in_x;
1492                                         point->control_y1 = cursor_y - gui->y_origin + gui->control_in_y;
1493                                         break;
1495                                 case CWINDOW_MASK_CONTROL_OUT:
1496                                         point->control_x2 = cursor_x - gui->x_origin + gui->control_out_x;
1497                                         point->control_y2 = cursor_y - gui->y_origin + gui->control_out_y;
1498                                         break;
1500                                 case CWINDOW_MASK_TRANSLATE:
1501                                         for(int i = 0; i < mask->points.total; i++)
1502                                         {
1503                                                 mask->points.values[i]->x += cursor_x - gui->x_origin;
1504                                                 mask->points.values[i]->y += cursor_y - gui->y_origin;
1505                                         }
1506                                         gui->x_origin = cursor_x;
1507                                         gui->y_origin = cursor_y;
1508                                         break;
1509                         }
1512                         if( !EQUIV(last_x, point->x) ||
1513                                 !EQUIV(last_y, point->y) ||
1514                                 !EQUIV(last_control_x1, point->control_x1) ||
1515                                 !EQUIV(last_control_y1, point->control_y1) ||
1516                                 !EQUIV(last_control_x2, point->control_x2) ||
1517                                 !EQUIV(last_control_y2, point->control_y2))
1518                         {
1519                                 rerender = 1;
1520                                 redraw = 1;
1521                         }
1522                 }
1523                 result = 1;
1524         }
1525 //printf("CWindowCanvas::do_mask 2 %d %d %d\n", result, rerender, redraw);
1527         points.remove_all_objects();
1528 //printf("CWindowCanvas::do_mask 20\n");
1529         return result;
1533 int CWindowCanvas::do_eyedrop(int &rerender, int button_press)
1535         int result = 0;
1536         float cursor_x = get_cursor_x();
1537         float cursor_y = get_cursor_y();
1540         if(button_press)
1541         {
1542                 gui->current_operation = CWINDOW_EYEDROP;
1543         }
1545         if(gui->current_operation == CWINDOW_EYEDROP)
1546         {
1547                 canvas_to_output(mwindow->edl, 0, cursor_x, cursor_y);
1549 // Get color out of frame.
1550 // Doesn't work during playback because that bypasses the refresh frame.
1551                 if(refresh_frame)
1552                 {
1553                         CLAMP(cursor_x, 0, refresh_frame->get_w() - 1);
1554                         CLAMP(cursor_y, 0, refresh_frame->get_h() - 1);
1556 // Decompression coefficients straight out of jpeglib
1557 #define V_TO_R    1.40200
1558 #define V_TO_G    -0.71414
1560 #define U_TO_G    -0.34414
1561 #define U_TO_B    1.77200
1563 #define GET_COLOR(type, components, max, do_yuv) \
1564 { \
1565         type *row = (type*)(refresh_frame->get_rows()[(int)cursor_y]) + \
1566                 (int)cursor_x * components; \
1567         float red = (float)*row++ / max; \
1568         float green = (float)*row++ / max; \
1569         float blue = (float)*row++ / max; \
1570         if(do_yuv) \
1571         { \
1572                 mwindow->edl->local_session->red = red + V_TO_R * (blue - 0.5); \
1573                 mwindow->edl->local_session->green = red + U_TO_G * (green - 0.5) + V_TO_G * (blue - 0.5); \
1574                 mwindow->edl->local_session->blue = red + U_TO_B * (green - 0.5); \
1575         } \
1576         else \
1577         { \
1578                 mwindow->edl->local_session->red = red; \
1579                 mwindow->edl->local_session->green = green; \
1580                 mwindow->edl->local_session->blue = blue; \
1581         } \
1584                         switch(refresh_frame->get_color_model())
1585                         {
1586                                 case BC_YUV888:
1587                                         GET_COLOR(unsigned char, 3, 0xff, 1);
1588                                         break;
1589                                 case BC_YUVA8888:
1590                                         GET_COLOR(unsigned char, 4, 0xff, 1);
1591                                         break;
1592                                 case BC_YUV161616:
1593                                         GET_COLOR(uint16_t, 3, 0xffff, 1);
1594                                         break;
1595                                 case BC_YUVA16161616:
1596                                         GET_COLOR(uint16_t, 4, 0xffff, 1);
1597                                         break;
1598                                 case BC_RGB888:
1599                                         GET_COLOR(unsigned char, 3, 0xff, 0);
1600                                         break;
1601                                 case BC_RGBA8888:
1602                                         GET_COLOR(unsigned char, 4, 0xff, 0);
1603                                         break;
1604                                 case BC_RGB_FLOAT:
1605                                         GET_COLOR(float, 3, 1.0, 0);
1606                                         break;
1607                                 case BC_RGBA_FLOAT:
1608                                         GET_COLOR(float, 4, 1.0, 0);
1609                                         break;
1610                         }
1611                 }
1612                 else
1613                 {
1614                         mwindow->edl->local_session->red = 0;
1615                         mwindow->edl->local_session->green = 0;
1616                         mwindow->edl->local_session->blue = 0;
1617                 }
1620                 gui->update_tool();             
1624                 result = 1;
1625 // Can't rerender since the color value is from the output of any effect it
1626 // goes into.
1627 //              rerender = 1;
1628         }
1630         return result;
1633 void CWindowCanvas::draw_overlays()
1635         if(mwindow->edl->session->safe_regions)
1636         {
1637                 draw_safe_regions();
1638         }
1640         if(mwindow->edl->session->cwindow_scrollbars)
1641         {
1642 // Always draw output rectangle
1643                 float x1, y1, x2, y2;
1644                 x1 = 0;
1645                 x2 = mwindow->edl->session->output_w;
1646                 y1 = 0;
1647                 y2 = mwindow->edl->session->output_h;
1648                 output_to_canvas(mwindow->edl, 0, x1, y1);
1649                 output_to_canvas(mwindow->edl, 0, x2, y2);
1651                 get_canvas()->set_inverse();
1652                 get_canvas()->set_color(WHITE);
1654                 get_canvas()->draw_rectangle((int)x1, 
1655                                 (int)y1, 
1656                                 (int)(x2 - x1), 
1657                                 (int)(y2 - y1));
1659                 get_canvas()->set_opaque();
1660         }
1662         if(mwindow->session->ccanvas_highlighted)
1663         {
1664                 get_canvas()->set_color(WHITE);
1665                 get_canvas()->set_inverse();
1666                 get_canvas()->draw_rectangle(0, 0, get_canvas()->get_w(), get_canvas()->get_h());
1667                 get_canvas()->draw_rectangle(1, 1, get_canvas()->get_w() - 2, get_canvas()->get_h() - 2);
1668                 get_canvas()->set_opaque();
1669         }
1671         int temp1 = 0, temp2 = 0;
1672 //printf("CWindowCanvas::draw_overlays 1 %d\n", mwindow->edl->session->cwindow_operation);
1673         switch(mwindow->edl->session->cwindow_operation)
1674         {
1675                 case CWINDOW_CAMERA:
1676                         draw_bezier(1);
1677                         break;
1679                 case CWINDOW_PROJECTOR:
1680                         draw_bezier(0);
1681                         break;
1683                 case CWINDOW_CROP:
1684                         draw_crop();
1685                         break;
1687                 case CWINDOW_MASK:
1688                         do_mask(temp1, temp2, 0, 0, 1);
1689                         break;
1690         }
1693 void CWindowCanvas::draw_safe_regions()
1695         float action_x1, action_x2, action_y1, action_y2;
1696         float title_x1, title_x2, title_y1, title_y2;
1698         action_x1 = mwindow->edl->session->output_w / 2 - mwindow->edl->session->output_w / 2 * 0.9;
1699         action_x2 = mwindow->edl->session->output_w / 2 + mwindow->edl->session->output_w / 2 * 0.9;
1700         action_y1 = mwindow->edl->session->output_h / 2 - mwindow->edl->session->output_h / 2 * 0.9;
1701         action_y2 = mwindow->edl->session->output_h / 2 + mwindow->edl->session->output_h / 2 * 0.9;
1702         title_x1 = mwindow->edl->session->output_w / 2 - mwindow->edl->session->output_w / 2 * 0.8;
1703         title_x2 = mwindow->edl->session->output_w / 2 + mwindow->edl->session->output_w / 2 * 0.8;
1704         title_y1 = mwindow->edl->session->output_h / 2 - mwindow->edl->session->output_h / 2 * 0.8;
1705         title_y2 = mwindow->edl->session->output_h / 2 + mwindow->edl->session->output_h / 2 * 0.8;
1707         output_to_canvas(mwindow->edl, 0, action_x1, action_y1);
1708         output_to_canvas(mwindow->edl, 0, action_x2, action_y2);
1709         output_to_canvas(mwindow->edl, 0, title_x1, title_y1);
1710         output_to_canvas(mwindow->edl, 0, title_x2, title_y2);
1712         get_canvas()->set_inverse();
1713         get_canvas()->set_color(WHITE);
1715         get_canvas()->draw_rectangle((int)action_x1, 
1716                         (int)action_y1, 
1717                         (int)(action_x2 - action_x1), 
1718                         (int)(action_y2 - action_y1));
1719         get_canvas()->draw_rectangle((int)title_x1, 
1720                         (int)title_y1, 
1721                         (int)(title_x2 - title_x1), 
1722                         (int)(title_y2 - title_y1));
1724         get_canvas()->set_opaque();
1727 void CWindowCanvas::reset_keyframe(int do_camera)
1729         FloatAuto *x_keyframe = 0;
1730         FloatAuto *y_keyframe = 0;
1731         FloatAuto *z_keyframe = 0;
1732         Track *affected_track = 0;
1734         affected_track = gui->cwindow->calculate_affected_track();
1736         if(affected_track)
1737         {
1738                 gui->cwindow->calculate_affected_autos(&x_keyframe,
1739                         &y_keyframe,
1740                         &z_keyframe,
1741                         affected_track,
1742                         do_camera,
1743                         1,
1744                         1,
1745                         1);
1747                 x_keyframe->value = 0;
1748                 y_keyframe->value = 0;
1749                 z_keyframe->value = 1;
1751                 mwindow->sync_parameters(CHANGE_PARAMS);
1752                 gui->update_tool();
1753         }
1756 void CWindowCanvas::reset_camera()
1758         reset_keyframe(1);
1761 void CWindowCanvas::reset_projector()
1763         reset_keyframe(0);
1766 int CWindowCanvas::test_crop(int button_press, int &redraw)
1768         int result = 0;
1769         int handle_selected = -1;
1770         float x1 = mwindow->edl->session->crop_x1;
1771         float y1 = mwindow->edl->session->crop_y1;
1772         float x2 = mwindow->edl->session->crop_x2;
1773         float y2 = mwindow->edl->session->crop_y2;
1774         float cursor_x = get_cursor_x();
1775         float cursor_y = get_cursor_y();
1776         float canvas_x1 = x1;
1777         float canvas_y1 = y1;
1778         float canvas_x2 = x2;
1779         float canvas_y2 = y2;
1780         float canvas_cursor_x = cursor_x;
1781         float canvas_cursor_y = cursor_y;
1783         canvas_to_output(mwindow->edl, 0, cursor_x, cursor_y);
1784 // Use screen normalized coordinates for hot spot tests.
1785         output_to_canvas(mwindow->edl, 0, canvas_x1, canvas_y1);
1786         output_to_canvas(mwindow->edl, 0, canvas_x2, canvas_y2);
1789         if(gui->current_operation == CWINDOW_CROP)
1790         {
1791                 handle_selected = gui->crop_handle;
1792         }
1793         else
1794         if(canvas_cursor_x >= canvas_x1 && canvas_cursor_x < canvas_x1 + CROPHANDLE_W &&
1795                 canvas_cursor_y >= canvas_y1 && canvas_cursor_y < canvas_y1 + CROPHANDLE_H)
1796         {
1797                 handle_selected = 0;
1798                 gui->crop_origin_x = x1;
1799                 gui->crop_origin_y = y1;
1800         }
1801         else
1802         if(canvas_cursor_x >= canvas_x2 - CROPHANDLE_W && canvas_cursor_x < canvas_x2 &&
1803                 canvas_cursor_y >= canvas_y1 && canvas_cursor_y < canvas_y1 + CROPHANDLE_H)
1804         {
1805                 handle_selected = 1;
1806                 gui->crop_origin_x = x2;
1807                 gui->crop_origin_y = y1;
1808         }
1809         else
1810         if(canvas_cursor_x >= canvas_x1 && canvas_cursor_x < canvas_x1 + CROPHANDLE_W &&
1811                 canvas_cursor_y >= canvas_y2 - CROPHANDLE_H && canvas_cursor_y < canvas_y2)
1812         {
1813                 handle_selected = 2;
1814                 gui->crop_origin_x = x1;
1815                 gui->crop_origin_y = y2;
1816         }
1817         else
1818         if(canvas_cursor_x >= canvas_x2 - CROPHANDLE_W && canvas_cursor_x < canvas_x2 &&
1819                 canvas_cursor_y >= canvas_y2 - CROPHANDLE_H && canvas_cursor_y < canvas_y2)
1820         {
1821                 handle_selected = 3;
1822                 gui->crop_origin_x = x2;
1823                 gui->crop_origin_y = y2;
1824         }
1825         else
1826 // Start new box
1827         {
1828                 gui->crop_origin_x = cursor_x;
1829                 gui->crop_origin_y = cursor_y;
1830         }
1832 // printf("test crop %d %d\n", 
1833 //      gui->current_operation,
1834 //      handle_selected);
1836 // Start dragging.
1837         if(button_press)
1838         {
1839                 if(gui->alt_down())
1840                 {
1841                         gui->crop_translate = 1;
1842                         gui->crop_origin_x1 = x1;
1843                         gui->crop_origin_y1 = y1;
1844                         gui->crop_origin_x2 = x2;
1845                         gui->crop_origin_y2 = y2;
1846                 }
1847                 else
1848                         gui->crop_translate = 0;
1850                 gui->current_operation = CWINDOW_CROP;
1851                 gui->crop_handle = handle_selected;
1852                 gui->x_origin = cursor_x;
1853                 gui->y_origin = cursor_y;
1854                 result = 1;
1856                 if(handle_selected < 0 && !gui->crop_translate) 
1857                 {
1858                         x2 = x1 = cursor_x;
1859                         y2 = y1 = cursor_y;
1860                         mwindow->edl->session->crop_x1 = (int)x1;
1861                         mwindow->edl->session->crop_y1 = (int)y1;
1862                         mwindow->edl->session->crop_x2 = (int)x2;
1863                         mwindow->edl->session->crop_y2 = (int)y2;
1864                         redraw = 1;
1865                 }
1866         }
1867     else
1868 // Translate all 4 points
1869         if(gui->current_operation == CWINDOW_CROP && gui->crop_translate)
1870         {
1871                 x1 = cursor_x - gui->x_origin + gui->crop_origin_x1;
1872                 y1 = cursor_y - gui->y_origin + gui->crop_origin_y1;
1873                 x2 = cursor_x - gui->x_origin + gui->crop_origin_x2;
1874                 y2 = cursor_y - gui->y_origin + gui->crop_origin_y2;
1876                 mwindow->edl->session->crop_x1 = (int)x1;
1877                 mwindow->edl->session->crop_y1 = (int)y1;
1878                 mwindow->edl->session->crop_x2 = (int)x2;
1879                 mwindow->edl->session->crop_y2 = (int)y2;
1880                 result = 1;
1881                 redraw = 1;
1882         }
1883         else
1884 // Update dragging
1885         if(gui->current_operation == CWINDOW_CROP)
1886         {
1887                 switch(gui->crop_handle)
1888                 {
1889                         case -1:
1890                                 x1 = gui->crop_origin_x;
1891                                 y1 = gui->crop_origin_y;
1892                                 x2 = gui->crop_origin_x;
1893                                 y2 = gui->crop_origin_y;
1894                                 if(cursor_x < gui->x_origin)
1895                                 {
1896                                         if(cursor_y < gui->y_origin)
1897                                         {
1898                                                 x1 = cursor_x;
1899                                                 y1 = cursor_y;
1900                                         }
1901                                         else
1902                                         if(cursor_y >= gui->y_origin)
1903                                         {
1904                                                 x1 = cursor_x;
1905                                                 y2 = cursor_y;
1906                                         }
1907                                 }
1908                                 else
1909                                 if(cursor_x  >= gui->x_origin)
1910                                 {
1911                                         if(cursor_y < gui->y_origin)
1912                                         {
1913                                                 y1 = cursor_y;
1914                                                 x2 = cursor_x;
1915                                         }
1916                                         else
1917                                         if(cursor_y >= gui->y_origin)
1918                                         {
1919                                                 x2 = cursor_x;
1920                                                 y2 = cursor_y;
1921                                         }
1922                                 }
1924 // printf("test crop %d %d %d %d\n", 
1925 //      mwindow->edl->session->crop_x1,
1926 //      mwindow->edl->session->crop_y1,
1927 //      mwindow->edl->session->crop_x2,
1928 //      mwindow->edl->session->crop_y2);
1929                                 break;
1930                         case 0:
1931                                 x1 = cursor_x - gui->x_origin + gui->crop_origin_x;
1932                                 y1 = cursor_y - gui->y_origin + gui->crop_origin_y;
1933                                 break;
1934                         case 1:
1935                                 x2 = cursor_x - gui->x_origin + gui->crop_origin_x;
1936                                 y1 = cursor_y - gui->y_origin + gui->crop_origin_y;
1937                                 break;
1938                         case 2:
1939                                 x1 = cursor_x - gui->x_origin + gui->crop_origin_x;
1940                                 y2 = cursor_y - gui->y_origin + gui->crop_origin_y;
1941                                 break;
1942                         case 3:
1943                                 x2 = cursor_x - gui->x_origin + gui->crop_origin_x;
1944                                 y2 = cursor_y - gui->y_origin + gui->crop_origin_y;
1945                                 break;
1946                 }
1948                 if(!EQUIV(mwindow->edl->session->crop_x1, x1) ||
1949                         !EQUIV(mwindow->edl->session->crop_x2, x2) ||
1950                         !EQUIV(mwindow->edl->session->crop_y1, y1) ||
1951                         !EQUIV(mwindow->edl->session->crop_y2, y2))
1952                 {
1953                         if (x1 > x2) 
1954                         {
1955                                 float tmp = x1;
1956                                 x1 = x2;
1957                                 x2 = tmp;
1958                                 switch (gui->crop_handle) 
1959                                 {
1960                                         case 0: gui->crop_handle = 1; break;
1961                                         case 1: gui->crop_handle = 0; break;
1962                                         case 2: gui->crop_handle = 3; break;
1963                                         case 3: gui->crop_handle = 2; break;
1964                                         default: break;
1965                                 }
1967                         }
1968                         if (y1 > y2) 
1969                         {
1970                                 float tmp = y1;
1971                                 y1 = y2;
1972                                 y2 = tmp;
1973                                 switch (gui->crop_handle) 
1974                                 {
1975                                         case 0: gui->crop_handle = 2; break;
1976                                         case 1: gui->crop_handle = 3; break;
1977                                         case 2: gui->crop_handle = 0; break;
1978                                         case 3: gui->crop_handle = 1; break;
1979                                         default: break;
1980                                 }
1981                         }
1983                         mwindow->edl->session->crop_x1 = (int)x1;
1984                         mwindow->edl->session->crop_y1 = (int)y1;
1985                         mwindow->edl->session->crop_x2 = (int)x2;
1986                         mwindow->edl->session->crop_y2 = (int)y2;
1987                         result = 1;
1988                         redraw = 1;
1989                 }
1990         }
1991         else
1992 // Update cursor font
1993         if(handle_selected >= 0)
1994         {
1995                 switch(handle_selected)
1996                 {
1997                         case 0:
1998                                 set_cursor(UPLEFT_RESIZE);
1999                                 break;
2000                         case 1:
2001                                 set_cursor(UPRIGHT_RESIZE);
2002                                 break;
2003                         case 2:
2004                                 set_cursor(DOWNLEFT_RESIZE);
2005                                 break;
2006                         case 3:
2007                                 set_cursor(DOWNRIGHT_RESIZE);
2008                                 break;
2009                 }
2010                 result = 1;
2011         }
2012         else
2013         {
2014                 set_cursor(ARROW_CURSOR);
2015         }
2016 #define CLAMP(x, y, z) ((x) = ((x) < (y) ? (y) : ((x) > (z) ? (z) : (x))))
2017         
2018         if(redraw)
2019         {
2020                 CLAMP(mwindow->edl->session->crop_x1, 0, mwindow->edl->session->output_w);
2021                 CLAMP(mwindow->edl->session->crop_x2, 0, mwindow->edl->session->output_w);
2022                 CLAMP(mwindow->edl->session->crop_y1, 0, mwindow->edl->session->output_h);
2023                 CLAMP(mwindow->edl->session->crop_y2, 0, mwindow->edl->session->output_h);
2024 // printf("CWindowCanvas::test_crop %d %d %d %d\n", 
2025 //      mwindow->edl->session->crop_x2,
2026 //      mwindow->edl->session->crop_y2,
2027 //      mwindow->edl->calculate_output_w(0), 
2028 //      mwindow->edl->calculate_output_h(0));
2029         }
2030         return result;
2034 void CWindowCanvas::draw_crop()
2036         get_canvas()->set_inverse();
2037         get_canvas()->set_color(WHITE);
2039         float x1 = mwindow->edl->session->crop_x1;
2040         float y1 = mwindow->edl->session->crop_y1;
2041         float x2 = mwindow->edl->session->crop_x2;
2042         float y2 = mwindow->edl->session->crop_y2;
2044         output_to_canvas(mwindow->edl, 0, x1, y1);
2045         output_to_canvas(mwindow->edl, 0, x2, y2);
2047         if(x2 - x1 && y2 - y1)
2048                 get_canvas()->draw_rectangle((int)x1, 
2049                         (int)y1, 
2050                         (int)(x2 - x1), 
2051                         (int)(y2 - y1));
2053         draw_crophandle((int)x1, (int)y1);
2054         draw_crophandle((int)x2 - CROPHANDLE_W, (int)y1);
2055         draw_crophandle((int)x1, (int)y2 - CROPHANDLE_H);
2056         draw_crophandle((int)x2 - CROPHANDLE_W, (int)y2 - CROPHANDLE_H);
2057         get_canvas()->set_opaque();
2067 void CWindowCanvas::draw_bezier(int do_camera)
2069         Track *track = gui->cwindow->calculate_affected_track();
2070         
2071         if(!track) return;
2073         float center_x;
2074         float center_y;
2075         float center_z;
2076         int64_t position = track->to_units(
2077                 mwindow->edl->local_session->get_selectionstart(1), 
2078                 0);
2080         track->automation->get_projector(&center_x, 
2081                 &center_y, 
2082                 &center_z, 
2083                 position,
2084                 PLAY_FORWARD);
2086 //      center_x += track->track_w / 2;
2087 //      center_y += track->track_h / 2;
2088         center_x += mwindow->edl->session->output_w / 2;
2089         center_y += mwindow->edl->session->output_h / 2;
2090         float track_x1 = center_x - track->track_w / 2 * center_z;
2091         float track_y1 = center_y - track->track_h / 2 * center_z;
2092         float track_x2 = track_x1 + track->track_w * center_z;
2093         float track_y2 = track_y1 + track->track_h * center_z;
2095         output_to_canvas(mwindow->edl, 0, track_x1, track_y1);
2096         output_to_canvas(mwindow->edl, 0, track_x2, track_y2);
2098 #define DRAW_PROJECTION(offset) \
2099         get_canvas()->draw_rectangle((int)track_x1 + offset, \
2100                 (int)track_y1 + offset, \
2101                 (int)(track_x2 - track_x1), \
2102                 (int)(track_y2 - track_y1)); \
2103         get_canvas()->draw_line((int)track_x1 + offset,  \
2104                 (int)track_y1 + offset, \
2105                 (int)track_x2 + offset, \
2106                 (int)track_y2 + offset); \
2107         get_canvas()->draw_line((int)track_x2 + offset,  \
2108                 (int)track_y1 + offset, \
2109                 (int)track_x1 + offset, \
2110                 (int)track_y2 + offset); \
2113 // Drop shadow
2114         get_canvas()->set_color(BLACK);
2115         DRAW_PROJECTION(1);
2117 //      canvas->set_inverse();
2118         if(do_camera)
2119                 get_canvas()->set_color(GREEN);
2120         else
2121                 get_canvas()->set_color(RED);
2123         DRAW_PROJECTION(0);
2124 //      canvas->set_opaque();
2130 int CWindowCanvas::test_bezier(int button_press, 
2131         int &redraw, 
2132         int &redraw_canvas,
2133         int &rerender,
2134         int do_camera)
2136         int result = 0;
2138 // Processing drag operation.
2139 // Create keyframe during first cursor motion.
2140         if(!button_press)
2141         {
2143                 float cursor_x = get_cursor_x();
2144                 float cursor_y = get_cursor_y();
2145                 canvas_to_output(mwindow->edl, 0, cursor_x, cursor_y);
2147                 if(gui->current_operation == CWINDOW_CAMERA ||
2148                         gui->current_operation == CWINDOW_PROJECTOR)
2149                 {
2150                         if(!gui->ctrl_down() && gui->shift_down() && !gui->translating_zoom)
2151                         {
2152                                 gui->translating_zoom = 1;
2153                                 gui->reset_affected();
2154                         }
2155                         else
2156                         if(!gui->ctrl_down() && !gui->shift_down() && gui->translating_zoom)
2157                         {
2158                                 gui->translating_zoom = 0;
2159                                 gui->reset_affected();
2160                         }
2162 // Get target keyframe
2163                         float last_center_x;
2164                         float last_center_y;
2165                         float last_center_z;
2168                         if(!gui->affected_x && !gui->affected_y && !gui->affected_z)
2169                         {
2170                                 FloatAutos *affected_x_autos;
2171                                 FloatAutos *affected_y_autos;
2172                                 FloatAutos *affected_z_autos;
2173                                 if(!gui->affected_track) return 0;
2174                                 if(mwindow->edl->session->cwindow_operation == CWINDOW_CAMERA)
2175                                 {
2176                                         affected_x_autos = (FloatAutos*)gui->affected_track->automation->autos[AUTOMATION_CAMERA_X];
2177                                         affected_y_autos = (FloatAutos*)gui->affected_track->automation->autos[AUTOMATION_CAMERA_Y];
2178                                         affected_z_autos = (FloatAutos*)gui->affected_track->automation->autos[AUTOMATION_CAMERA_Z];
2179                                 }
2180                                 else
2181                                 {
2182                                         affected_x_autos = (FloatAutos*)gui->affected_track->automation->autos[AUTOMATION_PROJECTOR_X];
2183                                         affected_y_autos = (FloatAutos*)gui->affected_track->automation->autos[AUTOMATION_PROJECTOR_Y];
2184                                         affected_z_autos = (FloatAutos*)gui->affected_track->automation->autos[AUTOMATION_PROJECTOR_Z];
2185                                 }
2188                                 if(gui->translating_zoom)
2189                                 {
2190                                         gui->affected_z = 
2191                                                 (FloatAuto*)gui->cwindow->calculate_affected_auto(
2192                                                         affected_z_autos, 1);
2193                                 }
2194                                 else
2195                                 {
2196                                         gui->affected_x = 
2197                                                 (FloatAuto*)gui->cwindow->calculate_affected_auto(
2198                                                         affected_x_autos, 1);
2199                                         gui->affected_y = 
2200                                                 (FloatAuto*)gui->cwindow->calculate_affected_auto(
2201                                                         affected_y_autos, 1);
2202                                 }
2204                                 calculate_origin();
2206                                 if(gui->translating_zoom)
2207                                 {
2208                                         gui->center_z = gui->affected_z->value;
2209                                 }
2210                                 else
2211                                 {
2212                                         gui->center_x = gui->affected_x->value;
2213                                         gui->center_y = gui->affected_y->value;
2214                                 }
2216                                 rerender = 1;
2217                                 redraw = 1;
2218                         }
2221                         if(gui->translating_zoom)
2222                         {
2223                                 last_center_z = gui->affected_z->value;
2224                         }
2225                         else
2226                         {
2227                                 last_center_x = gui->affected_x->value;
2228                                 last_center_y = gui->affected_y->value;
2229                         }
2231                         if(gui->translating_zoom)
2232                         {
2233                                 gui->affected_z->value = gui->center_z + 
2234                                         (cursor_y - gui->y_origin) / 128;
2235                                 if(!EQUIV(last_center_z, gui->affected_z->value))
2236                                 {
2237                                         rerender = 1;
2238                                         redraw = 1;
2239                                         redraw_canvas = 1;
2240                                 }
2241                         }
2242                         else
2243                         {
2244                                 gui->affected_x->value = gui->center_x + cursor_x - gui->x_origin;
2245                                 gui->affected_y->value = gui->center_y + cursor_y - gui->y_origin;
2246                                 if(!EQUIV(last_center_x,  gui->affected_x->value) ||
2247                                         !EQUIV(last_center_y, gui->affected_y->value))
2248                                 {
2249                                         rerender = 1;
2250                                         redraw = 1;
2251                                         redraw_canvas = 1;
2252                                 }
2253                         }
2254                 }
2256                 result = 1;
2257         }
2258         else
2259 // Begin drag operation.  Don't create keyframe here.
2260         {
2261 // Get affected track off of the first recordable video track.
2262 // Calculating based on the alpha channel would require recording what layer
2263 // each output pixel belongs to as they're rendered and stacked.  Forget it.
2264                 gui->affected_track = gui->cwindow->calculate_affected_track();
2265                 gui->reset_affected();
2267                 if(gui->affected_track)
2268                 {
2269                         gui->current_operation = 
2270                                 mwindow->edl->session->cwindow_operation;
2271                         result = 1;
2272                 }
2273         }
2274         
2275         return result;
2278 int CWindowCanvas::test_zoom(int &redraw)
2280         int result = 0;
2281         float zoom = get_zoom();
2282         float x;
2283         float y;
2285         if(!mwindow->edl->session->cwindow_scrollbars)
2286         {
2287                 mwindow->edl->session->cwindow_scrollbars = 1;
2288                 zoom = 1.0;
2289                 x = mwindow->edl->session->output_w / 2;
2290                 y = mwindow->edl->session->output_h / 2;
2291         }
2292         else
2293         {
2294                 x = get_cursor_x();
2295                 y = get_cursor_y();
2296                 canvas_to_output(mwindow->edl, 
2297                                 0, 
2298                                 x, 
2299                                 y);
2301 //printf("CWindowCanvas::test_zoom 1 %f %f\n", x, y);
2303 // Find current zoom in table
2304                 int current_index = 0;
2305                 for(current_index = 0 ; current_index < total_zooms; current_index++)
2306                         if(EQUIV(my_zoom_table[current_index], zoom)) break;
2309 // Zoom out
2310                 if(get_buttonpress() == 5 ||
2311                         gui->ctrl_down() || 
2312                         gui->shift_down())
2313                 {
2314                         current_index--;
2315                 }
2316                 else
2317 // Zoom in
2318                 {
2319                         current_index++;
2320                 }
2321                 CLAMP(current_index, 0, total_zooms - 1);
2322                 zoom = my_zoom_table[current_index];
2323         }
2325         x = x - w / zoom / 2;
2326         y = y - h / zoom / 2;
2329         int x_i = (int)x;
2330         int y_i = (int)y;
2331 //      check_boundaries(mwindow->edl, x_i, y_i, zoom);
2333 //printf("CWindowCanvas::test_zoom 2 %d %d\n", x_i, y_i);
2335         update_zoom(x_i, 
2336                         y_i, 
2337                         zoom);
2338         reposition_window(mwindow->edl, 
2339                         mwindow->theme->ccanvas_x,
2340                         mwindow->theme->ccanvas_y,
2341                         mwindow->theme->ccanvas_w,
2342                         mwindow->theme->ccanvas_h);
2343         redraw = 1;
2344         result = 1;
2346         
2347         gui->zoom_panel->update(zoom);
2348         
2349         return result;
2353 void CWindowCanvas::calculate_origin()
2355         gui->x_origin = get_cursor_x();
2356         gui->y_origin = get_cursor_y();
2357 //printf("CWindowCanvas::calculate_origin 1 %f %f\n", gui->x_origin, gui->y_origin);
2358         canvas_to_output(mwindow->edl, 0, gui->x_origin, gui->y_origin);
2359 //printf("CWindowCanvas::calculate_origin 2 %f %f\n", gui->x_origin, gui->y_origin);
2363 int CWindowCanvas::cursor_leave_event()
2365         set_cursor(ARROW_CURSOR);
2366         return 1;
2369 int CWindowCanvas::cursor_enter_event()
2371         int redraw = 0;
2372         switch(mwindow->edl->session->cwindow_operation)
2373         {
2374                 case CWINDOW_CAMERA:
2375                 case CWINDOW_PROJECTOR:
2376                         set_cursor(MOVE_CURSOR);
2377                         break;
2378                 case CWINDOW_ZOOM:
2379                         set_cursor(MOVE_CURSOR);
2380                         break;
2381                 case CWINDOW_CROP:
2382                         test_crop(0, redraw);
2383                         break;
2384                 case CWINDOW_PROTECT:
2385                         set_cursor(ARROW_CURSOR);
2386                         break;
2387                 case CWINDOW_MASK:
2388                         set_cursor(CROSS_CURSOR);
2389                         break;
2390                 case CWINDOW_EYEDROP:
2391                         set_cursor(CROSS_CURSOR);
2392                         break;
2393         }
2394         return 1;
2397 int CWindowCanvas::cursor_motion_event()
2399         int redraw = 0, result = 0, rerender = 0, redraw_canvas = 0;
2402         switch(gui->current_operation)
2403         {
2404                 case CWINDOW_SCROLL:
2405                 {
2406                         float zoom = get_zoom();
2407                         float cursor_x = get_cursor_x();
2408                         float cursor_y = get_cursor_y();
2410                         float zoom_x, zoom_y, conformed_w, conformed_h;
2411                         get_zooms(mwindow->edl, 0, zoom_x, zoom_y, conformed_w, conformed_h);
2412                         cursor_x = (float)cursor_x / zoom_x + gui->x_offset;
2413                         cursor_y = (float)cursor_y / zoom_y + gui->y_offset;
2417                         int x = (int)(gui->x_origin - cursor_x + gui->x_offset);
2418                         int y = (int)(gui->y_origin - cursor_y + gui->y_offset);
2420                         update_zoom(x, 
2421                                 y, 
2422                                 zoom);
2423                         update_scrollbars();
2424                         redraw = 1;
2425                         result = 1;
2426                         break;
2427                 }
2429                 case CWINDOW_CAMERA:
2430                         result = test_bezier(0, redraw, redraw_canvas, rerender, 1);
2431                         break;
2433                 case CWINDOW_PROJECTOR:
2434                         result = test_bezier(0, redraw, redraw_canvas, rerender, 0);
2435                         break;
2438                 case CWINDOW_CROP:
2439 //printf("CWindowCanvas::cursor_motion_event 1 %d %d\n", x, y);
2440                         result = test_crop(0, redraw);
2441                         break;
2443                 case CWINDOW_MASK:
2444                 case CWINDOW_MASK_CONTROL_IN:
2445                 case CWINDOW_MASK_CONTROL_OUT:
2446                 case CWINDOW_MASK_TRANSLATE:
2447                         result = do_mask(redraw, 
2448                                 rerender, 
2449                                 0, 
2450                                 1,
2451                                 0);
2452                         break;
2454                 case CWINDOW_EYEDROP:
2455                         result = do_eyedrop(rerender, 0);
2456                         break;
2458         }
2462         if(!result)
2463         {
2464                 switch(mwindow->edl->session->cwindow_operation)
2465                 {
2466                         case CWINDOW_CROP:
2467                                 result = test_crop(0, redraw);
2468                                 break;
2469                 }
2470         }
2473 // If the window is never unlocked before calling send_command the
2474 // display shouldn't get stuck on the old video frame although it will
2475 // flicker between the old video frame and the new video frame.
2477         if(redraw)
2478         {
2479                 draw_refresh();
2480                 gui->update_tool();
2481         }
2483         if(redraw_canvas)
2484         {
2485                 mwindow->gui->lock_window("CWindowCanvas::cursor_motion_event 1");
2486                 mwindow->gui->canvas->draw_overlays();
2487                 mwindow->gui->canvas->flash();
2488                 mwindow->gui->unlock_window();
2489         }
2491         if(rerender)
2492         {
2493                 mwindow->restart_brender();
2494                 mwindow->sync_parameters(CHANGE_PARAMS);
2495                 gui->cwindow->playback_engine->que->send_command(CURRENT_FRAME, 
2496                         CHANGE_NONE,
2497                         mwindow->edl,
2498                         1);
2499                 if(!redraw) gui->update_tool();
2500         }
2501         return result;
2504 int CWindowCanvas::button_press_event()
2506         int result = 0;
2507         int redraw = 0;
2508         int redraw_canvas = 0;
2509         int rerender = 0;
2511         if(Canvas::button_press_event()) return 1;
2513         gui->translating_zoom = gui->shift_down(); 
2515         calculate_origin();
2516 //printf("CWindowCanvas::button_press_event 2 %f %f\n", gui->x_origin, gui->y_origin, gui->x_origin, gui->y_origin);
2518         float zoom_x, zoom_y, conformed_w, conformed_h;
2519         get_zooms(mwindow->edl, 0, zoom_x, zoom_y, conformed_w, conformed_h);
2520         gui->x_offset = get_x_offset(mwindow->edl, 0, zoom_x, conformed_w, conformed_h);
2521         gui->y_offset = get_y_offset(mwindow->edl, 0, zoom_y, conformed_w, conformed_h);
2523 // Scroll view
2524         if(get_buttonpress() == 2)
2525         {
2526                 gui->current_operation = CWINDOW_SCROLL;
2527                 result = 1;
2528         }
2529         else
2530 // Adjust parameter
2531         {
2532                 switch(mwindow->edl->session->cwindow_operation)
2533                 {
2534                         case CWINDOW_CAMERA:
2535                                 result = test_bezier(1, redraw, redraw_canvas, rerender, 1);
2536                                 break;
2538                         case CWINDOW_PROJECTOR:
2539                                 result = test_bezier(1, redraw, redraw_canvas, rerender, 0);
2540                                 break;
2542                         case CWINDOW_ZOOM:
2543                                 result = test_zoom(redraw);
2544                                 break;
2546                         case CWINDOW_CROP:
2547                                 result = test_crop(1, redraw);
2548                                 break;
2550                         case CWINDOW_MASK:
2551                                 if(get_buttonpress() == 1)
2552                                         result = do_mask(redraw, rerender, 1, 0, 0);
2553                                 break;
2555                         case CWINDOW_EYEDROP:
2556                                 result = do_eyedrop(rerender, 1);
2557                                 break;
2558                 }
2559         }
2561         if(redraw)
2562         {
2563                 draw_refresh();
2564                 gui->update_tool();
2565         }
2567 // rerendering can also be caused by press event
2568         if(rerender) 
2569         {
2570                 mwindow->restart_brender();
2571                 mwindow->sync_parameters(CHANGE_PARAMS);
2572                 gui->cwindow->playback_engine->que->send_command(CURRENT_FRAME, 
2573                         CHANGE_NONE,
2574                         mwindow->edl,
2575                         1);
2576                 if(!redraw) gui->update_tool();
2577         }
2578         return result;
2581 int CWindowCanvas::button_release_event()
2583         int result = 0;
2585         switch(gui->current_operation)
2586         {
2587                 case CWINDOW_SCROLL:
2588                         result = 1;
2589                         break;
2591                 case CWINDOW_CAMERA:
2592                         mwindow->undo->update_undo(_("camera"), LOAD_AUTOMATION);
2593                         break;
2595                 case CWINDOW_PROJECTOR:
2596                         mwindow->undo->update_undo(_("projector"), LOAD_AUTOMATION);
2597                         break;
2599                 case CWINDOW_MASK:
2600                 case CWINDOW_MASK_CONTROL_IN:
2601                 case CWINDOW_MASK_CONTROL_OUT:
2602                 case CWINDOW_MASK_TRANSLATE:
2603                         mwindow->undo->update_undo(_("mask point"), LOAD_AUTOMATION);
2604                         break;
2606         }
2608         gui->current_operation = CWINDOW_NONE;
2609         return result;
2612 void CWindowCanvas::zoom_resize_window(float percentage)
2614         int canvas_w, canvas_h;
2615         calculate_sizes(mwindow->edl->get_aspect_ratio(), 
2616                 mwindow->edl->session->output_w, 
2617                 mwindow->edl->session->output_h, 
2618                 percentage,
2619                 canvas_w,
2620                 canvas_h);
2621         int new_w, new_h;
2622         new_w = canvas_w + (gui->get_w() - mwindow->theme->ccanvas_w);
2623         new_h = canvas_h + (gui->get_h() - mwindow->theme->ccanvas_h);
2624         gui->resize_window(new_w, new_h);
2625         gui->resize_event(new_w, new_h);
2628 void CWindowCanvas::toggle_controls()
2630         mwindow->session->cwindow_controls = !mwindow->session->cwindow_controls;
2631         gui->resize_event(gui->get_w(), gui->get_h());
2634 int CWindowCanvas::get_cwindow_controls()
2636         return mwindow->session->cwindow_controls;