r136: This commit was manufactured by cvs2svn to create tag 'hv_1_1_8'.
[cinelerra_cv/mob.git] / hvirtual / cinelerra / cwindowgui.C
blobc3e5b2bf01f3fc3a62f85cc1b148eca97095cbae
1 #include "automation.h"
2 #include "autos.h"
3 #include "bezierauto.h"
4 #include "bezierautos.h"
5 #include "canvas.h"
6 #include "clip.h"
7 #include "cpanel.h"
8 #include "cplayback.h"
9 #include "ctimebar.h"
10 #include "cursors.h"
11 #include "cwindowgui.h"
12 #include "cwindow.h"
13 #include "cwindowtool.h"
14 #include "editpanel.h"
15 #include "edl.h"
16 #include "edlsession.h"
17 #include "floatauto.h"
18 #include "floatautos.h"
19 #include "language.h"
20 #include "localsession.h"
21 #include "mainclock.h"
22 #include "mainmenu.h"
23 #include "mainundo.h"
24 #include "mainsession.h"
25 #include "maskauto.h"
26 #include "maskautos.h"
27 #include "meterpanel.h"
28 #include "mwindowgui.h"
29 #include "mwindow.h"
30 #include "mwindow.h"
31 #include "playtransport.h"
32 #include "theme.h"
33 #include "trackcanvas.h"
34 #include "tracks.h"
35 #include "transportque.h"
36 #include "vtrack.h"
41 CWindowGUI::CWindowGUI(MWindow *mwindow, CWindow *cwindow)
42  : BC_Window(PROGRAM_NAME ": Compositor",
43         mwindow->session->cwindow_x, 
44     mwindow->session->cwindow_y, 
45     mwindow->session->cwindow_w, 
46     mwindow->session->cwindow_h,
47     100,
48     100,
49     1,
50     1,
51     1,
52         BLACK,
53         mwindow->edl->session->get_cwindow_display())
55         this->mwindow = mwindow;
56     this->cwindow = cwindow;
57         affected_track = 0;
58         affected_auto = 0;
59         affected_point = 0;
60         x_offset = 0;
61         y_offset = 0;
62         x_origin = 0;
63         y_origin = 0;
64         current_operation = CWINDOW_NONE;
65         tool_panel = 0;
66         translating_zoom = 0;
69 CWindowGUI::~CWindowGUI()
71         if(tool_panel) delete tool_panel;
72         delete meters;
73         delete composite_panel;
74         delete canvas;
75         delete transport;
76         delete edit_panel;
77         delete zoom_panel;
80 int CWindowGUI::create_objects()
82         set_icon(mwindow->theme->cwindow_icon);
84         mwindow->theme->get_cwindow_sizes(this);
85         mwindow->theme->draw_cwindow_bg(this);
86         flash();
88 // Meters required by composite panel
89         meters = new CWindowMeters(mwindow, 
90                 this,
91                 mwindow->theme->cmeter_x,
92                 mwindow->theme->cmeter_y,
93                 mwindow->theme->cmeter_h);
94         meters->create_objects();
97         composite_panel = new CPanel(mwindow, 
98                 this, 
99                 mwindow->theme->ccomposite_x,
100                 mwindow->theme->ccomposite_y,
101                 mwindow->theme->ccomposite_w,
102                 mwindow->theme->ccomposite_h);
103         composite_panel->create_objects();
105         canvas = new CWindowCanvas(mwindow, this);
106         canvas->create_objects(mwindow->edl);
109         add_subwindow(timebar = new CTimeBar(mwindow,
110                 this,
111                 mwindow->theme->ctimebar_x,
112                 mwindow->theme->ctimebar_y,
113                 mwindow->theme->ctimebar_w, 
114                 mwindow->theme->ctimebar_h));
115         timebar->create_objects();
117         add_subwindow(slider = new CWindowSlider(mwindow, 
118                 cwindow, 
119                 mwindow->theme->cslider_x,
120                 mwindow->theme->cslider_y, 
121                 mwindow->theme->cslider_w));
123         transport = new CWindowTransport(mwindow, 
124                 this, 
125                 mwindow->theme->ctransport_x, 
126                 mwindow->theme->ctransport_y);
127         transport->create_objects();
128         transport->set_slider(slider);
130         edit_panel = new CWindowEditing(mwindow, cwindow);
131         edit_panel->set_meters(meters);
132         edit_panel->create_objects();
134 //      add_subwindow(clock = new MainClock(mwindow, 
135 //              mwindow->theme->ctime_x, 
136 //              mwindow->theme->ctime_y));
138         zoom_panel = new CWindowZoom(mwindow, 
139                 this, 
140                 mwindow->theme->czoom_x, 
141                 mwindow->theme->czoom_y);
142         zoom_panel->create_objects();
143         zoom_panel->zoom_text->add_item(new BC_MenuItem(AUTO_ZOOM));
144         if(!mwindow->edl->session->cwindow_scrollbars) zoom_panel->set_text(AUTO_ZOOM);
146 //      destination = new CWindowDestination(mwindow, 
147 //              this, 
148 //              mwindow->theme->cdest_x,
149 //              mwindow->theme->cdest_y);
150 //      destination->create_objects();
152 // Must create after meter panel
153         tool_panel = new CWindowTool(mwindow, this);
154         tool_panel->Thread::start();
155         
156         set_operation(mwindow->edl->session->cwindow_operation);
157         canvas->draw_refresh();
160         return 0;
163 int CWindowGUI::translation_event()
165         mwindow->session->cwindow_x = get_x();
166         mwindow->session->cwindow_y = get_y();
167         return 0;
170 int CWindowGUI::resize_event(int w, int h)
172         mwindow->session->cwindow_x = get_x();
173         mwindow->session->cwindow_y = get_y();
174         mwindow->session->cwindow_w = w;
175         mwindow->session->cwindow_h = h;
177 //printf("CWindowGUI::resize_event 1\n");
178         mwindow->theme->get_cwindow_sizes(this);
179         mwindow->theme->draw_cwindow_bg(this);
180         flash();
182 //printf("CWindowGUI::resize_event 1\n");
183         composite_panel->reposition_buttons(mwindow->theme->ccomposite_x,
184                 mwindow->theme->ccomposite_y);
185 //printf("CWindowGUI::resize_event 1\n");
187         canvas->reposition_window(mwindow->edl,
188                 mwindow->theme->ccanvas_x,
189                 mwindow->theme->ccanvas_y,
190                 mwindow->theme->ccanvas_w,
191                 mwindow->theme->ccanvas_h);
193         timebar->resize_event();
195         slider->reposition_window(mwindow->theme->cslider_x,
196                 mwindow->theme->cslider_y, 
197                 mwindow->theme->cslider_w);
198 // Recalibrate pointer motion range
199         slider->set_position();
200 //printf("CWindowGUI::resize_event 1\n");
202         transport->reposition_buttons(mwindow->theme->ctransport_x, 
203                 mwindow->theme->ctransport_y);
204 //printf("CWindowGUI::resize_event 1\n");
206         edit_panel->reposition_buttons(mwindow->theme->cedit_x, 
207                 mwindow->theme->cedit_y);
208 //printf("CWindowGUI::resize_event 1\n");
210 //      clock->reposition_window(mwindow->theme->ctime_x, 
211 //              mwindow->theme->ctime_y);
212 //printf("CWindowGUI::resize_event 1\n");
214         zoom_panel->reposition_window(mwindow->theme->czoom_x, 
215                 mwindow->theme->czoom_y);
216 //printf("CWindowGUI::resize_event 1\n");
218 //      destination->reposition_window(mwindow->theme->cdest_x,
219 //              mwindow->theme->cdest_y);
220 //printf("CWindowGUI::resize_event 1\n");
222         meters->reposition_window(mwindow->theme->cmeter_x,
223                 mwindow->theme->cmeter_y,
224                 mwindow->theme->cmeter_h);
225 //printf("CWindowGUI::resize_event 2\n");
227         BC_WindowBase::resize_event(w, h);
228         return 1;
236 // TODO
237 // Don't refresh the canvas in a load file operation which is going to
238 // refresh it anyway.
239 void CWindowGUI::set_operation(int value)
241 //printf("CWindowGUI::set_operation 1 %d\n", value);
242         mwindow->edl->session->cwindow_operation = value;
243 //printf("CWindowGUI::set_operation 1 %d\n", value);
245         composite_panel->set_operation(value);
246 //printf("CWindowGUI::set_operation 1 %d\n", value);
247         edit_panel->update();
249         tool_panel->start_tool(value);
250         canvas->draw_refresh();
251 //printf("CWindowGUI::set_operation 2 %d\n", value);
254 void CWindowGUI::update_tool()
256 //printf("CWindowGUI::update_tool 1\n");
257         tool_panel->update_values();
260 int CWindowGUI::close_event()
262         hide_window();
263         mwindow->session->show_cwindow = 0;
264         mwindow->gui->lock_window("CWindowGUI::close_event");
265         mwindow->gui->mainmenu->show_cwindow->set_checked(0);
266         mwindow->gui->unlock_window();
267         mwindow->save_defaults();
268         return 1;
272 int CWindowGUI::keypress_event()
274         int result = 0;
276 //printf("CWindowGUI::keypress_event 1\n");
277         switch(get_keypress())
278         {
279                 case 'w':
280                 case 'W':
281                         close_event();
282                         result = 1;
283                         break;
284         }
286 //printf("CWindowGUI::keypress_event 1\n");
287         if(!result) result = transport->keypress_event();
289 //printf("CWindowGUI::keypress_event 2\n");
290         return result;
293 void CWindowGUI::drag_motion()
295         if(get_hidden()) return;
297         if(mwindow->session->current_operation == DRAG_ASSET ||
298                 mwindow->session->current_operation == DRAG_VTRANSITION ||
299                 mwindow->session->current_operation == DRAG_VEFFECT)
300         {
301                 int old_status = mwindow->session->ccanvas_highlighted;
302                 int cursor_x = get_relative_cursor_x();
303                 int cursor_y = get_relative_cursor_y();
305                 mwindow->session->ccanvas_highlighted = get_cursor_over_window() &&
306                         cursor_x >= canvas->x &&
307                         cursor_x < canvas->x + canvas->w &&
308                         cursor_y >= canvas->y &&
309                         cursor_y < canvas->y + canvas->h;
312                 if(old_status != mwindow->session->ccanvas_highlighted)
313                         canvas->draw_refresh();
314         }
317 int CWindowGUI::drag_stop()
319         int result = 0;
320         if(get_hidden()) return 0;
322         if((mwindow->session->current_operation == DRAG_ASSET ||
323                 mwindow->session->current_operation == DRAG_VTRANSITION ||
324                 mwindow->session->current_operation == DRAG_VEFFECT) &&
325                 mwindow->session->ccanvas_highlighted)
326         {
327 // Hide highlighting
328                 mwindow->session->ccanvas_highlighted = 0;
329                 canvas->draw_refresh();
330                 result = 1;
331         }
332         else
333                 return 0;
335         if(mwindow->session->current_operation == DRAG_ASSET)
336         {
337                 if(mwindow->session->drag_assets->total)
338                 {
339                         mwindow->gui->lock_window("CWindowGUI::drag_stop 1");
340                         mwindow->undo->update_undo_before(_("insert assets"), 
341                                 LOAD_ALL);
342                         mwindow->clear(0);
343                         mwindow->load_assets(mwindow->session->drag_assets, 
344                                 mwindow->edl->local_session->get_selectionstart(), 
345                                 LOAD_PASTE,
346                                 mwindow->session->track_highlighted,
347                                 0,
348                                 mwindow->edl->session->labels_follow_edits, 
349                                 mwindow->edl->session->plugins_follow_edits);
350                 }
352                 if(mwindow->session->drag_clips->total)
353                 {
354                         mwindow->gui->lock_window("CWindowGUI::drag_stop 2");
355                         mwindow->undo->update_undo_before(_("insert assets"), 
356                                 LOAD_ALL);
357                         mwindow->clear(0);
358                         mwindow->paste_edls(mwindow->session->drag_clips, 
359                                 LOAD_PASTE, 
360                                 mwindow->session->track_highlighted,
361                                 mwindow->edl->local_session->get_selectionstart(),
362                                 mwindow->edl->session->labels_follow_edits, 
363                                 mwindow->edl->session->plugins_follow_edits);
364                 }
366                 if(mwindow->session->drag_assets->total ||
367                         mwindow->session->drag_clips->total)
368                 {
369                         mwindow->save_backup();
370                         mwindow->restart_brender();
371                         mwindow->gui->update(1, 1, 1, 1, 0, 1, 0);
372                         mwindow->undo->update_undo_after();
373                         mwindow->gui->unlock_window();
374                         mwindow->sync_parameters(LOAD_ALL);
375                 }
376         }
378         if(mwindow->session->current_operation == DRAG_VEFFECT)
379         {
380 //printf("CWindowGUI::drag_stop 1\n");
381                 Track *affected_track = cwindow->calculate_affected_track();
382 //printf("CWindowGUI::drag_stop 2\n");
384                 mwindow->gui->lock_window("CWindowGUI::drag_stop 3");
385                 mwindow->insert_effects_cwindow(affected_track);
386                 mwindow->session->current_operation = NO_OPERATION;
387                 mwindow->gui->unlock_window();
388         }
390         if(mwindow->session->current_operation == DRAG_VTRANSITION)
391         {
392                 Track *affected_track = cwindow->calculate_affected_track();
393                 mwindow->gui->lock_window("CWindowGUI::drag_stop 4");
394                 mwindow->paste_transition_cwindow(affected_track);
395                 mwindow->session->current_operation = NO_OPERATION;
396                 mwindow->gui->unlock_window();
397         }
399         return result;
403 CWindowEditing::CWindowEditing(MWindow *mwindow, CWindow *cwindow)
404  : EditPanel(mwindow, 
405                 cwindow->gui, 
406                 mwindow->theme->cedit_x, 
407                 mwindow->theme->cedit_y,
408                 mwindow->edl->session->editing_mode, 
409                 0,
410                 1,
411                 0, 
412                 0,
413                 1,
414                 1,
415                 1,
416                 1,
417                 1,
418                 0,
419                 1,
420                 1,
421                 1,
422                 0,
423                 1)
425         this->mwindow = mwindow;
426         this->cwindow = cwindow;
429 void CWindowEditing::set_inpoint()
431         mwindow->set_inpoint(0);
434 void CWindowEditing::set_outpoint()
436         mwindow->set_outpoint(0);
443 CWindowMeters::CWindowMeters(MWindow *mwindow, CWindowGUI *gui, int x, int y, int h)
444  : MeterPanel(mwindow, 
445                 gui,
446                 x,
447                 y,
448                 h,
449                 mwindow->edl->session->audio_channels,
450                 mwindow->edl->session->cwindow_meter)
452         this->mwindow = mwindow;
453         this->gui = gui;
456 CWindowMeters::~CWindowMeters()
460 int CWindowMeters::change_status_event()
462 //printf("CWindowMeters::change_status_event 1 %d\n", gui->meters->use_meters);
463         mwindow->edl->session->cwindow_meter = use_meters;
464         mwindow->theme->get_cwindow_sizes(gui);
465         gui->resize_event(gui->get_w(), gui->get_h());
466         return 1;
471 #define MIN_ZOOM 0.25
472 #define MAX_ZOOM 4.0
474 CWindowZoom::CWindowZoom(MWindow *mwindow, CWindowGUI *gui, int x, int y)
475  : ZoomPanel(mwindow, 
476         gui, 
477         (long)mwindow->edl->session->cwindow_zoom, 
478         x, 
479         y,
480         100, 
481         MIN_ZOOM, 
482         MAX_ZOOM, 
483         ZOOM_PERCENTAGE)
485         this->mwindow = mwindow;
486         this->gui = gui;
489 CWindowZoom::~CWindowZoom()
493 int CWindowZoom::handle_event()
495         if(!strcasecmp(AUTO_ZOOM, get_text()))
496         {
497                 mwindow->edl->session->cwindow_scrollbars = 0;
498         }
499         else
500         {
501                 mwindow->edl->session->cwindow_scrollbars = 1;
502         }
504 //printf("CWindowZoom::handle_event 1 %d %d\n", gui->canvas->get_xscroll(), gui->canvas->get_yscroll());
505         gui->canvas->update_zoom(gui->canvas->get_xscroll(), 
506                 gui->canvas->get_yscroll(), 
507                 get_value());
508 //printf("CWindowZoom::handle_event 2 %d %d\n", gui->canvas->get_xscroll(), gui->canvas->get_yscroll());
509         gui->canvas->reposition_window(mwindow->edl, 
510                 mwindow->theme->ccanvas_x,
511                 mwindow->theme->ccanvas_y,
512                 mwindow->theme->ccanvas_w,
513                 mwindow->theme->ccanvas_h);
514 //printf("CWindowZoom::handle_event 3 %d %d\n", gui->canvas->get_xscroll(), gui->canvas->get_yscroll());
515         gui->canvas->draw_refresh();
516 //printf("CWindowZoom::handle_event 4 %d %d\n", gui->canvas->get_xscroll(), gui->canvas->get_yscroll());
517         return 1;
522 CWindowSlider::CWindowSlider(MWindow *mwindow, CWindow *cwindow, int x, int y, int pixels)
523  : BC_PercentageSlider(x, 
524                         y,
525                         0,
526                         pixels, 
527                         pixels, 
528                         0, 
529                         1, 
530                         0)
532         this->mwindow = mwindow;
533         this->cwindow = cwindow;
536 CWindowSlider::~CWindowSlider()
540 int CWindowSlider::handle_event()
542         unlock_window();
543         cwindow->playback_engine->interrupt_playback(1);
544         lock_window("CWindowSlider::handle_event 1");
545         
546         mwindow->gui->lock_window("CWindowSlider::handle_event 2");
547         mwindow->select_point((double)get_value());
548         mwindow->gui->unlock_window();
549         return 1;
552 void CWindowSlider::set_position()
554         double new_length = mwindow->edl->tracks->total_playable_length();
555         if(mwindow->edl->local_session->preview_end <= 0 ||
556                 mwindow->edl->local_session->preview_end > new_length)
557                 mwindow->edl->local_session->preview_end = new_length;
558         if(mwindow->edl->local_session->preview_start > 
559                 mwindow->edl->local_session->preview_end)
560                 mwindow->edl->local_session->preview_start = 0;
564         update(mwindow->theme->cslider_w, 
565                 mwindow->edl->local_session->selectionstart, 
566                 mwindow->edl->local_session->preview_start, 
567                 mwindow->edl->local_session->preview_end);
571 int CWindowSlider::increase_value()
573         unlock_window();
574         cwindow->gui->transport->handle_transport(SINGLE_FRAME_FWD);
575         lock_window("CWindowSlider::increase_value");
576         return 1;
579 int CWindowSlider::decrease_value()
581         unlock_window();
582         cwindow->gui->transport->handle_transport(SINGLE_FRAME_REWIND);
583         lock_window("CWindowSlider::decrease_value");
584         return 1;
588 // CWindowDestination::CWindowDestination(MWindow *mwindow, CWindowGUI *cwindow, int x, int y)
589 //  : BC_PopupTextBox(cwindow, 
590 //      &cwindow->destinations, 
591 //      cwindow->destinations.values[cwindow->cwindow->destination]->get_text(),
592 //      x, 
593 //      y, 
594 //      70, 
595 //      200)
596 // {
597 //      this->mwindow = mwindow;
598 //      this->cwindow = cwindow;
599 // }
600 // 
601 // CWindowDestination::~CWindowDestination()
602 // {
603 // }
604 // 
605 // int CWindowDestination::handle_event()
606 // {
607 //      return 1;
608 // }
611 CWindowTransport::CWindowTransport(MWindow *mwindow, 
612         CWindowGUI *gui, 
613         int x, 
614         int y)
615  : PlayTransport(mwindow, 
616         gui, 
617         x, 
618         y)
620         this->gui = gui;
623 EDL* CWindowTransport::get_edl()
625         return mwindow->edl;
628 void CWindowTransport::goto_start()
630         gui->unlock_window();
631         handle_transport(REWIND, 1);
633         mwindow->gui->lock_window("CWindowTransport::goto_start 1");
634         mwindow->goto_start();
635         mwindow->gui->unlock_window();
637         gui->lock_window("CWindowTransport::goto_start 2");
640 void CWindowTransport::goto_end()
642         gui->unlock_window();
643         handle_transport(GOTO_END, 1);
645         mwindow->gui->lock_window("CWindowTransport::goto_end 1");
646         mwindow->goto_end();
647         mwindow->gui->unlock_window();
649         gui->lock_window("CWindowTransport::goto_end 2");
654 CWindowCanvas::CWindowCanvas(MWindow *mwindow, CWindowGUI *gui)
655  : Canvas(gui,
656                 mwindow->theme->ccanvas_x,
657                 mwindow->theme->ccanvas_y,
658                 mwindow->theme->ccanvas_w,
659                 mwindow->theme->ccanvas_h,
660                 0,
661                 0,
662                 mwindow->edl->session->cwindow_scrollbars,
663                 1)
665         this->mwindow = mwindow;
666         this->gui = gui;
669 void CWindowCanvas::update_zoom(int x, int y, float zoom)
671         use_scrollbars = mwindow->edl->session->cwindow_scrollbars;
673         mwindow->edl->session->cwindow_xscroll = x;
674         mwindow->edl->session->cwindow_yscroll = y;
675         mwindow->edl->session->cwindow_zoom = zoom;
678 int CWindowCanvas::get_xscroll()
680         return mwindow->edl->session->cwindow_xscroll;
683 int CWindowCanvas::get_yscroll()
685         return mwindow->edl->session->cwindow_yscroll;
689 float CWindowCanvas::get_zoom()
691         return mwindow->edl->session->cwindow_zoom;
694 void CWindowCanvas::draw_refresh()
696         if(!canvas->video_is_on())
697         {
698 //printf("CWindowCanvas::draw_refresh 1 %f\n", mwindow->edl->session->cwindow_zoom);
699                 canvas->clear_box(0, 0, canvas->get_w(), canvas->get_h());
700 //printf("CWindowCanvas::draw_refresh 2\n");
702                 if(refresh_frame)
703                 {
704                         int in_x, in_y, in_w, in_h, out_x, out_y, out_w, out_h;
705 //printf("CWindowCanvas::draw_refresh 3\n");
706                         get_transfers(mwindow->edl, 
707                                 in_x, 
708                                 in_y, 
709                                 in_w, 
710                                 in_h, 
711                                 out_x, 
712                                 out_y, 
713                                 out_w, 
714                                 out_h);
717 // printf("CWindowCanvas::draw_refresh %d %d %d %d -> %d %d %d %d\n", in_x, in_y, in_w, in_h, out_x, out_y, out_w, out_h);
718 //                      canvas->clear_box(0, 0, canvas->get_w(), canvas->get_h());
721 //printf("CWindowCanvas::draw_refresh 5\n");
722                         if(out_w > 0 && out_h > 0 && in_w > 0 && in_h > 0)
723                                 canvas->draw_vframe(refresh_frame,
724                                                 out_x, 
725                                                 out_y, 
726                                                 out_w, 
727                                                 out_h,
728                                                 in_x, 
729                                                 in_y, 
730                                                 in_w, 
731                                                 in_h,
732                                                 0);
733 //printf("CWindowCanvas::draw_refresh 6\n");
734                 }
735                 else
736                 {
737 //printf("CWindowCanvas::draw_refresh 7\n");
738                         canvas->clear_box(0, 0, canvas->get_w(), canvas->get_h());
739 //printf("CWindowCanvas::draw_refresh 8\n");
740                 }
742 //printf("CWindowCanvas::draw_refresh 9\n");
743                 draw_overlays();
744                 canvas->flash();
745                 canvas->flush();
746 //printf("CWindowCanvas::draw_refresh 10\n");
747         }
750 #define CROPHANDLE_W 10
751 #define CROPHANDLE_H 10
753 void CWindowCanvas::draw_crophandle(int x, int y)
755         canvas->draw_box(x, y, CROPHANDLE_W, CROPHANDLE_H);
758 #define CONTROL_W 10
759 #define CONTROL_H 10
760 #define FIRST_CONTROL_W 20
761 #define FIRST_CONTROL_H 20
762 #undef BC_INFINITY
763 #define BC_INFINITY 65536
764 #ifndef SQR
765 #define SQR(x) ((x) * (x))
766 #endif
768 int CWindowCanvas::do_mask(int &redraw, 
769                 int &rerender, 
770                 int button_press, 
771                 int cursor_motion,
772                 int draw)
774 // Retrieve points from top recordable track
775 //printf("CWindowCanvas::do_mask 1\n");
776         Track *track = gui->cwindow->calculate_affected_track();
777 //printf("CWindowCanvas::do_mask 2\n");
779         if(!track) return 0;
780 //printf("CWindowCanvas::do_mask 3\n");
782         MaskAutos *mask_autos = track->automation->mask_autos;
783         long position = track->to_units(mwindow->edl->local_session->selectionstart,
784                 0);
785         ArrayList<MaskPoint*> points;
786         mask_autos->get_points(&points, mwindow->edl->session->cwindow_mask,
787                 position, 
788                 PLAY_FORWARD);
789 //printf("CWindowCanvas::do_mask 4\n");
791 // Translate mask to projection
792         BezierAutos *projector_autos = track->automation->projector_autos;
793         FloatAutos *projector_zooms = track->automation->pzoom_autos;
794         BezierAuto *before = 0, *after = 0;
795         FloatAuto *zoom_before = 0, *zoom_after = 0;
796         float projector_x, projector_y, projector_z;
797 // Projector zooms relative to the center of the track output.
798         float half_track_w = (float)track->track_w / 2;
799         float half_track_h = (float)track->track_h / 2;
800         projector_autos->get_center(projector_x, 
801                         projector_y, 
802                         projector_z, 
803                         position, 
804                         PLAY_FORWARD, 
805                         &before, 
806                         &after);
807         projector_z = projector_zooms->get_value(position,
808                 PLAY_FORWARD,
809                 zoom_before,
810                 zoom_after);
811 // printf("CWindowCanvas::do_mask 1 %f %f %f\n", projector_x, 
812 //                      projector_y, 
813 //                      projector_z);
816 // Get position of cursor relative to mask
817         float mask_cursor_x = get_cursor_x();
818         float mask_cursor_y = get_cursor_y();
819         canvas_to_output(mwindow->edl, 0, mask_cursor_x, mask_cursor_y);
821         mask_cursor_x -= projector_x;
822         mask_cursor_y -= projector_y;
823         mask_cursor_x = half_track_w + (mask_cursor_x - half_track_w) / projector_z;
824         mask_cursor_y = half_track_h + (mask_cursor_y - half_track_h) / projector_z;
826 // Fix cursor origin
827         if(button_press)
828         {
829                 gui->x_origin = mask_cursor_x;
830                 gui->y_origin = mask_cursor_y;
831         }
833         int result = 0;
834 // Points of closest line
835         int shortest_point1 = -1;
836         int shortest_point2 = -1;
837 // Closest point
838         int shortest_point = -1;
839 // Distance to closest line
840         float shortest_line_distance = BC_INFINITY;
841 // Distance to closest point
842         float shortest_point_distance = BC_INFINITY;
843         int selected_point = -1;
844         int selected_control_point = -1;
845         float selected_control_point_distance = BC_INFINITY;
846         ArrayList<int> x_points;
847         ArrayList<int> y_points;
849         if(!cursor_motion)
850         {
851                 if(draw)
852                 {
853                         canvas->set_color(WHITE);
854                         canvas->set_inverse();
855                 }
856 //printf("CWindowCanvas::do_mask 1 %d\n", points.total);
858 // Never draw closed polygon and a closed
859 // polygon is harder to add points to.
860                 for(int i = 0; i < points.total && !result; i++)
861                 {
862                         MaskPoint *point1 = points.values[i];
863                         MaskPoint *point2 = (i >= points.total - 1) ? 
864                                 points.values[0] : 
865                                 points.values[i + 1];
866                         float x0, x1, x2, x3;
867                         float y0, y1, y2, y3;
868                         float old_x, old_y, x, y;
869                         int segments = (int)(sqrt(SQR(point1->x - point2->x) + SQR(point1->y - point2->y)));
871 //printf("CWindowCanvas::do_mask 1 %f, %f -> %f, %f projectorz=%f\n",
872 //point1->x, point1->y, point2->x, point2->y, projector_z);
873                         for(int j = 0; j <= segments && !result; j++)
874                         {
875 //printf("CWindowCanvas::do_mask 1 %f, %f -> %f, %f\n", x0, y0, x3, y3);
876                                 x0 = point1->x;
877                                 y0 = point1->y;
878                                 x1 = point1->x + point1->control_x2;
879                                 y1 = point1->y + point1->control_y2;
880                                 x2 = point2->x + point2->control_x1;
881                                 y2 = point2->y + point2->control_y1;
882                                 x3 = point2->x;
883                                 y3 = point2->y;
885                                 float t = (float)j / segments;
886                                 float tpow2 = t * t;
887                                 float tpow3 = t * t * t;
888                                 float invt = 1 - t;
889                                 float invtpow2 = invt * invt;
890                                 float invtpow3 = invt * invt * invt;
892                                 x = (        invtpow3 * x0
893                                         + 3 * t     * invtpow2 * x1
894                                         + 3 * tpow2 * invt     * x2 
895                                         +     tpow3            * x3);
896                                 y = (        invtpow3 * y0 
897                                         + 3 * t     * invtpow2 * y1
898                                         + 3 * tpow2 * invt     * y2 
899                                         +     tpow3            * y3);
901                                 x = half_track_w + (x - half_track_w) * projector_z + projector_x;
902                                 y = half_track_h + (y - half_track_h) * projector_z + projector_y;
905 // Test new point addition
906                                 if(button_press)
907                                 {
908                                         float line_distance = 
909                                                 sqrt(SQR(x - mask_cursor_x) + SQR(y - mask_cursor_y));
911 //printf("CWindowCanvas::do_mask 1 x=%f mask_cursor_x=%f y=%f mask_cursor_y=%f %f %f %d, %d\n", 
912 //x, mask_cursor_x, y, mask_cursor_y, line_distance, shortest_line_distance, shortest_point1, shortest_point2);
913                                         if(line_distance < shortest_line_distance || 
914                                                 shortest_point1 < 0)
915                                         {
916                                                 shortest_line_distance = line_distance;
917                                                 shortest_point1 = i;
918                                                 shortest_point2 = (i >= points.total - 1) ? 0 : (i + 1);
919 //printf("CWindowCanvas::do_mask 2 %f %f %d, %d\n", line_distance, shortest_line_distance, shortest_point1, shortest_point2);
920                                         }
923                                         float point_distance1 = 
924                                                 sqrt(SQR(point1->x - mask_cursor_x) + SQR(point1->y - mask_cursor_y));
925                                         float point_distance2 = 
926                                                 sqrt(SQR(point2->x - mask_cursor_x) + SQR(point2->y - mask_cursor_y));
928                                         if(point_distance1 < shortest_point_distance || 
929                                                 shortest_point < 0)
930                                         {
931                                                 shortest_point_distance = point_distance1;
932                                                 shortest_point = i;
933                                         }
935                                         if(point_distance2 < shortest_point_distance || 
936                                                 shortest_point < 0)
937                                         {
938                                                 shortest_point_distance = point_distance2;
939                                                 shortest_point = (i >= points.total - 1) ? 0 : (i + 1);
940                                         }
941                                 }
943                                 output_to_canvas(mwindow->edl, 0, x, y);
946 #define TEST_BOX(cursor_x, cursor_y, target_x, target_y) \
947         (cursor_x >= target_x - CONTROL_W / 2 && \
948         cursor_x < target_x + CONTROL_W / 2 && \
949         cursor_y >= target_y - CONTROL_H / 2 && \
950         cursor_y < target_y + CONTROL_H / 2)
952 // Test existing point selection
953                                 if(button_press)
954                                 {
955                                         float canvas_x = half_track_w + (x0 - half_track_w) * projector_z + projector_x;
956                                         float canvas_y = half_track_h + (y0 - half_track_h) * projector_z + projector_y;
957                                         int cursor_x = get_cursor_x();
958                                         int cursor_y = get_cursor_y();
960 // Test first point
961                                         if(gui->shift_down())
962                                         {
963                                                 float control_x = half_track_w + (x1 - half_track_w) * projector_z + projector_x;
964                                                 float control_y = half_track_h + (y1 - half_track_h) * projector_z + projector_y;
965                                                 output_to_canvas(mwindow->edl, 0, control_x, control_y);
967                                                 float distance = 
968                                                         sqrt(SQR(control_x - cursor_x) + SQR(control_y - cursor_y));
970                                                 if(distance < selected_control_point_distance)
971                                                 {
972                                                         selected_point = i;
973                                                         selected_control_point = 1;
974                                                         selected_control_point_distance = distance;
975                                                 }
976                                         }
977                                         else
978                                         {
979                                                 output_to_canvas(mwindow->edl, 0, canvas_x, canvas_y);
980                                                 if(!gui->ctrl_down())
981                                                 {
982                                                         if(TEST_BOX(cursor_x, cursor_y, canvas_x, canvas_y))
983                                                         {
984                                                                 selected_point = i;
985                                                         }
986                                                 }
987                                                 else
988                                                 {
989                                                         selected_point = shortest_point;
990                                                 }
991                                         }
993 // Test second point
994                                         canvas_x = half_track_w + (x3 - half_track_w) * projector_z + projector_x;
995                                         canvas_y = half_track_h + (y3 - half_track_h) * projector_z + projector_y;
996                                         if(gui->shift_down())
997                                         {
998                                                 float control_x = half_track_w + (x2 - half_track_w) * projector_z + projector_x;
999                                                 float control_y = half_track_h + (y2 - half_track_h) * projector_z + projector_y;
1000                                                 output_to_canvas(mwindow->edl, 0, control_x, control_y);
1002                                                 float distance = 
1003                                                         sqrt(SQR(control_x - cursor_x) + SQR(control_y - cursor_y));
1005 //printf("CWindowCanvas::do_mask %d %f %f\n", i, distance, selected_control_point_distance);
1006                                                 if(distance < selected_control_point_distance)
1007                                                 {
1008                                                         selected_point = (i < points.total - 1 ? i + 1 : 0);
1009                                                         selected_control_point = 0;
1010                                                         selected_control_point_distance = distance;
1011                                                 }
1012                                         }
1013                                         else
1014                                         if(i < points.total - 1)
1015                                         {
1016                                                 output_to_canvas(mwindow->edl, 0, canvas_x, canvas_y);
1017                                                 if(!gui->ctrl_down())
1018                                                 {
1019                                                         if(TEST_BOX(cursor_x, cursor_y, canvas_x, canvas_y))
1020                                                         {
1021                                                                 selected_point = (i < points.total - 1 ? i + 1 : 0);
1022                                                         }
1023                                                 }
1024                                                 else
1025                                                 {
1026                                                         selected_point = shortest_point;
1027                                                 }
1028                                         }
1029                                 }
1033                                 if(j > 0)
1034                                 {
1035 // Draw joining line
1036                                         if(draw)
1037                                         {
1038                                                 x_points.append((int)x);
1039                                                 y_points.append((int)y);
1040                                         }
1042                                         if(j == segments)
1043                                         {
1048                                                 if(draw)
1049                                                 {
1050 // Draw second anchor
1051                                                         if(i < points.total - 1)
1052                                                         {
1053                                                                 if(i == gui->affected_point - 1)
1054                                                                         canvas->draw_disc((int)x - CONTROL_W / 2, 
1055                                                                                 (int)y - CONTROL_W / 2, 
1056                                                                                 CONTROL_W, 
1057                                                                                 CONTROL_W);
1058                                                                 else
1059                                                                         canvas->draw_circle((int)x - CONTROL_W / 2, 
1060                                                                                 (int)y - CONTROL_W / 2, 
1061                                                                                 CONTROL_W, 
1062                                                                                 CONTROL_W);
1063 // char string[BCTEXTLEN];
1064 // sprintf(string, "%d", (i < points.total - 1 ? i + 1 : 0));
1065 // canvas->draw_text((int)x + CONTROL_W, (int)y + CONTROL_W, string);
1066                                                         }
1068 // Draw second control point.  Discard x2 and y2 after this.
1069                                                         x2 = half_track_w + (x2 - half_track_w) * projector_z + projector_x;
1070                                                         y2 = half_track_h + (y2 - half_track_h) * projector_z + projector_y;
1071                                                         output_to_canvas(mwindow->edl, 0, x2, y2);
1072                                                         canvas->draw_line((int)x, (int)y, (int)x2, (int)y2);
1073                                                         canvas->draw_rectangle((int)x2 - CONTROL_W / 2,
1074                                                                 (int)y2 - CONTROL_H / 2,
1075                                                                 CONTROL_W,
1076                                                                 CONTROL_H);
1077                                                 }
1078                                         }
1079                                 }
1080                                 else
1081                                 {
1084 // Draw first anchor
1085                                         if(i == 0 && draw)
1086                                         {
1087                                                 canvas->draw_disc((int)x - FIRST_CONTROL_W / 2, 
1088                                                         (int)y - FIRST_CONTROL_H / 2, 
1089                                                         FIRST_CONTROL_W, 
1090                                                         FIRST_CONTROL_H);
1091                                         }
1093 // Draw first control point.  Discard x1 and y1 after this.
1094                                         if(draw)
1095                                         {
1096                                                 x1 = half_track_w + (x1 - half_track_w) * projector_z + projector_x;
1097                                                 y1 = half_track_h + (y1 - half_track_h) * projector_z + projector_y;
1098                                                 output_to_canvas(mwindow->edl, 0, x1, y1);
1099                                                 canvas->draw_line((int)x, (int)y, (int)x1, (int)y1);
1100                                                 canvas->draw_rectangle((int)x1 - CONTROL_W / 2,
1101                                                         (int)y1 - CONTROL_H / 2,
1102                                                         CONTROL_W,
1103                                                         CONTROL_H);
1104                                         
1105                                                 x_points.append((int)x);
1106                                                 y_points.append((int)y);
1107                                         }
1108                                 }
1109 //printf("CWindowCanvas::do_mask 1\n");
1111                                 old_x = x;
1112                                 old_y = y;
1113                         }
1114                 }
1115 //printf("CWindowCanvas::do_mask 1\n");
1117                 if(draw)
1118                 {
1119                         canvas->draw_polygon(&x_points, &y_points);
1120                         canvas->set_opaque();
1121                 }
1122 //printf("CWindowCanvas::do_mask 1\n");
1123         }
1131         if(button_press && !result)
1132         {
1133 //printf("CWindowCanvas::do_mask 5\n");
1134                 gui->affected_track = gui->cwindow->calculate_affected_track();
1135 // Get current keyframe
1136                 if(gui->affected_track)
1137                         gui->affected_auto = 
1138                                 gui->cwindow->calculate_affected_auto(gui->affected_track->automation->mask_autos);
1140                 MaskAuto *keyframe = (MaskAuto*)gui->affected_auto;
1141                 SubMask *mask = keyframe->get_submask(mwindow->edl->session->cwindow_mask);
1143 //printf("CWindowCanvas::do_mask 6 %d %d\n", gui->alt_down(), mask->points.total);
1145 // Translate entire keyframe
1146                 if(gui->alt_down() && mask->points.total)
1147                 {
1148                         gui->current_operation = CWINDOW_MASK_TRANSLATE;
1149                         gui->affected_point = 0;
1150                 }
1151                 else
1152 // Existing point or control point was selected
1153                 if(selected_point >= 0)
1154                 {
1155                         gui->affected_point = selected_point;
1157                         if(selected_control_point == 0)
1158                                 gui->current_operation = CWINDOW_MASK_CONTROL_IN;
1159                         else
1160                         if(selected_control_point == 1)
1161                                 gui->current_operation = CWINDOW_MASK_CONTROL_OUT;
1162                         else
1163                                 gui->current_operation = mwindow->edl->session->cwindow_operation;
1164                 }
1165                 else
1166 // No existing point or control point was selected so create a new one
1167                 if(!gui->shift_down() && !gui->alt_down())
1168                 {
1169 // Create the template
1170                         MaskPoint *point = new MaskPoint;
1171                         point->x = mask_cursor_x;
1172                         point->y = mask_cursor_y;
1173                         point->control_x1 = 0;
1174                         point->control_y1 = 0;
1175                         point->control_x2 = 0;
1176                         point->control_y2 = 0;
1178                         mwindow->undo->update_undo_before(_("mask point"), LOAD_AUTOMATION);
1180                         if(shortest_point2 < shortest_point1)
1181                         {
1182                                 shortest_point2 ^= shortest_point1;
1183                                 shortest_point1 ^= shortest_point2;
1184                                 shortest_point2 ^= shortest_point1;
1185                         }
1192 //printf("CWindowCanvas::do_mask 1 %f %f %d %d\n", 
1193 //      shortest_line_distance, shortest_point_distance, shortest_point1, shortest_point2);
1194 //printf("CWindowCanvas::do_mask %d %d\n", shortest_point1, shortest_point2);
1196 // Append to end of list
1197                         if(labs(shortest_point1 - shortest_point2) > 1)
1198                         {
1199 // Need to apply the new point to every keyframe
1200                                 for(MaskAuto *current = (MaskAuto*)mask_autos->default_auto;
1201                                         current; )
1202                                 {
1203                                         SubMask *submask = current->get_submask(mwindow->edl->session->cwindow_mask);
1204                                         MaskPoint *new_point = new MaskPoint;
1205                                         submask->points.append(new_point);
1206                                         *new_point = *point;
1207                                         if(current == (MaskAuto*)mask_autos->default_auto)
1208                                                 current = (MaskAuto*)mask_autos->first;
1209                                         else
1210                                                 current = (MaskAuto*)NEXT;
1211                                 }
1213                                 gui->affected_point = mask->points.total - 1;
1214                                 result = 1;
1215                         }
1216                         else
1217 // Insert between 2 points, shifting back point 2
1218                         if(shortest_point1 >= 0 && shortest_point2 >= 0)
1219                         {
1220                                 for(MaskAuto *current = (MaskAuto*)mask_autos->default_auto;
1221                                         current; )
1222                                 {
1223                                         SubMask *submask = current->get_submask(mwindow->edl->session->cwindow_mask);
1224                                         MaskPoint *new_point = new MaskPoint;
1225                                         submask->points.append(0);
1226                                         for(int i = submask->points.total - 1; 
1227                                                 i > shortest_point2; 
1228                                                 i--)
1229                                                 submask->points.values[i] = submask->points.values[i - 1];
1230                                         submask->points.values[shortest_point2] = new_point;
1232                                         *new_point = *point;
1233                                         if(current == (MaskAuto*)mask_autos->default_auto)
1234                                                 current = (MaskAuto*)mask_autos->first;
1235                                         else
1236                                                 current = (MaskAuto*)NEXT;
1237                                 }
1240                                 gui->affected_point = shortest_point2;
1241                                 result = 1;
1242                         }
1243 //printf("CWindowCanvas::do_mask 3 %d\n", mask->points.total);
1250 // Create the first point.
1251                         if(!result)
1252                         {
1253 //printf("CWindowCanvas::do_mask 1\n");
1254                                 for(MaskAuto *current = (MaskAuto*)mask_autos->default_auto;
1255                                         current; )
1256                                 {
1257                                         SubMask *submask = current->get_submask(mwindow->edl->session->cwindow_mask);
1258                                         MaskPoint *new_point = new MaskPoint;
1259                                         submask->points.append(new_point);
1260                                         *new_point = *point;
1261                                         if(current == (MaskAuto*)mask_autos->default_auto)
1262                                                 current = (MaskAuto*)mask_autos->first;
1263                                         else
1264                                                 current = (MaskAuto*)NEXT;
1265                                 }
1267 //printf("CWindowCanvas::do_mask 2\n");
1268 // Create a second point if none existed before
1269                                 if(mask->points.total < 2)
1270                                 {
1271                                         for(MaskAuto *current = (MaskAuto*)mask_autos->default_auto;
1272                                                 current; )
1273                                         {
1274                                                 SubMask *submask = current->get_submask(mwindow->edl->session->cwindow_mask);
1275                                                 MaskPoint *new_point = new MaskPoint;
1276                                                 submask->points.append(new_point);
1277                                                 *new_point = *point;
1278                                                 if(current == (MaskAuto*)mask_autos->default_auto)
1279                                                         current = (MaskAuto*)mask_autos->first;
1280                                                 else
1281                                                         current = (MaskAuto*)NEXT;
1282                                         }
1283                                 }
1284                                 gui->affected_point = mask->points.total - 1;
1285 //printf("CWindowCanvas::do_mask 3 %d\n", mask->points.total);
1286                         }
1290 //printf("CWindowCanvas::do_mask 2 %d %d %f %f\n", get_cursor_x(), get_cursor_y(), gui->affected_point->x, gui->affected_point->y);
1291                         gui->current_operation = mwindow->edl->session->cwindow_operation;
1292 // Delete the template
1293                         delete point;
1294                         mwindow->undo->update_undo_after();
1295 //printf("CWindowCanvas::do_mask 4\n");
1296                 }
1298                 result = 1;
1299                 redraw = 1;
1300         }
1301 //printf("CWindowCanvas::do_mask 7\n");
1303         if(button_press && result)
1304         {
1305                 MaskAuto *keyframe = (MaskAuto*)gui->affected_auto;
1306                 SubMask *mask = keyframe->get_submask(mwindow->edl->session->cwindow_mask);
1307                 MaskPoint *point = mask->points.values[gui->affected_point];
1308                 gui->center_x = point->x;
1309                 gui->center_y = point->y;
1310                 gui->control_in_x = point->control_x1;
1311                 gui->control_in_y = point->control_y1;
1312                 gui->control_out_x = point->control_x2;
1313                 gui->control_out_y = point->control_y2;
1314 // printf("CWindowCanvas::do_mask 1 %p %p %d\n", 
1315 //      gui->affected_auto, 
1316 //      gui->affected_point,
1317 //      gui->current_operation);
1318         }
1320 //printf("CWindowCanvas::do_mask 8\n");
1321         if(cursor_motion)
1322         {
1323                 MaskAuto *keyframe = (MaskAuto*)gui->affected_auto;
1324                 SubMask *mask = keyframe->get_submask(mwindow->edl->session->cwindow_mask);
1325                 if(gui->affected_point < mask->points.total)
1326                 {
1327                         MaskPoint *point = mask->points.values[gui->affected_point];
1328 //                      float cursor_x = get_cursor_x();
1329 //                      float cursor_y = get_cursor_y();
1330 //                      canvas_to_output(mwindow->edl, 0, cursor_x, cursor_y);
1331                         float cursor_x = mask_cursor_x;
1332                         float cursor_y = mask_cursor_y;
1333 //printf("CWindowCanvas::do_mask 9 %d %d\n", mask->points.total, gui->affected_point);
1335                         float last_x = point->x;
1336                         float last_y = point->y;
1337                         float last_control_x1 = point->control_x1;
1338                         float last_control_y1 = point->control_y1;
1339                         float last_control_x2 = point->control_x2;
1340                         float last_control_y2 = point->control_y2;
1343                         switch(gui->current_operation)
1344                         {
1345                                 case CWINDOW_MASK:
1346                                         point->x = cursor_x - gui->x_origin + gui->center_x;
1347                                         point->y = cursor_y - gui->y_origin + gui->center_y;
1348                                         break;
1350                                 case CWINDOW_MASK_CONTROL_IN:
1351                                         point->control_x1 = cursor_x - gui->x_origin + gui->control_in_x;
1352                                         point->control_y1 = cursor_y - gui->y_origin + gui->control_in_y;
1353                                         break;
1355                                 case CWINDOW_MASK_CONTROL_OUT:
1356                                         point->control_x2 = cursor_x - gui->x_origin + gui->control_out_x;
1357                                         point->control_y2 = cursor_y - gui->y_origin + gui->control_out_y;
1358                                         break;
1360                                 case CWINDOW_MASK_TRANSLATE:
1361                                         for(int i = 0; i < mask->points.total; i++)
1362                                         {
1363                                                 mask->points.values[i]->x += cursor_x - gui->x_origin;
1364                                                 mask->points.values[i]->y += cursor_y - gui->y_origin;
1365                                         }
1366                                         gui->x_origin = cursor_x;
1367                                         gui->y_origin = cursor_y;
1368                                         break;
1369                         }
1372                         if( !EQUIV(last_x, point->x) ||
1373                                 !EQUIV(last_y, point->y) ||
1374                                 !EQUIV(last_control_x1, point->control_x1) ||
1375                                 !EQUIV(last_control_y1, point->control_y1) ||
1376                                 !EQUIV(last_control_x2, point->control_x2) ||
1377                                 !EQUIV(last_control_y2, point->control_y2))
1378                         {
1379                                 mwindow->undo->update_undo_before(_("tweek"), LOAD_AUTOMATION);
1380                                 rerender = 1;
1381                                 redraw = 1;
1382                         }
1383                 }
1384                 result = 1;
1385         }
1386 //printf("CWindowCanvas::do_mask 2 %d %d %d\n", result, rerender, redraw);
1388         points.remove_all_objects();
1389 //printf("CWindowCanvas::do_mask 20\n");
1390         return result;
1393 void CWindowCanvas::draw_overlays()
1395 //printf("CWindowCanvas::draw_overlays 1\n");
1396         if(mwindow->edl->session->safe_regions)
1397         {
1398                 draw_safe_regions();
1399         }
1401         if(mwindow->edl->session->cwindow_scrollbars)
1402         {
1403 // Always draw output rectangle
1404                 float x1, y1, x2, y2;
1405                 x1 = 0;
1406                 x2 = mwindow->edl->session->output_w;
1407                 y1 = 0;
1408                 y2 = mwindow->edl->session->output_h;
1409                 output_to_canvas(mwindow->edl, 0, x1, y1);
1410                 output_to_canvas(mwindow->edl, 0, x2, y2);
1412                 canvas->set_inverse();
1413                 canvas->set_color(WHITE);
1415                 canvas->draw_rectangle((int)x1, 
1416                                 (int)y1, 
1417                                 (int)(x2 - x1), 
1418                                 (int)(y2 - y1));
1420                 canvas->set_opaque();
1421         }
1423         if(mwindow->session->ccanvas_highlighted)
1424         {
1425                 canvas->set_color(WHITE);
1426                 canvas->set_inverse();
1427                 canvas->draw_rectangle(0, 0, canvas->get_w(), canvas->get_h());
1428                 canvas->draw_rectangle(1, 1, canvas->get_w() - 2, canvas->get_h() - 2);
1429                 canvas->set_opaque();
1430         }
1432         int temp1 = 0, temp2 = 0;
1433 //printf("CWindowCanvas::draw_overlays 1 %d\n", mwindow->edl->session->cwindow_operation);
1434         switch(mwindow->edl->session->cwindow_operation)
1435         {
1436                 case CWINDOW_CAMERA:
1437                         draw_bezier(1);
1438                         break;
1440                 case CWINDOW_PROJECTOR:
1441                         draw_bezier(0);
1442                         break;
1444                 case CWINDOW_CROP:
1445                         draw_crop();
1446                         break;
1448                 case CWINDOW_MASK:
1449                         do_mask(temp1, temp2, 0, 0, 1);
1450                         break;
1451         }
1452 //printf("CWindowCanvas::draw_overlays 2\n");
1455 void CWindowCanvas::draw_safe_regions()
1457         float action_x1, action_x2, action_y1, action_y2;
1458         float title_x1, title_x2, title_y1, title_y2;
1460         action_x1 = mwindow->edl->session->output_w / 2 - mwindow->edl->session->output_w / 2 * 0.9;
1461         action_x2 = mwindow->edl->session->output_w / 2 + mwindow->edl->session->output_w / 2 * 0.9;
1462         action_y1 = mwindow->edl->session->output_h / 2 - mwindow->edl->session->output_h / 2 * 0.9;
1463         action_y2 = mwindow->edl->session->output_h / 2 + mwindow->edl->session->output_h / 2 * 0.9;
1464         title_x1 = mwindow->edl->session->output_w / 2 - mwindow->edl->session->output_w / 2 * 0.8;
1465         title_x2 = mwindow->edl->session->output_w / 2 + mwindow->edl->session->output_w / 2 * 0.8;
1466         title_y1 = mwindow->edl->session->output_h / 2 - mwindow->edl->session->output_h / 2 * 0.8;
1467         title_y2 = mwindow->edl->session->output_h / 2 + mwindow->edl->session->output_h / 2 * 0.8;
1469         output_to_canvas(mwindow->edl, 0, action_x1, action_y1);
1470         output_to_canvas(mwindow->edl, 0, action_x2, action_y2);
1471         output_to_canvas(mwindow->edl, 0, title_x1, title_y1);
1472         output_to_canvas(mwindow->edl, 0, title_x2, title_y2);
1474         canvas->set_inverse();
1475         canvas->set_color(WHITE);
1477         canvas->draw_rectangle((int)action_x1, 
1478                         (int)action_y1, 
1479                         (int)(action_x2 - action_x1), 
1480                         (int)(action_y2 - action_y1));
1481         canvas->draw_rectangle((int)title_x1, 
1482                         (int)title_y1, 
1483                         (int)(title_x2 - title_x1), 
1484                         (int)(title_y2 - title_y1));
1486         canvas->set_opaque();
1489 void CWindowCanvas::reset_keyframe(int do_camera)
1491         BezierAuto *translate_keyframe = 0;
1492         FloatAuto *zoom_keyframe = 0;
1493         Track *affected_track = 0;
1495         affected_track = gui->cwindow->calculate_affected_track();
1497         if(affected_track)
1498         {
1499                 if(do_camera)
1500                 {
1501                         translate_keyframe = (BezierAuto*)gui->cwindow->calculate_affected_auto(
1502                                 affected_track->automation->camera_autos);
1503                         zoom_keyframe = (FloatAuto*)gui->cwindow->calculate_affected_auto(
1504                                 affected_track->automation->czoom_autos);
1505                 }
1506                 else
1507                 {
1508                         translate_keyframe = (BezierAuto*)gui->cwindow->calculate_affected_auto(
1509                                 affected_track->automation->projector_autos);
1510                         zoom_keyframe = (FloatAuto*)gui->cwindow->calculate_affected_auto(
1511                                 affected_track->automation->pzoom_autos);
1512                 }
1514                 translate_keyframe->center_x = 0;
1515                 translate_keyframe->center_y = 0;
1516                 translate_keyframe->center_z = 1;
1517                 zoom_keyframe->value = 1;
1519                 mwindow->sync_parameters(CHANGE_PARAMS);
1520                 gui->update_tool();
1521 //              gui->cwindow->playback_engine->que->send_command(CURRENT_FRAME, 
1522 //                      CHANGE_NONE,
1523 //                      mwindow->edl,
1524 //                      1);
1525         }
1528 void CWindowCanvas::reset_camera()
1530         reset_keyframe(1);
1533 void CWindowCanvas::reset_projector()
1535         reset_keyframe(0);
1538 int CWindowCanvas::test_crop(int button_press, int &redraw)
1540         int result = 0;
1541         int handle_selected = -1;
1542         float x1 = mwindow->edl->session->crop_x1;
1543         float y1 = mwindow->edl->session->crop_y1;
1544         float x2 = mwindow->edl->session->crop_x2;
1545         float y2 = mwindow->edl->session->crop_y2;
1546         float cursor_x = get_cursor_x();
1547         float cursor_y = get_cursor_y();
1548         float canvas_x1 = x1;
1549         float canvas_y1 = y1;
1550         float canvas_x2 = x2;
1551         float canvas_y2 = y2;
1552         float canvas_cursor_x = cursor_x;
1553         float canvas_cursor_y = cursor_y;
1555         canvas_to_output(mwindow->edl, 0, cursor_x, cursor_y);
1556 // Use screen normalized coordinates for hot spot tests.
1557         output_to_canvas(mwindow->edl, 0, canvas_x1, canvas_y1);
1558         output_to_canvas(mwindow->edl, 0, canvas_x2, canvas_y2);
1560         if(gui->current_operation == CWINDOW_CROP)
1561         {
1562                 handle_selected = gui->crop_handle;
1563         }
1564         else
1565         if(canvas_cursor_x >= canvas_x1 && canvas_cursor_x < canvas_x1 + CROPHANDLE_W &&
1566                 canvas_cursor_y >= canvas_y1 && canvas_cursor_y < canvas_y1 + CROPHANDLE_H)
1567         {
1568                 handle_selected = 0;
1569                 gui->crop_origin_x = x1;
1570                 gui->crop_origin_y = y1;
1571         }
1572         else
1573         if(canvas_cursor_x >= canvas_x2 - CROPHANDLE_W && canvas_cursor_x < canvas_x2 &&
1574                 canvas_cursor_y >= canvas_y1 && canvas_cursor_y < canvas_y1 + CROPHANDLE_H)
1575         {
1576                 handle_selected = 1;
1577                 gui->crop_origin_x = x2;
1578                 gui->crop_origin_y = y1;
1579         }
1580         else
1581         if(canvas_cursor_x >= canvas_x1 && canvas_cursor_x < canvas_x1 + CROPHANDLE_W &&
1582                 canvas_cursor_y >= canvas_y2 - CROPHANDLE_H && canvas_cursor_y < canvas_y2)
1583         {
1584                 handle_selected = 2;
1585                 gui->crop_origin_x = x1;
1586                 gui->crop_origin_y = y2;
1587         }
1588         else
1589         if(canvas_cursor_x >= canvas_x2 - CROPHANDLE_W && canvas_cursor_x < canvas_x2 &&
1590                 canvas_cursor_y >= canvas_y2 - CROPHANDLE_H && canvas_cursor_y < canvas_y2)
1591         {
1592                 handle_selected = 3;
1593                 gui->crop_origin_x = x2;
1594                 gui->crop_origin_y = y2;
1595         }
1596         else
1597 // Start new box
1598         {
1599                 gui->crop_origin_x = cursor_x;
1600                 gui->crop_origin_y = cursor_y;
1601         }
1603 // printf("test crop %d %d\n", 
1604 //      gui->current_operation,
1605 //      handle_selected);
1607 // Start dragging.
1608         if(button_press)
1609         {
1610                 gui->current_operation = CWINDOW_CROP;
1611                 gui->crop_handle = handle_selected;
1612                 gui->x_origin = cursor_x;
1613                 gui->y_origin = cursor_y;
1614                 result = 1;
1616                 if(handle_selected < 0) 
1617                 {
1618                         x2 = x1 = cursor_x;
1619                         y2 = y1 = cursor_y;
1620                         mwindow->edl->session->crop_x1 = (int)x1;
1621                         mwindow->edl->session->crop_y1 = (int)y1;
1622                         mwindow->edl->session->crop_x2 = (int)x2;
1623                         mwindow->edl->session->crop_y2 = (int)y2;
1624                         redraw = 1;
1625                 }
1626         }
1627     else
1628 // Update dragging
1629         if(gui->current_operation == CWINDOW_CROP)
1630         {
1631                 float x_difference, y_difference;
1632                 if(gui->crop_handle >= 0)
1633                 {
1634                         float zoom_x, zoom_y, conformed_w, conformed_h;
1635                         get_zooms(mwindow->edl, 0, zoom_x, zoom_y, conformed_w, conformed_h);
1636                         x_difference = cursor_x - gui->x_origin;
1637                 }
1639                 switch(gui->crop_handle)
1640                 {
1641                         case -1:
1642                                 x1 = gui->crop_origin_x;
1643                                 y1 = gui->crop_origin_y;
1644                                 x2 = gui->crop_origin_x;
1645                                 y2 = gui->crop_origin_y;
1646                                 if(cursor_x < gui->x_origin)
1647                                 {
1648                                         if(cursor_y < gui->y_origin)
1649                                         {
1650                                                 x1 = cursor_x;
1651                                                 y1 = cursor_y;
1652                                         }
1653                                         else
1654                                         if(cursor_y >= gui->y_origin)
1655                                         {
1656                                                 x1 = cursor_x;
1657                                                 y2 = cursor_y;
1658                                         }
1659                                 }
1660                                 else
1661                                 if(cursor_x  >= gui->x_origin)
1662                                 {
1663                                         if(cursor_y < gui->y_origin)
1664                                         {
1665                                                 y1 = cursor_y;
1666                                                 x2 = cursor_x;
1667                                         }
1668                                         else
1669                                         if(cursor_y >= gui->y_origin)
1670                                         {
1671                                                 x2 = cursor_x;
1672                                                 y2 = cursor_y;
1673                                         }
1674                                 }
1676 // printf("test crop %d %d %d %d\n", 
1677 //      mwindow->edl->session->crop_x1,
1678 //      mwindow->edl->session->crop_y1,
1679 //      mwindow->edl->session->crop_x2,
1680 //      mwindow->edl->session->crop_y2);
1681                                 break;
1682                         case 0:
1683                                 x1 = cursor_x - gui->x_origin + gui->crop_origin_x;
1684                                 y1 = cursor_y - gui->y_origin + gui->crop_origin_y;
1685                                 break;
1686                         case 1:
1687                                 x2 = cursor_x - gui->x_origin + gui->crop_origin_x;
1688                                 y1 = cursor_y - gui->y_origin + gui->crop_origin_y;
1689                                 break;
1690                         case 2:
1691                                 x1 = cursor_x - gui->x_origin + gui->crop_origin_x;
1692                                 y2 = cursor_y - gui->y_origin + gui->crop_origin_y;
1693                                 break;
1694                         case 3:
1695                                 x2 = cursor_x - gui->x_origin + gui->crop_origin_x;
1696                                 y2 = cursor_y - gui->y_origin + gui->crop_origin_y;
1697                                 break;
1698                 }
1700                 if(!EQUIV(mwindow->edl->session->crop_x1, x1) ||
1701                         !EQUIV(mwindow->edl->session->crop_x2, x2) ||
1702                         !EQUIV(mwindow->edl->session->crop_y1, y1) ||
1703                         !EQUIV(mwindow->edl->session->crop_y2, y2))
1704                 {
1705                         mwindow->edl->session->crop_x1 = (int)x1;
1706                         mwindow->edl->session->crop_y1 = (int)y1;
1707                         mwindow->edl->session->crop_x2 = (int)x2;
1708                         mwindow->edl->session->crop_y2 = (int)y2;
1709                         result = 1;
1710                         redraw = 1;
1711                 }
1712         }
1713         else
1714 // Update cursor font
1715         if(handle_selected >= 0)
1716         {
1717                 switch(handle_selected)
1718                 {
1719                         case 0:
1720                                 set_cursor(UPLEFT_RESIZE);
1721                                 break;
1722                         case 1:
1723                                 set_cursor(UPRIGHT_RESIZE);
1724                                 break;
1725                         case 2:
1726                                 set_cursor(DOWNLEFT_RESIZE);
1727                                 break;
1728                         case 3:
1729                                 set_cursor(DOWNRIGHT_RESIZE);
1730                                 break;
1731                 }
1732                 result = 1;
1733         }
1734         else
1735         {
1736                 set_cursor(ARROW_CURSOR);
1737         }
1738 #define CLAMP(x, y, z) ((x) = ((x) < (y) ? (y) : ((x) > (z) ? (z) : (x))))
1739         
1740         if(redraw)
1741         {
1742                 CLAMP(mwindow->edl->session->crop_x1, 0, mwindow->edl->calculate_output_w(0));
1743                 CLAMP(mwindow->edl->session->crop_x2, 0, mwindow->edl->calculate_output_w(0));
1744                 CLAMP(mwindow->edl->session->crop_y1, 0, mwindow->edl->calculate_output_h(0));
1745                 CLAMP(mwindow->edl->session->crop_y2, 0, mwindow->edl->calculate_output_h(0));
1746 // printf("CWindowCanvas::test_crop %d %d %d %d\n", 
1747 //      mwindow->edl->session->crop_x2,
1748 //      mwindow->edl->session->crop_y2,
1749 //      mwindow->edl->calculate_output_w(0), 
1750 //      mwindow->edl->calculate_output_h(0));
1751         }
1752         return result;
1756 void CWindowCanvas::draw_crop()
1758         canvas->set_inverse();
1759         canvas->set_color(WHITE);
1761         float x1 = mwindow->edl->session->crop_x1;
1762         float y1 = mwindow->edl->session->crop_y1;
1763         float x2 = mwindow->edl->session->crop_x2;
1764         float y2 = mwindow->edl->session->crop_y2;
1766         output_to_canvas(mwindow->edl, 0, x1, y1);
1767         output_to_canvas(mwindow->edl, 0, x2, y2);
1769         if(x2 - x1 && y2 - y1)
1770                 canvas->draw_rectangle((int)x1, 
1771                         (int)y1, 
1772                         (int)(x2 - x1), 
1773                         (int)(y2 - y1));
1775         draw_crophandle((int)x1, (int)y1);
1776         draw_crophandle((int)x2 - CROPHANDLE_W, (int)y1);
1777         draw_crophandle((int)x1, (int)y2 - CROPHANDLE_H);
1778         draw_crophandle((int)x2 - CROPHANDLE_W, (int)y2 - CROPHANDLE_H);
1779         canvas->set_opaque();
1784 #define BEZIER_W 20
1785 #define BEZIER_H 20
1787 int CWindowCanvas::do_bezier_center(BezierAuto *current, 
1788         BezierAutos *camera_autos,
1789         BezierAutos *projector_autos, 
1790         FloatAutos *czoom_autos,
1791         FloatAutos *pzoom_autos,
1792         int camera, 
1793         int draw)
1795         float center_x = 0, center_y = 0, center_z = 0;
1796         BezierAuto *before = 0, *after = 0;
1797         FloatAuto *previous = 0, *next = 0;
1798         VTrack *track = (VTrack*)current->autos->track;
1799         long position = track->to_units(
1800                                 mwindow->edl->local_session->selectionstart, 
1801                                 0);
1803 // Get center of current frame.  Draw everything relative to this.
1804         if(camera)
1805         {
1806                 camera_autos->get_center(center_x, 
1807                         center_y, 
1808                         center_z, 
1809                         (float)position,
1810                         PLAY_FORWARD, 
1811                         &before, 
1812                         &after);
1813                 center_z = czoom_autos->get_value(position,
1814                         PLAY_FORWARD,
1815                         previous,
1816                         next);
1818                 float projector_x, projector_y, projector_z;
1819                 before = after = 0;
1820                 projector_autos->get_center(projector_x, 
1821                         projector_y, 
1822                         projector_z,
1823                         (float)position,
1824                         PLAY_FORWARD,
1825                         &before,
1826                         &after);
1827                 previous = next = 0;
1828                 projector_z = pzoom_autos->get_value(position,
1829                         PLAY_FORWARD,
1830                         previous,
1831                         next);
1833                 center_x -= projector_x;
1834                 center_y -= projector_y;
1835                 center_z = projector_z;
1836 //printf("CWindowCanvas::do_bezier_center 1 %p %f %f\n", 
1837 //current, projector_y, center_y);
1838         }
1839         else
1840         {
1841                 center_z = pzoom_autos->get_value(current->position,
1842                         PLAY_FORWARD,
1843                         previous,
1844                         next);
1845         }
1849         float auto_x = current->center_x - center_x + mwindow->edl->session->output_w / 2;
1850         float auto_y = current->center_y - center_y + mwindow->edl->session->output_h / 2;
1851         float track_x1 = auto_x - track->track_w / 2 * center_z;
1852         float track_y1 = auto_y - track->track_h / 2 * center_z;
1853         float track_x2 = track_x1 + track->track_w * center_z;
1854         float track_y2 = track_y1 + track->track_h * center_z;
1855         float control_in_x = auto_x + current->control_in_x;
1856         float control_in_y = auto_y + current->control_in_y;
1857         float control_out_x = auto_x + current->control_out_x;
1858         float control_out_y = auto_y + current->control_out_y;
1859         int control_point = 0;
1862         output_to_canvas(mwindow->edl, 0, auto_x, auto_y);
1863         output_to_canvas(mwindow->edl, 0, control_out_x, control_out_y);
1864         output_to_canvas(mwindow->edl, 0, control_in_x, control_in_y);
1865         output_to_canvas(mwindow->edl, 0, track_x1, track_y1);
1866         output_to_canvas(mwindow->edl, 0, track_x2, track_y2);
1868 #define DRAW_THING(offset) \
1869         canvas->draw_line((int)control_in_x + offset,  \
1870                 (int)control_in_y + offset,  \
1871                 (int)auto_x + offset,  \
1872                 (int)auto_y + offset); \
1873         canvas->draw_line((int)control_out_x + offset,  \
1874                 (int)control_out_y + offset,  \
1875                 (int)auto_x + offset,  \
1876                 (int)auto_y + offset); \
1877         canvas->draw_rectangle((int)control_in_x - CONTROL_W / 2 + offset,  \
1878                 (int)control_in_y - CONTROL_H / 2 + offset, \
1879                 CONTROL_W, \
1880                 CONTROL_H); \
1881         canvas->draw_rectangle((int)control_out_x - CONTROL_W / 2 + offset,  \
1882                 (int)control_out_y - CONTROL_H / 2 + offset, \
1883                 CONTROL_W, \
1884                 CONTROL_H); \
1886         if(0) \
1887         { \
1888                 canvas->draw_line((int)auto_x - BEZIER_W / 2,  \
1889                         (int)auto_y - BEZIER_H / 2 + offset, \
1890                         (int)auto_x + BEZIER_W / 2, \
1891                         (int)auto_y + BEZIER_H / 2 + offset); \
1892                 canvas->draw_line((int)auto_x - BEZIER_W / 2,  \
1893                         (int)auto_y + BEZIER_H / 2 + offset, \
1894                         (int)auto_x + BEZIER_W / 2, \
1895                         (int)auto_y - BEZIER_H / 2 + offset); \
1896         } \
1897         else \
1898         { \
1899                 canvas->draw_rectangle((int)track_x1 + offset, \
1900                         (int)track_y1 + offset, \
1901                         (int)(track_x2 - track_x1), \
1902                         (int)(track_y2 - track_y1)); \
1903                 canvas->draw_line((int)track_x1 + offset,  \
1904                         (int)track_y1 + offset, \
1905                         (int)track_x2 + offset, \
1906                         (int)track_y2 + offset); \
1907                 canvas->draw_line((int)track_x2 + offset,  \
1908                         (int)track_y1 + offset, \
1909                         (int)track_x1 + offset, \
1910                         (int)track_y2 + offset); \
1911         }
1913         if(draw)
1914         {
1915                 canvas->set_color(BLACK);
1916                 DRAW_THING(1);
1918                 if(current->position > position)
1919                         canvas->set_color(GREEN);
1920                 else
1921                         canvas->set_color(RED);
1923                 DRAW_THING(0);
1924 // printf("CWindowCanvas::do_bezier_center 2 %f,%f %f,%f\n", 
1925 // control_in_x, 
1926 // control_in_y, 
1927 // control_out_x,
1928 // control_out_y);
1929         }
1930         else
1931         {
1932                 int cursor_x = get_cursor_x();
1933                 int cursor_y = get_cursor_y();
1934                 
1935 #ifndef SQR
1936 #define SQR(x) ((x) * (x))
1937 #endif
1939                 float distance1 = sqrt(SQR(cursor_x - control_in_x) + 
1940                         SQR(cursor_y - control_in_y));
1941                 float distance2 = sqrt(SQR(cursor_x - control_out_x) + 
1942                         SQR(cursor_y - control_out_y));
1943 // printf("CWindowCanvas::do_bezier_center 3 %f,%f %f,%f\n", 
1944 // control_in_x, 
1945 // control_in_y, 
1946 // control_out_x,
1947 // control_out_y);
1949                 control_point = distance2 < distance1;
1950         }
1951         
1952         return control_point;
1957 void CWindowCanvas::draw_bezier_joining(BezierAuto *first, 
1958         BezierAuto *last, 
1959         BezierAutos *camera_autos,
1960         BezierAutos *projector_autos, 
1961         FloatAutos *czoom_autos,
1962         FloatAutos *pzoom_autos,
1963         int camera)
1965         if(first == last) return;
1966         
1967         float center_x = 0, center_y = 0, center_z = 0;
1968         BezierAuto *before = 0, *after = 0;
1969         long position = first->autos->track->to_units(
1970                                         mwindow->edl->local_session->selectionstart, 
1971                                         0);
1973 // Get center of current position.  Draw everything relative to this.
1974         if(camera)
1975         {
1976                 camera_autos->get_center(center_x, 
1977                                 center_y, 
1978                                 center_z, 
1979                                 (float)position, 
1980                                 PLAY_FORWARD, 
1981                                 &before, 
1982                                 &after);
1984                 float projector_x, projector_y, projector_z;
1985                 before = after = 0;
1986                 projector_autos->get_center(projector_x, 
1987                         projector_y, 
1988                         projector_z,
1989                         (float)position,
1990                         PLAY_FORWARD,
1991                         &before,
1992                         &after);
1994                 center_x -= projector_x;
1995                 center_y -= projector_y;
1996         }
1998 //      int segments = 10;
1999         int segments = MAX(canvas->get_w(), canvas->get_h());
2000         int step = (last->position - first->position) / segments;
2001         float old_x, old_y;
2002         if(step < 1) step = 1;
2004         for(long frame = first->position; 
2005                 frame < last->position; 
2006                 frame += step)
2007         {
2008                 float new_x, new_y, new_z;
2009                 float x1, y1, x2, y2;
2011                 ((BezierAutos*)(first->autos))->get_center(new_x, 
2012                         new_y, 
2013                         new_z, 
2014                         frame, 
2015                         PLAY_FORWARD, 
2016                         &before, 
2017                         &after);
2019                 if(frame == first->position)
2020                 {
2021                         old_x = new_x;
2022                         old_y = new_y;
2023                 }
2025                 x1 = old_x - center_x + mwindow->edl->session->output_w / 2;
2026                 y1 = old_y - center_y + mwindow->edl->session->output_h / 2;
2027                 x2 = new_x - center_x + mwindow->edl->session->output_w / 2;
2028                 y2 = new_y - center_y + mwindow->edl->session->output_h / 2;
2029                 output_to_canvas(mwindow->edl, 0, x1, y1);
2030                 output_to_canvas(mwindow->edl, 0, x2, y2);
2032                 canvas->set_color(BLACK);
2033                 canvas->draw_line((int)x1 + 1, (int)y1 + 1, (int)x2 + 1, (int)y2 + 1);
2035                 if(frame >= position)
2036                         canvas->set_color(GREEN);
2037                 else
2038                         canvas->set_color(RED);
2040                 canvas->draw_line((int)x1, (int)y1, (int)x2, (int)y2);
2041                 old_x = new_x;
2042                 old_y = new_y;
2043         }
2048 void CWindowCanvas::draw_bezier(int do_camera)
2050         Track *track = gui->cwindow->calculate_affected_track();
2051         BezierAutos *autos, *camera_autos, *projector_autos;
2052         BezierAuto *first = 0, *mid = 0, *last = 0;
2053         BezierAuto *before = 0, *after = 0;
2054         FloatAutos *czoom_autos, *pzoom_autos;
2056 // No track at initialization
2057         if(!track) return;
2059         camera_autos = track->automation->camera_autos;
2060         projector_autos = track->automation->projector_autos;
2061         czoom_autos = track->automation->czoom_autos;
2062         pzoom_autos = track->automation->pzoom_autos;
2064         if(do_camera)
2065                 autos = track->automation->camera_autos;
2066         else
2067                 autos = track->automation->projector_autos;
2070         long position = track->to_units(mwindow->edl->local_session->selectionstart, 
2071                                         0);
2074 // Rules for which autos to draw:
2076 // No automation besides default:
2077 //     mid = default
2079 // Automation on or after current position only
2080 //     mid = first, last = next
2082 // Automation before current position only
2083 //     mid = last, first = previous
2084 // 
2085 // Automation on current position only
2086 //     mid = first
2088 // Automation before and after current position
2089 //     first = previous, mid = next, last = next->next
2091         for(first = (BezierAuto*)autos->last; 
2092                 first; 
2093                 first = (BezierAuto*)first->previous)
2094                 if(first->position < position)
2095                         break;
2097         if(first)
2098         {
2099                 mid = (BezierAuto*)first->next;
2100                 if(!mid)
2101                 {
2102                         mid = first;
2103                         first = (BezierAuto*)first->previous;
2104                 }
2105         }
2106         else
2107                 mid = (BezierAuto*)autos->first;
2109         if(mid)
2110                 last = (BezierAuto*)mid->next;
2111         else
2112                 mid = (BezierAuto*)autos->default_auto;
2114         if(!last)
2115         {
2116                 last = mid;
2117                 mid = first;
2118                 if(mid) first = (BezierAuto*)mid->previous;
2119         }
2120         
2121         if(!first)
2122         {
2123                 first = mid;
2124                 mid = last;
2125                 if(mid) last = (BezierAuto*)mid->next;
2126         }
2128 //printf("draw_bezier 1 %p %p %p\n", first, mid, last);
2132 // Draw joining lines
2133         if(first && mid)
2134                 draw_bezier_joining(first, 
2135                         mid, 
2136                         camera_autos, 
2137                         projector_autos, 
2138                         czoom_autos,
2139                         pzoom_autos,
2140                         do_camera);
2142         if(mid && last)
2143                 draw_bezier_joining(mid, 
2144                         last, 
2145                         camera_autos, 
2146                         projector_autos, 
2147                         czoom_autos,
2148                         pzoom_autos,
2149                         do_camera);
2151 //printf("draw_bezier 2 %p %p %p\n", first, mid, last);
2154 // Draw centers of autos
2155         if(first) 
2156                 do_bezier_center(first, 
2157                         camera_autos, 
2158                         projector_autos, 
2159                         czoom_autos,
2160                         pzoom_autos,
2161                         do_camera, 
2162                         1);
2163         if(mid) 
2164                 do_bezier_center(mid, 
2165                         camera_autos, 
2166                         projector_autos, 
2167                         czoom_autos,
2168                         pzoom_autos,
2169                         do_camera, 
2170                         1);
2171         if(last) 
2172                 do_bezier_center(last, 
2173                         camera_autos, 
2174                         projector_autos, 
2175                         czoom_autos,
2176                         pzoom_autos,
2177                         do_camera, 
2178                         1);
2180 //printf("draw_bezier 3 %p %p %p\n", first, mid, last);
2188 int CWindowCanvas::test_bezier(int button_press, 
2189         int &redraw, 
2190         int &redraw_canvas,
2191         int &rerender,
2192         int do_camera)
2194         int result = 0;
2196 // Processing drag operation.
2197 // Create keyframe during first cursor motion.
2198         if(!button_press)
2199         {
2201                 float cursor_x = get_cursor_x();
2202                 float cursor_y = get_cursor_y();
2203                 canvas_to_output(mwindow->edl, 0, cursor_x, cursor_y);
2205                 if(gui->current_operation == CWINDOW_CAMERA ||
2206                         gui->current_operation == CWINDOW_PROJECTOR)
2207                 {
2208                         if(!gui->ctrl_down() && gui->shift_down() && !gui->translating_zoom)
2209                         {
2210                                 gui->translating_zoom = 1;
2211                                 gui->affected_auto = 0;
2212                         }
2213                         else
2214                         if(!gui->ctrl_down() && !gui->shift_down() && gui->translating_zoom)
2215                         {
2216                                 gui->translating_zoom = 0;
2217                                 gui->affected_auto = 0;
2218                         }
2220 // Get target keyframe
2221                         BezierAutos *camera_autos = gui->affected_track->automation->camera_autos;
2222                         BezierAutos *projector_autos = gui->affected_track->automation->projector_autos;
2223                         FloatAutos *czoom_autos = gui->affected_track->automation->czoom_autos;
2224                         FloatAutos *pzoom_autos = gui->affected_track->automation->pzoom_autos;
2225                         float last_center_x;
2226                         float last_center_y;
2227                         float last_center_z;
2230                         if(!gui->affected_auto)
2231                         {
2232                                 mwindow->undo->update_undo_before(_("keyframe"), LOAD_AUTOMATION);
2233                                 if(mwindow->edl->session->cwindow_operation == CWINDOW_CAMERA)
2234                                 {
2235                                         if(gui->translating_zoom)
2236                                         {
2237                                                 gui->affected_auto = 
2238                                                         gui->cwindow->calculate_affected_auto((Autos*)czoom_autos, 1);
2239                                         }
2240                                         else
2241                                                 gui->affected_auto = 
2242                                                         gui->cwindow->calculate_affected_auto((Autos*)camera_autos, 1);
2243                                 }
2244                                 else
2245                                 if(mwindow->edl->session->cwindow_operation == CWINDOW_PROJECTOR)
2246                                 {
2247                                         if(gui->translating_zoom)
2248                                         {
2249                                                 gui->affected_auto = 
2250                                                         gui->cwindow->calculate_affected_auto((Autos*)pzoom_autos, 1);
2251                                         }
2252                                         else
2253                                                 gui->affected_auto = 
2254                                                         gui->cwindow->calculate_affected_auto((Autos*)projector_autos, 1);
2255                                 }
2257                                 calculate_origin();
2258                                 
2259                                 if(gui->translating_zoom)
2260                                 {
2261                                         gui->center_z = ((FloatAuto*)gui->affected_auto)->value;
2262                                 }
2263                                 else
2264                                 {
2265                                         gui->center_x = ((BezierAuto*)gui->affected_auto)->center_x;
2266                                         gui->center_y = ((BezierAuto*)gui->affected_auto)->center_y;
2267                                 }
2269                                 rerender = 1;
2270                                 redraw = 1;
2271                         }
2273                         BezierAuto *bezier_keyframe = (BezierAuto*)gui->affected_auto;
2274                         FloatAuto *zoom_keyframe = (FloatAuto*)gui->affected_auto;
2276                         if(gui->translating_zoom)
2277                         {
2278                                 last_center_z = zoom_keyframe->value;
2279                         }
2280                         else
2281                         {
2282                                 last_center_x = bezier_keyframe->center_x;
2283                                 last_center_y = bezier_keyframe->center_y;
2284                         }
2286                         if(gui->translating_zoom)
2287                         {
2288                                 zoom_keyframe->value = gui->center_z + (cursor_y - gui->y_origin) / 128;
2289                                 if(!EQUIV(last_center_z, zoom_keyframe->value))
2290                                 {
2291                                         mwindow->undo->update_undo_before(_("tweek"), LOAD_AUTOMATION);
2292                                         rerender = 1;
2293                                         redraw = 1;
2294                                         redraw_canvas = 1;
2295                                 }
2296                         }
2297                         else
2298                         {
2299                                 bezier_keyframe->center_x = gui->center_x + cursor_x - gui->x_origin;
2300                                 bezier_keyframe->center_y = gui->center_y + cursor_y - gui->y_origin;
2301                                 if(!EQUIV(last_center_x,  bezier_keyframe->center_x) ||
2302                                         !EQUIV(last_center_y, bezier_keyframe->center_y))
2303                                 {
2304                                         mwindow->undo->update_undo_before(_("tweek"), LOAD_AUTOMATION);
2305                                         rerender = 1;
2306                                         redraw = 1;
2307                                 }
2308                         }
2309                 }
2310                 else
2311                 if(gui->current_operation == CWINDOW_CAMERA_CONTROL_IN ||
2312                         gui->current_operation == CWINDOW_PROJECTOR_CONTROL_IN)
2313                 {
2314                         BezierAuto *bezier_keyframe = (BezierAuto*)gui->affected_auto;
2315                         float last_control_in_x = bezier_keyframe->control_in_x;
2316                         float last_control_in_y = bezier_keyframe->control_in_y;
2317                         bezier_keyframe->control_in_x = gui->control_in_x + cursor_x - gui->x_origin;
2318                         bezier_keyframe->control_in_y = gui->control_in_y + cursor_y - gui->y_origin;
2320                         if(!EQUIV(last_control_in_x, bezier_keyframe->control_in_x) ||
2321                                 !EQUIV(last_control_in_y, bezier_keyframe->control_in_y))
2322                         {
2323                                 mwindow->undo->update_undo_before(_("tweek"), LOAD_AUTOMATION);
2324                                 rerender = 1;
2325                                 redraw = 1;
2326                         }
2327                 }
2328                 else
2329                 if(gui->current_operation == CWINDOW_CAMERA_CONTROL_OUT ||
2330                         gui->current_operation == CWINDOW_PROJECTOR_CONTROL_OUT)
2331                 {
2332                         BezierAuto *bezier_keyframe = (BezierAuto*)gui->affected_auto;
2333                         float last_control_out_x = bezier_keyframe->control_out_x;
2334                         float last_control_out_y = bezier_keyframe->control_out_y;
2335                         bezier_keyframe->control_out_x = gui->control_out_x + cursor_x - gui->x_origin;
2336                         bezier_keyframe->control_out_y = gui->control_out_y + cursor_y - gui->y_origin;
2338                         if(!EQUIV(last_control_out_x, bezier_keyframe->control_out_x) ||
2339                                 !EQUIV(last_control_out_y, bezier_keyframe->control_out_y))
2340                         {
2341                                 mwindow->undo->update_undo_before(_("tweek"), LOAD_AUTOMATION);
2342                                 rerender = 1;
2343                                 redraw = 1;
2344                         }
2345                 }
2347                 result = 1;
2348         }
2349         else
2350 // Begin drag operation.  Don't create keyframe here.
2351         {
2352 // Get affected track off of the first recordable video track.
2353 // Calculating based on the alpha channel would require rendering
2354 // each layer and its effects and trapping the result in VirtualVNode before
2355 // compositing onto the output.
2356                 gui->affected_track = gui->cwindow->calculate_affected_track();
2357                 gui->affected_auto = 0;
2359                 if(gui->affected_track)
2360                 {
2361                         BezierAutos *camera_autos = gui->affected_track->automation->camera_autos;
2362                         BezierAutos *projector_autos = gui->affected_track->automation->projector_autos;
2363                         FloatAutos *czoom_autos = gui->affected_track->automation->czoom_autos;
2364                         FloatAutos *pzoom_autos = gui->affected_track->automation->pzoom_autos;
2367                         if(!gui->ctrl_down())
2368                         {
2369                                 gui->current_operation = 
2370                                         mwindow->edl->session->cwindow_operation;
2371                                 gui->affected_auto = 0;
2372                         }
2373                         else
2374                         {
2375 // Get nearest control point
2376                                 if(mwindow->edl->session->cwindow_operation == CWINDOW_CAMERA)
2377                                         gui->affected_auto = 
2378                                                 gui->cwindow->calculate_affected_auto(camera_autos, 0);
2379                                 else
2380                                 if(mwindow->edl->session->cwindow_operation == CWINDOW_PROJECTOR)
2381                                         gui->affected_auto = 
2382                                                 gui->cwindow->calculate_affected_auto(projector_autos, 0);
2384 //printf("CWindowCanvas::test_bezier 1 %d\n", gui->current_operation);
2385                                 int control_point = do_bezier_center(
2386                                         (BezierAuto*)gui->affected_auto, 
2387                                         camera_autos,
2388                                         projector_autos,
2389                                         czoom_autos,
2390                                         pzoom_autos,
2391                                         mwindow->edl->session->cwindow_operation == CWINDOW_CAMERA,
2392                                         0);
2394 //printf("CWindowCanvas::test_bezier 2 %d\n", control_point);
2395                                 if(control_point == 0)
2396                                 {
2397                                         if(mwindow->edl->session->cwindow_operation == CWINDOW_CAMERA)
2398                                                 gui->current_operation = CWINDOW_CAMERA_CONTROL_IN;
2399                                         else
2400                                                 gui->current_operation = CWINDOW_PROJECTOR_CONTROL_IN;
2401                                 }
2402                                 else
2403                                 {
2404                                         if(mwindow->edl->session->cwindow_operation == CWINDOW_CAMERA)
2405                                                 gui->current_operation = CWINDOW_CAMERA_CONTROL_OUT;
2406                                         else
2407                                                 gui->current_operation = CWINDOW_PROJECTOR_CONTROL_OUT;
2408                                 }
2410                                 BezierAuto *keyframe = (BezierAuto*)gui->affected_auto;
2411                                 gui->center_x = keyframe->center_x;
2412                                 gui->center_y = keyframe->center_y;
2413                                 gui->center_z = keyframe->center_z;
2414                                 gui->control_in_x = keyframe->control_in_x;
2415                                 gui->control_in_y = keyframe->control_in_y;
2416                                 gui->control_out_x = keyframe->control_out_x;
2417                                 gui->control_out_y = keyframe->control_out_y;
2418                         }
2421                         result = 1;
2422                 }
2423         }
2424         
2425         return result;
2428 int CWindowCanvas::test_zoom(int &redraw)
2430         int result = 0;
2431         float zoom = get_zoom();
2432         float x;
2433         float y;
2435         if(!mwindow->edl->session->cwindow_scrollbars)
2436         {
2437                 mwindow->edl->session->cwindow_scrollbars = 1;
2438                 zoom = 1.0;
2439                 x = 0;
2440                 y = 0;
2441         }
2442         else
2443         {
2444                 x = get_cursor_x();
2445                 y = get_cursor_y();
2446                 canvas_to_output(mwindow->edl, 
2447                                 0, 
2448                                 x, 
2449                                 y);
2451 //printf("CWindowCanvas::test_zoom 1 %f %f\n", x, y);
2453 // Zoom out
2454                 if(get_buttonpress() == 5 ||
2455                         gui->ctrl_down() || 
2456                         gui->shift_down())
2457                 {
2458                         if(zoom > MIN_ZOOM)
2459                         {
2460                                 zoom /= 2;
2461                                 x -= w_visible * 2 / 2;
2462                                 y -= h_visible * 2 / 2;
2463                         }
2464                         else
2465                         {
2466                                 x -= w_visible / 2;
2467                                 y -= h_visible / 2;
2468                         }
2469                 }
2470                 else
2471 // Zoom in
2472                 {
2473                         if(zoom < MAX_ZOOM)
2474                         {
2475                                 zoom *= 2;
2476                                 x -= w_visible / 2 / 2;
2477                                 y -= h_visible / 2 / 2;
2478                         }
2479                         else
2480                         {
2481                                 x -= w_visible / 2;
2482                                 y -= h_visible / 2;
2483                         }
2484                 }
2485         }
2487         int x_i = (int)x;
2488         int y_i = (int)y;
2489 //      check_boundaries(mwindow->edl, x_i, y_i, zoom);
2491 //printf("CWindowCanvas::test_zoom 2 %d %d\n", x_i, y_i);
2493         update_zoom(x_i, 
2494                         y_i, 
2495                         zoom);
2496         reposition_window(mwindow->edl, 
2497                         mwindow->theme->ccanvas_x,
2498                         mwindow->theme->ccanvas_y,
2499                         mwindow->theme->ccanvas_w,
2500                         mwindow->theme->ccanvas_h);
2501         redraw = 1;
2502         result = 1;
2504         
2505         gui->zoom_panel->update(zoom);
2506         
2507         return result;
2511 void CWindowCanvas::calculate_origin()
2513         gui->x_origin = get_cursor_x();
2514         gui->y_origin = get_cursor_y();
2515 //printf("CWindowCanvas::calculate_origin 1 %f %f\n", gui->x_origin, gui->y_origin);
2516         canvas_to_output(mwindow->edl, 0, gui->x_origin, gui->y_origin);
2517 //printf("CWindowCanvas::calculate_origin 2 %f %f\n", gui->x_origin, gui->y_origin);
2521 int CWindowCanvas::cursor_leave_event()
2523         set_cursor(ARROW_CURSOR);
2524         return 1;
2527 int CWindowCanvas::cursor_enter_event()
2529         int redraw = 0;
2530         switch(mwindow->edl->session->cwindow_operation)
2531         {
2532                 case CWINDOW_CAMERA:
2533                 case CWINDOW_PROJECTOR:
2534                         set_cursor(MOVE_CURSOR);
2535                         break;
2536                 case CWINDOW_ZOOM:
2537                         set_cursor(MOVE_CURSOR);
2538                         break;
2539                 case CWINDOW_CROP:
2540                         test_crop(0, redraw);
2541                         break;
2542                 case CWINDOW_PROTECT:
2543                         set_cursor(ARROW_CURSOR);
2544                         break;
2545                 case CWINDOW_MASK:
2546                         set_cursor(CROSS_CURSOR);
2547                         break;
2548         }
2549         return 1;
2552 int CWindowCanvas::cursor_motion_event()
2554         int redraw = 0, result = 0, rerender = 0, redraw_canvas = 0;
2557         switch(gui->current_operation)
2558         {
2559                 case CWINDOW_SCROLL:
2560                 {
2561                         float zoom = get_zoom();
2562                         float cursor_x = get_cursor_x();
2563                         float cursor_y = get_cursor_y();
2565                         float zoom_x, zoom_y, conformed_w, conformed_h;
2566                         get_zooms(mwindow->edl, 0, zoom_x, zoom_y, conformed_w, conformed_h);
2567                         cursor_x = (float)cursor_x / zoom_x + gui->x_offset;
2568                         cursor_y = (float)cursor_y / zoom_y + gui->y_offset;
2572                         int x = (int)(gui->x_origin - cursor_x + gui->x_offset);
2573                         int y = (int)(gui->y_origin - cursor_y + gui->y_offset);
2576                         update_zoom(x, 
2577                                 y, 
2578                                 zoom);
2579                         update_scrollbars();
2580                         redraw = 1;
2581                         result = 1;
2582                         break;
2583                 }
2585                 case CWINDOW_CAMERA:
2586                 case CWINDOW_CAMERA_CONTROL_IN:
2587                 case CWINDOW_CAMERA_CONTROL_OUT:
2588                         result = test_bezier(0, redraw, redraw_canvas, rerender, 1);
2589                         break;
2591                 case CWINDOW_PROJECTOR:
2592                 case CWINDOW_PROJECTOR_CONTROL_IN:
2593                 case CWINDOW_PROJECTOR_CONTROL_OUT:
2594                         result = test_bezier(0, redraw, redraw_canvas, rerender, 0);
2595                         break;
2598                 case CWINDOW_CROP:
2599 //printf("CWindowCanvas::cursor_motion_event 1 %d %d\n", x, y);
2600                         result = test_crop(0, redraw);
2601                         break;
2603                 case CWINDOW_MASK:
2604                 case CWINDOW_MASK_CONTROL_IN:
2605                 case CWINDOW_MASK_CONTROL_OUT:
2606                 case CWINDOW_MASK_TRANSLATE:
2607                         result = do_mask(redraw, 
2608                                 rerender, 
2609                                 0, 
2610                                 1,
2611                                 0);
2612                         break;
2613         }
2617         if(!result)
2618         {
2619                 switch(mwindow->edl->session->cwindow_operation)
2620                 {
2621                         case CWINDOW_CROP:
2622                                 result = test_crop(0, redraw);
2623                                 break;
2624                 }
2625         }
2628 // If the window is never unlocked before calling send_command the
2629 // display shouldn't get stuck on the old video frame although it will
2630 // flicker between the old video frame and the new video frame.
2632         if(redraw)
2633         {
2634                 draw_refresh();
2635                 gui->update_tool();
2636         }
2638         if(redraw_canvas)
2639         {
2640                 mwindow->gui->lock_window("CWindowCanvas::cursor_motion_event 1");
2641                 mwindow->gui->canvas->draw_overlays();
2642                 mwindow->gui->canvas->flash();
2643                 mwindow->gui->unlock_window();
2644         }
2646         if(rerender)
2647         {
2648                 mwindow->restart_brender();
2649                 mwindow->sync_parameters(CHANGE_PARAMS);
2650                 gui->cwindow->playback_engine->que->send_command(CURRENT_FRAME, 
2651                         CHANGE_NONE,
2652                         mwindow->edl,
2653                         1);
2654                 if(!redraw) gui->update_tool();
2655         }
2656         return result;
2659 int CWindowCanvas::button_press_event()
2661         int result = 0;
2662         int redraw = 0;
2663         int redraw_canvas = 0;
2664         int rerender = 0;
2666         if(Canvas::button_press_event()) return 1;
2668         gui->translating_zoom = gui->shift_down(); 
2670         calculate_origin();
2671 //printf("CWindowCanvas::button_press_event 2 %f %f\n", gui->x_origin, gui->y_origin, gui->x_origin, gui->y_origin);
2673         float zoom_x, zoom_y, conformed_w, conformed_h;
2674         get_zooms(mwindow->edl, 0, zoom_x, zoom_y, conformed_w, conformed_h);
2675         gui->x_offset = get_x_offset(mwindow->edl, 0, zoom_x, conformed_w, conformed_h);
2676         gui->y_offset = get_y_offset(mwindow->edl, 0, zoom_y, conformed_w, conformed_h);
2678 // Scroll view
2679         if(get_buttonpress() == 2)
2680         {
2681                 gui->current_operation = CWINDOW_SCROLL;
2682                 result = 1;
2683         }
2684         else
2685 // Adjust parameter
2686         {
2687                 switch(mwindow->edl->session->cwindow_operation)
2688                 {
2689                         case CWINDOW_CAMERA:
2690                                 result = test_bezier(1, redraw, redraw_canvas, rerender, 1);
2691                                 break;
2693                         case CWINDOW_PROJECTOR:
2694                                 result = test_bezier(1, redraw, redraw_canvas, rerender, 0);
2695                                 break;
2697                         case CWINDOW_ZOOM:
2698                                 result = test_zoom(redraw);
2699                                 break;
2701                         case CWINDOW_CROP:
2702                                 result = test_crop(1, redraw);
2703                                 break;
2705                         case CWINDOW_MASK:
2706                                 if(get_buttonpress() == 1)
2707                                         result = do_mask(redraw, rerender, 1, 0, 0);
2708                                 break;
2709                 }
2710         }
2712         if(redraw)
2713         {
2714                 draw_refresh();
2715                 gui->update_tool();
2716         }
2717         return result;
2720 int CWindowCanvas::button_release_event()
2722         int result = 0;
2724         switch(gui->current_operation)
2725         {
2726                 case CWINDOW_SCROLL:
2727                         result = 1;
2728                         break;
2729         }
2731         gui->current_operation = CWINDOW_NONE;
2732         mwindow->undo->update_undo_after();
2733 //printf("CWindowCanvas::button_release_event %d\n", result);
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->calculate_output_w(0), 
2742                 mwindow->edl->calculate_output_h(0), 
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);