r914: Fix a long outstanding bug regarding dragndroping
[cinelerra_cv/mob.git] / cinelerra / cwindowgui.C
blobd75f5f314748a668181a6734133cd527b6cd8f22
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 "mbuttons.h"
28 #include "meterpanel.h"
29 #include "mwindowgui.h"
30 #include "mwindow.h"
31 #include "mwindow.h"
32 #include "playback3d.h"
33 #include "playtransport.h"
34 #include "theme.h"
35 #include "trackcanvas.h"
36 #include "tracks.h"
37 #include "transportque.h"
38 #include "vtrack.h"
41 static double my_zoom_table[] = 
43         0.25,
44         0.33,
45         0.50,
46         0.75,
47         1.0,
48         1.5,
49         2.0,
50         3.0,
51         4.0
54 static int total_zooms = sizeof(my_zoom_table) / sizeof(double);
57 CWindowGUI::CWindowGUI(MWindow *mwindow, CWindow *cwindow)
58  : BC_Window(PROGRAM_NAME ": Compositor",
59         mwindow->session->cwindow_x, 
60     mwindow->session->cwindow_y, 
61     mwindow->session->cwindow_w, 
62     mwindow->session->cwindow_h,
63     100,
64     100,
65     1,
66     1,
67     1,
68         BC_WindowBase::get_resources()->bg_color,
69         mwindow->edl->session->get_cwindow_display())
71         this->mwindow = mwindow;
72     this->cwindow = cwindow;
73         affected_track = 0;
74         affected_x = 0;
75         affected_y = 0;
76         affected_z = 0;
77         affected_keyframe = 0;
78         affected_point = 0;
79         x_offset = 0;
80         y_offset = 0;
81         x_origin = 0;
82         y_origin = 0;
83         current_operation = CWINDOW_NONE;
84         tool_panel = 0;
85         translating_zoom = 0;
86         active = 0;
87         inactive = 0;
88         crop_translate = 0;
91 CWindowGUI::~CWindowGUI()
93         if(tool_panel) delete tool_panel;
94         delete meters;
95         delete composite_panel;
96         delete canvas;
97         delete transport;
98         delete edit_panel;
99         delete zoom_panel;
100         delete active;
101         delete inactive;
104 int CWindowGUI::create_objects()
106         set_icon(mwindow->theme->get_image("cwindow_icon"));
108         active = new BC_Pixmap(this, mwindow->theme->get_image("cwindow_active"));
109         inactive = new BC_Pixmap(this, mwindow->theme->get_image("cwindow_inactive"));
111         mwindow->theme->get_cwindow_sizes(this, mwindow->session->cwindow_controls);
112         mwindow->theme->draw_cwindow_bg(this);
113         flash();
115 // Meters required by composite panel
116         meters = new CWindowMeters(mwindow, 
117                 this,
118                 mwindow->theme->cmeter_x,
119                 mwindow->theme->cmeter_y,
120                 mwindow->theme->cmeter_h);
121         meters->create_objects();
124         composite_panel = new CPanel(mwindow, 
125                 this, 
126                 mwindow->theme->ccomposite_x,
127                 mwindow->theme->ccomposite_y,
128                 mwindow->theme->ccomposite_w,
129                 mwindow->theme->ccomposite_h);
130         composite_panel->create_objects();
132         canvas = new CWindowCanvas(mwindow, this);
133         canvas->create_objects(mwindow->edl);
136         add_subwindow(timebar = new CTimeBar(mwindow,
137                 this,
138                 mwindow->theme->ctimebar_x,
139                 mwindow->theme->ctimebar_y,
140                 mwindow->theme->ctimebar_w, 
141                 mwindow->theme->ctimebar_h));
142         timebar->create_objects();
144         add_subwindow(slider = new CWindowSlider(mwindow, 
145                 cwindow, 
146                 mwindow->theme->cslider_x,
147                 mwindow->theme->cslider_y, 
148                 mwindow->theme->cslider_w));
150         transport = new CWindowTransport(mwindow, 
151                 this, 
152                 mwindow->theme->ctransport_x, 
153                 mwindow->theme->ctransport_y);
154         transport->create_objects();
155         transport->set_slider(slider);
157         edit_panel = new CWindowEditing(mwindow, cwindow);
158         edit_panel->set_meters(meters);
159         edit_panel->create_objects();
161 //      add_subwindow(clock = new MainClock(mwindow, 
162 //              mwindow->theme->ctime_x, 
163 //              mwindow->theme->ctime_y));
165         zoom_panel = new CWindowZoom(mwindow, 
166                 this, 
167                 mwindow->theme->czoom_x, 
168                 mwindow->theme->czoom_y);
169         zoom_panel->create_objects();
170         zoom_panel->zoom_text->add_item(new BC_MenuItem(AUTO_ZOOM));
171         if(!mwindow->edl->session->cwindow_scrollbars) zoom_panel->set_text(AUTO_ZOOM);
173 //      destination = new CWindowDestination(mwindow, 
174 //              this, 
175 //              mwindow->theme->cdest_x,
176 //              mwindow->theme->cdest_y);
177 //      destination->create_objects();
179 // Must create after meter panel
180         tool_panel = new CWindowTool(mwindow, this);
181         tool_panel->Thread::start();
182         
183         set_operation(mwindow->edl->session->cwindow_operation);
186         canvas->draw_refresh();
188         draw_status();
190         return 0;
193 int CWindowGUI::translation_event()
195         mwindow->session->cwindow_x = get_x();
196         mwindow->session->cwindow_y = get_y();
197         return 0;
200 int CWindowGUI::resize_event(int w, int h)
202         mwindow->session->cwindow_x = get_x();
203         mwindow->session->cwindow_y = get_y();
204         mwindow->session->cwindow_w = w;
205         mwindow->session->cwindow_h = h;
207         mwindow->theme->get_cwindow_sizes(this, mwindow->session->cwindow_controls);
208         mwindow->theme->draw_cwindow_bg(this);
209         flash();
211         composite_panel->reposition_buttons(mwindow->theme->ccomposite_x,
212                 mwindow->theme->ccomposite_y);
214         canvas->reposition_window(mwindow->edl,
215                 mwindow->theme->ccanvas_x,
216                 mwindow->theme->ccanvas_y,
217                 mwindow->theme->ccanvas_w,
218                 mwindow->theme->ccanvas_h);
220         timebar->resize_event();
222         slider->reposition_window(mwindow->theme->cslider_x,
223                 mwindow->theme->cslider_y, 
224                 mwindow->theme->cslider_w);
225 // Recalibrate pointer motion range
226         slider->set_position();
228         transport->reposition_buttons(mwindow->theme->ctransport_x, 
229                 mwindow->theme->ctransport_y);
231         edit_panel->reposition_buttons(mwindow->theme->cedit_x, 
232                 mwindow->theme->cedit_y);
234 //      clock->reposition_window(mwindow->theme->ctime_x, 
235 //              mwindow->theme->ctime_y);
237         zoom_panel->reposition_window(mwindow->theme->czoom_x, 
238                 mwindow->theme->czoom_y);
240 //      destination->reposition_window(mwindow->theme->cdest_x,
241 //              mwindow->theme->cdest_y);
243         meters->reposition_window(mwindow->theme->cmeter_x,
244                 mwindow->theme->cmeter_y,
245                 mwindow->theme->cmeter_h);
247         draw_status();
249         BC_WindowBase::resize_event(w, h);
250         return 1;
253 int CWindowGUI::button_press_event()
255         if(canvas->get_canvas())
256                 return canvas->button_press_event_base(canvas->get_canvas());
257         return 0;
260 int CWindowGUI::cursor_leave_event()
262         if(canvas->get_canvas())
263                 return canvas->cursor_leave_event_base(canvas->get_canvas());
264         return 0;
267 int CWindowGUI::cursor_enter_event()
269         if(canvas->get_canvas())
270                 return canvas->cursor_enter_event_base(canvas->get_canvas());
271         return 0;
274 int CWindowGUI::button_release_event()
276         if(canvas->get_canvas())
277                 return canvas->button_release_event();
278         return 0;
281 int CWindowGUI::cursor_motion_event()
283         if(canvas->get_canvas())
284         {
285                 canvas->get_canvas()->unhide_cursor();
286                 return canvas->cursor_motion_event();
287         }
288         return 0;
297 void CWindowGUI::draw_status()
299         if(canvas->get_canvas() && 
300                 canvas->get_canvas()->get_video_on() ||
301                 canvas->is_processing)
302         {
303                 draw_pixmap(active, 
304                         mwindow->theme->cstatus_x, 
305                         mwindow->theme->cstatus_y);
306         }
307         else
308         {
309                 draw_pixmap(inactive, 
310                         mwindow->theme->cstatus_x, 
311                         mwindow->theme->cstatus_y);
312         }
313         
314         flash(mwindow->theme->cstatus_x,
315                 mwindow->theme->cstatus_y,
316                 active->get_w(),
317                 active->get_h());
321 void CWindowGUI::zoom_canvas(int do_auto, double value, int update_menu)
323         if(do_auto)
324                 mwindow->edl->session->cwindow_scrollbars = 0;
325         else
326                 mwindow->edl->session->cwindow_scrollbars = 1;
328         float old_zoom = mwindow->edl->session->cwindow_zoom;
329         float new_zoom = value;
330         float x = canvas->w / 2;
331         float y = canvas->h / 2;
332         canvas->canvas_to_output(mwindow->edl, 
333                                 0, 
334                                 x, 
335                                 y);
336         x -= canvas->w_visible / 2 * old_zoom / new_zoom;
337         y -= canvas->h_visible / 2 * old_zoom / new_zoom;
338         if(update_menu)
339         {
340                 if(do_auto)
341                 {
342                         zoom_panel->update(AUTO_ZOOM);
343                 }
344                 else
345                 {
346                         zoom_panel->update(value);
347                 }
348         }
350         canvas->update_zoom((int)x, 
351                 (int)y, 
352                 new_zoom);
353         canvas->reposition_window(mwindow->edl, 
354                 mwindow->theme->ccanvas_x,
355                 mwindow->theme->ccanvas_y,
356                 mwindow->theme->ccanvas_w,
357                 mwindow->theme->ccanvas_h);
358         canvas->draw_refresh();
362 // TODO
363 // Don't refresh the canvas in a load file operation which is going to
364 // refresh it anyway.
365 void CWindowGUI::set_operation(int value)
367         mwindow->edl->session->cwindow_operation = value;
369         composite_panel->set_operation(value);
370         edit_panel->update();
372         tool_panel->start_tool(value);
373         canvas->draw_refresh();
376 void CWindowGUI::update_tool()
378         tool_panel->update_values();
381 int CWindowGUI::close_event()
383         cwindow->hide_window();
384         return 1;
388 int CWindowGUI::keypress_event()
390         int result = 0;
392         switch(get_keypress())
393         {
394                 case 'w':
395                 case 'W':
396                         close_event();
397                         result = 1;
398                         break;
399                 case '+':
400                 case '=':
401                         keyboard_zoomin();
402                         result = 1;
403                         break;
404                 case '-':
405                         keyboard_zoomout();
406                         result = 1;
407                         break;
408                 case 'f':
409                         unlock_window();
410                         if(mwindow->session->cwindow_fullscreen)
411                                 canvas->stop_fullscreen();
412                         else
413                                 canvas->start_fullscreen();
414                         lock_window("CWindowGUI::keypress_event 1");
415                         break;
416                 case ESC:
417                         unlock_window();
418                         if(mwindow->session->cwindow_fullscreen)
419                                 canvas->stop_fullscreen();
420                         lock_window("CWindowGUI::keypress_event 2");
421                         break;
422                 case LEFT:
423                         if(!ctrl_down()) 
424                         { 
425                                 if (alt_down())
426                                 {
427                                         int shift_down = this->shift_down();
428                                         unlock_window();
429                                         mwindow->gui->mbuttons->transport->handle_transport(STOP, 1, 0, 0);
431                                         mwindow->gui->lock_window("CWindowGUI::keypress_event 2");
432                                         mwindow->prev_edit_handle(shift_down);
433                                         mwindow->gui->unlock_window();
435                                         lock_window("CWindowGUI::keypress_event 1");
436                                 }
437                                 else
438                                 {
439                                         mwindow->move_left(); 
440                                 }
441                                 result = 1; 
442                         }
443                         break;
444                 case RIGHT:
445                         if(!ctrl_down()) 
446                         { 
447                                 if (alt_down())
448                                 {
449                                         int shift_down = this->shift_down();
450                                         unlock_window();
451                                         mwindow->gui->mbuttons->transport->handle_transport(STOP, 1, 0, 0);
453                                         mwindow->gui->lock_window("CWindowGUI::keypress_event 2");
454                                         mwindow->next_edit_handle(shift_down);
455                                         mwindow->gui->unlock_window();
457                                         lock_window("CWindowGUI::keypress_event 2");
458                                 }
459                                 else
460                                         mwindow->move_right(); 
461                                 result = 1; 
462                         }
463                         break;
464         }
466         if(!result) result = transport->keypress_event();
468         return result;
472 void CWindowGUI::reset_affected()
474         affected_x = 0;
475         affected_y = 0;
476         affected_z = 0;
479 void CWindowGUI::keyboard_zoomin()
481 //      if(mwindow->edl->session->cwindow_scrollbars)
482 //      {
483                 zoom_panel->zoom_tumbler->handle_up_event();
484 //      }
485 //      else
486 //      {
487 //      }
490 void CWindowGUI::keyboard_zoomout()
492 //      if(mwindow->edl->session->cwindow_scrollbars)
493 //      {
494                 zoom_panel->zoom_tumbler->handle_down_event();
495 //      }
496 //      else
497 //      {
498 //      }
502 void CWindowGUI::drag_motion()
504         if(get_hidden()) return;
506         if(mwindow->session->current_operation == DRAG_ASSET ||
507                 mwindow->session->current_operation == DRAG_VTRANSITION ||
508                 mwindow->session->current_operation == DRAG_VEFFECT)
509         {
510                 int old_status = mwindow->session->ccanvas_highlighted;
511                 int cursor_x = get_relative_cursor_x();
512                 int cursor_y = get_relative_cursor_y();
514                 mwindow->session->ccanvas_highlighted = get_cursor_over_window() &&
515                         cursor_x >= canvas->x &&
516                         cursor_x < canvas->x + canvas->w &&
517                         cursor_y >= canvas->y &&
518                         cursor_y < canvas->y + canvas->h;
521                 if(old_status != mwindow->session->ccanvas_highlighted)
522                         canvas->draw_refresh();
523         }
526 int CWindowGUI::drag_stop()
528         int result = 0;
529         if(get_hidden()) return 0;
531         if((mwindow->session->current_operation == DRAG_ASSET ||
532                 mwindow->session->current_operation == DRAG_VTRANSITION ||
533                 mwindow->session->current_operation == DRAG_VEFFECT) &&
534                 mwindow->session->ccanvas_highlighted)
535         {
536 // Hide highlighting
537                 mwindow->session->ccanvas_highlighted = 0;
538                 canvas->draw_refresh();
539                 result = 1;
540         }
541         else
542                 return 0;
544         if(mwindow->session->current_operation == DRAG_ASSET)
545         {
546                 if(mwindow->session->drag_assets->total)
547                 {
548                         mwindow->gui->lock_window("CWindowGUI::drag_stop 1");
549                         mwindow->clear(0);
550                         mwindow->load_assets(mwindow->session->drag_assets, 
551                                 mwindow->edl->local_session->get_selectionstart(), 
552                                 LOAD_PASTE,
553                                 mwindow->session->track_highlighted,
554                                 0,
555                                 mwindow->edl->session->labels_follow_edits, 
556                                 mwindow->edl->session->plugins_follow_edits,
557                                 0); // overwrite
558                 }
560                 if(mwindow->session->drag_clips->total)
561                 {
562                         mwindow->gui->lock_window("CWindowGUI::drag_stop 2");
563                         mwindow->clear(0);
564                         mwindow->paste_edls(mwindow->session->drag_clips, 
565                                 LOAD_PASTE, 
566                                 mwindow->session->track_highlighted,
567                                 mwindow->edl->local_session->get_selectionstart(),
568                                 mwindow->edl->session->labels_follow_edits, 
569                                 mwindow->edl->session->plugins_follow_edits,
570                                 0); // overwrite
571                 }
573                 if(mwindow->session->drag_assets->total ||
574                         mwindow->session->drag_clips->total)
575                 {
576                         mwindow->save_backup();
577                         mwindow->restart_brender();
578                         mwindow->gui->update(1, 1, 1, 1, 0, 1, 0);
579                         mwindow->undo->update_undo(_("insert assets"), LOAD_ALL);
580                         mwindow->gui->unlock_window();
581                         mwindow->sync_parameters(LOAD_ALL);
582                 }
583         }
585         if(mwindow->session->current_operation == DRAG_VEFFECT)
586         {
587 //printf("CWindowGUI::drag_stop 1\n");
588                 Track *affected_track = cwindow->calculate_affected_track();
589 //printf("CWindowGUI::drag_stop 2\n");
591                 mwindow->gui->lock_window("CWindowGUI::drag_stop 3");
592                 mwindow->insert_effects_cwindow(affected_track);
593                 mwindow->session->current_operation = NO_OPERATION;
594                 mwindow->gui->unlock_window();
595         }
597         if(mwindow->session->current_operation == DRAG_VTRANSITION)
598         {
599                 Track *affected_track = cwindow->calculate_affected_track();
600                 mwindow->gui->lock_window("CWindowGUI::drag_stop 4");
601                 mwindow->paste_transition_cwindow(affected_track);
602                 mwindow->session->current_operation = NO_OPERATION;
603                 mwindow->gui->unlock_window();
604         }
606         return result;
610 CWindowEditing::CWindowEditing(MWindow *mwindow, CWindow *cwindow)
611  : EditPanel(mwindow, 
612                 cwindow->gui, 
613                 mwindow->theme->cedit_x, 
614                 mwindow->theme->cedit_y,
615                 mwindow->edl->session->editing_mode, 
616                 0,
617                 1,
618                 0, 
619                 0,
620                 1,
621                 1,
622                 1,
623                 1,
624                 1,
625                 0,
626                 1,
627                 1,
628                 1,
629                 0,
630                 1)
632         this->mwindow = mwindow;
633         this->cwindow = cwindow;
636 void CWindowEditing::set_inpoint()
638         mwindow->set_inpoint(0);
641 void CWindowEditing::set_outpoint()
643         mwindow->set_outpoint(0);
650 CWindowMeters::CWindowMeters(MWindow *mwindow, CWindowGUI *gui, int x, int y, int h)
651  : MeterPanel(mwindow, 
652                 gui,
653                 x,
654                 y,
655                 h,
656                 mwindow->edl->session->audio_channels,
657                 mwindow->edl->session->cwindow_meter)
659         this->mwindow = mwindow;
660         this->gui = gui;
663 CWindowMeters::~CWindowMeters()
667 int CWindowMeters::change_status_event()
669         mwindow->edl->session->cwindow_meter = use_meters;
670         mwindow->theme->get_cwindow_sizes(gui, mwindow->session->cwindow_controls);
671         gui->resize_event(gui->get_w(), gui->get_h());
672         return 1;
678 CWindowZoom::CWindowZoom(MWindow *mwindow, CWindowGUI *gui, int x, int y)
679  : ZoomPanel(mwindow, 
680         gui, 
681         (double)mwindow->edl->session->cwindow_zoom, 
682         x, 
683         y,
684         80, 
685         my_zoom_table, 
686         total_zooms, 
687         ZOOM_PERCENTAGE)
689         this->mwindow = mwindow;
690         this->gui = gui;
693 CWindowZoom::~CWindowZoom()
697 int CWindowZoom::handle_event()
699         if(!strcasecmp(AUTO_ZOOM, get_text()))
700         {
701                 gui->zoom_canvas(1, get_value(), 0);
702         }
703         else
704         {
705                 gui->zoom_canvas(0, get_value(), 0);
706         }
708         return 1;
713 CWindowSlider::CWindowSlider(MWindow *mwindow, CWindow *cwindow, int x, int y, int pixels)
714  : BC_PercentageSlider(x, 
715                         y,
716                         0,
717                         pixels, 
718                         pixels, 
719                         0, 
720                         1, 
721                         0)
723         this->mwindow = mwindow;
724         this->cwindow = cwindow;
725         set_precision(0.00001);
728 CWindowSlider::~CWindowSlider()
732 int CWindowSlider::handle_event()
734         unlock_window();
735         cwindow->playback_engine->interrupt_playback(1);
736         lock_window("CWindowSlider::handle_event 1");
737         
738         mwindow->gui->lock_window("CWindowSlider::handle_event 2");
739         mwindow->select_point((double)get_value());
740         mwindow->gui->unlock_window();
741         return 1;
744 void CWindowSlider::set_position()
746         double new_length = mwindow->edl->tracks->total_playable_length();
747         if(mwindow->edl->local_session->preview_end <= 0 ||
748                 mwindow->edl->local_session->preview_end > new_length)
749                 mwindow->edl->local_session->preview_end = new_length;
750         if(mwindow->edl->local_session->preview_start > 
751                 mwindow->edl->local_session->preview_end)
752                 mwindow->edl->local_session->preview_start = 0;
756         update(mwindow->theme->cslider_w, 
757                 mwindow->edl->local_session->get_selectionstart(1), 
758                 mwindow->edl->local_session->preview_start, 
759                 mwindow->edl->local_session->preview_end);
763 int CWindowSlider::increase_value()
765         unlock_window();
766         cwindow->gui->transport->handle_transport(SINGLE_FRAME_FWD);
767         lock_window("CWindowSlider::increase_value");
768         return 1;
771 int CWindowSlider::decrease_value()
773         unlock_window();
774         cwindow->gui->transport->handle_transport(SINGLE_FRAME_REWIND);
775         lock_window("CWindowSlider::decrease_value");
776         return 1;
780 // CWindowDestination::CWindowDestination(MWindow *mwindow, CWindowGUI *cwindow, int x, int y)
781 //  : BC_PopupTextBox(cwindow, 
782 //      &cwindow->destinations, 
783 //      cwindow->destinations.values[cwindow->cwindow->destination]->get_text(),
784 //      x, 
785 //      y, 
786 //      70, 
787 //      200)
788 // {
789 //      this->mwindow = mwindow;
790 //      this->cwindow = cwindow;
791 // }
792 // 
793 // CWindowDestination::~CWindowDestination()
794 // {
795 // }
796 // 
797 // int CWindowDestination::handle_event()
798 // {
799 //      return 1;
800 // }
803 CWindowTransport::CWindowTransport(MWindow *mwindow, 
804         CWindowGUI *gui, 
805         int x, 
806         int y)
807  : PlayTransport(mwindow, 
808         gui, 
809         x, 
810         y)
812         this->gui = gui;
815 EDL* CWindowTransport::get_edl()
817         return mwindow->edl;
820 void CWindowTransport::goto_start()
822         gui->unlock_window();
823         handle_transport(REWIND, 1);
825         mwindow->gui->lock_window("CWindowTransport::goto_start 1");
826         mwindow->goto_start();
827         mwindow->gui->unlock_window();
829         gui->lock_window("CWindowTransport::goto_start 2");
832 void CWindowTransport::goto_end()
834         gui->unlock_window();
835         handle_transport(GOTO_END, 1);
837         mwindow->gui->lock_window("CWindowTransport::goto_end 1");
838         mwindow->goto_end();
839         mwindow->gui->unlock_window();
841         gui->lock_window("CWindowTransport::goto_end 2");
846 CWindowCanvas::CWindowCanvas(MWindow *mwindow, CWindowGUI *gui)
847  : Canvas(mwindow,
848         gui,
849         mwindow->theme->ccanvas_x,
850         mwindow->theme->ccanvas_y,
851         mwindow->theme->ccanvas_w,
852         mwindow->theme->ccanvas_h,
853         0,
854         0,
855         mwindow->edl->session->cwindow_scrollbars,
856         1)
858         this->mwindow = mwindow;
859         this->gui = gui;
862 void CWindowCanvas::status_event()
864         gui->draw_status();
867 int CWindowCanvas::get_fullscreen()
869         return mwindow->session->cwindow_fullscreen;
872 void CWindowCanvas::set_fullscreen(int value)
874         mwindow->session->cwindow_fullscreen = value;
878 void CWindowCanvas::update_zoom(int x, int y, float zoom)
880         use_scrollbars = mwindow->edl->session->cwindow_scrollbars;
882         mwindow->edl->session->cwindow_xscroll = x;
883         mwindow->edl->session->cwindow_yscroll = y;
884         mwindow->edl->session->cwindow_zoom = zoom;
887 void CWindowCanvas::zoom_auto()
889         gui->zoom_canvas(1, 1.0, 1);
892 int CWindowCanvas::get_xscroll()
894         return mwindow->edl->session->cwindow_xscroll;
897 int CWindowCanvas::get_yscroll()
899         return mwindow->edl->session->cwindow_yscroll;
903 float CWindowCanvas::get_zoom()
905         return mwindow->edl->session->cwindow_zoom;
908 void CWindowCanvas::draw_refresh()
910         if(get_canvas() && !get_canvas()->get_video_on())
911         {
913                 if(refresh_frame)
914                 {
915                         float in_x1, in_y1, in_x2, in_y2;
916                         float out_x1, out_y1, out_x2, out_y2;
917                         get_transfers(mwindow->edl, 
918                                 in_x1, 
919                                 in_y1, 
920                                 in_x2, 
921                                 in_y2, 
922                                 out_x1, 
923                                 out_y1, 
924                                 out_x2, 
925                                 out_y2);
927                         get_canvas()->clear_box(0, 
928                                 0, 
929                                 get_canvas()->get_w(), 
930                                 get_canvas()->get_h());
932 // printf("CWindowCanvas::draw_refresh %f %f %f %f -> %f %f %f %f\n", 
933 // in_x1, in_y1, in_x2, in_y2, out_x1, out_y1, out_x2, out_y2);
936                         if(out_x2 > out_x1 && 
937                                 out_y2 > out_y1 && 
938                                 in_x2 > in_x1 && 
939                                 in_y2 > in_y1)
940                         {
941 // Can't use OpenGL here because it is called asynchronously of the
942 // playback operation.
943                                 get_canvas()->draw_vframe(refresh_frame,
944                                                 (int)out_x1, 
945                                                 (int)out_y1, 
946                                                 (int)(out_x2 - out_x1), 
947                                                 (int)(out_y2 - out_y1),
948                                                 (int)in_x1, 
949                                                 (int)in_y1, 
950                                                 (int)(in_x2 - in_x1), 
951                                                 (int)(in_y2 - in_y1),
952                                                 0);
953                         }
954                 }
956                 draw_overlays();
957                 get_canvas()->flash();
958         }
959 //printf("CWindowCanvas::draw_refresh 10\n");
962 #define CROPHANDLE_W 10
963 #define CROPHANDLE_H 10
965 void CWindowCanvas::draw_crophandle(int x, int y)
967         get_canvas()->draw_box(x, y, CROPHANDLE_W, CROPHANDLE_H);
970 #define CONTROL_W 10
971 #define CONTROL_H 10
972 #define FIRST_CONTROL_W 20
973 #define FIRST_CONTROL_H 20
974 #undef BC_INFINITY
975 #define BC_INFINITY 65536
976 #ifndef SQR
977 #define SQR(x) ((x) * (x))
978 #endif
980 int CWindowCanvas::do_mask(int &redraw, 
981                 int &rerender, 
982                 int button_press, 
983                 int cursor_motion,
984                 int draw)
986 // Retrieve points from top recordable track
987 //printf("CWindowCanvas::do_mask 1\n");
988         Track *track = gui->cwindow->calculate_affected_track();
989 //printf("CWindowCanvas::do_mask 2\n");
991         if(!track) return 0;
992 //printf("CWindowCanvas::do_mask 3\n");
994         MaskAutos *mask_autos = (MaskAutos*)track->automation->autos[AUTOMATION_MASK];
995         int64_t position = track->to_units(
996                 mwindow->edl->local_session->get_selectionstart(1),
997                 0);
998         ArrayList<MaskPoint*> points;
999         mask_autos->get_points(&points, mwindow->edl->session->cwindow_mask,
1000                 position, 
1001                 PLAY_FORWARD);
1002 //printf("CWindowCanvas::do_mask 4\n");
1004 // Projector zooms relative to the center of the track output.
1005         float half_track_w = (float)track->track_w / 2;
1006         float half_track_h = (float)track->track_h / 2;
1007 // Translate mask to projection
1008         float projector_x, projector_y, projector_z;
1009         track->automation->get_projector(&projector_x,
1010                 &projector_y,
1011                 &projector_z,
1012                 position,
1013                 PLAY_FORWARD);
1016 // Get position of cursor relative to mask
1017         float mask_cursor_x = get_cursor_x();
1018         float mask_cursor_y = get_cursor_y();
1019         canvas_to_output(mwindow->edl, 0, mask_cursor_x, mask_cursor_y);
1021         projector_x += mwindow->edl->session->output_w / 2;
1022         projector_y += mwindow->edl->session->output_h / 2;
1024         mask_cursor_x -= projector_x;
1025         mask_cursor_y -= projector_y;
1026         mask_cursor_x = mask_cursor_x / projector_z + half_track_w;
1027         mask_cursor_y = mask_cursor_y / projector_z + half_track_h;
1029 // Fix cursor origin
1030         if(button_press)
1031         {
1032                 gui->x_origin = mask_cursor_x;
1033                 gui->y_origin = mask_cursor_y;
1034         }
1036         int result = 0;
1037 // Points of closest line
1038         int shortest_point1 = -1;
1039         int shortest_point2 = -1;
1040 // Closest point
1041         int shortest_point = -1;
1042 // Distance to closest line
1043         float shortest_line_distance = BC_INFINITY;
1044 // Distance to closest point
1045         float shortest_point_distance = BC_INFINITY;
1046         int selected_point = -1;
1047         int selected_control_point = -1;
1048         float selected_control_point_distance = BC_INFINITY;
1049         ArrayList<int> x_points;
1050         ArrayList<int> y_points;
1052         if(!cursor_motion)
1053         {
1054                 if(draw)
1055                 {
1056                         get_canvas()->set_color(WHITE);
1057                         get_canvas()->set_inverse();
1058                 }
1059 //printf("CWindowCanvas::do_mask 1 %d\n", points.total);
1061 // Never draw closed polygon and a closed
1062 // polygon is harder to add points to.
1063                 for(int i = 0; i < points.total && !result; i++)
1064                 {
1065                         MaskPoint *point1 = points.values[i];
1066                         MaskPoint *point2 = (i >= points.total - 1) ? 
1067                                 points.values[0] : 
1068                                 points.values[i + 1];
1069                         float x0, x1, x2, x3;
1070                         float y0, y1, y2, y3;
1071                         float old_x, old_y, x, y;
1072                         int segments = (int)(sqrt(SQR(point1->x - point2->x) + SQR(point1->y - point2->y)));
1074 //printf("CWindowCanvas::do_mask 1 %f, %f -> %f, %f projectorz=%f\n",
1075 //point1->x, point1->y, point2->x, point2->y, projector_z);
1076                         for(int j = 0; j <= segments && !result; j++)
1077                         {
1078 //printf("CWindowCanvas::do_mask 1 %f, %f -> %f, %f\n", x0, y0, x3, y3);
1079                                 x0 = point1->x;
1080                                 y0 = point1->y;
1081                                 x1 = point1->x + point1->control_x2;
1082                                 y1 = point1->y + point1->control_y2;
1083                                 x2 = point2->x + point2->control_x1;
1084                                 y2 = point2->y + point2->control_y1;
1085                                 x3 = point2->x;
1086                                 y3 = point2->y;
1088                                 float t = (float)j / segments;
1089                                 float tpow2 = t * t;
1090                                 float tpow3 = t * t * t;
1091                                 float invt = 1 - t;
1092                                 float invtpow2 = invt * invt;
1093                                 float invtpow3 = invt * invt * invt;
1095                                 x = (        invtpow3 * x0
1096                                         + 3 * t     * invtpow2 * x1
1097                                         + 3 * tpow2 * invt     * x2 
1098                                         +     tpow3            * x3);
1099                                 y = (        invtpow3 * y0 
1100                                         + 3 * t     * invtpow2 * y1
1101                                         + 3 * tpow2 * invt     * y2 
1102                                         +     tpow3            * y3);
1104                                 x = (x - half_track_w) * projector_z + projector_x;
1105                                 y = (y - half_track_h) * projector_z + projector_y;
1108 // Test new point addition
1109                                 if(button_press)
1110                                 {
1111                                         float line_distance = 
1112                                                 sqrt(SQR(x - mask_cursor_x) + SQR(y - mask_cursor_y));
1114 //printf("CWindowCanvas::do_mask 1 x=%f mask_cursor_x=%f y=%f mask_cursor_y=%f %f %f %d, %d\n", 
1115 //x, mask_cursor_x, y, mask_cursor_y, line_distance, shortest_line_distance, shortest_point1, shortest_point2);
1116                                         if(line_distance < shortest_line_distance || 
1117                                                 shortest_point1 < 0)
1118                                         {
1119                                                 shortest_line_distance = line_distance;
1120                                                 shortest_point1 = i;
1121                                                 shortest_point2 = (i >= points.total - 1) ? 0 : (i + 1);
1122 //printf("CWindowCanvas::do_mask 2 %f %f %d, %d\n", line_distance, shortest_line_distance, shortest_point1, shortest_point2);
1123                                         }
1126                                         float point_distance1 = 
1127                                                 sqrt(SQR(point1->x - mask_cursor_x) + SQR(point1->y - mask_cursor_y));
1128                                         float point_distance2 = 
1129                                                 sqrt(SQR(point2->x - mask_cursor_x) + SQR(point2->y - mask_cursor_y));
1131                                         if(point_distance1 < shortest_point_distance || 
1132                                                 shortest_point < 0)
1133                                         {
1134                                                 shortest_point_distance = point_distance1;
1135                                                 shortest_point = i;
1136                                         }
1138                                         if(point_distance2 < shortest_point_distance || 
1139                                                 shortest_point < 0)
1140                                         {
1141                                                 shortest_point_distance = point_distance2;
1142                                                 shortest_point = (i >= points.total - 1) ? 0 : (i + 1);
1143                                         }
1144                                 }
1146                                 output_to_canvas(mwindow->edl, 0, x, y);
1149 #define TEST_BOX(cursor_x, cursor_y, target_x, target_y) \
1150         (cursor_x >= target_x - CONTROL_W / 2 && \
1151         cursor_x < target_x + CONTROL_W / 2 && \
1152         cursor_y >= target_y - CONTROL_H / 2 && \
1153         cursor_y < target_y + CONTROL_H / 2)
1155 // Test existing point selection
1156                                 if(button_press)
1157                                 {
1158                                         float canvas_x = (x0 - half_track_w) * projector_z + projector_x;
1159                                         float canvas_y = (y0 - half_track_h) * projector_z + projector_y;
1160                                         int cursor_x = get_cursor_x();
1161                                         int cursor_y = get_cursor_y();
1163 // Test first point
1164                                         if(gui->shift_down())
1165                                         {
1166                                                 float control_x = (x1 - half_track_w) * projector_z + projector_x;
1167                                                 float control_y = (y1 - half_track_h) * projector_z + projector_y;
1168                                                 output_to_canvas(mwindow->edl, 0, control_x, control_y);
1170                                                 float distance = 
1171                                                         sqrt(SQR(control_x - cursor_x) + SQR(control_y - cursor_y));
1173                                                 if(distance < selected_control_point_distance)
1174                                                 {
1175                                                         selected_point = i;
1176                                                         selected_control_point = 1;
1177                                                         selected_control_point_distance = distance;
1178                                                 }
1179                                         }
1180                                         else
1181                                         {
1182                                                 output_to_canvas(mwindow->edl, 0, canvas_x, canvas_y);
1183                                                 if(!gui->ctrl_down())
1184                                                 {
1185                                                         if(TEST_BOX(cursor_x, cursor_y, canvas_x, canvas_y))
1186                                                         {
1187                                                                 selected_point = i;
1188                                                         }
1189                                                 }
1190                                                 else
1191                                                 {
1192                                                         selected_point = shortest_point;
1193                                                 }
1194                                         }
1196 // Test second point
1197                                         canvas_x = (x3 - half_track_w) * projector_z + projector_x;
1198                                         canvas_y = (y3 - half_track_h) * projector_z + projector_y;
1199                                         if(gui->shift_down())
1200                                         {
1201                                                 float control_x = (x2 - half_track_w) * projector_z + projector_x;
1202                                                 float control_y = (y2 - half_track_h) * projector_z + projector_y;
1203                                                 output_to_canvas(mwindow->edl, 0, control_x, control_y);
1205                                                 float distance = 
1206                                                         sqrt(SQR(control_x - cursor_x) + SQR(control_y - cursor_y));
1208 //printf("CWindowCanvas::do_mask %d %f %f\n", i, distance, selected_control_point_distance);
1209                                                 if(distance < selected_control_point_distance)
1210                                                 {
1211                                                         selected_point = (i < points.total - 1 ? i + 1 : 0);
1212                                                         selected_control_point = 0;
1213                                                         selected_control_point_distance = distance;
1214                                                 }
1215                                         }
1216                                         else
1217                                         if(i < points.total - 1)
1218                                         {
1219                                                 output_to_canvas(mwindow->edl, 0, canvas_x, canvas_y);
1220                                                 if(!gui->ctrl_down())
1221                                                 {
1222                                                         if(TEST_BOX(cursor_x, cursor_y, canvas_x, canvas_y))
1223                                                         {
1224                                                                 selected_point = (i < points.total - 1 ? i + 1 : 0);
1225                                                         }
1226                                                 }
1227                                                 else
1228                                                 {
1229                                                         selected_point = shortest_point;
1230                                                 }
1231                                         }
1232                                 }
1236                                 if(j > 0)
1237                                 {
1238 // Draw joining line
1239                                         if(draw)
1240                                         {
1241                                                 x_points.append((int)x);
1242                                                 y_points.append((int)y);
1243                                         }
1245                                         if(j == segments)
1246                                         {
1251                                                 if(draw)
1252                                                 {
1253 // Draw second anchor
1254                                                         if(i < points.total - 1)
1255                                                         {
1256                                                                 if(i == gui->affected_point - 1)
1257                                                                         get_canvas()->draw_disc((int)x - CONTROL_W / 2, 
1258                                                                                 (int)y - CONTROL_W / 2, 
1259                                                                                 CONTROL_W, 
1260                                                                                 CONTROL_W);
1261                                                                 else
1262                                                                         get_canvas()->draw_circle((int)x - CONTROL_W / 2, 
1263                                                                                 (int)y - CONTROL_W / 2, 
1264                                                                                 CONTROL_W, 
1265                                                                                 CONTROL_W);
1266 // char string[BCTEXTLEN];
1267 // sprintf(string, "%d", (i < points.total - 1 ? i + 1 : 0));
1268 // canvas->draw_text((int)x + CONTROL_W, (int)y + CONTROL_W, string);
1269                                                         }
1271 // Draw second control point.  Discard x2 and y2 after this.
1272                                                         x2 = (x2 - half_track_w) * projector_z + projector_x;
1273                                                         y2 = (y2 - half_track_h) * projector_z + projector_y;
1274                                                         output_to_canvas(mwindow->edl, 0, x2, y2);
1275                                                         get_canvas()->draw_line((int)x, (int)y, (int)x2, (int)y2);
1276                                                         get_canvas()->draw_rectangle((int)x2 - CONTROL_W / 2,
1277                                                                 (int)y2 - CONTROL_H / 2,
1278                                                                 CONTROL_W,
1279                                                                 CONTROL_H);
1280                                                 }
1281                                         }
1282                                 }
1283                                 else
1284                                 {
1287 // Draw first anchor
1288                                         if(i == 0 && draw)
1289                                         {
1290                                                 get_canvas()->draw_disc((int)x - FIRST_CONTROL_W / 2, 
1291                                                         (int)y - FIRST_CONTROL_H / 2, 
1292                                                         FIRST_CONTROL_W, 
1293                                                         FIRST_CONTROL_H);
1294                                         }
1296 // Draw first control point.  Discard x1 and y1 after this.
1297                                         if(draw)
1298                                         {
1299                                                 x1 = (x1 - half_track_w) * projector_z + projector_x;
1300                                                 y1 = (y1 - half_track_h) * projector_z + projector_y;
1301                                                 output_to_canvas(mwindow->edl, 0, x1, y1);
1302                                                 get_canvas()->draw_line((int)x, (int)y, (int)x1, (int)y1);
1303                                                 get_canvas()->draw_rectangle((int)x1 - CONTROL_W / 2,
1304                                                         (int)y1 - CONTROL_H / 2,
1305                                                         CONTROL_W,
1306                                                         CONTROL_H);
1307                                         
1308                                                 x_points.append((int)x);
1309                                                 y_points.append((int)y);
1310                                         }
1311                                 }
1312 //printf("CWindowCanvas::do_mask 1\n");
1314                                 old_x = x;
1315                                 old_y = y;
1316                         }
1317                 }
1318 //printf("CWindowCanvas::do_mask 1\n");
1320                 if(draw)
1321                 {
1322                         get_canvas()->draw_polygon(&x_points, &y_points);
1323                         get_canvas()->set_opaque();
1324                 }
1325 //printf("CWindowCanvas::do_mask 1\n");
1326         }
1334         if(button_press && !result)
1335         {
1336                 gui->affected_track = gui->cwindow->calculate_affected_track();
1337 // Get current keyframe
1338                 if(gui->affected_track)
1339                         gui->affected_keyframe = 
1340                                 gui->cwindow->calculate_affected_auto(
1341                                         gui->affected_track->automation->autos[AUTOMATION_MASK],
1342                                         1);
1344                 MaskAuto *keyframe = (MaskAuto*)gui->affected_keyframe;
1345                 SubMask *mask = keyframe->get_submask(mwindow->edl->session->cwindow_mask);
1348 // Translate entire keyframe
1349                 if(gui->alt_down() && mask->points.total)
1350                 {
1351                         gui->current_operation = CWINDOW_MASK_TRANSLATE;
1352                         gui->affected_point = 0;
1353                 }
1354                 else
1355 // Existing point or control point was selected
1356                 if(selected_point >= 0)
1357                 {
1358                         gui->affected_point = selected_point;
1360                         if(selected_control_point == 0)
1361                                 gui->current_operation = CWINDOW_MASK_CONTROL_IN;
1362                         else
1363                         if(selected_control_point == 1)
1364                                 gui->current_operation = CWINDOW_MASK_CONTROL_OUT;
1365                         else
1366                                 gui->current_operation = mwindow->edl->session->cwindow_operation;
1367                 }
1368                 else
1369 // No existing point or control point was selected so create a new one
1370                 if(!gui->shift_down() && !gui->alt_down())
1371                 {
1372 // Create the template
1373                         MaskPoint *point = new MaskPoint;
1374                         point->x = mask_cursor_x;
1375                         point->y = mask_cursor_y;
1376                         point->control_x1 = 0;
1377                         point->control_y1 = 0;
1378                         point->control_x2 = 0;
1379                         point->control_y2 = 0;
1382                         if(shortest_point2 < shortest_point1)
1383                         {
1384                                 shortest_point2 ^= shortest_point1;
1385                                 shortest_point1 ^= shortest_point2;
1386                                 shortest_point2 ^= shortest_point1;
1387                         }
1391 // printf("CWindowGUI::do_mask 40\n");
1392 // mwindow->edl->dump();
1393 // printf("CWindowGUI::do_mask 50\n");
1397 //printf("CWindowCanvas::do_mask 1 %f %f %d %d\n", 
1398 //      shortest_line_distance, shortest_point_distance, shortest_point1, shortest_point2);
1399 //printf("CWindowCanvas::do_mask %d %d\n", shortest_point1, shortest_point2);
1401 // Append to end of list
1402                         if(labs(shortest_point1 - shortest_point2) > 1)
1403                         {
1404 // Need to apply the new point to every keyframe
1405                                 for(MaskAuto *current = (MaskAuto*)mask_autos->default_auto;
1406                                         current; )
1407                                 {
1408                                         SubMask *submask = current->get_submask(mwindow->edl->session->cwindow_mask);
1409                                         MaskPoint *new_point = new MaskPoint;
1410                                         submask->points.append(new_point);
1411                                         *new_point = *point;
1412                                         if(current == (MaskAuto*)mask_autos->default_auto)
1413                                                 current = (MaskAuto*)mask_autos->first;
1414                                         else
1415                                                 current = (MaskAuto*)NEXT;
1416                                 }
1418                                 gui->affected_point = mask->points.total - 1;
1419                                 result = 1;
1420                         }
1421                         else
1422 // Insert between 2 points, shifting back point 2
1423                         if(shortest_point1 >= 0 && shortest_point2 >= 0)
1424                         {
1425                                 for(MaskAuto *current = (MaskAuto*)mask_autos->default_auto;
1426                                         current; )
1427                                 {
1428                                         SubMask *submask = current->get_submask(mwindow->edl->session->cwindow_mask);
1429 // In case the keyframe point count isn't synchronized with the rest of the keyframes,
1430 // avoid a crash.
1431                                         if(submask->points.total >= shortest_point2)
1432                                         {
1433                                                 MaskPoint *new_point = new MaskPoint;
1434                                                 submask->points.append(0);
1435                                                 for(int i = submask->points.total - 1; 
1436                                                         i > shortest_point2; 
1437                                                         i--)
1438                                                         submask->points.values[i] = submask->points.values[i - 1];
1439                                                 submask->points.values[shortest_point2] = new_point;
1441                                                 *new_point = *point;
1442                                         }
1444                                         if(current == (MaskAuto*)mask_autos->default_auto)
1445                                                 current = (MaskAuto*)mask_autos->first;
1446                                         else
1447                                                 current = (MaskAuto*)NEXT;
1448                                 }
1451                                 gui->affected_point = shortest_point2;
1452                                 result = 1;
1453                         }
1456 // printf("CWindowGUI::do_mask 20\n");
1457 // mwindow->edl->dump();
1458 // printf("CWindowGUI::do_mask 30\n");
1463 // Create the first point.
1464                         if(!result)
1465                         {
1466 //printf("CWindowCanvas::do_mask 1\n");
1467                                 for(MaskAuto *current = (MaskAuto*)mask_autos->default_auto;
1468                                         current; )
1469                                 {
1470                                         SubMask *submask = current->get_submask(mwindow->edl->session->cwindow_mask);
1471                                         MaskPoint *new_point = new MaskPoint;
1472                                         submask->points.append(new_point);
1473                                         *new_point = *point;
1474                                         if(current == (MaskAuto*)mask_autos->default_auto)
1475                                                 current = (MaskAuto*)mask_autos->first;
1476                                         else
1477                                                 current = (MaskAuto*)NEXT;
1478                                 }
1480 //printf("CWindowCanvas::do_mask 2\n");
1481 // Create a second point if none existed before
1482                                 if(mask->points.total < 2)
1483                                 {
1484                                         for(MaskAuto *current = (MaskAuto*)mask_autos->default_auto;
1485                                                 current; )
1486                                         {
1487                                                 SubMask *submask = current->get_submask(mwindow->edl->session->cwindow_mask);
1488                                                 MaskPoint *new_point = new MaskPoint;
1489                                                 submask->points.append(new_point);
1490                                                 *new_point = *point;
1491                                                 if(current == (MaskAuto*)mask_autos->default_auto)
1492                                                         current = (MaskAuto*)mask_autos->first;
1493                                                 else
1494                                                         current = (MaskAuto*)NEXT;
1495                                         }
1496                                 }
1497                                 gui->affected_point = mask->points.total - 1;
1498 //printf("CWindowCanvas::do_mask 3 %d\n", mask->points.total);
1499                         }
1503                         gui->current_operation = mwindow->edl->session->cwindow_operation;
1504 // Delete the template
1505                         delete point;
1506 //printf("CWindowGUI::do_mask 1\n");
1507                         mwindow->undo->update_undo(_("mask point"), LOAD_AUTOMATION);
1508 //printf("CWindowGUI::do_mask 10\n");
1510                 }
1512                 result = 1;
1513                 rerender = 1;
1514                 redraw = 1;
1515         }
1517         if(button_press && result)
1518         {
1519                 MaskAuto *keyframe = (MaskAuto*)gui->affected_keyframe;
1520                 SubMask *mask = keyframe->get_submask(mwindow->edl->session->cwindow_mask);
1521                 MaskPoint *point = mask->points.values[gui->affected_point];
1522                 gui->center_x = point->x;
1523                 gui->center_y = point->y;
1524                 gui->control_in_x = point->control_x1;
1525                 gui->control_in_y = point->control_y1;
1526                 gui->control_out_x = point->control_x2;
1527                 gui->control_out_y = point->control_y2;
1528         }
1530 //printf("CWindowCanvas::do_mask 8\n");
1531         if(cursor_motion)
1532         {
1533                 MaskAuto *keyframe = (MaskAuto*)gui->affected_keyframe;
1534                 SubMask *mask = keyframe->get_submask(mwindow->edl->session->cwindow_mask);
1535                 if(gui->affected_point < mask->points.total)
1536                 {
1537                         MaskPoint *point = mask->points.values[gui->affected_point];
1538 //                      float cursor_x = get_cursor_x();
1539 //                      float cursor_y = get_cursor_y();
1540 //                      canvas_to_output(mwindow->edl, 0, cursor_x, cursor_y);
1541                         float cursor_x = mask_cursor_x;
1542                         float cursor_y = mask_cursor_y;
1543 //printf("CWindowCanvas::do_mask 9 %d %d\n", mask->points.total, gui->affected_point);
1545                         float last_x = point->x;
1546                         float last_y = point->y;
1547                         float last_control_x1 = point->control_x1;
1548                         float last_control_y1 = point->control_y1;
1549                         float last_control_x2 = point->control_x2;
1550                         float last_control_y2 = point->control_y2;
1553                         switch(gui->current_operation)
1554                         {
1555                                 case CWINDOW_MASK:
1556                                         point->x = cursor_x - gui->x_origin + gui->center_x;
1557                                         point->y = cursor_y - gui->y_origin + gui->center_y;
1558                                         break;
1560                                 case CWINDOW_MASK_CONTROL_IN:
1561                                         point->control_x1 = cursor_x - gui->x_origin + gui->control_in_x;
1562                                         point->control_y1 = cursor_y - gui->y_origin + gui->control_in_y;
1563                                         break;
1565                                 case CWINDOW_MASK_CONTROL_OUT:
1566                                         point->control_x2 = cursor_x - gui->x_origin + gui->control_out_x;
1567                                         point->control_y2 = cursor_y - gui->y_origin + gui->control_out_y;
1568                                         break;
1570                                 case CWINDOW_MASK_TRANSLATE:
1571                                         for(int i = 0; i < mask->points.total; i++)
1572                                         {
1573                                                 mask->points.values[i]->x += cursor_x - gui->x_origin;
1574                                                 mask->points.values[i]->y += cursor_y - gui->y_origin;
1575                                         }
1576                                         gui->x_origin = cursor_x;
1577                                         gui->y_origin = cursor_y;
1578                                         break;
1579                         }
1582                         if( !EQUIV(last_x, point->x) ||
1583                                 !EQUIV(last_y, point->y) ||
1584                                 !EQUIV(last_control_x1, point->control_x1) ||
1585                                 !EQUIV(last_control_y1, point->control_y1) ||
1586                                 !EQUIV(last_control_x2, point->control_x2) ||
1587                                 !EQUIV(last_control_y2, point->control_y2))
1588                         {
1589                                 rerender = 1;
1590                                 redraw = 1;
1591                         }
1592                 }
1593                 result = 1;
1594         }
1595 //printf("CWindowCanvas::do_mask 2 %d %d %d\n", result, rerender, redraw);
1597         points.remove_all_objects();
1598 //printf("CWindowCanvas::do_mask 20\n");
1599         return result;
1603 int CWindowCanvas::do_eyedrop(int &rerender, int button_press)
1605         int result = 0;
1606         float cursor_x = get_cursor_x();
1607         float cursor_y = get_cursor_y();
1610         if(button_press)
1611         {
1612                 gui->current_operation = CWINDOW_EYEDROP;
1613         }
1615         if(gui->current_operation == CWINDOW_EYEDROP)
1616         {
1617                 canvas_to_output(mwindow->edl, 0, cursor_x, cursor_y);
1619 // Get color out of frame.
1620 // Doesn't work during playback because that bypasses the refresh frame.
1621                 if(refresh_frame)
1622                 {
1623                         CLAMP(cursor_x, 0, refresh_frame->get_w() - 1);
1624                         CLAMP(cursor_y, 0, refresh_frame->get_h() - 1);
1626 // Decompression coefficients straight out of jpeglib
1627 #define V_TO_R    1.40200
1628 #define V_TO_G    -0.71414
1630 #define U_TO_G    -0.34414
1631 #define U_TO_B    1.77200
1633 #define GET_COLOR(type, components, max, do_yuv) \
1634 { \
1635         type *row = (type*)(refresh_frame->get_rows()[(int)cursor_y]) + \
1636                 (int)cursor_x * components; \
1637         float red = (float)*row++ / max; \
1638         float green = (float)*row++ / max; \
1639         float blue = (float)*row++ / max; \
1640         if(do_yuv) \
1641         { \
1642                 mwindow->edl->local_session->red = red + V_TO_R * (blue - 0.5); \
1643                 mwindow->edl->local_session->green = red + U_TO_G * (green - 0.5) + V_TO_G * (blue - 0.5); \
1644                 mwindow->edl->local_session->blue = red + U_TO_B * (green - 0.5); \
1645         } \
1646         else \
1647         { \
1648                 mwindow->edl->local_session->red = red; \
1649                 mwindow->edl->local_session->green = green; \
1650                 mwindow->edl->local_session->blue = blue; \
1651         } \
1654                         switch(refresh_frame->get_color_model())
1655                         {
1656                                 case BC_YUV888:
1657                                         GET_COLOR(unsigned char, 3, 0xff, 1);
1658                                         break;
1659                                 case BC_YUVA8888:
1660                                         GET_COLOR(unsigned char, 4, 0xff, 1);
1661                                         break;
1662                                 case BC_YUV161616:
1663                                         GET_COLOR(uint16_t, 3, 0xffff, 1);
1664                                         break;
1665                                 case BC_YUVA16161616:
1666                                         GET_COLOR(uint16_t, 4, 0xffff, 1);
1667                                         break;
1668                                 case BC_RGB888:
1669                                         GET_COLOR(unsigned char, 3, 0xff, 0);
1670                                         break;
1671                                 case BC_RGBA8888:
1672                                         GET_COLOR(unsigned char, 4, 0xff, 0);
1673                                         break;
1674                                 case BC_RGB_FLOAT:
1675                                         GET_COLOR(float, 3, 1.0, 0);
1676                                         break;
1677                                 case BC_RGBA_FLOAT:
1678                                         GET_COLOR(float, 4, 1.0, 0);
1679                                         break;
1680                         }
1681                 }
1682                 else
1683                 {
1684                         mwindow->edl->local_session->red = 0;
1685                         mwindow->edl->local_session->green = 0;
1686                         mwindow->edl->local_session->blue = 0;
1687                 }
1690                 gui->update_tool();             
1694                 result = 1;
1695 // Can't rerender since the color value is from the output of any effect it
1696 // goes into.
1697 //              rerender = 1;
1698         }
1700         return result;
1703 void CWindowCanvas::draw_overlays()
1705         if(mwindow->edl->session->safe_regions)
1706         {
1707                 draw_safe_regions();
1708         }
1710         if(mwindow->edl->session->cwindow_scrollbars)
1711         {
1712 // Always draw output rectangle
1713                 float x1, y1, x2, y2;
1714                 x1 = 0;
1715                 x2 = mwindow->edl->session->output_w;
1716                 y1 = 0;
1717                 y2 = mwindow->edl->session->output_h;
1718                 output_to_canvas(mwindow->edl, 0, x1, y1);
1719                 output_to_canvas(mwindow->edl, 0, x2, y2);
1721                 get_canvas()->set_inverse();
1722                 get_canvas()->set_color(WHITE);
1724                 get_canvas()->draw_rectangle((int)x1, 
1725                                 (int)y1, 
1726                                 (int)(x2 - x1), 
1727                                 (int)(y2 - y1));
1729                 get_canvas()->set_opaque();
1730         }
1732         if(mwindow->session->ccanvas_highlighted)
1733         {
1734                 get_canvas()->set_color(WHITE);
1735                 get_canvas()->set_inverse();
1736                 get_canvas()->draw_rectangle(0, 0, get_canvas()->get_w(), get_canvas()->get_h());
1737                 get_canvas()->draw_rectangle(1, 1, get_canvas()->get_w() - 2, get_canvas()->get_h() - 2);
1738                 get_canvas()->set_opaque();
1739         }
1741         int temp1 = 0, temp2 = 0;
1742 //printf("CWindowCanvas::draw_overlays 1 %d\n", mwindow->edl->session->cwindow_operation);
1743         switch(mwindow->edl->session->cwindow_operation)
1744         {
1745                 case CWINDOW_CAMERA:
1746                         draw_bezier(1);
1747                         break;
1749                 case CWINDOW_PROJECTOR:
1750                         draw_bezier(0);
1751                         break;
1753                 case CWINDOW_CROP:
1754                         draw_crop();
1755                         break;
1757                 case CWINDOW_MASK:
1758                         do_mask(temp1, temp2, 0, 0, 1);
1759                         break;
1760         }
1763 void CWindowCanvas::draw_safe_regions()
1765         float action_x1, action_x2, action_y1, action_y2;
1766         float title_x1, title_x2, title_y1, title_y2;
1768         action_x1 = mwindow->edl->session->output_w / 2 - mwindow->edl->session->output_w / 2 * 0.9;
1769         action_x2 = mwindow->edl->session->output_w / 2 + mwindow->edl->session->output_w / 2 * 0.9;
1770         action_y1 = mwindow->edl->session->output_h / 2 - mwindow->edl->session->output_h / 2 * 0.9;
1771         action_y2 = mwindow->edl->session->output_h / 2 + mwindow->edl->session->output_h / 2 * 0.9;
1772         title_x1 = mwindow->edl->session->output_w / 2 - mwindow->edl->session->output_w / 2 * 0.8;
1773         title_x2 = mwindow->edl->session->output_w / 2 + mwindow->edl->session->output_w / 2 * 0.8;
1774         title_y1 = mwindow->edl->session->output_h / 2 - mwindow->edl->session->output_h / 2 * 0.8;
1775         title_y2 = mwindow->edl->session->output_h / 2 + mwindow->edl->session->output_h / 2 * 0.8;
1777         output_to_canvas(mwindow->edl, 0, action_x1, action_y1);
1778         output_to_canvas(mwindow->edl, 0, action_x2, action_y2);
1779         output_to_canvas(mwindow->edl, 0, title_x1, title_y1);
1780         output_to_canvas(mwindow->edl, 0, title_x2, title_y2);
1782         get_canvas()->set_inverse();
1783         get_canvas()->set_color(WHITE);
1785         get_canvas()->draw_rectangle((int)action_x1, 
1786                         (int)action_y1, 
1787                         (int)(action_x2 - action_x1), 
1788                         (int)(action_y2 - action_y1));
1789         get_canvas()->draw_rectangle((int)title_x1, 
1790                         (int)title_y1, 
1791                         (int)(title_x2 - title_x1), 
1792                         (int)(title_y2 - title_y1));
1794         get_canvas()->set_opaque();
1797 void CWindowCanvas::reset_keyframe(int do_camera)
1799         FloatAuto *x_keyframe = 0;
1800         FloatAuto *y_keyframe = 0;
1801         FloatAuto *z_keyframe = 0;
1802         Track *affected_track = 0;
1804         affected_track = gui->cwindow->calculate_affected_track();
1806         if(affected_track)
1807         {
1808                 gui->cwindow->calculate_affected_autos(&x_keyframe,
1809                         &y_keyframe,
1810                         &z_keyframe,
1811                         affected_track,
1812                         do_camera,
1813                         1,
1814                         1,
1815                         1);
1817                 x_keyframe->value = 0;
1818                 y_keyframe->value = 0;
1819                 z_keyframe->value = 1;
1821                 mwindow->sync_parameters(CHANGE_PARAMS);
1822                 gui->update_tool();
1823         }
1826 void CWindowCanvas::reset_camera()
1828         reset_keyframe(1);
1831 void CWindowCanvas::reset_projector()
1833         reset_keyframe(0);
1836 int CWindowCanvas::test_crop(int button_press, int &redraw)
1838         int result = 0;
1839         int handle_selected = -1;
1840         float x1 = mwindow->edl->session->crop_x1;
1841         float y1 = mwindow->edl->session->crop_y1;
1842         float x2 = mwindow->edl->session->crop_x2;
1843         float y2 = mwindow->edl->session->crop_y2;
1844         float cursor_x = get_cursor_x();
1845         float cursor_y = get_cursor_y();
1846         float canvas_x1 = x1;
1847         float canvas_y1 = y1;
1848         float canvas_x2 = x2;
1849         float canvas_y2 = y2;
1850         float canvas_cursor_x = cursor_x;
1851         float canvas_cursor_y = cursor_y;
1853         canvas_to_output(mwindow->edl, 0, cursor_x, cursor_y);
1854 // Use screen normalized coordinates for hot spot tests.
1855         output_to_canvas(mwindow->edl, 0, canvas_x1, canvas_y1);
1856         output_to_canvas(mwindow->edl, 0, canvas_x2, canvas_y2);
1859         if(gui->current_operation == CWINDOW_CROP)
1860         {
1861                 handle_selected = gui->crop_handle;
1862         }
1863         else
1864         if(canvas_cursor_x >= canvas_x1 && canvas_cursor_x < canvas_x1 + CROPHANDLE_W &&
1865                 canvas_cursor_y >= canvas_y1 && canvas_cursor_y < canvas_y1 + CROPHANDLE_H)
1866         {
1867                 handle_selected = 0;
1868                 gui->crop_origin_x = x1;
1869                 gui->crop_origin_y = y1;
1870         }
1871         else
1872         if(canvas_cursor_x >= canvas_x2 - CROPHANDLE_W && canvas_cursor_x < canvas_x2 &&
1873                 canvas_cursor_y >= canvas_y1 && canvas_cursor_y < canvas_y1 + CROPHANDLE_H)
1874         {
1875                 handle_selected = 1;
1876                 gui->crop_origin_x = x2;
1877                 gui->crop_origin_y = y1;
1878         }
1879         else
1880         if(canvas_cursor_x >= canvas_x1 && canvas_cursor_x < canvas_x1 + CROPHANDLE_W &&
1881                 canvas_cursor_y >= canvas_y2 - CROPHANDLE_H && canvas_cursor_y < canvas_y2)
1882         {
1883                 handle_selected = 2;
1884                 gui->crop_origin_x = x1;
1885                 gui->crop_origin_y = y2;
1886         }
1887         else
1888         if(canvas_cursor_x >= canvas_x2 - CROPHANDLE_W && canvas_cursor_x < canvas_x2 &&
1889                 canvas_cursor_y >= canvas_y2 - CROPHANDLE_H && canvas_cursor_y < canvas_y2)
1890         {
1891                 handle_selected = 3;
1892                 gui->crop_origin_x = x2;
1893                 gui->crop_origin_y = y2;
1894         }
1895         else
1896 // Start new box
1897         {
1898                 gui->crop_origin_x = cursor_x;
1899                 gui->crop_origin_y = cursor_y;
1900         }
1902 // printf("test crop %d %d\n", 
1903 //      gui->current_operation,
1904 //      handle_selected);
1906 // Start dragging.
1907         if(button_press)
1908         {
1909                 if(gui->alt_down())
1910                 {
1911                         gui->crop_translate = 1;
1912                         gui->crop_origin_x1 = x1;
1913                         gui->crop_origin_y1 = y1;
1914                         gui->crop_origin_x2 = x2;
1915                         gui->crop_origin_y2 = y2;
1916                 }
1917                 else
1918                         gui->crop_translate = 0;
1920                 gui->current_operation = CWINDOW_CROP;
1921                 gui->crop_handle = handle_selected;
1922                 gui->x_origin = cursor_x;
1923                 gui->y_origin = cursor_y;
1924                 result = 1;
1926                 if(handle_selected < 0 && !gui->crop_translate) 
1927                 {
1928                         x2 = x1 = cursor_x;
1929                         y2 = y1 = cursor_y;
1930                         mwindow->edl->session->crop_x1 = (int)x1;
1931                         mwindow->edl->session->crop_y1 = (int)y1;
1932                         mwindow->edl->session->crop_x2 = (int)x2;
1933                         mwindow->edl->session->crop_y2 = (int)y2;
1934                         redraw = 1;
1935                 }
1936         }
1937     else
1938 // Translate all 4 points
1939         if(gui->current_operation == CWINDOW_CROP && gui->crop_translate)
1940         {
1941                 x1 = cursor_x - gui->x_origin + gui->crop_origin_x1;
1942                 y1 = cursor_y - gui->y_origin + gui->crop_origin_y1;
1943                 x2 = cursor_x - gui->x_origin + gui->crop_origin_x2;
1944                 y2 = cursor_y - gui->y_origin + gui->crop_origin_y2;
1946                 mwindow->edl->session->crop_x1 = (int)x1;
1947                 mwindow->edl->session->crop_y1 = (int)y1;
1948                 mwindow->edl->session->crop_x2 = (int)x2;
1949                 mwindow->edl->session->crop_y2 = (int)y2;
1950                 result = 1;
1951                 redraw = 1;
1952         }
1953         else
1954 // Update dragging
1955         if(gui->current_operation == CWINDOW_CROP)
1956         {
1957                 switch(gui->crop_handle)
1958                 {
1959                         case -1:
1960                                 x1 = gui->crop_origin_x;
1961                                 y1 = gui->crop_origin_y;
1962                                 x2 = gui->crop_origin_x;
1963                                 y2 = gui->crop_origin_y;
1964                                 if(cursor_x < gui->x_origin)
1965                                 {
1966                                         if(cursor_y < gui->y_origin)
1967                                         {
1968                                                 x1 = cursor_x;
1969                                                 y1 = cursor_y;
1970                                         }
1971                                         else
1972                                         if(cursor_y >= gui->y_origin)
1973                                         {
1974                                                 x1 = cursor_x;
1975                                                 y2 = cursor_y;
1976                                         }
1977                                 }
1978                                 else
1979                                 if(cursor_x  >= gui->x_origin)
1980                                 {
1981                                         if(cursor_y < gui->y_origin)
1982                                         {
1983                                                 y1 = cursor_y;
1984                                                 x2 = cursor_x;
1985                                         }
1986                                         else
1987                                         if(cursor_y >= gui->y_origin)
1988                                         {
1989                                                 x2 = cursor_x;
1990                                                 y2 = cursor_y;
1991                                         }
1992                                 }
1994 // printf("test crop %d %d %d %d\n", 
1995 //      mwindow->edl->session->crop_x1,
1996 //      mwindow->edl->session->crop_y1,
1997 //      mwindow->edl->session->crop_x2,
1998 //      mwindow->edl->session->crop_y2);
1999                                 break;
2000                         case 0:
2001                                 x1 = cursor_x - gui->x_origin + gui->crop_origin_x;
2002                                 y1 = cursor_y - gui->y_origin + gui->crop_origin_y;
2003                                 break;
2004                         case 1:
2005                                 x2 = cursor_x - gui->x_origin + gui->crop_origin_x;
2006                                 y1 = cursor_y - gui->y_origin + gui->crop_origin_y;
2007                                 break;
2008                         case 2:
2009                                 x1 = cursor_x - gui->x_origin + gui->crop_origin_x;
2010                                 y2 = cursor_y - gui->y_origin + gui->crop_origin_y;
2011                                 break;
2012                         case 3:
2013                                 x2 = cursor_x - gui->x_origin + gui->crop_origin_x;
2014                                 y2 = cursor_y - gui->y_origin + gui->crop_origin_y;
2015                                 break;
2016                 }
2018                 if(!EQUIV(mwindow->edl->session->crop_x1, x1) ||
2019                         !EQUIV(mwindow->edl->session->crop_x2, x2) ||
2020                         !EQUIV(mwindow->edl->session->crop_y1, y1) ||
2021                         !EQUIV(mwindow->edl->session->crop_y2, y2))
2022                 {
2023                         if (x1 > x2) 
2024                         {
2025                                 float tmp = x1;
2026                                 x1 = x2;
2027                                 x2 = tmp;
2028                                 switch (gui->crop_handle) 
2029                                 {
2030                                         case 0: gui->crop_handle = 1; break;
2031                                         case 1: gui->crop_handle = 0; break;
2032                                         case 2: gui->crop_handle = 3; break;
2033                                         case 3: gui->crop_handle = 2; break;
2034                                         default: break;
2035                                 }
2037                         }
2038                         if (y1 > y2) 
2039                         {
2040                                 float tmp = y1;
2041                                 y1 = y2;
2042                                 y2 = tmp;
2043                                 switch (gui->crop_handle) 
2044                                 {
2045                                         case 0: gui->crop_handle = 2; break;
2046                                         case 1: gui->crop_handle = 3; break;
2047                                         case 2: gui->crop_handle = 0; break;
2048                                         case 3: gui->crop_handle = 1; break;
2049                                         default: break;
2050                                 }
2051                         }
2053                         mwindow->edl->session->crop_x1 = (int)x1;
2054                         mwindow->edl->session->crop_y1 = (int)y1;
2055                         mwindow->edl->session->crop_x2 = (int)x2;
2056                         mwindow->edl->session->crop_y2 = (int)y2;
2057                         result = 1;
2058                         redraw = 1;
2059                 }
2060         }
2061         else
2062 // Update cursor font
2063         if(handle_selected >= 0)
2064         {
2065                 switch(handle_selected)
2066                 {
2067                         case 0:
2068                                 set_cursor(UPLEFT_RESIZE);
2069                                 break;
2070                         case 1:
2071                                 set_cursor(UPRIGHT_RESIZE);
2072                                 break;
2073                         case 2:
2074                                 set_cursor(DOWNLEFT_RESIZE);
2075                                 break;
2076                         case 3:
2077                                 set_cursor(DOWNRIGHT_RESIZE);
2078                                 break;
2079                 }
2080                 result = 1;
2081         }
2082         else
2083         {
2084                 set_cursor(ARROW_CURSOR);
2085         }
2086 #define CLAMP(x, y, z) ((x) = ((x) < (y) ? (y) : ((x) > (z) ? (z) : (x))))
2087         
2088         if(redraw)
2089         {
2090                 CLAMP(mwindow->edl->session->crop_x1, 0, mwindow->edl->session->output_w);
2091                 CLAMP(mwindow->edl->session->crop_x2, 0, mwindow->edl->session->output_w);
2092                 CLAMP(mwindow->edl->session->crop_y1, 0, mwindow->edl->session->output_h);
2093                 CLAMP(mwindow->edl->session->crop_y2, 0, mwindow->edl->session->output_h);
2094 // printf("CWindowCanvas::test_crop %d %d %d %d\n", 
2095 //      mwindow->edl->session->crop_x2,
2096 //      mwindow->edl->session->crop_y2,
2097 //      mwindow->edl->calculate_output_w(0), 
2098 //      mwindow->edl->calculate_output_h(0));
2099         }
2100         return result;
2104 void CWindowCanvas::draw_crop()
2106         get_canvas()->set_inverse();
2107         get_canvas()->set_color(WHITE);
2109         float x1 = mwindow->edl->session->crop_x1;
2110         float y1 = mwindow->edl->session->crop_y1;
2111         float x2 = mwindow->edl->session->crop_x2;
2112         float y2 = mwindow->edl->session->crop_y2;
2114         output_to_canvas(mwindow->edl, 0, x1, y1);
2115         output_to_canvas(mwindow->edl, 0, x2, y2);
2117         if(x2 - x1 && y2 - y1)
2118                 get_canvas()->draw_rectangle((int)x1, 
2119                         (int)y1, 
2120                         (int)(x2 - x1), 
2121                         (int)(y2 - y1));
2123         draw_crophandle((int)x1, (int)y1);
2124         draw_crophandle((int)x2 - CROPHANDLE_W, (int)y1);
2125         draw_crophandle((int)x1, (int)y2 - CROPHANDLE_H);
2126         draw_crophandle((int)x2 - CROPHANDLE_W, (int)y2 - CROPHANDLE_H);
2127         get_canvas()->set_opaque();
2137 void CWindowCanvas::draw_bezier(int do_camera)
2139         Track *track = gui->cwindow->calculate_affected_track();
2140         
2141         if(!track) return;
2143         float center_x;
2144         float center_y;
2145         float center_z;
2146         int64_t position = track->to_units(
2147                 mwindow->edl->local_session->get_selectionstart(1), 
2148                 0);
2150         track->automation->get_projector(&center_x, 
2151                 &center_y, 
2152                 &center_z, 
2153                 position,
2154                 PLAY_FORWARD);
2156 //      center_x += track->track_w / 2;
2157 //      center_y += track->track_h / 2;
2158         center_x += mwindow->edl->session->output_w / 2;
2159         center_y += mwindow->edl->session->output_h / 2;
2160         float track_x1 = center_x - track->track_w / 2 * center_z;
2161         float track_y1 = center_y - track->track_h / 2 * center_z;
2162         float track_x2 = track_x1 + track->track_w * center_z;
2163         float track_y2 = track_y1 + track->track_h * center_z;
2165         output_to_canvas(mwindow->edl, 0, track_x1, track_y1);
2166         output_to_canvas(mwindow->edl, 0, track_x2, track_y2);
2168 #define DRAW_PROJECTION(offset) \
2169         get_canvas()->draw_rectangle((int)track_x1 + offset, \
2170                 (int)track_y1 + offset, \
2171                 (int)(track_x2 - track_x1), \
2172                 (int)(track_y2 - track_y1)); \
2173         get_canvas()->draw_line((int)track_x1 + offset,  \
2174                 (int)track_y1 + offset, \
2175                 (int)track_x2 + offset, \
2176                 (int)track_y2 + offset); \
2177         get_canvas()->draw_line((int)track_x2 + offset,  \
2178                 (int)track_y1 + offset, \
2179                 (int)track_x1 + offset, \
2180                 (int)track_y2 + offset); \
2183 // Drop shadow
2184         get_canvas()->set_color(BLACK);
2185         DRAW_PROJECTION(1);
2187 //      canvas->set_inverse();
2188         if(do_camera)
2189                 get_canvas()->set_color(GREEN);
2190         else
2191                 get_canvas()->set_color(RED);
2193         DRAW_PROJECTION(0);
2194 //      canvas->set_opaque();
2200 int CWindowCanvas::test_bezier(int button_press, 
2201         int &redraw, 
2202         int &redraw_canvas,
2203         int &rerender,
2204         int do_camera)
2206         int result = 0;
2208 // Processing drag operation.
2209 // Create keyframe during first cursor motion.
2210         if(!button_press)
2211         {
2213                 float cursor_x = get_cursor_x();
2214                 float cursor_y = get_cursor_y();
2215                 canvas_to_output(mwindow->edl, 0, cursor_x, cursor_y);
2217                 if(gui->current_operation == CWINDOW_CAMERA ||
2218                         gui->current_operation == CWINDOW_PROJECTOR)
2219                 {
2220                         if(!gui->ctrl_down() && gui->shift_down() && !gui->translating_zoom)
2221                         {
2222                                 gui->translating_zoom = 1;
2223                                 gui->reset_affected();
2224                         }
2225                         else
2226                         if(!gui->ctrl_down() && !gui->shift_down() && gui->translating_zoom)
2227                         {
2228                                 gui->translating_zoom = 0;
2229                                 gui->reset_affected();
2230                         }
2232 // Get target keyframe
2233                         float last_center_x;
2234                         float last_center_y;
2235                         float last_center_z;
2236                         int created;
2238                         if(!gui->affected_x && !gui->affected_y && !gui->affected_z)
2239                         {
2240                                 FloatAutos *affected_x_autos;
2241                                 FloatAutos *affected_y_autos;
2242                                 FloatAutos *affected_z_autos;
2243                                 if(!gui->affected_track) return 0;
2244                                 double position = mwindow->edl->local_session->get_selectionstart(1);
2245                                 int64_t track_position = gui->affected_track->to_units(position, 0);
2247                                 if(mwindow->edl->session->cwindow_operation == CWINDOW_CAMERA)
2248                                 {
2249                                         affected_x_autos = (FloatAutos*)gui->affected_track->automation->autos[AUTOMATION_CAMERA_X];
2250                                         affected_y_autos = (FloatAutos*)gui->affected_track->automation->autos[AUTOMATION_CAMERA_Y];
2251                                         affected_z_autos = (FloatAutos*)gui->affected_track->automation->autos[AUTOMATION_CAMERA_Z];
2252                                 }
2253                                 else
2254                                 {
2255                                         affected_x_autos = (FloatAutos*)gui->affected_track->automation->autos[AUTOMATION_PROJECTOR_X];
2256                                         affected_y_autos = (FloatAutos*)gui->affected_track->automation->autos[AUTOMATION_PROJECTOR_Y];
2257                                         affected_z_autos = (FloatAutos*)gui->affected_track->automation->autos[AUTOMATION_PROJECTOR_Z];
2258                                 }
2261                                 if(gui->translating_zoom)
2262                                 {
2263                                         FloatAuto *previous = 0;
2264                                         FloatAuto *next = 0;
2265                                         float new_z = affected_z_autos->get_value(
2266                                                 track_position, 
2267                                                 PLAY_FORWARD,
2268                                                 previous,
2269                                                 next);
2270                                         gui->affected_z = 
2271                                                 (FloatAuto*)gui->cwindow->calculate_affected_auto(
2272                                                         affected_z_autos, 1, &created, 0);
2273                                         if(created) 
2274                                         {
2275                                                 gui->affected_z->value = new_z;
2276                                                 gui->affected_z->control_in_value = 0;
2277                                                 gui->affected_z->control_out_value = 0;
2278                                                 gui->affected_z->control_in_position = 0;
2279                                                 gui->affected_z->control_out_position = 0;
2280                                                 redraw_canvas = 1;
2281                                         }
2282                                 }
2283                                 else
2284                                 {
2285                                         FloatAuto *previous = 0;
2286                                         FloatAuto *next = 0;
2287                                         float new_x = affected_x_autos->get_value(
2288                                                 track_position, 
2289                                                 PLAY_FORWARD,
2290                                                 previous,
2291                                                 next);
2292                                         previous = 0;
2293                                         next = 0;
2294                                         float new_y = affected_y_autos->get_value(
2295                                                 track_position, 
2296                                                 PLAY_FORWARD,
2297                                                 previous,
2298                                                 next);
2299                                         gui->affected_x = 
2300                                                 (FloatAuto*)gui->cwindow->calculate_affected_auto(
2301                                                         affected_x_autos, 1, &created, 0);
2302                                         if(created) 
2303                                         {
2304                                                 gui->affected_x->value = new_x;
2305                                                 gui->affected_x->control_in_value = 0;
2306                                                 gui->affected_x->control_out_value = 0;
2307                                                 gui->affected_x->control_in_position = 0;
2308                                                 gui->affected_x->control_out_position = 0;
2309                                                 redraw_canvas = 1;
2310                                         }
2311                                         gui->affected_y = 
2312                                                 (FloatAuto*)gui->cwindow->calculate_affected_auto(
2313                                                         affected_y_autos, 1, &created, 0);
2314                                         if(created) 
2315                                         {
2316                                                 gui->affected_y->value = new_y;
2317                                                 gui->affected_y->control_in_value = 0;
2318                                                 gui->affected_y->control_out_value = 0;
2319                                                 gui->affected_y->control_in_position = 0;
2320                                                 gui->affected_y->control_out_position = 0;
2321                                                 redraw_canvas = 1;
2322                                         }
2323                                 }
2325                                 calculate_origin();
2327                                 if(gui->translating_zoom)
2328                                 {
2329                                         gui->center_z = gui->affected_z->value;
2330                                 }
2331                                 else
2332                                 {
2333                                         gui->center_x = gui->affected_x->value;
2334                                         gui->center_y = gui->affected_y->value;
2335                                 }
2337                                 rerender = 1;
2338                                 redraw = 1;
2339                         }
2342                         if(gui->translating_zoom)
2343                         {
2344                                 last_center_z = gui->affected_z->value;
2345                         }
2346                         else
2347                         {
2348                                 last_center_x = gui->affected_x->value;
2349                                 last_center_y = gui->affected_y->value;
2350                         }
2352                         if(gui->translating_zoom)
2353                         {
2354                                 gui->affected_z->value = gui->center_z + 
2355                                         (cursor_y - gui->y_origin) / 128;
2357                                 if(gui->affected_z->value < 0) gui->affected_z->value = 0;
2358                                 if(!EQUIV(last_center_z, gui->affected_z->value))
2359                                 {
2360                                         rerender = 1;
2361                                         redraw = 1;
2362                                         redraw_canvas = 1;
2363                                 }
2364                         }
2365                         else
2366                         {
2367                                 gui->affected_x->value = gui->center_x + cursor_x - gui->x_origin;
2368                                 gui->affected_y->value = gui->center_y + cursor_y - gui->y_origin;
2369                                 if(!EQUIV(last_center_x,  gui->affected_x->value) ||
2370                                         !EQUIV(last_center_y, gui->affected_y->value))
2371                                 {
2372                                         rerender = 1;
2373                                         redraw = 1;
2374                                         redraw_canvas = 1;
2375                                 }
2376                         }
2377                 }
2379                 result = 1;
2380         }
2381         else
2382 // Begin drag operation.  Don't create keyframe here.
2383         {
2384 // Get affected track off of the first recordable video track.
2385 // Calculating based on the alpha channel would require recording what layer
2386 // each output pixel belongs to as they're rendered and stacked.  Forget it.
2387                 gui->affected_track = gui->cwindow->calculate_affected_track();
2388                 gui->reset_affected();
2390                 if(gui->affected_track)
2391                 {
2392                         gui->current_operation = 
2393                                 mwindow->edl->session->cwindow_operation;
2394                         result = 1;
2395                 }
2396         }
2397         
2398         return result;
2401 int CWindowCanvas::test_zoom(int &redraw)
2403         int result = 0;
2404         float zoom = get_zoom();
2405         float x;
2406         float y;
2408         if(!mwindow->edl->session->cwindow_scrollbars)
2409         {
2410                 mwindow->edl->session->cwindow_scrollbars = 1;
2411                 zoom = 1.0;
2412                 x = mwindow->edl->session->output_w / 2;
2413                 y = mwindow->edl->session->output_h / 2;
2414         }
2415         else
2416         {
2417                 x = get_cursor_x();
2418                 y = get_cursor_y();
2419                 canvas_to_output(mwindow->edl, 
2420                                 0, 
2421                                 x, 
2422                                 y);
2424 //printf("CWindowCanvas::test_zoom 1 %f %f\n", x, y);
2426 // Find current zoom in table
2427                 int current_index = 0;
2428                 for(current_index = 0 ; current_index < total_zooms; current_index++)
2429                         if(EQUIV(my_zoom_table[current_index], zoom)) break;
2432 // Zoom out
2433                 if(get_buttonpress() == 5 ||
2434                         gui->ctrl_down() || 
2435                         gui->shift_down())
2436                 {
2437                         current_index--;
2438                 }
2439                 else
2440 // Zoom in
2441                 {
2442                         current_index++;
2443                 }
2444                 CLAMP(current_index, 0, total_zooms - 1);
2445                 zoom = my_zoom_table[current_index];
2446         }
2448         x = x - w / zoom / 2;
2449         y = y - h / zoom / 2;
2452         int x_i = (int)x;
2453         int y_i = (int)y;
2454 //      check_boundaries(mwindow->edl, x_i, y_i, zoom);
2456 //printf("CWindowCanvas::test_zoom 2 %d %d\n", x_i, y_i);
2458         update_zoom(x_i, 
2459                         y_i, 
2460                         zoom);
2461         reposition_window(mwindow->edl, 
2462                         mwindow->theme->ccanvas_x,
2463                         mwindow->theme->ccanvas_y,
2464                         mwindow->theme->ccanvas_w,
2465                         mwindow->theme->ccanvas_h);
2466         redraw = 1;
2467         result = 1;
2469         
2470         gui->zoom_panel->update(zoom);
2471         
2472         return result;
2476 void CWindowCanvas::calculate_origin()
2478         gui->x_origin = get_cursor_x();
2479         gui->y_origin = get_cursor_y();
2480 //printf("CWindowCanvas::calculate_origin 1 %f %f\n", gui->x_origin, gui->y_origin);
2481         canvas_to_output(mwindow->edl, 0, gui->x_origin, gui->y_origin);
2482 //printf("CWindowCanvas::calculate_origin 2 %f %f\n", gui->x_origin, gui->y_origin);
2486 int CWindowCanvas::cursor_leave_event()
2488         set_cursor(ARROW_CURSOR);
2489         return 1;
2492 int CWindowCanvas::cursor_enter_event()
2494         int redraw = 0;
2495         switch(mwindow->edl->session->cwindow_operation)
2496         {
2497                 case CWINDOW_CAMERA:
2498                 case CWINDOW_PROJECTOR:
2499                         set_cursor(MOVE_CURSOR);
2500                         break;
2501                 case CWINDOW_ZOOM:
2502                         set_cursor(MOVE_CURSOR);
2503                         break;
2504                 case CWINDOW_CROP:
2505                         test_crop(0, redraw);
2506                         break;
2507                 case CWINDOW_PROTECT:
2508                         set_cursor(ARROW_CURSOR);
2509                         break;
2510                 case CWINDOW_MASK:
2511                         set_cursor(CROSS_CURSOR);
2512                         break;
2513                 case CWINDOW_EYEDROP:
2514                         set_cursor(CROSS_CURSOR);
2515                         break;
2516         }
2517         return 1;
2520 int CWindowCanvas::cursor_motion_event()
2522         int redraw = 0, result = 0, rerender = 0, redraw_canvas = 0;
2525         switch(gui->current_operation)
2526         {
2527                 case CWINDOW_SCROLL:
2528                 {
2529                         float zoom = get_zoom();
2530                         float cursor_x = get_cursor_x();
2531                         float cursor_y = get_cursor_y();
2533                         float zoom_x, zoom_y, conformed_w, conformed_h;
2534                         get_zooms(mwindow->edl, 0, zoom_x, zoom_y, conformed_w, conformed_h);
2535                         cursor_x = (float)cursor_x / zoom_x + gui->x_offset;
2536                         cursor_y = (float)cursor_y / zoom_y + gui->y_offset;
2540                         int x = (int)(gui->x_origin - cursor_x + gui->x_offset);
2541                         int y = (int)(gui->y_origin - cursor_y + gui->y_offset);
2543                         update_zoom(x, 
2544                                 y, 
2545                                 zoom);
2546                         update_scrollbars();
2547                         redraw = 1;
2548                         result = 1;
2549                         break;
2550                 }
2552                 case CWINDOW_CAMERA:
2553                         result = test_bezier(0, redraw, redraw_canvas, rerender, 1);
2554                         break;
2556                 case CWINDOW_PROJECTOR:
2557                         result = test_bezier(0, redraw, redraw_canvas, rerender, 0);
2558                         break;
2561                 case CWINDOW_CROP:
2562 //printf("CWindowCanvas::cursor_motion_event 1 %d %d\n", x, y);
2563                         result = test_crop(0, redraw);
2564                         break;
2566                 case CWINDOW_MASK:
2567                 case CWINDOW_MASK_CONTROL_IN:
2568                 case CWINDOW_MASK_CONTROL_OUT:
2569                 case CWINDOW_MASK_TRANSLATE:
2570                         result = do_mask(redraw, 
2571                                 rerender, 
2572                                 0, 
2573                                 1,
2574                                 0);
2575                         break;
2577                 case CWINDOW_EYEDROP:
2578                         result = do_eyedrop(rerender, 0);
2579                         break;
2581         }
2585         if(!result)
2586         {
2587                 switch(mwindow->edl->session->cwindow_operation)
2588                 {
2589                         case CWINDOW_CROP:
2590                                 result = test_crop(0, redraw);
2591                                 break;
2592                 }
2593         }
2596 // If the window is never unlocked before calling send_command the
2597 // display shouldn't get stuck on the old video frame although it will
2598 // flicker between the old video frame and the new video frame.
2600         if(redraw)
2601         {
2602                 draw_refresh();
2603                 gui->update_tool();
2604         }
2606         if(redraw_canvas)
2607         {
2608                 mwindow->gui->lock_window("CWindowCanvas::cursor_motion_event 1");
2609                 mwindow->gui->canvas->draw_overlays();
2610                 mwindow->gui->canvas->flash();
2611                 mwindow->gui->unlock_window();
2612         }
2614         if(rerender)
2615         {
2616                 mwindow->restart_brender();
2617                 mwindow->sync_parameters(CHANGE_PARAMS);
2618                 gui->cwindow->playback_engine->que->send_command(CURRENT_FRAME, 
2619                         CHANGE_NONE,
2620                         mwindow->edl,
2621                         1);
2622                 if(!redraw) gui->update_tool();
2623         }
2624         return result;
2627 int CWindowCanvas::button_press_event()
2629         int result = 0;
2630         int redraw = 0;
2631         int redraw_canvas = 0;
2632         int rerender = 0;
2634         if(Canvas::button_press_event()) return 1;
2636         gui->translating_zoom = gui->shift_down(); 
2638         calculate_origin();
2639 //printf("CWindowCanvas::button_press_event 2 %f %f\n", gui->x_origin, gui->y_origin, gui->x_origin, gui->y_origin);
2641         float zoom_x, zoom_y, conformed_w, conformed_h;
2642         get_zooms(mwindow->edl, 0, zoom_x, zoom_y, conformed_w, conformed_h);
2643         gui->x_offset = get_x_offset(mwindow->edl, 0, zoom_x, conformed_w, conformed_h);
2644         gui->y_offset = get_y_offset(mwindow->edl, 0, zoom_y, conformed_w, conformed_h);
2646 // Scroll view
2647         if(get_buttonpress() == 2)
2648         {
2649                 gui->current_operation = CWINDOW_SCROLL;
2650                 result = 1;
2651         }
2652         else
2653 // Adjust parameter
2654         {
2655                 switch(mwindow->edl->session->cwindow_operation)
2656                 {
2657                         case CWINDOW_CAMERA:
2658                                 result = test_bezier(1, redraw, redraw_canvas, rerender, 1);
2659                                 break;
2661                         case CWINDOW_PROJECTOR:
2662                                 result = test_bezier(1, redraw, redraw_canvas, rerender, 0);
2663                                 break;
2665                         case CWINDOW_ZOOM:
2666                                 result = test_zoom(redraw);
2667                                 break;
2669                         case CWINDOW_CROP:
2670                                 result = test_crop(1, redraw);
2671                                 break;
2673                         case CWINDOW_MASK:
2674                                 if(get_buttonpress() == 1)
2675                                         result = do_mask(redraw, rerender, 1, 0, 0);
2676                                 break;
2678                         case CWINDOW_EYEDROP:
2679                                 result = do_eyedrop(rerender, 1);
2680                                 break;
2681                 }
2682         }
2684         if(redraw)
2685         {
2686                 draw_refresh();
2687                 gui->update_tool();
2688         }
2690 // rerendering can also be caused by press event
2691         if(rerender) 
2692         {
2693                 mwindow->restart_brender();
2694                 mwindow->sync_parameters(CHANGE_PARAMS);
2695                 gui->cwindow->playback_engine->que->send_command(CURRENT_FRAME, 
2696                         CHANGE_NONE,
2697                         mwindow->edl,
2698                         1);
2699                 if(!redraw) gui->update_tool();
2700         }
2701         return result;
2704 int CWindowCanvas::button_release_event()
2706         int result = 0;
2708         switch(gui->current_operation)
2709         {
2710                 case CWINDOW_SCROLL:
2711                         result = 1;
2712                         break;
2714                 case CWINDOW_CAMERA:
2715                         mwindow->undo->update_undo(_("camera"), LOAD_AUTOMATION);
2716                         break;
2718                 case CWINDOW_PROJECTOR:
2719                         mwindow->undo->update_undo(_("projector"), LOAD_AUTOMATION);
2720                         break;
2722                 case CWINDOW_MASK:
2723                 case CWINDOW_MASK_CONTROL_IN:
2724                 case CWINDOW_MASK_CONTROL_OUT:
2725                 case CWINDOW_MASK_TRANSLATE:
2726                         mwindow->undo->update_undo(_("mask point"), LOAD_AUTOMATION);
2727                         break;
2729         }
2731         gui->current_operation = CWINDOW_NONE;
2732         return result;
2735 void CWindowCanvas::zoom_resize_window(float percentage)
2737         int canvas_w, canvas_h;
2738         calculate_sizes(mwindow->edl->get_aspect_ratio(), 
2739                 mwindow->edl->session->output_w, 
2740                 mwindow->edl->session->output_h, 
2741                 percentage,
2742                 canvas_w,
2743                 canvas_h);
2744         int new_w, new_h;
2745         new_w = canvas_w + (gui->get_w() - mwindow->theme->ccanvas_w);
2746         new_h = canvas_h + (gui->get_h() - mwindow->theme->ccanvas_h);
2747         gui->resize_window(new_w, new_h);
2748         gui->resize_event(new_w, new_h);
2751 void CWindowCanvas::toggle_controls()
2753         mwindow->session->cwindow_controls = !mwindow->session->cwindow_controls;
2754         gui->resize_event(gui->get_w(), gui->get_h());
2757 int CWindowCanvas::get_cwindow_controls()
2759         return mwindow->session->cwindow_controls;