r854: Merge 2.1:
[cinelerra_cv/ct.git] / cinelerra / cwindowgui.C
blobbc2c066855a99c01aef143591e424dca2f1ac928
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                         float in_x1, in_y1, in_x2, in_y2;
855                         float out_x1, out_y1, out_x2, out_y2;
856                         get_transfers(mwindow->edl, 
857                                 in_x1, 
858                                 in_y1, 
859                                 in_x2, 
860                                 in_y2, 
861                                 out_x1, 
862                                 out_y1, 
863                                 out_x2, 
864                                 out_y2);
866                         get_canvas()->clear_box(0, 
867                                 0, 
868                                 get_canvas()->get_w(), 
869                                 get_canvas()->get_h());
871 // printf("CWindowCanvas::draw_refresh %f %f %f %f -> %f %f %f %f\n", 
872 // in_x1, in_y1, in_x2, in_y2, out_x1, out_y1, out_x2, out_y2);
875                         if(out_x2 > out_x1 && 
876                                 out_y2 > out_y1 && 
877                                 in_x2 > in_x1 && 
878                                 in_y2 > in_y1)
879                         {
880 // Can't use OpenGL here because it is called asynchronously of the
881 // playback operation.
882                                 get_canvas()->draw_vframe(refresh_frame,
883                                                 (int)out_x1, 
884                                                 (int)out_y1, 
885                                                 (int)(out_x2 - out_x1), 
886                                                 (int)(out_y2 - out_y1),
887                                                 (int)in_x1, 
888                                                 (int)in_y1, 
889                                                 (int)(in_x2 - in_x1), 
890                                                 (int)(in_y2 - in_y1),
891                                                 0);
892                         }
893                 }
895                 draw_overlays();
896                 get_canvas()->flash();
897         }
898 //printf("CWindowCanvas::draw_refresh 10\n");
901 #define CROPHANDLE_W 10
902 #define CROPHANDLE_H 10
904 void CWindowCanvas::draw_crophandle(int x, int y)
906         get_canvas()->draw_box(x, y, CROPHANDLE_W, CROPHANDLE_H);
909 #define CONTROL_W 10
910 #define CONTROL_H 10
911 #define FIRST_CONTROL_W 20
912 #define FIRST_CONTROL_H 20
913 #undef BC_INFINITY
914 #define BC_INFINITY 65536
915 #ifndef SQR
916 #define SQR(x) ((x) * (x))
917 #endif
919 int CWindowCanvas::do_mask(int &redraw, 
920                 int &rerender, 
921                 int button_press, 
922                 int cursor_motion,
923                 int draw)
925 // Retrieve points from top recordable track
926 //printf("CWindowCanvas::do_mask 1\n");
927         Track *track = gui->cwindow->calculate_affected_track();
928 //printf("CWindowCanvas::do_mask 2\n");
930         if(!track) return 0;
931 //printf("CWindowCanvas::do_mask 3\n");
933         MaskAutos *mask_autos = (MaskAutos*)track->automation->autos[AUTOMATION_MASK];
934         int64_t position = track->to_units(
935                 mwindow->edl->local_session->get_selectionstart(1),
936                 0);
937         ArrayList<MaskPoint*> points;
938         mask_autos->get_points(&points, mwindow->edl->session->cwindow_mask,
939                 position, 
940                 PLAY_FORWARD);
941 //printf("CWindowCanvas::do_mask 4\n");
943 // Projector zooms relative to the center of the track output.
944         float half_track_w = (float)track->track_w / 2;
945         float half_track_h = (float)track->track_h / 2;
946 // Translate mask to projection
947         float projector_x, projector_y, projector_z;
948         track->automation->get_projector(&projector_x,
949                 &projector_y,
950                 &projector_z,
951                 position,
952                 PLAY_FORWARD);
955 // Get position of cursor relative to mask
956         float mask_cursor_x = get_cursor_x();
957         float mask_cursor_y = get_cursor_y();
958         canvas_to_output(mwindow->edl, 0, mask_cursor_x, mask_cursor_y);
960         projector_x += mwindow->edl->session->output_w / 2;
961         projector_y += mwindow->edl->session->output_h / 2;
963         mask_cursor_x -= projector_x;
964         mask_cursor_y -= projector_y;
965         mask_cursor_x = mask_cursor_x / projector_z + half_track_w;
966         mask_cursor_y = mask_cursor_y / projector_z + half_track_h;
968 // Fix cursor origin
969         if(button_press)
970         {
971                 gui->x_origin = mask_cursor_x;
972                 gui->y_origin = mask_cursor_y;
973         }
975         int result = 0;
976 // Points of closest line
977         int shortest_point1 = -1;
978         int shortest_point2 = -1;
979 // Closest point
980         int shortest_point = -1;
981 // Distance to closest line
982         float shortest_line_distance = BC_INFINITY;
983 // Distance to closest point
984         float shortest_point_distance = BC_INFINITY;
985         int selected_point = -1;
986         int selected_control_point = -1;
987         float selected_control_point_distance = BC_INFINITY;
988         ArrayList<int> x_points;
989         ArrayList<int> y_points;
991         if(!cursor_motion)
992         {
993                 if(draw)
994                 {
995                         get_canvas()->set_color(WHITE);
996                         get_canvas()->set_inverse();
997                 }
998 //printf("CWindowCanvas::do_mask 1 %d\n", points.total);
1000 // Never draw closed polygon and a closed
1001 // polygon is harder to add points to.
1002                 for(int i = 0; i < points.total && !result; i++)
1003                 {
1004                         MaskPoint *point1 = points.values[i];
1005                         MaskPoint *point2 = (i >= points.total - 1) ? 
1006                                 points.values[0] : 
1007                                 points.values[i + 1];
1008                         float x0, x1, x2, x3;
1009                         float y0, y1, y2, y3;
1010                         float old_x, old_y, x, y;
1011                         int segments = (int)(sqrt(SQR(point1->x - point2->x) + SQR(point1->y - point2->y)));
1013 //printf("CWindowCanvas::do_mask 1 %f, %f -> %f, %f projectorz=%f\n",
1014 //point1->x, point1->y, point2->x, point2->y, projector_z);
1015                         for(int j = 0; j <= segments && !result; j++)
1016                         {
1017 //printf("CWindowCanvas::do_mask 1 %f, %f -> %f, %f\n", x0, y0, x3, y3);
1018                                 x0 = point1->x;
1019                                 y0 = point1->y;
1020                                 x1 = point1->x + point1->control_x2;
1021                                 y1 = point1->y + point1->control_y2;
1022                                 x2 = point2->x + point2->control_x1;
1023                                 y2 = point2->y + point2->control_y1;
1024                                 x3 = point2->x;
1025                                 y3 = point2->y;
1027                                 float t = (float)j / segments;
1028                                 float tpow2 = t * t;
1029                                 float tpow3 = t * t * t;
1030                                 float invt = 1 - t;
1031                                 float invtpow2 = invt * invt;
1032                                 float invtpow3 = invt * invt * invt;
1034                                 x = (        invtpow3 * x0
1035                                         + 3 * t     * invtpow2 * x1
1036                                         + 3 * tpow2 * invt     * x2 
1037                                         +     tpow3            * x3);
1038                                 y = (        invtpow3 * y0 
1039                                         + 3 * t     * invtpow2 * y1
1040                                         + 3 * tpow2 * invt     * y2 
1041                                         +     tpow3            * y3);
1043                                 x = (x - half_track_w) * projector_z + projector_x;
1044                                 y = (y - half_track_h) * projector_z + projector_y;
1047 // Test new point addition
1048                                 if(button_press)
1049                                 {
1050                                         float line_distance = 
1051                                                 sqrt(SQR(x - mask_cursor_x) + SQR(y - mask_cursor_y));
1053 //printf("CWindowCanvas::do_mask 1 x=%f mask_cursor_x=%f y=%f mask_cursor_y=%f %f %f %d, %d\n", 
1054 //x, mask_cursor_x, y, mask_cursor_y, line_distance, shortest_line_distance, shortest_point1, shortest_point2);
1055                                         if(line_distance < shortest_line_distance || 
1056                                                 shortest_point1 < 0)
1057                                         {
1058                                                 shortest_line_distance = line_distance;
1059                                                 shortest_point1 = i;
1060                                                 shortest_point2 = (i >= points.total - 1) ? 0 : (i + 1);
1061 //printf("CWindowCanvas::do_mask 2 %f %f %d, %d\n", line_distance, shortest_line_distance, shortest_point1, shortest_point2);
1062                                         }
1065                                         float point_distance1 = 
1066                                                 sqrt(SQR(point1->x - mask_cursor_x) + SQR(point1->y - mask_cursor_y));
1067                                         float point_distance2 = 
1068                                                 sqrt(SQR(point2->x - mask_cursor_x) + SQR(point2->y - mask_cursor_y));
1070                                         if(point_distance1 < shortest_point_distance || 
1071                                                 shortest_point < 0)
1072                                         {
1073                                                 shortest_point_distance = point_distance1;
1074                                                 shortest_point = i;
1075                                         }
1077                                         if(point_distance2 < shortest_point_distance || 
1078                                                 shortest_point < 0)
1079                                         {
1080                                                 shortest_point_distance = point_distance2;
1081                                                 shortest_point = (i >= points.total - 1) ? 0 : (i + 1);
1082                                         }
1083                                 }
1085                                 output_to_canvas(mwindow->edl, 0, x, y);
1088 #define TEST_BOX(cursor_x, cursor_y, target_x, target_y) \
1089         (cursor_x >= target_x - CONTROL_W / 2 && \
1090         cursor_x < target_x + CONTROL_W / 2 && \
1091         cursor_y >= target_y - CONTROL_H / 2 && \
1092         cursor_y < target_y + CONTROL_H / 2)
1094 // Test existing point selection
1095                                 if(button_press)
1096                                 {
1097                                         float canvas_x = (x0 - half_track_w) * projector_z + projector_x;
1098                                         float canvas_y = (y0 - half_track_h) * projector_z + projector_y;
1099                                         int cursor_x = get_cursor_x();
1100                                         int cursor_y = get_cursor_y();
1102 // Test first point
1103                                         if(gui->shift_down())
1104                                         {
1105                                                 float control_x = (x1 - half_track_w) * projector_z + projector_x;
1106                                                 float control_y = (y1 - half_track_h) * projector_z + projector_y;
1107                                                 output_to_canvas(mwindow->edl, 0, control_x, control_y);
1109                                                 float distance = 
1110                                                         sqrt(SQR(control_x - cursor_x) + SQR(control_y - cursor_y));
1112                                                 if(distance < selected_control_point_distance)
1113                                                 {
1114                                                         selected_point = i;
1115                                                         selected_control_point = 1;
1116                                                         selected_control_point_distance = distance;
1117                                                 }
1118                                         }
1119                                         else
1120                                         {
1121                                                 output_to_canvas(mwindow->edl, 0, canvas_x, canvas_y);
1122                                                 if(!gui->ctrl_down())
1123                                                 {
1124                                                         if(TEST_BOX(cursor_x, cursor_y, canvas_x, canvas_y))
1125                                                         {
1126                                                                 selected_point = i;
1127                                                         }
1128                                                 }
1129                                                 else
1130                                                 {
1131                                                         selected_point = shortest_point;
1132                                                 }
1133                                         }
1135 // Test second point
1136                                         canvas_x = (x3 - half_track_w) * projector_z + projector_x;
1137                                         canvas_y = (y3 - half_track_h) * projector_z + projector_y;
1138                                         if(gui->shift_down())
1139                                         {
1140                                                 float control_x = (x2 - half_track_w) * projector_z + projector_x;
1141                                                 float control_y = (y2 - half_track_h) * projector_z + projector_y;
1142                                                 output_to_canvas(mwindow->edl, 0, control_x, control_y);
1144                                                 float distance = 
1145                                                         sqrt(SQR(control_x - cursor_x) + SQR(control_y - cursor_y));
1147 //printf("CWindowCanvas::do_mask %d %f %f\n", i, distance, selected_control_point_distance);
1148                                                 if(distance < selected_control_point_distance)
1149                                                 {
1150                                                         selected_point = (i < points.total - 1 ? i + 1 : 0);
1151                                                         selected_control_point = 0;
1152                                                         selected_control_point_distance = distance;
1153                                                 }
1154                                         }
1155                                         else
1156                                         if(i < points.total - 1)
1157                                         {
1158                                                 output_to_canvas(mwindow->edl, 0, canvas_x, canvas_y);
1159                                                 if(!gui->ctrl_down())
1160                                                 {
1161                                                         if(TEST_BOX(cursor_x, cursor_y, canvas_x, canvas_y))
1162                                                         {
1163                                                                 selected_point = (i < points.total - 1 ? i + 1 : 0);
1164                                                         }
1165                                                 }
1166                                                 else
1167                                                 {
1168                                                         selected_point = shortest_point;
1169                                                 }
1170                                         }
1171                                 }
1175                                 if(j > 0)
1176                                 {
1177 // Draw joining line
1178                                         if(draw)
1179                                         {
1180                                                 x_points.append((int)x);
1181                                                 y_points.append((int)y);
1182                                         }
1184                                         if(j == segments)
1185                                         {
1190                                                 if(draw)
1191                                                 {
1192 // Draw second anchor
1193                                                         if(i < points.total - 1)
1194                                                         {
1195                                                                 if(i == gui->affected_point - 1)
1196                                                                         get_canvas()->draw_disc((int)x - CONTROL_W / 2, 
1197                                                                                 (int)y - CONTROL_W / 2, 
1198                                                                                 CONTROL_W, 
1199                                                                                 CONTROL_W);
1200                                                                 else
1201                                                                         get_canvas()->draw_circle((int)x - CONTROL_W / 2, 
1202                                                                                 (int)y - CONTROL_W / 2, 
1203                                                                                 CONTROL_W, 
1204                                                                                 CONTROL_W);
1205 // char string[BCTEXTLEN];
1206 // sprintf(string, "%d", (i < points.total - 1 ? i + 1 : 0));
1207 // canvas->draw_text((int)x + CONTROL_W, (int)y + CONTROL_W, string);
1208                                                         }
1210 // Draw second control point.  Discard x2 and y2 after this.
1211                                                         x2 = (x2 - half_track_w) * projector_z + projector_x;
1212                                                         y2 = (y2 - half_track_h) * projector_z + projector_y;
1213                                                         output_to_canvas(mwindow->edl, 0, x2, y2);
1214                                                         get_canvas()->draw_line((int)x, (int)y, (int)x2, (int)y2);
1215                                                         get_canvas()->draw_rectangle((int)x2 - CONTROL_W / 2,
1216                                                                 (int)y2 - CONTROL_H / 2,
1217                                                                 CONTROL_W,
1218                                                                 CONTROL_H);
1219                                                 }
1220                                         }
1221                                 }
1222                                 else
1223                                 {
1226 // Draw first anchor
1227                                         if(i == 0 && draw)
1228                                         {
1229                                                 get_canvas()->draw_disc((int)x - FIRST_CONTROL_W / 2, 
1230                                                         (int)y - FIRST_CONTROL_H / 2, 
1231                                                         FIRST_CONTROL_W, 
1232                                                         FIRST_CONTROL_H);
1233                                         }
1235 // Draw first control point.  Discard x1 and y1 after this.
1236                                         if(draw)
1237                                         {
1238                                                 x1 = (x1 - half_track_w) * projector_z + projector_x;
1239                                                 y1 = (y1 - half_track_h) * projector_z + projector_y;
1240                                                 output_to_canvas(mwindow->edl, 0, x1, y1);
1241                                                 get_canvas()->draw_line((int)x, (int)y, (int)x1, (int)y1);
1242                                                 get_canvas()->draw_rectangle((int)x1 - CONTROL_W / 2,
1243                                                         (int)y1 - CONTROL_H / 2,
1244                                                         CONTROL_W,
1245                                                         CONTROL_H);
1246                                         
1247                                                 x_points.append((int)x);
1248                                                 y_points.append((int)y);
1249                                         }
1250                                 }
1251 //printf("CWindowCanvas::do_mask 1\n");
1253                                 old_x = x;
1254                                 old_y = y;
1255                         }
1256                 }
1257 //printf("CWindowCanvas::do_mask 1\n");
1259                 if(draw)
1260                 {
1261                         get_canvas()->draw_polygon(&x_points, &y_points);
1262                         get_canvas()->set_opaque();
1263                 }
1264 //printf("CWindowCanvas::do_mask 1\n");
1265         }
1273         if(button_press && !result)
1274         {
1275                 gui->affected_track = gui->cwindow->calculate_affected_track();
1276 // Get current keyframe
1277                 if(gui->affected_track)
1278                         gui->affected_keyframe = 
1279                                 gui->cwindow->calculate_affected_auto(
1280                                         gui->affected_track->automation->autos[AUTOMATION_MASK],
1281                                         1);
1283                 MaskAuto *keyframe = (MaskAuto*)gui->affected_keyframe;
1284                 SubMask *mask = keyframe->get_submask(mwindow->edl->session->cwindow_mask);
1287 // Translate entire keyframe
1288                 if(gui->alt_down() && mask->points.total)
1289                 {
1290                         gui->current_operation = CWINDOW_MASK_TRANSLATE;
1291                         gui->affected_point = 0;
1292                 }
1293                 else
1294 // Existing point or control point was selected
1295                 if(selected_point >= 0)
1296                 {
1297                         gui->affected_point = selected_point;
1299                         if(selected_control_point == 0)
1300                                 gui->current_operation = CWINDOW_MASK_CONTROL_IN;
1301                         else
1302                         if(selected_control_point == 1)
1303                                 gui->current_operation = CWINDOW_MASK_CONTROL_OUT;
1304                         else
1305                                 gui->current_operation = mwindow->edl->session->cwindow_operation;
1306                 }
1307                 else
1308 // No existing point or control point was selected so create a new one
1309                 if(!gui->shift_down() && !gui->alt_down())
1310                 {
1311 // Create the template
1312                         MaskPoint *point = new MaskPoint;
1313                         point->x = mask_cursor_x;
1314                         point->y = mask_cursor_y;
1315                         point->control_x1 = 0;
1316                         point->control_y1 = 0;
1317                         point->control_x2 = 0;
1318                         point->control_y2 = 0;
1321                         if(shortest_point2 < shortest_point1)
1322                         {
1323                                 shortest_point2 ^= shortest_point1;
1324                                 shortest_point1 ^= shortest_point2;
1325                                 shortest_point2 ^= shortest_point1;
1326                         }
1330 // printf("CWindowGUI::do_mask 40\n");
1331 // mwindow->edl->dump();
1332 // printf("CWindowGUI::do_mask 50\n");
1336 //printf("CWindowCanvas::do_mask 1 %f %f %d %d\n", 
1337 //      shortest_line_distance, shortest_point_distance, shortest_point1, shortest_point2);
1338 //printf("CWindowCanvas::do_mask %d %d\n", shortest_point1, shortest_point2);
1340 // Append to end of list
1341                         if(labs(shortest_point1 - shortest_point2) > 1)
1342                         {
1343 // Need to apply the new point to every keyframe
1344                                 for(MaskAuto *current = (MaskAuto*)mask_autos->default_auto;
1345                                         current; )
1346                                 {
1347                                         SubMask *submask = current->get_submask(mwindow->edl->session->cwindow_mask);
1348                                         MaskPoint *new_point = new MaskPoint;
1349                                         submask->points.append(new_point);
1350                                         *new_point = *point;
1351                                         if(current == (MaskAuto*)mask_autos->default_auto)
1352                                                 current = (MaskAuto*)mask_autos->first;
1353                                         else
1354                                                 current = (MaskAuto*)NEXT;
1355                                 }
1357                                 gui->affected_point = mask->points.total - 1;
1358                                 result = 1;
1359                         }
1360                         else
1361 // Insert between 2 points, shifting back point 2
1362                         if(shortest_point1 >= 0 && shortest_point2 >= 0)
1363                         {
1364                                 for(MaskAuto *current = (MaskAuto*)mask_autos->default_auto;
1365                                         current; )
1366                                 {
1367                                         SubMask *submask = current->get_submask(mwindow->edl->session->cwindow_mask);
1368 // In case the keyframe point count isn't synchronized with the rest of the keyframes,
1369 // avoid a crash.
1370                                         if(submask->points.total >= shortest_point2)
1371                                         {
1372                                                 MaskPoint *new_point = new MaskPoint;
1373                                                 submask->points.append(0);
1374                                                 for(int i = submask->points.total - 1; 
1375                                                         i > shortest_point2; 
1376                                                         i--)
1377                                                         submask->points.values[i] = submask->points.values[i - 1];
1378                                                 submask->points.values[shortest_point2] = new_point;
1380                                                 *new_point = *point;
1381                                         }
1383                                         if(current == (MaskAuto*)mask_autos->default_auto)
1384                                                 current = (MaskAuto*)mask_autos->first;
1385                                         else
1386                                                 current = (MaskAuto*)NEXT;
1387                                 }
1390                                 gui->affected_point = shortest_point2;
1391                                 result = 1;
1392                         }
1395 // printf("CWindowGUI::do_mask 20\n");
1396 // mwindow->edl->dump();
1397 // printf("CWindowGUI::do_mask 30\n");
1402 // Create the first point.
1403                         if(!result)
1404                         {
1405 //printf("CWindowCanvas::do_mask 1\n");
1406                                 for(MaskAuto *current = (MaskAuto*)mask_autos->default_auto;
1407                                         current; )
1408                                 {
1409                                         SubMask *submask = current->get_submask(mwindow->edl->session->cwindow_mask);
1410                                         MaskPoint *new_point = new MaskPoint;
1411                                         submask->points.append(new_point);
1412                                         *new_point = *point;
1413                                         if(current == (MaskAuto*)mask_autos->default_auto)
1414                                                 current = (MaskAuto*)mask_autos->first;
1415                                         else
1416                                                 current = (MaskAuto*)NEXT;
1417                                 }
1419 //printf("CWindowCanvas::do_mask 2\n");
1420 // Create a second point if none existed before
1421                                 if(mask->points.total < 2)
1422                                 {
1423                                         for(MaskAuto *current = (MaskAuto*)mask_autos->default_auto;
1424                                                 current; )
1425                                         {
1426                                                 SubMask *submask = current->get_submask(mwindow->edl->session->cwindow_mask);
1427                                                 MaskPoint *new_point = new MaskPoint;
1428                                                 submask->points.append(new_point);
1429                                                 *new_point = *point;
1430                                                 if(current == (MaskAuto*)mask_autos->default_auto)
1431                                                         current = (MaskAuto*)mask_autos->first;
1432                                                 else
1433                                                         current = (MaskAuto*)NEXT;
1434                                         }
1435                                 }
1436                                 gui->affected_point = mask->points.total - 1;
1437 //printf("CWindowCanvas::do_mask 3 %d\n", mask->points.total);
1438                         }
1442                         gui->current_operation = mwindow->edl->session->cwindow_operation;
1443 // Delete the template
1444                         delete point;
1445 //printf("CWindowGUI::do_mask 1\n");
1446                         mwindow->undo->update_undo(_("mask point"), LOAD_AUTOMATION);
1447 //printf("CWindowGUI::do_mask 10\n");
1449                 }
1451                 result = 1;
1452                 rerender = 1;
1453                 redraw = 1;
1454         }
1456         if(button_press && result)
1457         {
1458                 MaskAuto *keyframe = (MaskAuto*)gui->affected_keyframe;
1459                 SubMask *mask = keyframe->get_submask(mwindow->edl->session->cwindow_mask);
1460                 MaskPoint *point = mask->points.values[gui->affected_point];
1461                 gui->center_x = point->x;
1462                 gui->center_y = point->y;
1463                 gui->control_in_x = point->control_x1;
1464                 gui->control_in_y = point->control_y1;
1465                 gui->control_out_x = point->control_x2;
1466                 gui->control_out_y = point->control_y2;
1467         }
1469 //printf("CWindowCanvas::do_mask 8\n");
1470         if(cursor_motion)
1471         {
1472                 MaskAuto *keyframe = (MaskAuto*)gui->affected_keyframe;
1473                 SubMask *mask = keyframe->get_submask(mwindow->edl->session->cwindow_mask);
1474                 if(gui->affected_point < mask->points.total)
1475                 {
1476                         MaskPoint *point = mask->points.values[gui->affected_point];
1477 //                      float cursor_x = get_cursor_x();
1478 //                      float cursor_y = get_cursor_y();
1479 //                      canvas_to_output(mwindow->edl, 0, cursor_x, cursor_y);
1480                         float cursor_x = mask_cursor_x;
1481                         float cursor_y = mask_cursor_y;
1482 //printf("CWindowCanvas::do_mask 9 %d %d\n", mask->points.total, gui->affected_point);
1484                         float last_x = point->x;
1485                         float last_y = point->y;
1486                         float last_control_x1 = point->control_x1;
1487                         float last_control_y1 = point->control_y1;
1488                         float last_control_x2 = point->control_x2;
1489                         float last_control_y2 = point->control_y2;
1492                         switch(gui->current_operation)
1493                         {
1494                                 case CWINDOW_MASK:
1495                                         point->x = cursor_x - gui->x_origin + gui->center_x;
1496                                         point->y = cursor_y - gui->y_origin + gui->center_y;
1497                                         break;
1499                                 case CWINDOW_MASK_CONTROL_IN:
1500                                         point->control_x1 = cursor_x - gui->x_origin + gui->control_in_x;
1501                                         point->control_y1 = cursor_y - gui->y_origin + gui->control_in_y;
1502                                         break;
1504                                 case CWINDOW_MASK_CONTROL_OUT:
1505                                         point->control_x2 = cursor_x - gui->x_origin + gui->control_out_x;
1506                                         point->control_y2 = cursor_y - gui->y_origin + gui->control_out_y;
1507                                         break;
1509                                 case CWINDOW_MASK_TRANSLATE:
1510                                         for(int i = 0; i < mask->points.total; i++)
1511                                         {
1512                                                 mask->points.values[i]->x += cursor_x - gui->x_origin;
1513                                                 mask->points.values[i]->y += cursor_y - gui->y_origin;
1514                                         }
1515                                         gui->x_origin = cursor_x;
1516                                         gui->y_origin = cursor_y;
1517                                         break;
1518                         }
1521                         if( !EQUIV(last_x, point->x) ||
1522                                 !EQUIV(last_y, point->y) ||
1523                                 !EQUIV(last_control_x1, point->control_x1) ||
1524                                 !EQUIV(last_control_y1, point->control_y1) ||
1525                                 !EQUIV(last_control_x2, point->control_x2) ||
1526                                 !EQUIV(last_control_y2, point->control_y2))
1527                         {
1528                                 rerender = 1;
1529                                 redraw = 1;
1530                         }
1531                 }
1532                 result = 1;
1533         }
1534 //printf("CWindowCanvas::do_mask 2 %d %d %d\n", result, rerender, redraw);
1536         points.remove_all_objects();
1537 //printf("CWindowCanvas::do_mask 20\n");
1538         return result;
1542 int CWindowCanvas::do_eyedrop(int &rerender, int button_press)
1544         int result = 0;
1545         float cursor_x = get_cursor_x();
1546         float cursor_y = get_cursor_y();
1549         if(button_press)
1550         {
1551                 gui->current_operation = CWINDOW_EYEDROP;
1552         }
1554         if(gui->current_operation == CWINDOW_EYEDROP)
1555         {
1556                 canvas_to_output(mwindow->edl, 0, cursor_x, cursor_y);
1558 // Get color out of frame.
1559 // Doesn't work during playback because that bypasses the refresh frame.
1560                 if(refresh_frame)
1561                 {
1562                         CLAMP(cursor_x, 0, refresh_frame->get_w() - 1);
1563                         CLAMP(cursor_y, 0, refresh_frame->get_h() - 1);
1565 // Decompression coefficients straight out of jpeglib
1566 #define V_TO_R    1.40200
1567 #define V_TO_G    -0.71414
1569 #define U_TO_G    -0.34414
1570 #define U_TO_B    1.77200
1572 #define GET_COLOR(type, components, max, do_yuv) \
1573 { \
1574         type *row = (type*)(refresh_frame->get_rows()[(int)cursor_y]) + \
1575                 (int)cursor_x * components; \
1576         float red = (float)*row++ / max; \
1577         float green = (float)*row++ / max; \
1578         float blue = (float)*row++ / max; \
1579         if(do_yuv) \
1580         { \
1581                 mwindow->edl->local_session->red = red + V_TO_R * (blue - 0.5); \
1582                 mwindow->edl->local_session->green = red + U_TO_G * (green - 0.5) + V_TO_G * (blue - 0.5); \
1583                 mwindow->edl->local_session->blue = red + U_TO_B * (green - 0.5); \
1584         } \
1585         else \
1586         { \
1587                 mwindow->edl->local_session->red = red; \
1588                 mwindow->edl->local_session->green = green; \
1589                 mwindow->edl->local_session->blue = blue; \
1590         } \
1593                         switch(refresh_frame->get_color_model())
1594                         {
1595                                 case BC_YUV888:
1596                                         GET_COLOR(unsigned char, 3, 0xff, 1);
1597                                         break;
1598                                 case BC_YUVA8888:
1599                                         GET_COLOR(unsigned char, 4, 0xff, 1);
1600                                         break;
1601                                 case BC_YUV161616:
1602                                         GET_COLOR(uint16_t, 3, 0xffff, 1);
1603                                         break;
1604                                 case BC_YUVA16161616:
1605                                         GET_COLOR(uint16_t, 4, 0xffff, 1);
1606                                         break;
1607                                 case BC_RGB888:
1608                                         GET_COLOR(unsigned char, 3, 0xff, 0);
1609                                         break;
1610                                 case BC_RGBA8888:
1611                                         GET_COLOR(unsigned char, 4, 0xff, 0);
1612                                         break;
1613                                 case BC_RGB_FLOAT:
1614                                         GET_COLOR(float, 3, 1.0, 0);
1615                                         break;
1616                                 case BC_RGBA_FLOAT:
1617                                         GET_COLOR(float, 4, 1.0, 0);
1618                                         break;
1619                         }
1620                 }
1621                 else
1622                 {
1623                         mwindow->edl->local_session->red = 0;
1624                         mwindow->edl->local_session->green = 0;
1625                         mwindow->edl->local_session->blue = 0;
1626                 }
1629                 gui->update_tool();             
1633                 result = 1;
1634 // Can't rerender since the color value is from the output of any effect it
1635 // goes into.
1636 //              rerender = 1;
1637         }
1639         return result;
1642 void CWindowCanvas::draw_overlays()
1644         if(mwindow->edl->session->safe_regions)
1645         {
1646                 draw_safe_regions();
1647         }
1649         if(mwindow->edl->session->cwindow_scrollbars)
1650         {
1651 // Always draw output rectangle
1652                 float x1, y1, x2, y2;
1653                 x1 = 0;
1654                 x2 = mwindow->edl->session->output_w;
1655                 y1 = 0;
1656                 y2 = mwindow->edl->session->output_h;
1657                 output_to_canvas(mwindow->edl, 0, x1, y1);
1658                 output_to_canvas(mwindow->edl, 0, x2, y2);
1660                 get_canvas()->set_inverse();
1661                 get_canvas()->set_color(WHITE);
1663                 get_canvas()->draw_rectangle((int)x1, 
1664                                 (int)y1, 
1665                                 (int)(x2 - x1), 
1666                                 (int)(y2 - y1));
1668                 get_canvas()->set_opaque();
1669         }
1671         if(mwindow->session->ccanvas_highlighted)
1672         {
1673                 get_canvas()->set_color(WHITE);
1674                 get_canvas()->set_inverse();
1675                 get_canvas()->draw_rectangle(0, 0, get_canvas()->get_w(), get_canvas()->get_h());
1676                 get_canvas()->draw_rectangle(1, 1, get_canvas()->get_w() - 2, get_canvas()->get_h() - 2);
1677                 get_canvas()->set_opaque();
1678         }
1680         int temp1 = 0, temp2 = 0;
1681 //printf("CWindowCanvas::draw_overlays 1 %d\n", mwindow->edl->session->cwindow_operation);
1682         switch(mwindow->edl->session->cwindow_operation)
1683         {
1684                 case CWINDOW_CAMERA:
1685                         draw_bezier(1);
1686                         break;
1688                 case CWINDOW_PROJECTOR:
1689                         draw_bezier(0);
1690                         break;
1692                 case CWINDOW_CROP:
1693                         draw_crop();
1694                         break;
1696                 case CWINDOW_MASK:
1697                         do_mask(temp1, temp2, 0, 0, 1);
1698                         break;
1699         }
1702 void CWindowCanvas::draw_safe_regions()
1704         float action_x1, action_x2, action_y1, action_y2;
1705         float title_x1, title_x2, title_y1, title_y2;
1707         action_x1 = mwindow->edl->session->output_w / 2 - mwindow->edl->session->output_w / 2 * 0.9;
1708         action_x2 = mwindow->edl->session->output_w / 2 + mwindow->edl->session->output_w / 2 * 0.9;
1709         action_y1 = mwindow->edl->session->output_h / 2 - mwindow->edl->session->output_h / 2 * 0.9;
1710         action_y2 = mwindow->edl->session->output_h / 2 + mwindow->edl->session->output_h / 2 * 0.9;
1711         title_x1 = mwindow->edl->session->output_w / 2 - mwindow->edl->session->output_w / 2 * 0.8;
1712         title_x2 = mwindow->edl->session->output_w / 2 + mwindow->edl->session->output_w / 2 * 0.8;
1713         title_y1 = mwindow->edl->session->output_h / 2 - mwindow->edl->session->output_h / 2 * 0.8;
1714         title_y2 = mwindow->edl->session->output_h / 2 + mwindow->edl->session->output_h / 2 * 0.8;
1716         output_to_canvas(mwindow->edl, 0, action_x1, action_y1);
1717         output_to_canvas(mwindow->edl, 0, action_x2, action_y2);
1718         output_to_canvas(mwindow->edl, 0, title_x1, title_y1);
1719         output_to_canvas(mwindow->edl, 0, title_x2, title_y2);
1721         get_canvas()->set_inverse();
1722         get_canvas()->set_color(WHITE);
1724         get_canvas()->draw_rectangle((int)action_x1, 
1725                         (int)action_y1, 
1726                         (int)(action_x2 - action_x1), 
1727                         (int)(action_y2 - action_y1));
1728         get_canvas()->draw_rectangle((int)title_x1, 
1729                         (int)title_y1, 
1730                         (int)(title_x2 - title_x1), 
1731                         (int)(title_y2 - title_y1));
1733         get_canvas()->set_opaque();
1736 void CWindowCanvas::reset_keyframe(int do_camera)
1738         FloatAuto *x_keyframe = 0;
1739         FloatAuto *y_keyframe = 0;
1740         FloatAuto *z_keyframe = 0;
1741         Track *affected_track = 0;
1743         affected_track = gui->cwindow->calculate_affected_track();
1745         if(affected_track)
1746         {
1747                 gui->cwindow->calculate_affected_autos(&x_keyframe,
1748                         &y_keyframe,
1749                         &z_keyframe,
1750                         affected_track,
1751                         do_camera,
1752                         1,
1753                         1,
1754                         1);
1756                 x_keyframe->value = 0;
1757                 y_keyframe->value = 0;
1758                 z_keyframe->value = 1;
1760                 mwindow->sync_parameters(CHANGE_PARAMS);
1761                 gui->update_tool();
1762         }
1765 void CWindowCanvas::reset_camera()
1767         reset_keyframe(1);
1770 void CWindowCanvas::reset_projector()
1772         reset_keyframe(0);
1775 int CWindowCanvas::test_crop(int button_press, int &redraw)
1777         int result = 0;
1778         int handle_selected = -1;
1779         float x1 = mwindow->edl->session->crop_x1;
1780         float y1 = mwindow->edl->session->crop_y1;
1781         float x2 = mwindow->edl->session->crop_x2;
1782         float y2 = mwindow->edl->session->crop_y2;
1783         float cursor_x = get_cursor_x();
1784         float cursor_y = get_cursor_y();
1785         float canvas_x1 = x1;
1786         float canvas_y1 = y1;
1787         float canvas_x2 = x2;
1788         float canvas_y2 = y2;
1789         float canvas_cursor_x = cursor_x;
1790         float canvas_cursor_y = cursor_y;
1792         canvas_to_output(mwindow->edl, 0, cursor_x, cursor_y);
1793 // Use screen normalized coordinates for hot spot tests.
1794         output_to_canvas(mwindow->edl, 0, canvas_x1, canvas_y1);
1795         output_to_canvas(mwindow->edl, 0, canvas_x2, canvas_y2);
1798         if(gui->current_operation == CWINDOW_CROP)
1799         {
1800                 handle_selected = gui->crop_handle;
1801         }
1802         else
1803         if(canvas_cursor_x >= canvas_x1 && canvas_cursor_x < canvas_x1 + CROPHANDLE_W &&
1804                 canvas_cursor_y >= canvas_y1 && canvas_cursor_y < canvas_y1 + CROPHANDLE_H)
1805         {
1806                 handle_selected = 0;
1807                 gui->crop_origin_x = x1;
1808                 gui->crop_origin_y = y1;
1809         }
1810         else
1811         if(canvas_cursor_x >= canvas_x2 - CROPHANDLE_W && canvas_cursor_x < canvas_x2 &&
1812                 canvas_cursor_y >= canvas_y1 && canvas_cursor_y < canvas_y1 + CROPHANDLE_H)
1813         {
1814                 handle_selected = 1;
1815                 gui->crop_origin_x = x2;
1816                 gui->crop_origin_y = y1;
1817         }
1818         else
1819         if(canvas_cursor_x >= canvas_x1 && canvas_cursor_x < canvas_x1 + CROPHANDLE_W &&
1820                 canvas_cursor_y >= canvas_y2 - CROPHANDLE_H && canvas_cursor_y < canvas_y2)
1821         {
1822                 handle_selected = 2;
1823                 gui->crop_origin_x = x1;
1824                 gui->crop_origin_y = y2;
1825         }
1826         else
1827         if(canvas_cursor_x >= canvas_x2 - CROPHANDLE_W && canvas_cursor_x < canvas_x2 &&
1828                 canvas_cursor_y >= canvas_y2 - CROPHANDLE_H && canvas_cursor_y < canvas_y2)
1829         {
1830                 handle_selected = 3;
1831                 gui->crop_origin_x = x2;
1832                 gui->crop_origin_y = y2;
1833         }
1834         else
1835 // Start new box
1836         {
1837                 gui->crop_origin_x = cursor_x;
1838                 gui->crop_origin_y = cursor_y;
1839         }
1841 // printf("test crop %d %d\n", 
1842 //      gui->current_operation,
1843 //      handle_selected);
1845 // Start dragging.
1846         if(button_press)
1847         {
1848                 if(gui->alt_down())
1849                 {
1850                         gui->crop_translate = 1;
1851                         gui->crop_origin_x1 = x1;
1852                         gui->crop_origin_y1 = y1;
1853                         gui->crop_origin_x2 = x2;
1854                         gui->crop_origin_y2 = y2;
1855                 }
1856                 else
1857                         gui->crop_translate = 0;
1859                 gui->current_operation = CWINDOW_CROP;
1860                 gui->crop_handle = handle_selected;
1861                 gui->x_origin = cursor_x;
1862                 gui->y_origin = cursor_y;
1863                 result = 1;
1865                 if(handle_selected < 0 && !gui->crop_translate) 
1866                 {
1867                         x2 = x1 = cursor_x;
1868                         y2 = y1 = cursor_y;
1869                         mwindow->edl->session->crop_x1 = (int)x1;
1870                         mwindow->edl->session->crop_y1 = (int)y1;
1871                         mwindow->edl->session->crop_x2 = (int)x2;
1872                         mwindow->edl->session->crop_y2 = (int)y2;
1873                         redraw = 1;
1874                 }
1875         }
1876     else
1877 // Translate all 4 points
1878         if(gui->current_operation == CWINDOW_CROP && gui->crop_translate)
1879         {
1880                 x1 = cursor_x - gui->x_origin + gui->crop_origin_x1;
1881                 y1 = cursor_y - gui->y_origin + gui->crop_origin_y1;
1882                 x2 = cursor_x - gui->x_origin + gui->crop_origin_x2;
1883                 y2 = cursor_y - gui->y_origin + gui->crop_origin_y2;
1885                 mwindow->edl->session->crop_x1 = (int)x1;
1886                 mwindow->edl->session->crop_y1 = (int)y1;
1887                 mwindow->edl->session->crop_x2 = (int)x2;
1888                 mwindow->edl->session->crop_y2 = (int)y2;
1889                 result = 1;
1890                 redraw = 1;
1891         }
1892         else
1893 // Update dragging
1894         if(gui->current_operation == CWINDOW_CROP)
1895         {
1896                 switch(gui->crop_handle)
1897                 {
1898                         case -1:
1899                                 x1 = gui->crop_origin_x;
1900                                 y1 = gui->crop_origin_y;
1901                                 x2 = gui->crop_origin_x;
1902                                 y2 = gui->crop_origin_y;
1903                                 if(cursor_x < gui->x_origin)
1904                                 {
1905                                         if(cursor_y < gui->y_origin)
1906                                         {
1907                                                 x1 = cursor_x;
1908                                                 y1 = cursor_y;
1909                                         }
1910                                         else
1911                                         if(cursor_y >= gui->y_origin)
1912                                         {
1913                                                 x1 = cursor_x;
1914                                                 y2 = cursor_y;
1915                                         }
1916                                 }
1917                                 else
1918                                 if(cursor_x  >= gui->x_origin)
1919                                 {
1920                                         if(cursor_y < gui->y_origin)
1921                                         {
1922                                                 y1 = cursor_y;
1923                                                 x2 = cursor_x;
1924                                         }
1925                                         else
1926                                         if(cursor_y >= gui->y_origin)
1927                                         {
1928                                                 x2 = cursor_x;
1929                                                 y2 = cursor_y;
1930                                         }
1931                                 }
1933 // printf("test crop %d %d %d %d\n", 
1934 //      mwindow->edl->session->crop_x1,
1935 //      mwindow->edl->session->crop_y1,
1936 //      mwindow->edl->session->crop_x2,
1937 //      mwindow->edl->session->crop_y2);
1938                                 break;
1939                         case 0:
1940                                 x1 = cursor_x - gui->x_origin + gui->crop_origin_x;
1941                                 y1 = cursor_y - gui->y_origin + gui->crop_origin_y;
1942                                 break;
1943                         case 1:
1944                                 x2 = cursor_x - gui->x_origin + gui->crop_origin_x;
1945                                 y1 = cursor_y - gui->y_origin + gui->crop_origin_y;
1946                                 break;
1947                         case 2:
1948                                 x1 = cursor_x - gui->x_origin + gui->crop_origin_x;
1949                                 y2 = cursor_y - gui->y_origin + gui->crop_origin_y;
1950                                 break;
1951                         case 3:
1952                                 x2 = cursor_x - gui->x_origin + gui->crop_origin_x;
1953                                 y2 = cursor_y - gui->y_origin + gui->crop_origin_y;
1954                                 break;
1955                 }
1957                 if(!EQUIV(mwindow->edl->session->crop_x1, x1) ||
1958                         !EQUIV(mwindow->edl->session->crop_x2, x2) ||
1959                         !EQUIV(mwindow->edl->session->crop_y1, y1) ||
1960                         !EQUIV(mwindow->edl->session->crop_y2, y2))
1961                 {
1962                         if (x1 > x2) 
1963                         {
1964                                 float tmp = x1;
1965                                 x1 = x2;
1966                                 x2 = tmp;
1967                                 switch (gui->crop_handle) 
1968                                 {
1969                                         case 0: gui->crop_handle = 1; break;
1970                                         case 1: gui->crop_handle = 0; break;
1971                                         case 2: gui->crop_handle = 3; break;
1972                                         case 3: gui->crop_handle = 2; break;
1973                                         default: break;
1974                                 }
1976                         }
1977                         if (y1 > y2) 
1978                         {
1979                                 float tmp = y1;
1980                                 y1 = y2;
1981                                 y2 = tmp;
1982                                 switch (gui->crop_handle) 
1983                                 {
1984                                         case 0: gui->crop_handle = 2; break;
1985                                         case 1: gui->crop_handle = 3; break;
1986                                         case 2: gui->crop_handle = 0; break;
1987                                         case 3: gui->crop_handle = 1; break;
1988                                         default: break;
1989                                 }
1990                         }
1992                         mwindow->edl->session->crop_x1 = (int)x1;
1993                         mwindow->edl->session->crop_y1 = (int)y1;
1994                         mwindow->edl->session->crop_x2 = (int)x2;
1995                         mwindow->edl->session->crop_y2 = (int)y2;
1996                         result = 1;
1997                         redraw = 1;
1998                 }
1999         }
2000         else
2001 // Update cursor font
2002         if(handle_selected >= 0)
2003         {
2004                 switch(handle_selected)
2005                 {
2006                         case 0:
2007                                 set_cursor(UPLEFT_RESIZE);
2008                                 break;
2009                         case 1:
2010                                 set_cursor(UPRIGHT_RESIZE);
2011                                 break;
2012                         case 2:
2013                                 set_cursor(DOWNLEFT_RESIZE);
2014                                 break;
2015                         case 3:
2016                                 set_cursor(DOWNRIGHT_RESIZE);
2017                                 break;
2018                 }
2019                 result = 1;
2020         }
2021         else
2022         {
2023                 set_cursor(ARROW_CURSOR);
2024         }
2025 #define CLAMP(x, y, z) ((x) = ((x) < (y) ? (y) : ((x) > (z) ? (z) : (x))))
2026         
2027         if(redraw)
2028         {
2029                 CLAMP(mwindow->edl->session->crop_x1, 0, mwindow->edl->session->output_w);
2030                 CLAMP(mwindow->edl->session->crop_x2, 0, mwindow->edl->session->output_w);
2031                 CLAMP(mwindow->edl->session->crop_y1, 0, mwindow->edl->session->output_h);
2032                 CLAMP(mwindow->edl->session->crop_y2, 0, mwindow->edl->session->output_h);
2033 // printf("CWindowCanvas::test_crop %d %d %d %d\n", 
2034 //      mwindow->edl->session->crop_x2,
2035 //      mwindow->edl->session->crop_y2,
2036 //      mwindow->edl->calculate_output_w(0), 
2037 //      mwindow->edl->calculate_output_h(0));
2038         }
2039         return result;
2043 void CWindowCanvas::draw_crop()
2045         get_canvas()->set_inverse();
2046         get_canvas()->set_color(WHITE);
2048         float x1 = mwindow->edl->session->crop_x1;
2049         float y1 = mwindow->edl->session->crop_y1;
2050         float x2 = mwindow->edl->session->crop_x2;
2051         float y2 = mwindow->edl->session->crop_y2;
2053         output_to_canvas(mwindow->edl, 0, x1, y1);
2054         output_to_canvas(mwindow->edl, 0, x2, y2);
2056         if(x2 - x1 && y2 - y1)
2057                 get_canvas()->draw_rectangle((int)x1, 
2058                         (int)y1, 
2059                         (int)(x2 - x1), 
2060                         (int)(y2 - y1));
2062         draw_crophandle((int)x1, (int)y1);
2063         draw_crophandle((int)x2 - CROPHANDLE_W, (int)y1);
2064         draw_crophandle((int)x1, (int)y2 - CROPHANDLE_H);
2065         draw_crophandle((int)x2 - CROPHANDLE_W, (int)y2 - CROPHANDLE_H);
2066         get_canvas()->set_opaque();
2076 void CWindowCanvas::draw_bezier(int do_camera)
2078         Track *track = gui->cwindow->calculate_affected_track();
2079         
2080         if(!track) return;
2082         float center_x;
2083         float center_y;
2084         float center_z;
2085         int64_t position = track->to_units(
2086                 mwindow->edl->local_session->get_selectionstart(1), 
2087                 0);
2089         track->automation->get_projector(&center_x, 
2090                 &center_y, 
2091                 &center_z, 
2092                 position,
2093                 PLAY_FORWARD);
2095 //      center_x += track->track_w / 2;
2096 //      center_y += track->track_h / 2;
2097         center_x += mwindow->edl->session->output_w / 2;
2098         center_y += mwindow->edl->session->output_h / 2;
2099         float track_x1 = center_x - track->track_w / 2 * center_z;
2100         float track_y1 = center_y - track->track_h / 2 * center_z;
2101         float track_x2 = track_x1 + track->track_w * center_z;
2102         float track_y2 = track_y1 + track->track_h * center_z;
2104         output_to_canvas(mwindow->edl, 0, track_x1, track_y1);
2105         output_to_canvas(mwindow->edl, 0, track_x2, track_y2);
2107 #define DRAW_PROJECTION(offset) \
2108         get_canvas()->draw_rectangle((int)track_x1 + offset, \
2109                 (int)track_y1 + offset, \
2110                 (int)(track_x2 - track_x1), \
2111                 (int)(track_y2 - track_y1)); \
2112         get_canvas()->draw_line((int)track_x1 + offset,  \
2113                 (int)track_y1 + offset, \
2114                 (int)track_x2 + offset, \
2115                 (int)track_y2 + offset); \
2116         get_canvas()->draw_line((int)track_x2 + offset,  \
2117                 (int)track_y1 + offset, \
2118                 (int)track_x1 + offset, \
2119                 (int)track_y2 + offset); \
2122 // Drop shadow
2123         get_canvas()->set_color(BLACK);
2124         DRAW_PROJECTION(1);
2126 //      canvas->set_inverse();
2127         if(do_camera)
2128                 get_canvas()->set_color(GREEN);
2129         else
2130                 get_canvas()->set_color(RED);
2132         DRAW_PROJECTION(0);
2133 //      canvas->set_opaque();
2139 int CWindowCanvas::test_bezier(int button_press, 
2140         int &redraw, 
2141         int &redraw_canvas,
2142         int &rerender,
2143         int do_camera)
2145         int result = 0;
2147 // Processing drag operation.
2148 // Create keyframe during first cursor motion.
2149         if(!button_press)
2150         {
2152                 float cursor_x = get_cursor_x();
2153                 float cursor_y = get_cursor_y();
2154                 canvas_to_output(mwindow->edl, 0, cursor_x, cursor_y);
2156                 if(gui->current_operation == CWINDOW_CAMERA ||
2157                         gui->current_operation == CWINDOW_PROJECTOR)
2158                 {
2159                         if(!gui->ctrl_down() && gui->shift_down() && !gui->translating_zoom)
2160                         {
2161                                 gui->translating_zoom = 1;
2162                                 gui->reset_affected();
2163                         }
2164                         else
2165                         if(!gui->ctrl_down() && !gui->shift_down() && gui->translating_zoom)
2166                         {
2167                                 gui->translating_zoom = 0;
2168                                 gui->reset_affected();
2169                         }
2171 // Get target keyframe
2172                         float last_center_x;
2173                         float last_center_y;
2174                         float last_center_z;
2177                         if(!gui->affected_x && !gui->affected_y && !gui->affected_z)
2178                         {
2179                                 FloatAutos *affected_x_autos;
2180                                 FloatAutos *affected_y_autos;
2181                                 FloatAutos *affected_z_autos;
2182                                 if(!gui->affected_track) return 0;
2183                                 if(mwindow->edl->session->cwindow_operation == CWINDOW_CAMERA)
2184                                 {
2185                                         affected_x_autos = (FloatAutos*)gui->affected_track->automation->autos[AUTOMATION_CAMERA_X];
2186                                         affected_y_autos = (FloatAutos*)gui->affected_track->automation->autos[AUTOMATION_CAMERA_Y];
2187                                         affected_z_autos = (FloatAutos*)gui->affected_track->automation->autos[AUTOMATION_CAMERA_Z];
2188                                 }
2189                                 else
2190                                 {
2191                                         affected_x_autos = (FloatAutos*)gui->affected_track->automation->autos[AUTOMATION_PROJECTOR_X];
2192                                         affected_y_autos = (FloatAutos*)gui->affected_track->automation->autos[AUTOMATION_PROJECTOR_Y];
2193                                         affected_z_autos = (FloatAutos*)gui->affected_track->automation->autos[AUTOMATION_PROJECTOR_Z];
2194                                 }
2197                                 if(gui->translating_zoom)
2198                                 {
2199                                         gui->affected_z = 
2200                                                 (FloatAuto*)gui->cwindow->calculate_affected_auto(
2201                                                         affected_z_autos, 1);
2202                                 }
2203                                 else
2204                                 {
2205                                         gui->affected_x = 
2206                                                 (FloatAuto*)gui->cwindow->calculate_affected_auto(
2207                                                         affected_x_autos, 1);
2208                                         gui->affected_y = 
2209                                                 (FloatAuto*)gui->cwindow->calculate_affected_auto(
2210                                                         affected_y_autos, 1);
2211                                 }
2213                                 calculate_origin();
2215                                 if(gui->translating_zoom)
2216                                 {
2217                                         gui->center_z = gui->affected_z->value;
2218                                 }
2219                                 else
2220                                 {
2221                                         gui->center_x = gui->affected_x->value;
2222                                         gui->center_y = gui->affected_y->value;
2223                                 }
2225                                 rerender = 1;
2226                                 redraw = 1;
2227                         }
2230                         if(gui->translating_zoom)
2231                         {
2232                                 last_center_z = gui->affected_z->value;
2233                         }
2234                         else
2235                         {
2236                                 last_center_x = gui->affected_x->value;
2237                                 last_center_y = gui->affected_y->value;
2238                         }
2240                         if(gui->translating_zoom)
2241                         {
2242                                 gui->affected_z->value = gui->center_z + 
2243                                         (cursor_y - gui->y_origin) / 128;
2244                                 if(!EQUIV(last_center_z, gui->affected_z->value))
2245                                 {
2246                                         rerender = 1;
2247                                         redraw = 1;
2248                                         redraw_canvas = 1;
2249                                 }
2250                         }
2251                         else
2252                         {
2253                                 gui->affected_x->value = gui->center_x + cursor_x - gui->x_origin;
2254                                 gui->affected_y->value = gui->center_y + cursor_y - gui->y_origin;
2255                                 if(!EQUIV(last_center_x,  gui->affected_x->value) ||
2256                                         !EQUIV(last_center_y, gui->affected_y->value))
2257                                 {
2258                                         rerender = 1;
2259                                         redraw = 1;
2260                                         redraw_canvas = 1;
2261                                 }
2262                         }
2263                 }
2265                 result = 1;
2266         }
2267         else
2268 // Begin drag operation.  Don't create keyframe here.
2269         {
2270 // Get affected track off of the first recordable video track.
2271 // Calculating based on the alpha channel would require recording what layer
2272 // each output pixel belongs to as they're rendered and stacked.  Forget it.
2273                 gui->affected_track = gui->cwindow->calculate_affected_track();
2274                 gui->reset_affected();
2276                 if(gui->affected_track)
2277                 {
2278                         gui->current_operation = 
2279                                 mwindow->edl->session->cwindow_operation;
2280                         result = 1;
2281                 }
2282         }
2283         
2284         return result;
2287 int CWindowCanvas::test_zoom(int &redraw)
2289         int result = 0;
2290         float zoom = get_zoom();
2291         float x;
2292         float y;
2294         if(!mwindow->edl->session->cwindow_scrollbars)
2295         {
2296                 mwindow->edl->session->cwindow_scrollbars = 1;
2297                 zoom = 1.0;
2298                 x = mwindow->edl->session->output_w / 2;
2299                 y = mwindow->edl->session->output_h / 2;
2300         }
2301         else
2302         {
2303                 x = get_cursor_x();
2304                 y = get_cursor_y();
2305                 canvas_to_output(mwindow->edl, 
2306                                 0, 
2307                                 x, 
2308                                 y);
2310 //printf("CWindowCanvas::test_zoom 1 %f %f\n", x, y);
2312 // Find current zoom in table
2313                 int current_index = 0;
2314                 for(current_index = 0 ; current_index < total_zooms; current_index++)
2315                         if(EQUIV(my_zoom_table[current_index], zoom)) break;
2318 // Zoom out
2319                 if(get_buttonpress() == 5 ||
2320                         gui->ctrl_down() || 
2321                         gui->shift_down())
2322                 {
2323                         current_index--;
2324                 }
2325                 else
2326 // Zoom in
2327                 {
2328                         current_index++;
2329                 }
2330                 CLAMP(current_index, 0, total_zooms - 1);
2331                 zoom = my_zoom_table[current_index];
2332         }
2334         x = x - w / zoom / 2;
2335         y = y - h / zoom / 2;
2338         int x_i = (int)x;
2339         int y_i = (int)y;
2340 //      check_boundaries(mwindow->edl, x_i, y_i, zoom);
2342 //printf("CWindowCanvas::test_zoom 2 %d %d\n", x_i, y_i);
2344         update_zoom(x_i, 
2345                         y_i, 
2346                         zoom);
2347         reposition_window(mwindow->edl, 
2348                         mwindow->theme->ccanvas_x,
2349                         mwindow->theme->ccanvas_y,
2350                         mwindow->theme->ccanvas_w,
2351                         mwindow->theme->ccanvas_h);
2352         redraw = 1;
2353         result = 1;
2355         
2356         gui->zoom_panel->update(zoom);
2357         
2358         return result;
2362 void CWindowCanvas::calculate_origin()
2364         gui->x_origin = get_cursor_x();
2365         gui->y_origin = get_cursor_y();
2366 //printf("CWindowCanvas::calculate_origin 1 %f %f\n", gui->x_origin, gui->y_origin);
2367         canvas_to_output(mwindow->edl, 0, gui->x_origin, gui->y_origin);
2368 //printf("CWindowCanvas::calculate_origin 2 %f %f\n", gui->x_origin, gui->y_origin);
2372 int CWindowCanvas::cursor_leave_event()
2374         set_cursor(ARROW_CURSOR);
2375         return 1;
2378 int CWindowCanvas::cursor_enter_event()
2380         int redraw = 0;
2381         switch(mwindow->edl->session->cwindow_operation)
2382         {
2383                 case CWINDOW_CAMERA:
2384                 case CWINDOW_PROJECTOR:
2385                         set_cursor(MOVE_CURSOR);
2386                         break;
2387                 case CWINDOW_ZOOM:
2388                         set_cursor(MOVE_CURSOR);
2389                         break;
2390                 case CWINDOW_CROP:
2391                         test_crop(0, redraw);
2392                         break;
2393                 case CWINDOW_PROTECT:
2394                         set_cursor(ARROW_CURSOR);
2395                         break;
2396                 case CWINDOW_MASK:
2397                         set_cursor(CROSS_CURSOR);
2398                         break;
2399                 case CWINDOW_EYEDROP:
2400                         set_cursor(CROSS_CURSOR);
2401                         break;
2402         }
2403         return 1;
2406 int CWindowCanvas::cursor_motion_event()
2408         int redraw = 0, result = 0, rerender = 0, redraw_canvas = 0;
2411         switch(gui->current_operation)
2412         {
2413                 case CWINDOW_SCROLL:
2414                 {
2415                         float zoom = get_zoom();
2416                         float cursor_x = get_cursor_x();
2417                         float cursor_y = get_cursor_y();
2419                         float zoom_x, zoom_y, conformed_w, conformed_h;
2420                         get_zooms(mwindow->edl, 0, zoom_x, zoom_y, conformed_w, conformed_h);
2421                         cursor_x = (float)cursor_x / zoom_x + gui->x_offset;
2422                         cursor_y = (float)cursor_y / zoom_y + gui->y_offset;
2426                         int x = (int)(gui->x_origin - cursor_x + gui->x_offset);
2427                         int y = (int)(gui->y_origin - cursor_y + gui->y_offset);
2429                         update_zoom(x, 
2430                                 y, 
2431                                 zoom);
2432                         update_scrollbars();
2433                         redraw = 1;
2434                         result = 1;
2435                         break;
2436                 }
2438                 case CWINDOW_CAMERA:
2439                         result = test_bezier(0, redraw, redraw_canvas, rerender, 1);
2440                         break;
2442                 case CWINDOW_PROJECTOR:
2443                         result = test_bezier(0, redraw, redraw_canvas, rerender, 0);
2444                         break;
2447                 case CWINDOW_CROP:
2448 //printf("CWindowCanvas::cursor_motion_event 1 %d %d\n", x, y);
2449                         result = test_crop(0, redraw);
2450                         break;
2452                 case CWINDOW_MASK:
2453                 case CWINDOW_MASK_CONTROL_IN:
2454                 case CWINDOW_MASK_CONTROL_OUT:
2455                 case CWINDOW_MASK_TRANSLATE:
2456                         result = do_mask(redraw, 
2457                                 rerender, 
2458                                 0, 
2459                                 1,
2460                                 0);
2461                         break;
2463                 case CWINDOW_EYEDROP:
2464                         result = do_eyedrop(rerender, 0);
2465                         break;
2467         }
2471         if(!result)
2472         {
2473                 switch(mwindow->edl->session->cwindow_operation)
2474                 {
2475                         case CWINDOW_CROP:
2476                                 result = test_crop(0, redraw);
2477                                 break;
2478                 }
2479         }
2482 // If the window is never unlocked before calling send_command the
2483 // display shouldn't get stuck on the old video frame although it will
2484 // flicker between the old video frame and the new video frame.
2486         if(redraw)
2487         {
2488                 draw_refresh();
2489                 gui->update_tool();
2490         }
2492         if(redraw_canvas)
2493         {
2494                 mwindow->gui->lock_window("CWindowCanvas::cursor_motion_event 1");
2495                 mwindow->gui->canvas->draw_overlays();
2496                 mwindow->gui->canvas->flash();
2497                 mwindow->gui->unlock_window();
2498         }
2500         if(rerender)
2501         {
2502                 mwindow->restart_brender();
2503                 mwindow->sync_parameters(CHANGE_PARAMS);
2504                 gui->cwindow->playback_engine->que->send_command(CURRENT_FRAME, 
2505                         CHANGE_NONE,
2506                         mwindow->edl,
2507                         1);
2508                 if(!redraw) gui->update_tool();
2509         }
2510         return result;
2513 int CWindowCanvas::button_press_event()
2515         int result = 0;
2516         int redraw = 0;
2517         int redraw_canvas = 0;
2518         int rerender = 0;
2520         if(Canvas::button_press_event()) return 1;
2522         gui->translating_zoom = gui->shift_down(); 
2524         calculate_origin();
2525 //printf("CWindowCanvas::button_press_event 2 %f %f\n", gui->x_origin, gui->y_origin, gui->x_origin, gui->y_origin);
2527         float zoom_x, zoom_y, conformed_w, conformed_h;
2528         get_zooms(mwindow->edl, 0, zoom_x, zoom_y, conformed_w, conformed_h);
2529         gui->x_offset = get_x_offset(mwindow->edl, 0, zoom_x, conformed_w, conformed_h);
2530         gui->y_offset = get_y_offset(mwindow->edl, 0, zoom_y, conformed_w, conformed_h);
2532 // Scroll view
2533         if(get_buttonpress() == 2)
2534         {
2535                 gui->current_operation = CWINDOW_SCROLL;
2536                 result = 1;
2537         }
2538         else
2539 // Adjust parameter
2540         {
2541                 switch(mwindow->edl->session->cwindow_operation)
2542                 {
2543                         case CWINDOW_CAMERA:
2544                                 result = test_bezier(1, redraw, redraw_canvas, rerender, 1);
2545                                 break;
2547                         case CWINDOW_PROJECTOR:
2548                                 result = test_bezier(1, redraw, redraw_canvas, rerender, 0);
2549                                 break;
2551                         case CWINDOW_ZOOM:
2552                                 result = test_zoom(redraw);
2553                                 break;
2555                         case CWINDOW_CROP:
2556                                 result = test_crop(1, redraw);
2557                                 break;
2559                         case CWINDOW_MASK:
2560                                 if(get_buttonpress() == 1)
2561                                         result = do_mask(redraw, rerender, 1, 0, 0);
2562                                 break;
2564                         case CWINDOW_EYEDROP:
2565                                 result = do_eyedrop(rerender, 1);
2566                                 break;
2567                 }
2568         }
2570         if(redraw)
2571         {
2572                 draw_refresh();
2573                 gui->update_tool();
2574         }
2576 // rerendering can also be caused by press event
2577         if(rerender) 
2578         {
2579                 mwindow->restart_brender();
2580                 mwindow->sync_parameters(CHANGE_PARAMS);
2581                 gui->cwindow->playback_engine->que->send_command(CURRENT_FRAME, 
2582                         CHANGE_NONE,
2583                         mwindow->edl,
2584                         1);
2585                 if(!redraw) gui->update_tool();
2586         }
2587         return result;
2590 int CWindowCanvas::button_release_event()
2592         int result = 0;
2594         switch(gui->current_operation)
2595         {
2596                 case CWINDOW_SCROLL:
2597                         result = 1;
2598                         break;
2600                 case CWINDOW_CAMERA:
2601                         mwindow->undo->update_undo(_("camera"), LOAD_AUTOMATION);
2602                         break;
2604                 case CWINDOW_PROJECTOR:
2605                         mwindow->undo->update_undo(_("projector"), LOAD_AUTOMATION);
2606                         break;
2608                 case CWINDOW_MASK:
2609                 case CWINDOW_MASK_CONTROL_IN:
2610                 case CWINDOW_MASK_CONTROL_OUT:
2611                 case CWINDOW_MASK_TRANSLATE:
2612                         mwindow->undo->update_undo(_("mask point"), LOAD_AUTOMATION);
2613                         break;
2615         }
2617         gui->current_operation = CWINDOW_NONE;
2618         return result;
2621 void CWindowCanvas::zoom_resize_window(float percentage)
2623         int canvas_w, canvas_h;
2624         calculate_sizes(mwindow->edl->get_aspect_ratio(), 
2625                 mwindow->edl->session->output_w, 
2626                 mwindow->edl->session->output_h, 
2627                 percentage,
2628                 canvas_w,
2629                 canvas_h);
2630         int new_w, new_h;
2631         new_w = canvas_w + (gui->get_w() - mwindow->theme->ccanvas_w);
2632         new_h = canvas_h + (gui->get_h() - mwindow->theme->ccanvas_h);
2633         gui->resize_window(new_w, new_h);
2634         gui->resize_event(new_w, new_h);
2637 void CWindowCanvas::toggle_controls()
2639         mwindow->session->cwindow_controls = !mwindow->session->cwindow_controls;
2640         gui->resize_event(gui->get_w(), gui->get_h());
2643 int CWindowCanvas::get_cwindow_controls()
2645         return mwindow->session->cwindow_controls;