r1006: configure: Use libx264_pic instead of libx264 if available.
[cinelerra_cv/mob.git] / cinelerra / cwindowgui.C
blobddce780254091080887e09437233c8fee32ca0d9
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                 0, // locklabels
627                 1,
628                 1,
629                 1,
630                 0,
631                 1)
633         this->mwindow = mwindow;
634         this->cwindow = cwindow;
637 void CWindowEditing::set_inpoint()
639         mwindow->set_inpoint(0);
642 void CWindowEditing::set_outpoint()
644         mwindow->set_outpoint(0);
651 CWindowMeters::CWindowMeters(MWindow *mwindow, CWindowGUI *gui, int x, int y, int h)
652  : MeterPanel(mwindow, 
653                 gui,
654                 x,
655                 y,
656                 h,
657                 mwindow->edl->session->audio_channels,
658                 mwindow->edl->session->cwindow_meter)
660         this->mwindow = mwindow;
661         this->gui = gui;
664 CWindowMeters::~CWindowMeters()
668 int CWindowMeters::change_status_event()
670         mwindow->edl->session->cwindow_meter = use_meters;
671         mwindow->theme->get_cwindow_sizes(gui, mwindow->session->cwindow_controls);
672         gui->resize_event(gui->get_w(), gui->get_h());
673         return 1;
679 CWindowZoom::CWindowZoom(MWindow *mwindow, CWindowGUI *gui, int x, int y)
680  : ZoomPanel(mwindow, 
681         gui, 
682         (double)mwindow->edl->session->cwindow_zoom, 
683         x, 
684         y,
685         80, 
686         my_zoom_table, 
687         total_zooms, 
688         ZOOM_PERCENTAGE)
690         this->mwindow = mwindow;
691         this->gui = gui;
694 CWindowZoom::~CWindowZoom()
698 int CWindowZoom::handle_event()
700         if(!strcasecmp(AUTO_ZOOM, get_text()))
701         {
702                 gui->zoom_canvas(1, get_value(), 0);
703         }
704         else
705         {
706                 gui->zoom_canvas(0, get_value(), 0);
707         }
709         return 1;
714 CWindowSlider::CWindowSlider(MWindow *mwindow, CWindow *cwindow, int x, int y, int pixels)
715  : BC_PercentageSlider(x, 
716                         y,
717                         0,
718                         pixels, 
719                         pixels, 
720                         0, 
721                         1, 
722                         0)
724         this->mwindow = mwindow;
725         this->cwindow = cwindow;
726         set_precision(0.00001);
727         set_pagination(1.0, 10.0);
730 CWindowSlider::~CWindowSlider()
734 int CWindowSlider::handle_event()
736         unlock_window();
737         cwindow->playback_engine->interrupt_playback(1);
738         lock_window("CWindowSlider::handle_event 1");
739         
740         mwindow->gui->lock_window("CWindowSlider::handle_event 2");
741         mwindow->select_point((double)get_value());
742         mwindow->gui->unlock_window();
743         return 1;
746 void CWindowSlider::set_position()
748         double new_length = mwindow->edl->tracks->total_playable_length();
749         if(mwindow->edl->local_session->preview_end <= 0 ||
750                 mwindow->edl->local_session->preview_end > new_length)
751                 mwindow->edl->local_session->preview_end = new_length;
752         if(mwindow->edl->local_session->preview_start > 
753                 mwindow->edl->local_session->preview_end)
754                 mwindow->edl->local_session->preview_start = 0;
758         update(mwindow->theme->cslider_w, 
759                 mwindow->edl->local_session->get_selectionstart(1), 
760                 mwindow->edl->local_session->preview_start, 
761                 mwindow->edl->local_session->preview_end);
765 int CWindowSlider::increase_value()
767         unlock_window();
768         cwindow->gui->transport->handle_transport(SINGLE_FRAME_FWD);
769         lock_window("CWindowSlider::increase_value");
770         return 1;
773 int CWindowSlider::decrease_value()
775         unlock_window();
776         cwindow->gui->transport->handle_transport(SINGLE_FRAME_REWIND);
777         lock_window("CWindowSlider::decrease_value");
778         return 1;
782 // CWindowDestination::CWindowDestination(MWindow *mwindow, CWindowGUI *cwindow, int x, int y)
783 //  : BC_PopupTextBox(cwindow, 
784 //      &cwindow->destinations, 
785 //      cwindow->destinations.values[cwindow->cwindow->destination]->get_text(),
786 //      x, 
787 //      y, 
788 //      70, 
789 //      200)
790 // {
791 //      this->mwindow = mwindow;
792 //      this->cwindow = cwindow;
793 // }
794 // 
795 // CWindowDestination::~CWindowDestination()
796 // {
797 // }
798 // 
799 // int CWindowDestination::handle_event()
800 // {
801 //      return 1;
802 // }
805 CWindowTransport::CWindowTransport(MWindow *mwindow, 
806         CWindowGUI *gui, 
807         int x, 
808         int y)
809  : PlayTransport(mwindow, 
810         gui, 
811         x, 
812         y)
814         this->gui = gui;
817 EDL* CWindowTransport::get_edl()
819         return mwindow->edl;
822 void CWindowTransport::goto_start()
824         gui->unlock_window();
825         handle_transport(REWIND, 1);
827         mwindow->gui->lock_window("CWindowTransport::goto_start 1");
828         mwindow->goto_start();
829         mwindow->gui->unlock_window();
831         gui->lock_window("CWindowTransport::goto_start 2");
834 void CWindowTransport::goto_end()
836         gui->unlock_window();
837         handle_transport(GOTO_END, 1);
839         mwindow->gui->lock_window("CWindowTransport::goto_end 1");
840         mwindow->goto_end();
841         mwindow->gui->unlock_window();
843         gui->lock_window("CWindowTransport::goto_end 2");
848 CWindowCanvas::CWindowCanvas(MWindow *mwindow, CWindowGUI *gui)
849  : Canvas(mwindow,
850         gui,
851         mwindow->theme->ccanvas_x,
852         mwindow->theme->ccanvas_y,
853         mwindow->theme->ccanvas_w,
854         mwindow->theme->ccanvas_h,
855         0,
856         0,
857         mwindow->edl->session->cwindow_scrollbars,
858         1)
860         this->mwindow = mwindow;
861         this->gui = gui;
864 void CWindowCanvas::status_event()
866         gui->draw_status();
869 int CWindowCanvas::get_fullscreen()
871         return mwindow->session->cwindow_fullscreen;
874 void CWindowCanvas::set_fullscreen(int value)
876         mwindow->session->cwindow_fullscreen = value;
880 void CWindowCanvas::update_zoom(int x, int y, float zoom)
882         use_scrollbars = mwindow->edl->session->cwindow_scrollbars;
884         mwindow->edl->session->cwindow_xscroll = x;
885         mwindow->edl->session->cwindow_yscroll = y;
886         mwindow->edl->session->cwindow_zoom = zoom;
889 void CWindowCanvas::zoom_auto()
891         gui->zoom_canvas(1, 1.0, 1);
894 int CWindowCanvas::get_xscroll()
896         return mwindow->edl->session->cwindow_xscroll;
899 int CWindowCanvas::get_yscroll()
901         return mwindow->edl->session->cwindow_yscroll;
905 float CWindowCanvas::get_zoom()
907         return mwindow->edl->session->cwindow_zoom;
910 void CWindowCanvas::draw_refresh()
912         if(get_canvas() && !get_canvas()->get_video_on())
913         {
915                 if(refresh_frame)
916                 {
917                         float in_x1, in_y1, in_x2, in_y2;
918                         float out_x1, out_y1, out_x2, out_y2;
919                         get_transfers(mwindow->edl, 
920                                 in_x1, 
921                                 in_y1, 
922                                 in_x2, 
923                                 in_y2, 
924                                 out_x1, 
925                                 out_y1, 
926                                 out_x2, 
927                                 out_y2);
929                         get_canvas()->clear_box(0, 
930                                 0, 
931                                 get_canvas()->get_w(), 
932                                 get_canvas()->get_h());
934 // printf("CWindowCanvas::draw_refresh %f %f %f %f -> %f %f %f %f\n", 
935 // in_x1, in_y1, in_x2, in_y2, out_x1, out_y1, out_x2, out_y2);
938                         if(out_x2 > out_x1 && 
939                                 out_y2 > out_y1 && 
940                                 in_x2 > in_x1 && 
941                                 in_y2 > in_y1)
942                         {
943 // Can't use OpenGL here because it is called asynchronously of the
944 // playback operation.
945                                 get_canvas()->draw_vframe(refresh_frame,
946                                                 (int)out_x1, 
947                                                 (int)out_y1, 
948                                                 (int)(out_x2 - out_x1), 
949                                                 (int)(out_y2 - out_y1),
950                                                 (int)in_x1, 
951                                                 (int)in_y1, 
952                                                 (int)(in_x2 - in_x1), 
953                                                 (int)(in_y2 - in_y1),
954                                                 0);
955                         }
956                 }
958                 draw_overlays();
959                 get_canvas()->flash();
960         }
961 //printf("CWindowCanvas::draw_refresh 10\n");
964 #define CROPHANDLE_W 10
965 #define CROPHANDLE_H 10
967 void CWindowCanvas::draw_crophandle(int x, int y)
969         get_canvas()->draw_box(x, y, CROPHANDLE_W, CROPHANDLE_H);
972 #define CONTROL_W 10
973 #define CONTROL_H 10
974 #define FIRST_CONTROL_W 20
975 #define FIRST_CONTROL_H 20
976 #undef BC_INFINITY
977 #define BC_INFINITY 65536
978 #ifndef SQR
979 #define SQR(x) ((x) * (x))
980 #endif
982 int CWindowCanvas::do_mask(int &redraw, 
983                 int &rerender, 
984                 int button_press, 
985                 int cursor_motion,
986                 int draw)
988 // Retrieve points from top recordable track
989 //printf("CWindowCanvas::do_mask 1\n");
990         Track *track = gui->cwindow->calculate_affected_track();
991 //printf("CWindowCanvas::do_mask 2\n");
993         if(!track) return 0;
994 //printf("CWindowCanvas::do_mask 3\n");
996         MaskAutos *mask_autos = (MaskAutos*)track->automation->autos[AUTOMATION_MASK];
997         int64_t position = track->to_units(
998                 mwindow->edl->local_session->get_selectionstart(1),
999                 0);
1000         ArrayList<MaskPoint*> points;
1001         mask_autos->get_points(&points, mwindow->edl->session->cwindow_mask,
1002                 position, 
1003                 PLAY_FORWARD);
1004 //printf("CWindowCanvas::do_mask 4\n");
1006 // Projector zooms relative to the center of the track output.
1007         float half_track_w = (float)track->track_w / 2;
1008         float half_track_h = (float)track->track_h / 2;
1009 // Translate mask to projection
1010         float projector_x, projector_y, projector_z;
1011         track->automation->get_projector(&projector_x,
1012                 &projector_y,
1013                 &projector_z,
1014                 position,
1015                 PLAY_FORWARD);
1018 // Get position of cursor relative to mask
1019         float mask_cursor_x = get_cursor_x();
1020         float mask_cursor_y = get_cursor_y();
1021         canvas_to_output(mwindow->edl, 0, mask_cursor_x, mask_cursor_y);
1023         projector_x += mwindow->edl->session->output_w / 2;
1024         projector_y += mwindow->edl->session->output_h / 2;
1026         mask_cursor_x -= projector_x;
1027         mask_cursor_y -= projector_y;
1028         mask_cursor_x = mask_cursor_x / projector_z + half_track_w;
1029         mask_cursor_y = mask_cursor_y / projector_z + half_track_h;
1031 // Fix cursor origin
1032         if(button_press)
1033         {
1034                 gui->x_origin = mask_cursor_x;
1035                 gui->y_origin = mask_cursor_y;
1036         }
1038         int result = 0;
1039 // Points of closest line
1040         int shortest_point1 = -1;
1041         int shortest_point2 = -1;
1042 // Closest point
1043         int shortest_point = -1;
1044 // Distance to closest line
1045         float shortest_line_distance = BC_INFINITY;
1046 // Distance to closest point
1047         float shortest_point_distance = BC_INFINITY;
1048         int selected_point = -1;
1049         int selected_control_point = -1;
1050         float selected_control_point_distance = BC_INFINITY;
1051         ArrayList<int> x_points;
1052         ArrayList<int> y_points;
1054         if(!cursor_motion)
1055         {
1056                 if(draw)
1057                 {
1058                         get_canvas()->set_color(WHITE);
1059                         get_canvas()->set_inverse();
1060                 }
1061 //printf("CWindowCanvas::do_mask 1 %d\n", points.total);
1063 // Never draw closed polygon and a closed
1064 // polygon is harder to add points to.
1065                 for(int i = 0; i < points.total && !result; i++)
1066                 {
1067                         MaskPoint *point1 = points.values[i];
1068                         MaskPoint *point2 = (i >= points.total - 1) ? 
1069                                 points.values[0] : 
1070                                 points.values[i + 1];
1071                         float x0, x1, x2, x3;
1072                         float y0, y1, y2, y3;
1073                         float old_x, old_y, x, y;
1074                         int segments = (int)(sqrt(SQR(point1->x - point2->x) + SQR(point1->y - point2->y)));
1076 //printf("CWindowCanvas::do_mask 1 %f, %f -> %f, %f projectorz=%f\n",
1077 //point1->x, point1->y, point2->x, point2->y, projector_z);
1078                         for(int j = 0; j <= segments && !result; j++)
1079                         {
1080 //printf("CWindowCanvas::do_mask 1 %f, %f -> %f, %f\n", x0, y0, x3, y3);
1081                                 x0 = point1->x;
1082                                 y0 = point1->y;
1083                                 x1 = point1->x + point1->control_x2;
1084                                 y1 = point1->y + point1->control_y2;
1085                                 x2 = point2->x + point2->control_x1;
1086                                 y2 = point2->y + point2->control_y1;
1087                                 x3 = point2->x;
1088                                 y3 = point2->y;
1090                                 float t = (float)j / segments;
1091                                 float tpow2 = t * t;
1092                                 float tpow3 = t * t * t;
1093                                 float invt = 1 - t;
1094                                 float invtpow2 = invt * invt;
1095                                 float invtpow3 = invt * invt * invt;
1097                                 x = (        invtpow3 * x0
1098                                         + 3 * t     * invtpow2 * x1
1099                                         + 3 * tpow2 * invt     * x2 
1100                                         +     tpow3            * x3);
1101                                 y = (        invtpow3 * y0 
1102                                         + 3 * t     * invtpow2 * y1
1103                                         + 3 * tpow2 * invt     * y2 
1104                                         +     tpow3            * y3);
1106                                 x = (x - half_track_w) * projector_z + projector_x;
1107                                 y = (y - half_track_h) * projector_z + projector_y;
1110 // Test new point addition
1111                                 if(button_press)
1112                                 {
1113                                         float line_distance = 
1114                                                 sqrt(SQR(x - mask_cursor_x) + SQR(y - mask_cursor_y));
1116 //printf("CWindowCanvas::do_mask 1 x=%f mask_cursor_x=%f y=%f mask_cursor_y=%f %f %f %d, %d\n", 
1117 //x, mask_cursor_x, y, mask_cursor_y, line_distance, shortest_line_distance, shortest_point1, shortest_point2);
1118                                         if(line_distance < shortest_line_distance || 
1119                                                 shortest_point1 < 0)
1120                                         {
1121                                                 shortest_line_distance = line_distance;
1122                                                 shortest_point1 = i;
1123                                                 shortest_point2 = (i >= points.total - 1) ? 0 : (i + 1);
1124 //printf("CWindowCanvas::do_mask 2 %f %f %d, %d\n", line_distance, shortest_line_distance, shortest_point1, shortest_point2);
1125                                         }
1128                                         float point_distance1 = 
1129                                                 sqrt(SQR(point1->x - mask_cursor_x) + SQR(point1->y - mask_cursor_y));
1130                                         float point_distance2 = 
1131                                                 sqrt(SQR(point2->x - mask_cursor_x) + SQR(point2->y - mask_cursor_y));
1133                                         if(point_distance1 < shortest_point_distance || 
1134                                                 shortest_point < 0)
1135                                         {
1136                                                 shortest_point_distance = point_distance1;
1137                                                 shortest_point = i;
1138                                         }
1140                                         if(point_distance2 < shortest_point_distance || 
1141                                                 shortest_point < 0)
1142                                         {
1143                                                 shortest_point_distance = point_distance2;
1144                                                 shortest_point = (i >= points.total - 1) ? 0 : (i + 1);
1145                                         }
1146                                 }
1148                                 output_to_canvas(mwindow->edl, 0, x, y);
1151 #define TEST_BOX(cursor_x, cursor_y, target_x, target_y) \
1152         (cursor_x >= target_x - CONTROL_W / 2 && \
1153         cursor_x < target_x + CONTROL_W / 2 && \
1154         cursor_y >= target_y - CONTROL_H / 2 && \
1155         cursor_y < target_y + CONTROL_H / 2)
1157 // Test existing point selection
1158                                 if(button_press)
1159                                 {
1160                                         float canvas_x = (x0 - half_track_w) * projector_z + projector_x;
1161                                         float canvas_y = (y0 - half_track_h) * projector_z + projector_y;
1162                                         int cursor_x = get_cursor_x();
1163                                         int cursor_y = get_cursor_y();
1165 // Test first point
1166                                         if(gui->shift_down())
1167                                         {
1168                                                 float control_x = (x1 - half_track_w) * projector_z + projector_x;
1169                                                 float control_y = (y1 - half_track_h) * projector_z + projector_y;
1170                                                 output_to_canvas(mwindow->edl, 0, control_x, control_y);
1172                                                 float distance = 
1173                                                         sqrt(SQR(control_x - cursor_x) + SQR(control_y - cursor_y));
1175                                                 if(distance < selected_control_point_distance)
1176                                                 {
1177                                                         selected_point = i;
1178                                                         selected_control_point = 1;
1179                                                         selected_control_point_distance = distance;
1180                                                 }
1181                                         }
1182                                         else
1183                                         {
1184                                                 output_to_canvas(mwindow->edl, 0, canvas_x, canvas_y);
1185                                                 if(!gui->ctrl_down())
1186                                                 {
1187                                                         if(TEST_BOX(cursor_x, cursor_y, canvas_x, canvas_y))
1188                                                         {
1189                                                                 selected_point = i;
1190                                                         }
1191                                                 }
1192                                                 else
1193                                                 {
1194                                                         selected_point = shortest_point;
1195                                                 }
1196                                         }
1198 // Test second point
1199                                         canvas_x = (x3 - half_track_w) * projector_z + projector_x;
1200                                         canvas_y = (y3 - half_track_h) * projector_z + projector_y;
1201                                         if(gui->shift_down())
1202                                         {
1203                                                 float control_x = (x2 - half_track_w) * projector_z + projector_x;
1204                                                 float control_y = (y2 - half_track_h) * projector_z + projector_y;
1205                                                 output_to_canvas(mwindow->edl, 0, control_x, control_y);
1207                                                 float distance = 
1208                                                         sqrt(SQR(control_x - cursor_x) + SQR(control_y - cursor_y));
1210 //printf("CWindowCanvas::do_mask %d %f %f\n", i, distance, selected_control_point_distance);
1211                                                 if(distance < selected_control_point_distance)
1212                                                 {
1213                                                         selected_point = (i < points.total - 1 ? i + 1 : 0);
1214                                                         selected_control_point = 0;
1215                                                         selected_control_point_distance = distance;
1216                                                 }
1217                                         }
1218                                         else
1219                                         if(i < points.total - 1)
1220                                         {
1221                                                 output_to_canvas(mwindow->edl, 0, canvas_x, canvas_y);
1222                                                 if(!gui->ctrl_down())
1223                                                 {
1224                                                         if(TEST_BOX(cursor_x, cursor_y, canvas_x, canvas_y))
1225                                                         {
1226                                                                 selected_point = (i < points.total - 1 ? i + 1 : 0);
1227                                                         }
1228                                                 }
1229                                                 else
1230                                                 {
1231                                                         selected_point = shortest_point;
1232                                                 }
1233                                         }
1234                                 }
1238                                 if(j > 0)
1239                                 {
1240 // Draw joining line
1241                                         if(draw)
1242                                         {
1243                                                 x_points.append((int)x);
1244                                                 y_points.append((int)y);
1245                                         }
1247                                         if(j == segments)
1248                                         {
1253                                                 if(draw)
1254                                                 {
1255 // Draw second anchor
1256                                                         if(i < points.total - 1)
1257                                                         {
1258                                                                 if(i == gui->affected_point - 1)
1259                                                                         get_canvas()->draw_disc((int)x - CONTROL_W / 2, 
1260                                                                                 (int)y - CONTROL_W / 2, 
1261                                                                                 CONTROL_W, 
1262                                                                                 CONTROL_W);
1263                                                                 else
1264                                                                         get_canvas()->draw_circle((int)x - CONTROL_W / 2, 
1265                                                                                 (int)y - CONTROL_W / 2, 
1266                                                                                 CONTROL_W, 
1267                                                                                 CONTROL_W);
1268 // char string[BCTEXTLEN];
1269 // sprintf(string, "%d", (i < points.total - 1 ? i + 1 : 0));
1270 // canvas->draw_text((int)x + CONTROL_W, (int)y + CONTROL_W, string);
1271                                                         }
1273 // Draw second control point.  Discard x2 and y2 after this.
1274                                                         x2 = (x2 - half_track_w) * projector_z + projector_x;
1275                                                         y2 = (y2 - half_track_h) * projector_z + projector_y;
1276                                                         output_to_canvas(mwindow->edl, 0, x2, y2);
1277                                                         get_canvas()->draw_line((int)x, (int)y, (int)x2, (int)y2);
1278                                                         get_canvas()->draw_rectangle((int)x2 - CONTROL_W / 2,
1279                                                                 (int)y2 - CONTROL_H / 2,
1280                                                                 CONTROL_W,
1281                                                                 CONTROL_H);
1282                                                 }
1283                                         }
1284                                 }
1285                                 else
1286                                 {
1289 // Draw first anchor
1290                                         if(i == 0 && draw)
1291                                         {
1292                                                 get_canvas()->draw_disc((int)x - FIRST_CONTROL_W / 2, 
1293                                                         (int)y - FIRST_CONTROL_H / 2, 
1294                                                         FIRST_CONTROL_W, 
1295                                                         FIRST_CONTROL_H);
1296                                         }
1298 // Draw first control point.  Discard x1 and y1 after this.
1299                                         if(draw)
1300                                         {
1301                                                 x1 = (x1 - half_track_w) * projector_z + projector_x;
1302                                                 y1 = (y1 - half_track_h) * projector_z + projector_y;
1303                                                 output_to_canvas(mwindow->edl, 0, x1, y1);
1304                                                 get_canvas()->draw_line((int)x, (int)y, (int)x1, (int)y1);
1305                                                 get_canvas()->draw_rectangle((int)x1 - CONTROL_W / 2,
1306                                                         (int)y1 - CONTROL_H / 2,
1307                                                         CONTROL_W,
1308                                                         CONTROL_H);
1309                                         
1310                                                 x_points.append((int)x);
1311                                                 y_points.append((int)y);
1312                                         }
1313                                 }
1314 //printf("CWindowCanvas::do_mask 1\n");
1316                                 old_x = x;
1317                                 old_y = y;
1318                         }
1319                 }
1320 //printf("CWindowCanvas::do_mask 1\n");
1322                 if(draw)
1323                 {
1324                         get_canvas()->draw_polygon(&x_points, &y_points);
1325                         get_canvas()->set_opaque();
1326                 }
1327 //printf("CWindowCanvas::do_mask 1\n");
1328         }
1336         if(button_press && !result)
1337         {
1338                 gui->affected_track = gui->cwindow->calculate_affected_track();
1339 // Get current keyframe
1340                 if(gui->affected_track)
1341                         gui->affected_keyframe = 
1342                                 gui->cwindow->calculate_affected_auto(
1343                                         gui->affected_track->automation->autos[AUTOMATION_MASK],
1344                                         1);
1346                 MaskAuto *keyframe = (MaskAuto*)gui->affected_keyframe;
1347                 SubMask *mask = keyframe->get_submask(mwindow->edl->session->cwindow_mask);
1350 // Translate entire keyframe
1351                 if(gui->alt_down() && mask->points.total)
1352                 {
1353                         gui->current_operation = CWINDOW_MASK_TRANSLATE;
1354                         gui->affected_point = 0;
1355                 }
1356                 else
1357 // Existing point or control point was selected
1358                 if(selected_point >= 0)
1359                 {
1360                         gui->affected_point = selected_point;
1362                         if(selected_control_point == 0)
1363                                 gui->current_operation = CWINDOW_MASK_CONTROL_IN;
1364                         else
1365                         if(selected_control_point == 1)
1366                                 gui->current_operation = CWINDOW_MASK_CONTROL_OUT;
1367                         else
1368                                 gui->current_operation = mwindow->edl->session->cwindow_operation;
1369                 }
1370                 else
1371 // No existing point or control point was selected so create a new one
1372                 if(!gui->shift_down() && !gui->alt_down())
1373                 {
1374 // Create the template
1375                         MaskPoint *point = new MaskPoint;
1376                         point->x = mask_cursor_x;
1377                         point->y = mask_cursor_y;
1378                         point->control_x1 = 0;
1379                         point->control_y1 = 0;
1380                         point->control_x2 = 0;
1381                         point->control_y2 = 0;
1384                         if(shortest_point2 < shortest_point1)
1385                         {
1386                                 shortest_point2 ^= shortest_point1;
1387                                 shortest_point1 ^= shortest_point2;
1388                                 shortest_point2 ^= shortest_point1;
1389                         }
1393 // printf("CWindowGUI::do_mask 40\n");
1394 // mwindow->edl->dump();
1395 // printf("CWindowGUI::do_mask 50\n");
1399 //printf("CWindowCanvas::do_mask 1 %f %f %d %d\n", 
1400 //      shortest_line_distance, shortest_point_distance, shortest_point1, shortest_point2);
1401 //printf("CWindowCanvas::do_mask %d %d\n", shortest_point1, shortest_point2);
1403 // Append to end of list
1404                         if(labs(shortest_point1 - shortest_point2) > 1)
1405                         {
1406 // Need to apply the new point to every keyframe
1407                                 for(MaskAuto *current = (MaskAuto*)mask_autos->default_auto;
1408                                         current; )
1409                                 {
1410                                         SubMask *submask = current->get_submask(mwindow->edl->session->cwindow_mask);
1411                                         MaskPoint *new_point = new MaskPoint;
1412                                         submask->points.append(new_point);
1413                                         *new_point = *point;
1414                                         if(current == (MaskAuto*)mask_autos->default_auto)
1415                                                 current = (MaskAuto*)mask_autos->first;
1416                                         else
1417                                                 current = (MaskAuto*)NEXT;
1418                                 }
1420                                 gui->affected_point = mask->points.total - 1;
1421                                 result = 1;
1422                         }
1423                         else
1424 // Insert between 2 points, shifting back point 2
1425                         if(shortest_point1 >= 0 && shortest_point2 >= 0)
1426                         {
1427                                 for(MaskAuto *current = (MaskAuto*)mask_autos->default_auto;
1428                                         current; )
1429                                 {
1430                                         SubMask *submask = current->get_submask(mwindow->edl->session->cwindow_mask);
1431 // In case the keyframe point count isn't synchronized with the rest of the keyframes,
1432 // avoid a crash.
1433                                         if(submask->points.total >= shortest_point2)
1434                                         {
1435                                                 MaskPoint *new_point = new MaskPoint;
1436                                                 submask->points.append(0);
1437                                                 for(int i = submask->points.total - 1; 
1438                                                         i > shortest_point2; 
1439                                                         i--)
1440                                                         submask->points.values[i] = submask->points.values[i - 1];
1441                                                 submask->points.values[shortest_point2] = new_point;
1443                                                 *new_point = *point;
1444                                         }
1446                                         if(current == (MaskAuto*)mask_autos->default_auto)
1447                                                 current = (MaskAuto*)mask_autos->first;
1448                                         else
1449                                                 current = (MaskAuto*)NEXT;
1450                                 }
1453                                 gui->affected_point = shortest_point2;
1454                                 result = 1;
1455                         }
1458 // printf("CWindowGUI::do_mask 20\n");
1459 // mwindow->edl->dump();
1460 // printf("CWindowGUI::do_mask 30\n");
1465 // Create the first point.
1466                         if(!result)
1467                         {
1468 //printf("CWindowCanvas::do_mask 1\n");
1469                                 for(MaskAuto *current = (MaskAuto*)mask_autos->default_auto;
1470                                         current; )
1471                                 {
1472                                         SubMask *submask = current->get_submask(mwindow->edl->session->cwindow_mask);
1473                                         MaskPoint *new_point = new MaskPoint;
1474                                         submask->points.append(new_point);
1475                                         *new_point = *point;
1476                                         if(current == (MaskAuto*)mask_autos->default_auto)
1477                                                 current = (MaskAuto*)mask_autos->first;
1478                                         else
1479                                                 current = (MaskAuto*)NEXT;
1480                                 }
1482 //printf("CWindowCanvas::do_mask 2\n");
1483 // Create a second point if none existed before
1484                                 if(mask->points.total < 2)
1485                                 {
1486                                         for(MaskAuto *current = (MaskAuto*)mask_autos->default_auto;
1487                                                 current; )
1488                                         {
1489                                                 SubMask *submask = current->get_submask(mwindow->edl->session->cwindow_mask);
1490                                                 MaskPoint *new_point = new MaskPoint;
1491                                                 submask->points.append(new_point);
1492                                                 *new_point = *point;
1493                                                 if(current == (MaskAuto*)mask_autos->default_auto)
1494                                                         current = (MaskAuto*)mask_autos->first;
1495                                                 else
1496                                                         current = (MaskAuto*)NEXT;
1497                                         }
1498                                 }
1499                                 gui->affected_point = mask->points.total - 1;
1500 //printf("CWindowCanvas::do_mask 3 %d\n", mask->points.total);
1501                         }
1505                         gui->current_operation = mwindow->edl->session->cwindow_operation;
1506 // Delete the template
1507                         delete point;
1508 //printf("CWindowGUI::do_mask 1\n");
1509                         mwindow->undo->update_undo(_("mask point"), LOAD_AUTOMATION);
1510 //printf("CWindowGUI::do_mask 10\n");
1512                 }
1514                 result = 1;
1515                 rerender = 1;
1516                 redraw = 1;
1517         }
1519         if(button_press && result)
1520         {
1521                 MaskAuto *keyframe = (MaskAuto*)gui->affected_keyframe;
1522                 SubMask *mask = keyframe->get_submask(mwindow->edl->session->cwindow_mask);
1523                 MaskPoint *point = mask->points.values[gui->affected_point];
1524                 gui->center_x = point->x;
1525                 gui->center_y = point->y;
1526                 gui->control_in_x = point->control_x1;
1527                 gui->control_in_y = point->control_y1;
1528                 gui->control_out_x = point->control_x2;
1529                 gui->control_out_y = point->control_y2;
1530         }
1532 //printf("CWindowCanvas::do_mask 8\n");
1533         if(cursor_motion)
1534         {
1535                 MaskAuto *keyframe = (MaskAuto*)gui->affected_keyframe;
1536                 SubMask *mask = keyframe->get_submask(mwindow->edl->session->cwindow_mask);
1537                 if(gui->affected_point < mask->points.total)
1538                 {
1539                         MaskPoint *point = mask->points.values[gui->affected_point];
1540 //                      float cursor_x = get_cursor_x();
1541 //                      float cursor_y = get_cursor_y();
1542 //                      canvas_to_output(mwindow->edl, 0, cursor_x, cursor_y);
1543                         float cursor_x = mask_cursor_x;
1544                         float cursor_y = mask_cursor_y;
1545 //printf("CWindowCanvas::do_mask 9 %d %d\n", mask->points.total, gui->affected_point);
1547                         float last_x = point->x;
1548                         float last_y = point->y;
1549                         float last_control_x1 = point->control_x1;
1550                         float last_control_y1 = point->control_y1;
1551                         float last_control_x2 = point->control_x2;
1552                         float last_control_y2 = point->control_y2;
1555                         switch(gui->current_operation)
1556                         {
1557                                 case CWINDOW_MASK:
1558                                         point->x = cursor_x - gui->x_origin + gui->center_x;
1559                                         point->y = cursor_y - gui->y_origin + gui->center_y;
1560                                         break;
1562                                 case CWINDOW_MASK_CONTROL_IN:
1563                                         point->control_x1 = cursor_x - gui->x_origin + gui->control_in_x;
1564                                         point->control_y1 = cursor_y - gui->y_origin + gui->control_in_y;
1565                                         break;
1567                                 case CWINDOW_MASK_CONTROL_OUT:
1568                                         point->control_x2 = cursor_x - gui->x_origin + gui->control_out_x;
1569                                         point->control_y2 = cursor_y - gui->y_origin + gui->control_out_y;
1570                                         break;
1572                                 case CWINDOW_MASK_TRANSLATE:
1573                                         for(int i = 0; i < mask->points.total; i++)
1574                                         {
1575                                                 mask->points.values[i]->x += cursor_x - gui->x_origin;
1576                                                 mask->points.values[i]->y += cursor_y - gui->y_origin;
1577                                         }
1578                                         gui->x_origin = cursor_x;
1579                                         gui->y_origin = cursor_y;
1580                                         break;
1581                         }
1584                         if( !EQUIV(last_x, point->x) ||
1585                                 !EQUIV(last_y, point->y) ||
1586                                 !EQUIV(last_control_x1, point->control_x1) ||
1587                                 !EQUIV(last_control_y1, point->control_y1) ||
1588                                 !EQUIV(last_control_x2, point->control_x2) ||
1589                                 !EQUIV(last_control_y2, point->control_y2))
1590                         {
1591                                 rerender = 1;
1592                                 redraw = 1;
1593                         }
1594                 }
1595                 result = 1;
1596         }
1597 //printf("CWindowCanvas::do_mask 2 %d %d %d\n", result, rerender, redraw);
1599         points.remove_all_objects();
1600 //printf("CWindowCanvas::do_mask 20\n");
1601         return result;
1605 int CWindowCanvas::do_eyedrop(int &rerender, int button_press)
1607         int result = 0;
1608         float cursor_x = get_cursor_x();
1609         float cursor_y = get_cursor_y();
1612         if(button_press)
1613         {
1614                 gui->current_operation = CWINDOW_EYEDROP;
1615         }
1617         if(gui->current_operation == CWINDOW_EYEDROP)
1618         {
1619                 canvas_to_output(mwindow->edl, 0, cursor_x, cursor_y);
1621 // Get color out of frame.
1622 // Doesn't work during playback because that bypasses the refresh frame.
1623                 if(refresh_frame)
1624                 {
1625                         CLAMP(cursor_x, 0, refresh_frame->get_w() - 1);
1626                         CLAMP(cursor_y, 0, refresh_frame->get_h() - 1);
1628 // Decompression coefficients straight out of jpeglib
1629 #define V_TO_R    1.40200
1630 #define V_TO_G    -0.71414
1632 #define U_TO_G    -0.34414
1633 #define U_TO_B    1.77200
1635 #define GET_COLOR(type, components, max, do_yuv) \
1636 { \
1637         type *row = (type*)(refresh_frame->get_rows()[(int)cursor_y]) + \
1638                 (int)cursor_x * components; \
1639         float red = (float)*row++ / max; \
1640         float green = (float)*row++ / max; \
1641         float blue = (float)*row++ / max; \
1642         if(do_yuv) \
1643         { \
1644                 mwindow->edl->local_session->red = red + V_TO_R * (blue - 0.5); \
1645                 mwindow->edl->local_session->green = red + U_TO_G * (green - 0.5) + V_TO_G * (blue - 0.5); \
1646                 mwindow->edl->local_session->blue = red + U_TO_B * (green - 0.5); \
1647         } \
1648         else \
1649         { \
1650                 mwindow->edl->local_session->red = red; \
1651                 mwindow->edl->local_session->green = green; \
1652                 mwindow->edl->local_session->blue = blue; \
1653         } \
1656                         switch(refresh_frame->get_color_model())
1657                         {
1658                                 case BC_YUV888:
1659                                         GET_COLOR(unsigned char, 3, 0xff, 1);
1660                                         break;
1661                                 case BC_YUVA8888:
1662                                         GET_COLOR(unsigned char, 4, 0xff, 1);
1663                                         break;
1664                                 case BC_YUV161616:
1665                                         GET_COLOR(uint16_t, 3, 0xffff, 1);
1666                                         break;
1667                                 case BC_YUVA16161616:
1668                                         GET_COLOR(uint16_t, 4, 0xffff, 1);
1669                                         break;
1670                                 case BC_RGB888:
1671                                         GET_COLOR(unsigned char, 3, 0xff, 0);
1672                                         break;
1673                                 case BC_RGBA8888:
1674                                         GET_COLOR(unsigned char, 4, 0xff, 0);
1675                                         break;
1676                                 case BC_RGB_FLOAT:
1677                                         GET_COLOR(float, 3, 1.0, 0);
1678                                         break;
1679                                 case BC_RGBA_FLOAT:
1680                                         GET_COLOR(float, 4, 1.0, 0);
1681                                         break;
1682                         }
1683                 }
1684                 else
1685                 {
1686                         mwindow->edl->local_session->red = 0;
1687                         mwindow->edl->local_session->green = 0;
1688                         mwindow->edl->local_session->blue = 0;
1689                 }
1692                 gui->update_tool();             
1696                 result = 1;
1697 // Can't rerender since the color value is from the output of any effect it
1698 // goes into.
1699 //              rerender = 1;
1700         }
1702         return result;
1705 void CWindowCanvas::draw_overlays()
1707         if(mwindow->edl->session->safe_regions)
1708         {
1709                 draw_safe_regions();
1710         }
1712         if(mwindow->edl->session->cwindow_scrollbars)
1713         {
1714 // Always draw output rectangle
1715                 float x1, y1, x2, y2;
1716                 x1 = 0;
1717                 x2 = mwindow->edl->session->output_w;
1718                 y1 = 0;
1719                 y2 = mwindow->edl->session->output_h;
1720                 output_to_canvas(mwindow->edl, 0, x1, y1);
1721                 output_to_canvas(mwindow->edl, 0, x2, y2);
1723                 get_canvas()->set_inverse();
1724                 get_canvas()->set_color(WHITE);
1726                 get_canvas()->draw_rectangle((int)x1, 
1727                                 (int)y1, 
1728                                 (int)(x2 - x1), 
1729                                 (int)(y2 - y1));
1731                 get_canvas()->set_opaque();
1732         }
1734         if(mwindow->session->ccanvas_highlighted)
1735         {
1736                 get_canvas()->set_color(WHITE);
1737                 get_canvas()->set_inverse();
1738                 get_canvas()->draw_rectangle(0, 0, get_canvas()->get_w(), get_canvas()->get_h());
1739                 get_canvas()->draw_rectangle(1, 1, get_canvas()->get_w() - 2, get_canvas()->get_h() - 2);
1740                 get_canvas()->set_opaque();
1741         }
1743         int temp1 = 0, temp2 = 0;
1744 //printf("CWindowCanvas::draw_overlays 1 %d\n", mwindow->edl->session->cwindow_operation);
1745         switch(mwindow->edl->session->cwindow_operation)
1746         {
1747                 case CWINDOW_CAMERA:
1748                         draw_bezier(1);
1749                         break;
1751                 case CWINDOW_PROJECTOR:
1752                         draw_bezier(0);
1753                         break;
1755                 case CWINDOW_CROP:
1756                         draw_crop();
1757                         break;
1759                 case CWINDOW_MASK:
1760                         do_mask(temp1, temp2, 0, 0, 1);
1761                         break;
1762         }
1765 void CWindowCanvas::draw_safe_regions()
1767         float action_x1, action_x2, action_y1, action_y2;
1768         float title_x1, title_x2, title_y1, title_y2;
1770         action_x1 = mwindow->edl->session->output_w / 2 - mwindow->edl->session->output_w / 2 * 0.9;
1771         action_x2 = mwindow->edl->session->output_w / 2 + mwindow->edl->session->output_w / 2 * 0.9;
1772         action_y1 = mwindow->edl->session->output_h / 2 - mwindow->edl->session->output_h / 2 * 0.9;
1773         action_y2 = mwindow->edl->session->output_h / 2 + mwindow->edl->session->output_h / 2 * 0.9;
1774         title_x1 = mwindow->edl->session->output_w / 2 - mwindow->edl->session->output_w / 2 * 0.8;
1775         title_x2 = mwindow->edl->session->output_w / 2 + mwindow->edl->session->output_w / 2 * 0.8;
1776         title_y1 = mwindow->edl->session->output_h / 2 - mwindow->edl->session->output_h / 2 * 0.8;
1777         title_y2 = mwindow->edl->session->output_h / 2 + mwindow->edl->session->output_h / 2 * 0.8;
1779         output_to_canvas(mwindow->edl, 0, action_x1, action_y1);
1780         output_to_canvas(mwindow->edl, 0, action_x2, action_y2);
1781         output_to_canvas(mwindow->edl, 0, title_x1, title_y1);
1782         output_to_canvas(mwindow->edl, 0, title_x2, title_y2);
1784         get_canvas()->set_inverse();
1785         get_canvas()->set_color(WHITE);
1787         get_canvas()->draw_rectangle((int)action_x1, 
1788                         (int)action_y1, 
1789                         (int)(action_x2 - action_x1), 
1790                         (int)(action_y2 - action_y1));
1791         get_canvas()->draw_rectangle((int)title_x1, 
1792                         (int)title_y1, 
1793                         (int)(title_x2 - title_x1), 
1794                         (int)(title_y2 - title_y1));
1796         get_canvas()->set_opaque();
1799 void CWindowCanvas::reset_keyframe(int do_camera)
1801         FloatAuto *x_keyframe = 0;
1802         FloatAuto *y_keyframe = 0;
1803         FloatAuto *z_keyframe = 0;
1804         Track *affected_track = 0;
1806         affected_track = gui->cwindow->calculate_affected_track();
1808         if(affected_track)
1809         {
1810                 gui->cwindow->calculate_affected_autos(&x_keyframe,
1811                         &y_keyframe,
1812                         &z_keyframe,
1813                         affected_track,
1814                         do_camera,
1815                         1,
1816                         1,
1817                         1);
1819                 x_keyframe->value = 0;
1820                 y_keyframe->value = 0;
1821                 z_keyframe->value = 1;
1823                 mwindow->sync_parameters(CHANGE_PARAMS);
1824                 gui->update_tool();
1825         }
1828 void CWindowCanvas::reset_camera()
1830         reset_keyframe(1);
1833 void CWindowCanvas::reset_projector()
1835         reset_keyframe(0);
1838 int CWindowCanvas::test_crop(int button_press, int &redraw)
1840         int result = 0;
1841         int handle_selected = -1;
1842         float x1 = mwindow->edl->session->crop_x1;
1843         float y1 = mwindow->edl->session->crop_y1;
1844         float x2 = mwindow->edl->session->crop_x2;
1845         float y2 = mwindow->edl->session->crop_y2;
1846         float cursor_x = get_cursor_x();
1847         float cursor_y = get_cursor_y();
1848         float canvas_x1 = x1;
1849         float canvas_y1 = y1;
1850         float canvas_x2 = x2;
1851         float canvas_y2 = y2;
1852         float canvas_cursor_x = cursor_x;
1853         float canvas_cursor_y = cursor_y;
1855         canvas_to_output(mwindow->edl, 0, cursor_x, cursor_y);
1856 // Use screen normalized coordinates for hot spot tests.
1857         output_to_canvas(mwindow->edl, 0, canvas_x1, canvas_y1);
1858         output_to_canvas(mwindow->edl, 0, canvas_x2, canvas_y2);
1861         if(gui->current_operation == CWINDOW_CROP)
1862         {
1863                 handle_selected = gui->crop_handle;
1864         }
1865         else
1866         if(canvas_cursor_x >= canvas_x1 && canvas_cursor_x < canvas_x1 + CROPHANDLE_W &&
1867                 canvas_cursor_y >= canvas_y1 && canvas_cursor_y < canvas_y1 + CROPHANDLE_H)
1868         {
1869                 handle_selected = 0;
1870                 gui->crop_origin_x = x1;
1871                 gui->crop_origin_y = y1;
1872         }
1873         else
1874         if(canvas_cursor_x >= canvas_x2 - CROPHANDLE_W && canvas_cursor_x < canvas_x2 &&
1875                 canvas_cursor_y >= canvas_y1 && canvas_cursor_y < canvas_y1 + CROPHANDLE_H)
1876         {
1877                 handle_selected = 1;
1878                 gui->crop_origin_x = x2;
1879                 gui->crop_origin_y = y1;
1880         }
1881         else
1882         if(canvas_cursor_x >= canvas_x1 && canvas_cursor_x < canvas_x1 + CROPHANDLE_W &&
1883                 canvas_cursor_y >= canvas_y2 - CROPHANDLE_H && canvas_cursor_y < canvas_y2)
1884         {
1885                 handle_selected = 2;
1886                 gui->crop_origin_x = x1;
1887                 gui->crop_origin_y = y2;
1888         }
1889         else
1890         if(canvas_cursor_x >= canvas_x2 - CROPHANDLE_W && canvas_cursor_x < canvas_x2 &&
1891                 canvas_cursor_y >= canvas_y2 - CROPHANDLE_H && canvas_cursor_y < canvas_y2)
1892         {
1893                 handle_selected = 3;
1894                 gui->crop_origin_x = x2;
1895                 gui->crop_origin_y = y2;
1896         }
1897         else
1898 // Start new box
1899         {
1900                 gui->crop_origin_x = cursor_x;
1901                 gui->crop_origin_y = cursor_y;
1902         }
1904 // printf("test crop %d %d\n", 
1905 //      gui->current_operation,
1906 //      handle_selected);
1908 // Start dragging.
1909         if(button_press)
1910         {
1911                 if(gui->alt_down())
1912                 {
1913                         gui->crop_translate = 1;
1914                         gui->crop_origin_x1 = x1;
1915                         gui->crop_origin_y1 = y1;
1916                         gui->crop_origin_x2 = x2;
1917                         gui->crop_origin_y2 = y2;
1918                 }
1919                 else
1920                         gui->crop_translate = 0;
1922                 gui->current_operation = CWINDOW_CROP;
1923                 gui->crop_handle = handle_selected;
1924                 gui->x_origin = cursor_x;
1925                 gui->y_origin = cursor_y;
1926                 result = 1;
1928                 if(handle_selected < 0 && !gui->crop_translate) 
1929                 {
1930                         x2 = x1 = cursor_x;
1931                         y2 = y1 = cursor_y;
1932                         mwindow->edl->session->crop_x1 = (int)x1;
1933                         mwindow->edl->session->crop_y1 = (int)y1;
1934                         mwindow->edl->session->crop_x2 = (int)x2;
1935                         mwindow->edl->session->crop_y2 = (int)y2;
1936                         redraw = 1;
1937                 }
1938         }
1939     else
1940 // Translate all 4 points
1941         if(gui->current_operation == CWINDOW_CROP && gui->crop_translate)
1942         {
1943                 x1 = cursor_x - gui->x_origin + gui->crop_origin_x1;
1944                 y1 = cursor_y - gui->y_origin + gui->crop_origin_y1;
1945                 x2 = cursor_x - gui->x_origin + gui->crop_origin_x2;
1946                 y2 = cursor_y - gui->y_origin + gui->crop_origin_y2;
1948                 mwindow->edl->session->crop_x1 = (int)x1;
1949                 mwindow->edl->session->crop_y1 = (int)y1;
1950                 mwindow->edl->session->crop_x2 = (int)x2;
1951                 mwindow->edl->session->crop_y2 = (int)y2;
1952                 result = 1;
1953                 redraw = 1;
1954         }
1955         else
1956 // Update dragging
1957         if(gui->current_operation == CWINDOW_CROP)
1958         {
1959                 switch(gui->crop_handle)
1960                 {
1961                         case -1:
1962                                 x1 = gui->crop_origin_x;
1963                                 y1 = gui->crop_origin_y;
1964                                 x2 = gui->crop_origin_x;
1965                                 y2 = gui->crop_origin_y;
1966                                 if(cursor_x < gui->x_origin)
1967                                 {
1968                                         if(cursor_y < gui->y_origin)
1969                                         {
1970                                                 x1 = cursor_x;
1971                                                 y1 = cursor_y;
1972                                         }
1973                                         else
1974                                         if(cursor_y >= gui->y_origin)
1975                                         {
1976                                                 x1 = cursor_x;
1977                                                 y2 = cursor_y;
1978                                         }
1979                                 }
1980                                 else
1981                                 if(cursor_x  >= gui->x_origin)
1982                                 {
1983                                         if(cursor_y < gui->y_origin)
1984                                         {
1985                                                 y1 = cursor_y;
1986                                                 x2 = cursor_x;
1987                                         }
1988                                         else
1989                                         if(cursor_y >= gui->y_origin)
1990                                         {
1991                                                 x2 = cursor_x;
1992                                                 y2 = cursor_y;
1993                                         }
1994                                 }
1996 // printf("test crop %d %d %d %d\n", 
1997 //      mwindow->edl->session->crop_x1,
1998 //      mwindow->edl->session->crop_y1,
1999 //      mwindow->edl->session->crop_x2,
2000 //      mwindow->edl->session->crop_y2);
2001                                 break;
2002                         case 0:
2003                                 x1 = cursor_x - gui->x_origin + gui->crop_origin_x;
2004                                 y1 = cursor_y - gui->y_origin + gui->crop_origin_y;
2005                                 break;
2006                         case 1:
2007                                 x2 = cursor_x - gui->x_origin + gui->crop_origin_x;
2008                                 y1 = cursor_y - gui->y_origin + gui->crop_origin_y;
2009                                 break;
2010                         case 2:
2011                                 x1 = cursor_x - gui->x_origin + gui->crop_origin_x;
2012                                 y2 = cursor_y - gui->y_origin + gui->crop_origin_y;
2013                                 break;
2014                         case 3:
2015                                 x2 = cursor_x - gui->x_origin + gui->crop_origin_x;
2016                                 y2 = cursor_y - gui->y_origin + gui->crop_origin_y;
2017                                 break;
2018                 }
2020                 if(!EQUIV(mwindow->edl->session->crop_x1, x1) ||
2021                         !EQUIV(mwindow->edl->session->crop_x2, x2) ||
2022                         !EQUIV(mwindow->edl->session->crop_y1, y1) ||
2023                         !EQUIV(mwindow->edl->session->crop_y2, y2))
2024                 {
2025                         if (x1 > x2) 
2026                         {
2027                                 float tmp = x1;
2028                                 x1 = x2;
2029                                 x2 = tmp;
2030                                 switch (gui->crop_handle) 
2031                                 {
2032                                         case 0: gui->crop_handle = 1; break;
2033                                         case 1: gui->crop_handle = 0; break;
2034                                         case 2: gui->crop_handle = 3; break;
2035                                         case 3: gui->crop_handle = 2; break;
2036                                         default: break;
2037                                 }
2039                         }
2040                         if (y1 > y2) 
2041                         {
2042                                 float tmp = y1;
2043                                 y1 = y2;
2044                                 y2 = tmp;
2045                                 switch (gui->crop_handle) 
2046                                 {
2047                                         case 0: gui->crop_handle = 2; break;
2048                                         case 1: gui->crop_handle = 3; break;
2049                                         case 2: gui->crop_handle = 0; break;
2050                                         case 3: gui->crop_handle = 1; break;
2051                                         default: break;
2052                                 }
2053                         }
2055                         mwindow->edl->session->crop_x1 = (int)x1;
2056                         mwindow->edl->session->crop_y1 = (int)y1;
2057                         mwindow->edl->session->crop_x2 = (int)x2;
2058                         mwindow->edl->session->crop_y2 = (int)y2;
2059                         result = 1;
2060                         redraw = 1;
2061                 }
2062         }
2063         else
2064 // Update cursor font
2065         if(handle_selected >= 0)
2066         {
2067                 switch(handle_selected)
2068                 {
2069                         case 0:
2070                                 set_cursor(UPLEFT_RESIZE);
2071                                 break;
2072                         case 1:
2073                                 set_cursor(UPRIGHT_RESIZE);
2074                                 break;
2075                         case 2:
2076                                 set_cursor(DOWNLEFT_RESIZE);
2077                                 break;
2078                         case 3:
2079                                 set_cursor(DOWNRIGHT_RESIZE);
2080                                 break;
2081                 }
2082                 result = 1;
2083         }
2084         else
2085         {
2086                 set_cursor(ARROW_CURSOR);
2087         }
2088 #define CLAMP(x, y, z) ((x) = ((x) < (y) ? (y) : ((x) > (z) ? (z) : (x))))
2089         
2090         if(redraw)
2091         {
2092                 CLAMP(mwindow->edl->session->crop_x1, 0, mwindow->edl->session->output_w);
2093                 CLAMP(mwindow->edl->session->crop_x2, 0, mwindow->edl->session->output_w);
2094                 CLAMP(mwindow->edl->session->crop_y1, 0, mwindow->edl->session->output_h);
2095                 CLAMP(mwindow->edl->session->crop_y2, 0, mwindow->edl->session->output_h);
2096 // printf("CWindowCanvas::test_crop %d %d %d %d\n", 
2097 //      mwindow->edl->session->crop_x2,
2098 //      mwindow->edl->session->crop_y2,
2099 //      mwindow->edl->calculate_output_w(0), 
2100 //      mwindow->edl->calculate_output_h(0));
2101         }
2102         return result;
2106 void CWindowCanvas::draw_crop()
2108         get_canvas()->set_inverse();
2109         get_canvas()->set_color(WHITE);
2111         float x1 = mwindow->edl->session->crop_x1;
2112         float y1 = mwindow->edl->session->crop_y1;
2113         float x2 = mwindow->edl->session->crop_x2;
2114         float y2 = mwindow->edl->session->crop_y2;
2116         output_to_canvas(mwindow->edl, 0, x1, y1);
2117         output_to_canvas(mwindow->edl, 0, x2, y2);
2119         if(x2 - x1 && y2 - y1)
2120                 get_canvas()->draw_rectangle((int)x1, 
2121                         (int)y1, 
2122                         (int)(x2 - x1), 
2123                         (int)(y2 - y1));
2125         draw_crophandle((int)x1, (int)y1);
2126         draw_crophandle((int)x2 - CROPHANDLE_W, (int)y1);
2127         draw_crophandle((int)x1, (int)y2 - CROPHANDLE_H);
2128         draw_crophandle((int)x2 - CROPHANDLE_W, (int)y2 - CROPHANDLE_H);
2129         get_canvas()->set_opaque();
2139 void CWindowCanvas::draw_bezier(int do_camera)
2141         Track *track = gui->cwindow->calculate_affected_track();
2142         
2143         if(!track) return;
2145         float center_x;
2146         float center_y;
2147         float center_z;
2148         int64_t position = track->to_units(
2149                 mwindow->edl->local_session->get_selectionstart(1), 
2150                 0);
2152         track->automation->get_projector(&center_x, 
2153                 &center_y, 
2154                 &center_z, 
2155                 position,
2156                 PLAY_FORWARD);
2158 //      center_x += track->track_w / 2;
2159 //      center_y += track->track_h / 2;
2160         center_x += mwindow->edl->session->output_w / 2;
2161         center_y += mwindow->edl->session->output_h / 2;
2162         float track_x1 = center_x - track->track_w / 2 * center_z;
2163         float track_y1 = center_y - track->track_h / 2 * center_z;
2164         float track_x2 = track_x1 + track->track_w * center_z;
2165         float track_y2 = track_y1 + track->track_h * center_z;
2167         output_to_canvas(mwindow->edl, 0, track_x1, track_y1);
2168         output_to_canvas(mwindow->edl, 0, track_x2, track_y2);
2170 #define DRAW_PROJECTION(offset) \
2171         get_canvas()->draw_rectangle((int)track_x1 + offset, \
2172                 (int)track_y1 + offset, \
2173                 (int)(track_x2 - track_x1), \
2174                 (int)(track_y2 - track_y1)); \
2175         get_canvas()->draw_line((int)track_x1 + offset,  \
2176                 (int)track_y1 + offset, \
2177                 (int)track_x2 + offset, \
2178                 (int)track_y2 + offset); \
2179         get_canvas()->draw_line((int)track_x2 + offset,  \
2180                 (int)track_y1 + offset, \
2181                 (int)track_x1 + offset, \
2182                 (int)track_y2 + offset); \
2185 // Drop shadow
2186         get_canvas()->set_color(BLACK);
2187         DRAW_PROJECTION(1);
2189 //      canvas->set_inverse();
2190         if(do_camera)
2191                 get_canvas()->set_color(GREEN);
2192         else
2193                 get_canvas()->set_color(RED);
2195         DRAW_PROJECTION(0);
2196 //      canvas->set_opaque();
2202 int CWindowCanvas::test_bezier(int button_press, 
2203         int &redraw, 
2204         int &redraw_canvas,
2205         int &rerender,
2206         int do_camera)
2208         int result = 0;
2210 // Processing drag operation.
2211 // Create keyframe during first cursor motion.
2212         if(!button_press)
2213         {
2215                 float cursor_x = get_cursor_x();
2216                 float cursor_y = get_cursor_y();
2217                 canvas_to_output(mwindow->edl, 0, cursor_x, cursor_y);
2219                 if(gui->current_operation == CWINDOW_CAMERA ||
2220                         gui->current_operation == CWINDOW_PROJECTOR)
2221                 {
2222                         if(!gui->ctrl_down() && gui->shift_down() && !gui->translating_zoom)
2223                         {
2224                                 gui->translating_zoom = 1;
2225                                 gui->reset_affected();
2226                         }
2227                         else
2228                         if(!gui->ctrl_down() && !gui->shift_down() && gui->translating_zoom)
2229                         {
2230                                 gui->translating_zoom = 0;
2231                                 gui->reset_affected();
2232                         }
2234 // Get target keyframe
2235                         float last_center_x;
2236                         float last_center_y;
2237                         float last_center_z;
2238                         int created;
2240                         if(!gui->affected_x && !gui->affected_y && !gui->affected_z)
2241                         {
2242                                 FloatAutos *affected_x_autos;
2243                                 FloatAutos *affected_y_autos;
2244                                 FloatAutos *affected_z_autos;
2245                                 if(!gui->affected_track) return 0;
2246                                 double position = mwindow->edl->local_session->get_selectionstart(1);
2247                                 int64_t track_position = gui->affected_track->to_units(position, 0);
2249                                 if(mwindow->edl->session->cwindow_operation == CWINDOW_CAMERA)
2250                                 {
2251                                         affected_x_autos = (FloatAutos*)gui->affected_track->automation->autos[AUTOMATION_CAMERA_X];
2252                                         affected_y_autos = (FloatAutos*)gui->affected_track->automation->autos[AUTOMATION_CAMERA_Y];
2253                                         affected_z_autos = (FloatAutos*)gui->affected_track->automation->autos[AUTOMATION_CAMERA_Z];
2254                                 }
2255                                 else
2256                                 {
2257                                         affected_x_autos = (FloatAutos*)gui->affected_track->automation->autos[AUTOMATION_PROJECTOR_X];
2258                                         affected_y_autos = (FloatAutos*)gui->affected_track->automation->autos[AUTOMATION_PROJECTOR_Y];
2259                                         affected_z_autos = (FloatAutos*)gui->affected_track->automation->autos[AUTOMATION_PROJECTOR_Z];
2260                                 }
2263                                 if(gui->translating_zoom)
2264                                 {
2265                                         FloatAuto *previous = 0;
2266                                         FloatAuto *next = 0;
2267                                         float new_z = affected_z_autos->get_value(
2268                                                 track_position, 
2269                                                 PLAY_FORWARD,
2270                                                 previous,
2271                                                 next);
2272                                         gui->affected_z = 
2273                                                 (FloatAuto*)gui->cwindow->calculate_affected_auto(
2274                                                         affected_z_autos, 1, &created, 0);
2275                                         if(created) 
2276                                         {
2277                                                 gui->affected_z->value = new_z;
2278                                                 gui->affected_z->control_in_value = 0;
2279                                                 gui->affected_z->control_out_value = 0;
2280                                                 gui->affected_z->control_in_position = 0;
2281                                                 gui->affected_z->control_out_position = 0;
2282                                                 redraw_canvas = 1;
2283                                         }
2284                                 }
2285                                 else
2286                                 {
2287                                         FloatAuto *previous = 0;
2288                                         FloatAuto *next = 0;
2289                                         float new_x = affected_x_autos->get_value(
2290                                                 track_position, 
2291                                                 PLAY_FORWARD,
2292                                                 previous,
2293                                                 next);
2294                                         previous = 0;
2295                                         next = 0;
2296                                         float new_y = affected_y_autos->get_value(
2297                                                 track_position, 
2298                                                 PLAY_FORWARD,
2299                                                 previous,
2300                                                 next);
2301                                         gui->affected_x = 
2302                                                 (FloatAuto*)gui->cwindow->calculate_affected_auto(
2303                                                         affected_x_autos, 1, &created, 0);
2304                                         if(created) 
2305                                         {
2306                                                 gui->affected_x->value = new_x;
2307                                                 gui->affected_x->control_in_value = 0;
2308                                                 gui->affected_x->control_out_value = 0;
2309                                                 gui->affected_x->control_in_position = 0;
2310                                                 gui->affected_x->control_out_position = 0;
2311                                                 redraw_canvas = 1;
2312                                         }
2313                                         gui->affected_y = 
2314                                                 (FloatAuto*)gui->cwindow->calculate_affected_auto(
2315                                                         affected_y_autos, 1, &created, 0);
2316                                         if(created) 
2317                                         {
2318                                                 gui->affected_y->value = new_y;
2319                                                 gui->affected_y->control_in_value = 0;
2320                                                 gui->affected_y->control_out_value = 0;
2321                                                 gui->affected_y->control_in_position = 0;
2322                                                 gui->affected_y->control_out_position = 0;
2323                                                 redraw_canvas = 1;
2324                                         }
2325                                 }
2327                                 calculate_origin();
2329                                 if(gui->translating_zoom)
2330                                 {
2331                                         gui->center_z = gui->affected_z->value;
2332                                 }
2333                                 else
2334                                 {
2335                                         gui->center_x = gui->affected_x->value;
2336                                         gui->center_y = gui->affected_y->value;
2337                                 }
2339                                 rerender = 1;
2340                                 redraw = 1;
2341                         }
2344                         if(gui->translating_zoom)
2345                         {
2346                                 last_center_z = gui->affected_z->value;
2347                         }
2348                         else
2349                         {
2350                                 last_center_x = gui->affected_x->value;
2351                                 last_center_y = gui->affected_y->value;
2352                         }
2354                         if(gui->translating_zoom)
2355                         {
2356                                 gui->affected_z->value = gui->center_z + 
2357                                         (cursor_y - gui->y_origin) / 128;
2359                                 if(gui->affected_z->value < 0) gui->affected_z->value = 0;
2360                                 if(!EQUIV(last_center_z, gui->affected_z->value))
2361                                 {
2362                                         rerender = 1;
2363                                         redraw = 1;
2364                                         redraw_canvas = 1;
2365                                 }
2366                         }
2367                         else
2368                         {
2369                                 gui->affected_x->value = gui->center_x + cursor_x - gui->x_origin;
2370                                 gui->affected_y->value = gui->center_y + cursor_y - gui->y_origin;
2371                                 if(!EQUIV(last_center_x,  gui->affected_x->value) ||
2372                                         !EQUIV(last_center_y, gui->affected_y->value))
2373                                 {
2374                                         rerender = 1;
2375                                         redraw = 1;
2376                                         redraw_canvas = 1;
2377                                 }
2378                         }
2379                 }
2381                 result = 1;
2382         }
2383         else
2384 // Begin drag operation.  Don't create keyframe here.
2385         {
2386 // Get affected track off of the first recordable video track.
2387 // Calculating based on the alpha channel would require recording what layer
2388 // each output pixel belongs to as they're rendered and stacked.  Forget it.
2389                 gui->affected_track = gui->cwindow->calculate_affected_track();
2390                 gui->reset_affected();
2392                 if(gui->affected_track)
2393                 {
2394                         gui->current_operation = 
2395                                 mwindow->edl->session->cwindow_operation;
2396                         result = 1;
2397                 }
2398         }
2399         
2400         return result;
2403 int CWindowCanvas::test_zoom(int &redraw)
2405         int result = 0;
2406         float zoom = get_zoom();
2407         float x;
2408         float y;
2410         if(!mwindow->edl->session->cwindow_scrollbars)
2411         {
2412                 mwindow->edl->session->cwindow_scrollbars = 1;
2413                 zoom = 1.0;
2414                 x = mwindow->edl->session->output_w / 2;
2415                 y = mwindow->edl->session->output_h / 2;
2416         }
2417         else
2418         {
2419                 x = get_cursor_x();
2420                 y = get_cursor_y();
2421                 canvas_to_output(mwindow->edl, 
2422                                 0, 
2423                                 x, 
2424                                 y);
2426 //printf("CWindowCanvas::test_zoom 1 %f %f\n", x, y);
2428 // Find current zoom in table
2429                 int current_index = 0;
2430                 for(current_index = 0 ; current_index < total_zooms; current_index++)
2431                         if(EQUIV(my_zoom_table[current_index], zoom)) break;
2434 // Zoom out
2435                 if(get_buttonpress() == 5 ||
2436                         gui->ctrl_down() || 
2437                         gui->shift_down())
2438                 {
2439                         current_index--;
2440                 }
2441                 else
2442 // Zoom in
2443                 {
2444                         current_index++;
2445                 }
2446                 CLAMP(current_index, 0, total_zooms - 1);
2447                 zoom = my_zoom_table[current_index];
2448         }
2450         x = x - w / zoom / 2;
2451         y = y - h / zoom / 2;
2454         int x_i = (int)x;
2455         int y_i = (int)y;
2456 //      check_boundaries(mwindow->edl, x_i, y_i, zoom);
2458 //printf("CWindowCanvas::test_zoom 2 %d %d\n", x_i, y_i);
2460         update_zoom(x_i, 
2461                         y_i, 
2462                         zoom);
2463         reposition_window(mwindow->edl, 
2464                         mwindow->theme->ccanvas_x,
2465                         mwindow->theme->ccanvas_y,
2466                         mwindow->theme->ccanvas_w,
2467                         mwindow->theme->ccanvas_h);
2468         redraw = 1;
2469         result = 1;
2471         
2472         gui->zoom_panel->update(zoom);
2473         
2474         return result;
2478 void CWindowCanvas::calculate_origin()
2480         gui->x_origin = get_cursor_x();
2481         gui->y_origin = get_cursor_y();
2482 //printf("CWindowCanvas::calculate_origin 1 %f %f\n", gui->x_origin, gui->y_origin);
2483         canvas_to_output(mwindow->edl, 0, gui->x_origin, gui->y_origin);
2484 //printf("CWindowCanvas::calculate_origin 2 %f %f\n", gui->x_origin, gui->y_origin);
2488 int CWindowCanvas::cursor_leave_event()
2490         set_cursor(ARROW_CURSOR);
2491         return 1;
2494 int CWindowCanvas::cursor_enter_event()
2496         int redraw = 0;
2497         switch(mwindow->edl->session->cwindow_operation)
2498         {
2499                 case CWINDOW_CAMERA:
2500                 case CWINDOW_PROJECTOR:
2501                         set_cursor(MOVE_CURSOR);
2502                         break;
2503                 case CWINDOW_ZOOM:
2504                         set_cursor(MOVE_CURSOR);
2505                         break;
2506                 case CWINDOW_CROP:
2507                         test_crop(0, redraw);
2508                         break;
2509                 case CWINDOW_PROTECT:
2510                         set_cursor(ARROW_CURSOR);
2511                         break;
2512                 case CWINDOW_MASK:
2513                         set_cursor(CROSS_CURSOR);
2514                         break;
2515                 case CWINDOW_EYEDROP:
2516                         set_cursor(CROSS_CURSOR);
2517                         break;
2518         }
2519         return 1;
2522 int CWindowCanvas::cursor_motion_event()
2524         int redraw = 0, result = 0, rerender = 0, redraw_canvas = 0;
2527         switch(gui->current_operation)
2528         {
2529                 case CWINDOW_SCROLL:
2530                 {
2531                         float zoom = get_zoom();
2532                         float cursor_x = get_cursor_x();
2533                         float cursor_y = get_cursor_y();
2535                         float zoom_x, zoom_y, conformed_w, conformed_h;
2536                         get_zooms(mwindow->edl, 0, zoom_x, zoom_y, conformed_w, conformed_h);
2537                         cursor_x = (float)cursor_x / zoom_x + gui->x_offset;
2538                         cursor_y = (float)cursor_y / zoom_y + gui->y_offset;
2542                         int x = (int)(gui->x_origin - cursor_x + gui->x_offset);
2543                         int y = (int)(gui->y_origin - cursor_y + gui->y_offset);
2545                         update_zoom(x, 
2546                                 y, 
2547                                 zoom);
2548                         update_scrollbars();
2549                         redraw = 1;
2550                         result = 1;
2551                         break;
2552                 }
2554                 case CWINDOW_CAMERA:
2555                         result = test_bezier(0, redraw, redraw_canvas, rerender, 1);
2556                         break;
2558                 case CWINDOW_PROJECTOR:
2559                         result = test_bezier(0, redraw, redraw_canvas, rerender, 0);
2560                         break;
2563                 case CWINDOW_CROP:
2564 //printf("CWindowCanvas::cursor_motion_event 1 %d %d\n", x, y);
2565                         result = test_crop(0, redraw);
2566                         break;
2568                 case CWINDOW_MASK:
2569                 case CWINDOW_MASK_CONTROL_IN:
2570                 case CWINDOW_MASK_CONTROL_OUT:
2571                 case CWINDOW_MASK_TRANSLATE:
2572                         result = do_mask(redraw, 
2573                                 rerender, 
2574                                 0, 
2575                                 1,
2576                                 0);
2577                         break;
2579                 case CWINDOW_EYEDROP:
2580                         result = do_eyedrop(rerender, 0);
2581                         break;
2583         }
2587         if(!result)
2588         {
2589                 switch(mwindow->edl->session->cwindow_operation)
2590                 {
2591                         case CWINDOW_CROP:
2592                                 result = test_crop(0, redraw);
2593                                 break;
2594                 }
2595         }
2598 // If the window is never unlocked before calling send_command the
2599 // display shouldn't get stuck on the old video frame although it will
2600 // flicker between the old video frame and the new video frame.
2602         if(redraw)
2603         {
2604                 draw_refresh();
2605                 gui->update_tool();
2606         }
2608         if(redraw_canvas)
2609         {
2610                 mwindow->gui->lock_window("CWindowCanvas::cursor_motion_event 1");
2611                 mwindow->gui->canvas->draw_overlays();
2612                 mwindow->gui->canvas->flash();
2613                 mwindow->gui->unlock_window();
2614         }
2616         if(rerender)
2617         {
2618                 mwindow->restart_brender();
2619                 mwindow->sync_parameters(CHANGE_PARAMS);
2620                 gui->cwindow->playback_engine->que->send_command(CURRENT_FRAME, 
2621                         CHANGE_NONE,
2622                         mwindow->edl,
2623                         1);
2624                 if(!redraw) gui->update_tool();
2625         }
2626         return result;
2629 int CWindowCanvas::button_press_event()
2631         int result = 0;
2632         int redraw = 0;
2633         int redraw_canvas = 0;
2634         int rerender = 0;
2636         if(Canvas::button_press_event()) return 1;
2638         gui->translating_zoom = gui->shift_down(); 
2640         calculate_origin();
2641 //printf("CWindowCanvas::button_press_event 2 %f %f\n", gui->x_origin, gui->y_origin, gui->x_origin, gui->y_origin);
2643         float zoom_x, zoom_y, conformed_w, conformed_h;
2644         get_zooms(mwindow->edl, 0, zoom_x, zoom_y, conformed_w, conformed_h);
2645         gui->x_offset = get_x_offset(mwindow->edl, 0, zoom_x, conformed_w, conformed_h);
2646         gui->y_offset = get_y_offset(mwindow->edl, 0, zoom_y, conformed_w, conformed_h);
2648 // Scroll view
2649         if(get_buttonpress() == 2)
2650         {
2651                 gui->current_operation = CWINDOW_SCROLL;
2652                 result = 1;
2653         }
2654         else
2655 // Adjust parameter
2656         {
2657                 switch(mwindow->edl->session->cwindow_operation)
2658                 {
2659                         case CWINDOW_CAMERA:
2660                                 result = test_bezier(1, redraw, redraw_canvas, rerender, 1);
2661                                 break;
2663                         case CWINDOW_PROJECTOR:
2664                                 result = test_bezier(1, redraw, redraw_canvas, rerender, 0);
2665                                 break;
2667                         case CWINDOW_ZOOM:
2668                                 result = test_zoom(redraw);
2669                                 break;
2671                         case CWINDOW_CROP:
2672                                 result = test_crop(1, redraw);
2673                                 break;
2675                         case CWINDOW_MASK:
2676                                 if(get_buttonpress() == 1)
2677                                         result = do_mask(redraw, rerender, 1, 0, 0);
2678                                 break;
2680                         case CWINDOW_EYEDROP:
2681                                 result = do_eyedrop(rerender, 1);
2682                                 break;
2683                 }
2684         }
2686         if(redraw)
2687         {
2688                 draw_refresh();
2689                 gui->update_tool();
2690         }
2692 // rerendering can also be caused by press event
2693         if(rerender) 
2694         {
2695                 mwindow->restart_brender();
2696                 mwindow->sync_parameters(CHANGE_PARAMS);
2697                 gui->cwindow->playback_engine->que->send_command(CURRENT_FRAME, 
2698                         CHANGE_NONE,
2699                         mwindow->edl,
2700                         1);
2701                 if(!redraw) gui->update_tool();
2702         }
2703         return result;
2706 int CWindowCanvas::button_release_event()
2708         int result = 0;
2710         switch(gui->current_operation)
2711         {
2712                 case CWINDOW_SCROLL:
2713                         result = 1;
2714                         break;
2716                 case CWINDOW_CAMERA:
2717                         mwindow->undo->update_undo(_("camera"), LOAD_AUTOMATION);
2718                         break;
2720                 case CWINDOW_PROJECTOR:
2721                         mwindow->undo->update_undo(_("projector"), LOAD_AUTOMATION);
2722                         break;
2724                 case CWINDOW_MASK:
2725                 case CWINDOW_MASK_CONTROL_IN:
2726                 case CWINDOW_MASK_CONTROL_OUT:
2727                 case CWINDOW_MASK_TRANSLATE:
2728                         mwindow->undo->update_undo(_("mask point"), LOAD_AUTOMATION);
2729                         break;
2731         }
2733         gui->current_operation = CWINDOW_NONE;
2734         return result;
2737 void CWindowCanvas::zoom_resize_window(float percentage)
2739         int canvas_w, canvas_h;
2740         calculate_sizes(mwindow->edl->get_aspect_ratio(), 
2741                 mwindow->edl->session->output_w, 
2742                 mwindow->edl->session->output_h, 
2743                 percentage,
2744                 canvas_w,
2745                 canvas_h);
2746         int new_w, new_h;
2747         new_w = canvas_w + (gui->get_w() - mwindow->theme->ccanvas_w);
2748         new_h = canvas_h + (gui->get_h() - mwindow->theme->ccanvas_h);
2749         gui->resize_window(new_w, new_h);
2750         gui->resize_event(new_w, new_h);
2753 void CWindowCanvas::toggle_controls()
2755         mwindow->session->cwindow_controls = !mwindow->session->cwindow_controls;
2756         gui->resize_event(gui->get_w(), gui->get_h());
2759 int CWindowCanvas::get_cwindow_controls()
2761         return mwindow->session->cwindow_controls;