r499: This commit was manufactured by cvs2svn to create tag 'r1_2_1-last'.
[cinelerra_cv/mob.git] / hvirtual / cinelerra / cwindowgui.C
blob645e62b46982cbe8f6336101c674c7d0242e1edf
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         BC_WindowBase::get_resources()->bg_color,
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, mwindow->session->cwindow_controls);
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, mwindow->session->cwindow_controls);
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         mwindow->edl->session->cwindow_operation = value;
243         composite_panel->set_operation(value);
244         edit_panel->update();
246         tool_panel->start_tool(value);
247         canvas->draw_refresh();
250 void CWindowGUI::update_tool()
252 //printf("CWindowGUI::update_tool 1\n");
253         tool_panel->update_values();
256 int CWindowGUI::close_event()
258         hide_window();
259         mwindow->session->show_cwindow = 0;
260         mwindow->gui->lock_window("CWindowGUI::close_event");
261         mwindow->gui->mainmenu->show_cwindow->set_checked(0);
262         mwindow->gui->unlock_window();
263         mwindow->save_defaults();
264         return 1;
268 int CWindowGUI::keypress_event()
270         int result = 0;
272 //printf("CWindowGUI::keypress_event 1\n");
273         switch(get_keypress())
274         {
275                 case 'w':
276                 case 'W':
277                         close_event();
278                         result = 1;
279                         break;
280         }
282 //printf("CWindowGUI::keypress_event 1\n");
283         if(!result) result = transport->keypress_event();
285 //printf("CWindowGUI::keypress_event 2\n");
286         return result;
289 void CWindowGUI::drag_motion()
291         if(get_hidden()) return;
293         if(mwindow->session->current_operation == DRAG_ASSET ||
294                 mwindow->session->current_operation == DRAG_VTRANSITION ||
295                 mwindow->session->current_operation == DRAG_VEFFECT)
296         {
297                 int old_status = mwindow->session->ccanvas_highlighted;
298                 int cursor_x = get_relative_cursor_x();
299                 int cursor_y = get_relative_cursor_y();
301                 mwindow->session->ccanvas_highlighted = get_cursor_over_window() &&
302                         cursor_x >= canvas->x &&
303                         cursor_x < canvas->x + canvas->w &&
304                         cursor_y >= canvas->y &&
305                         cursor_y < canvas->y + canvas->h;
308                 if(old_status != mwindow->session->ccanvas_highlighted)
309                         canvas->draw_refresh();
310         }
313 int CWindowGUI::drag_stop()
315         int result = 0;
316         if(get_hidden()) return 0;
318         if((mwindow->session->current_operation == DRAG_ASSET ||
319                 mwindow->session->current_operation == DRAG_VTRANSITION ||
320                 mwindow->session->current_operation == DRAG_VEFFECT) &&
321                 mwindow->session->ccanvas_highlighted)
322         {
323 // Hide highlighting
324                 mwindow->session->ccanvas_highlighted = 0;
325                 canvas->draw_refresh();
326                 result = 1;
327         }
328         else
329                 return 0;
331         if(mwindow->session->current_operation == DRAG_ASSET)
332         {
333                 if(mwindow->session->drag_assets->total)
334                 {
335                         mwindow->gui->lock_window("CWindowGUI::drag_stop 1");
336                         mwindow->undo->update_undo_before(_("insert assets"), 
337                                 LOAD_ALL);
338                         mwindow->clear(0);
339                         mwindow->load_assets(mwindow->session->drag_assets, 
340                                 mwindow->edl->local_session->get_selectionstart(), 
341                                 LOAD_PASTE,
342                                 mwindow->session->track_highlighted,
343                                 0,
344                                 mwindow->edl->session->labels_follow_edits, 
345                                 mwindow->edl->session->plugins_follow_edits);
346                 }
348                 if(mwindow->session->drag_clips->total)
349                 {
350                         mwindow->gui->lock_window("CWindowGUI::drag_stop 2");
351                         mwindow->undo->update_undo_before(_("insert assets"), 
352                                 LOAD_ALL);
353                         mwindow->clear(0);
354                         mwindow->paste_edls(mwindow->session->drag_clips, 
355                                 LOAD_PASTE, 
356                                 mwindow->session->track_highlighted,
357                                 mwindow->edl->local_session->get_selectionstart(),
358                                 mwindow->edl->session->labels_follow_edits, 
359                                 mwindow->edl->session->plugins_follow_edits);
360                 }
362                 if(mwindow->session->drag_assets->total ||
363                         mwindow->session->drag_clips->total)
364                 {
365                         mwindow->save_backup();
366                         mwindow->restart_brender();
367                         mwindow->gui->update(1, 1, 1, 1, 0, 1, 0);
368                         mwindow->undo->update_undo_after();
369                         mwindow->gui->unlock_window();
370                         mwindow->sync_parameters(LOAD_ALL);
371                 }
372         }
374         if(mwindow->session->current_operation == DRAG_VEFFECT)
375         {
376 //printf("CWindowGUI::drag_stop 1\n");
377                 Track *affected_track = cwindow->calculate_affected_track();
378 //printf("CWindowGUI::drag_stop 2\n");
380                 mwindow->gui->lock_window("CWindowGUI::drag_stop 3");
381                 mwindow->insert_effects_cwindow(affected_track);
382                 mwindow->session->current_operation = NO_OPERATION;
383                 mwindow->gui->unlock_window();
384         }
386         if(mwindow->session->current_operation == DRAG_VTRANSITION)
387         {
388                 Track *affected_track = cwindow->calculate_affected_track();
389                 mwindow->gui->lock_window("CWindowGUI::drag_stop 4");
390                 mwindow->paste_transition_cwindow(affected_track);
391                 mwindow->session->current_operation = NO_OPERATION;
392                 mwindow->gui->unlock_window();
393         }
395         return result;
399 CWindowEditing::CWindowEditing(MWindow *mwindow, CWindow *cwindow)
400  : EditPanel(mwindow, 
401                 cwindow->gui, 
402                 mwindow->theme->cedit_x, 
403                 mwindow->theme->cedit_y,
404                 mwindow->edl->session->editing_mode, 
405                 0,
406                 1,
407                 0, 
408                 0,
409                 1,
410                 1,
411                 1,
412                 1,
413                 1,
414                 0,
415                 1,
416                 1,
417                 1,
418                 0,
419                 1)
421         this->mwindow = mwindow;
422         this->cwindow = cwindow;
425 void CWindowEditing::set_inpoint()
427         mwindow->set_inpoint(0);
430 void CWindowEditing::set_outpoint()
432         mwindow->set_outpoint(0);
439 CWindowMeters::CWindowMeters(MWindow *mwindow, CWindowGUI *gui, int x, int y, int h)
440  : MeterPanel(mwindow, 
441                 gui,
442                 x,
443                 y,
444                 h,
445                 mwindow->edl->session->audio_channels,
446                 mwindow->edl->session->cwindow_meter)
448         this->mwindow = mwindow;
449         this->gui = gui;
452 CWindowMeters::~CWindowMeters()
456 int CWindowMeters::change_status_event()
458         mwindow->edl->session->cwindow_meter = use_meters;
459         mwindow->theme->get_cwindow_sizes(gui, mwindow->session->cwindow_controls);
460         gui->resize_event(gui->get_w(), gui->get_h());
461         return 1;
466 #define MIN_ZOOM 0.25
467 #define MAX_ZOOM 4.0
469 CWindowZoom::CWindowZoom(MWindow *mwindow, CWindowGUI *gui, int x, int y)
470  : ZoomPanel(mwindow, 
471         gui, 
472         (long)mwindow->edl->session->cwindow_zoom, 
473         x, 
474         y,
475         100, 
476         MIN_ZOOM, 
477         MAX_ZOOM, 
478         ZOOM_PERCENTAGE)
480         this->mwindow = mwindow;
481         this->gui = gui;
484 CWindowZoom::~CWindowZoom()
488 int CWindowZoom::handle_event()
490         if(!strcasecmp(AUTO_ZOOM, get_text()))
491         {
492                 mwindow->edl->session->cwindow_scrollbars = 0;
493         }
494         else
495         {
496                 mwindow->edl->session->cwindow_scrollbars = 1;
497         }
499         float old_zoom = mwindow->edl->session->cwindow_zoom;
500         float new_zoom = get_value();
501         float x = gui->canvas->w / 2;
502         float y = gui->canvas->h / 2;
503         gui->canvas->canvas_to_output(mwindow->edl, 
504                                 0, 
505                                 x, 
506                                 y);
507         x -= gui->canvas->w_visible / 2 * old_zoom / new_zoom;
508         y -= gui->canvas->h_visible / 2 * old_zoom / new_zoom;
509         gui->canvas->update_zoom((int)x, 
510                 (int)y, 
511                 new_zoom);
512         gui->canvas->reposition_window(mwindow->edl, 
513                 mwindow->theme->ccanvas_x,
514                 mwindow->theme->ccanvas_y,
515                 mwindow->theme->ccanvas_w,
516                 mwindow->theme->ccanvas_h);
517         gui->canvas->draw_refresh();
518         return 1;
523 CWindowSlider::CWindowSlider(MWindow *mwindow, CWindow *cwindow, int x, int y, int pixels)
524  : BC_PercentageSlider(x, 
525                         y,
526                         0,
527                         pixels, 
528                         pixels, 
529                         0, 
530                         1, 
531                         0)
533         this->mwindow = mwindow;
534         this->cwindow = cwindow;
537 CWindowSlider::~CWindowSlider()
541 int CWindowSlider::handle_event()
543         unlock_window();
544         cwindow->playback_engine->interrupt_playback(1);
545         lock_window("CWindowSlider::handle_event 1");
546         
547         mwindow->gui->lock_window("CWindowSlider::handle_event 2");
548         mwindow->select_point((double)get_value());
549         mwindow->gui->unlock_window();
550         return 1;
553 void CWindowSlider::set_position()
555         double new_length = mwindow->edl->tracks->total_playable_length();
556         if(mwindow->edl->local_session->preview_end <= 0 ||
557                 mwindow->edl->local_session->preview_end > new_length)
558                 mwindow->edl->local_session->preview_end = new_length;
559         if(mwindow->edl->local_session->preview_start > 
560                 mwindow->edl->local_session->preview_end)
561                 mwindow->edl->local_session->preview_start = 0;
565         update(mwindow->theme->cslider_w, 
566                 mwindow->edl->local_session->selectionstart, 
567                 mwindow->edl->local_session->preview_start, 
568                 mwindow->edl->local_session->preview_end);
572 int CWindowSlider::increase_value()
574         unlock_window();
575         cwindow->gui->transport->handle_transport(SINGLE_FRAME_FWD);
576         lock_window("CWindowSlider::increase_value");
577         return 1;
580 int CWindowSlider::decrease_value()
582         unlock_window();
583         cwindow->gui->transport->handle_transport(SINGLE_FRAME_REWIND);
584         lock_window("CWindowSlider::decrease_value");
585         return 1;
589 // CWindowDestination::CWindowDestination(MWindow *mwindow, CWindowGUI *cwindow, int x, int y)
590 //  : BC_PopupTextBox(cwindow, 
591 //      &cwindow->destinations, 
592 //      cwindow->destinations.values[cwindow->cwindow->destination]->get_text(),
593 //      x, 
594 //      y, 
595 //      70, 
596 //      200)
597 // {
598 //      this->mwindow = mwindow;
599 //      this->cwindow = cwindow;
600 // }
601 // 
602 // CWindowDestination::~CWindowDestination()
603 // {
604 // }
605 // 
606 // int CWindowDestination::handle_event()
607 // {
608 //      return 1;
609 // }
612 CWindowTransport::CWindowTransport(MWindow *mwindow, 
613         CWindowGUI *gui, 
614         int x, 
615         int y)
616  : PlayTransport(mwindow, 
617         gui, 
618         x, 
619         y)
621         this->gui = gui;
624 EDL* CWindowTransport::get_edl()
626         return mwindow->edl;
629 void CWindowTransport::goto_start()
631         gui->unlock_window();
632         handle_transport(REWIND, 1);
634         mwindow->gui->lock_window("CWindowTransport::goto_start 1");
635         mwindow->goto_start();
636         mwindow->gui->unlock_window();
638         gui->lock_window("CWindowTransport::goto_start 2");
641 void CWindowTransport::goto_end()
643         gui->unlock_window();
644         handle_transport(GOTO_END, 1);
646         mwindow->gui->lock_window("CWindowTransport::goto_end 1");
647         mwindow->goto_end();
648         mwindow->gui->unlock_window();
650         gui->lock_window("CWindowTransport::goto_end 2");
655 CWindowCanvas::CWindowCanvas(MWindow *mwindow, CWindowGUI *gui)
656  : Canvas(gui,
657                 mwindow->theme->ccanvas_x,
658                 mwindow->theme->ccanvas_y,
659                 mwindow->theme->ccanvas_w,
660                 mwindow->theme->ccanvas_h,
661                 0,
662                 0,
663                 mwindow->edl->session->cwindow_scrollbars,
664                 1)
666         this->mwindow = mwindow;
667         this->gui = gui;
670 void CWindowCanvas::update_zoom(int x, int y, float zoom)
672         use_scrollbars = mwindow->edl->session->cwindow_scrollbars;
674         mwindow->edl->session->cwindow_xscroll = x;
675         mwindow->edl->session->cwindow_yscroll = y;
676         mwindow->edl->session->cwindow_zoom = zoom;
679 int CWindowCanvas::get_xscroll()
681         return mwindow->edl->session->cwindow_xscroll;
684 int CWindowCanvas::get_yscroll()
686         return mwindow->edl->session->cwindow_yscroll;
690 float CWindowCanvas::get_zoom()
692         return mwindow->edl->session->cwindow_zoom;
695 void CWindowCanvas::draw_refresh()
697         if(!canvas->video_is_on())
698         {
699 //printf("CWindowCanvas::draw_refresh 1 %f\n", mwindow->edl->session->cwindow_zoom);
700                 canvas->clear_box(0, 0, canvas->get_w(), canvas->get_h());
701 //printf("CWindowCanvas::draw_refresh 2\n");
703                 if(refresh_frame)
704                 {
705                         int in_x, in_y, in_w, in_h, out_x, out_y, out_w, out_h;
706 //printf("CWindowCanvas::draw_refresh 3\n");
707                         get_transfers(mwindow->edl, 
708                                 in_x, 
709                                 in_y, 
710                                 in_w, 
711                                 in_h, 
712                                 out_x, 
713                                 out_y, 
714                                 out_w, 
715                                 out_h);
718 // printf("CWindowCanvas::draw_refresh %d %d %d %d -> %d %d %d %d\n", 
719 // in_x, in_y, in_w, in_h, out_x, out_y, out_w, out_h);
720 //canvas->clear_box(0, 0, canvas->get_w(), canvas->get_h());
723 //printf("CWindowCanvas::draw_refresh 5\n");
724                         if(out_w > 0 && out_h > 0 && in_w > 0 && in_h > 0)
725                                 canvas->draw_vframe(refresh_frame,
726                                                 out_x, 
727                                                 out_y, 
728                                                 out_w, 
729                                                 out_h,
730                                                 in_x, 
731                                                 in_y, 
732                                                 in_w, 
733                                                 in_h,
734                                                 0);
735 //printf("CWindowCanvas::draw_refresh 6\n");
736                 }
737                 else
738                 {
739 //printf("CWindowCanvas::draw_refresh 7\n");
740                         canvas->clear_box(0, 0, canvas->get_w(), canvas->get_h());
741 //printf("CWindowCanvas::draw_refresh 8\n");
742                 }
744 //printf("CWindowCanvas::draw_refresh 9\n");
745                 draw_overlays();
746                 canvas->flash();
747                 canvas->flush();
748 //printf("CWindowCanvas::draw_refresh 10\n");
749         }
752 #define CROPHANDLE_W 10
753 #define CROPHANDLE_H 10
755 void CWindowCanvas::draw_crophandle(int x, int y)
757         canvas->draw_box(x, y, CROPHANDLE_W, CROPHANDLE_H);
760 #define CONTROL_W 10
761 #define CONTROL_H 10
762 #define FIRST_CONTROL_W 20
763 #define FIRST_CONTROL_H 20
764 #undef BC_INFINITY
765 #define BC_INFINITY 65536
766 #ifndef SQR
767 #define SQR(x) ((x) * (x))
768 #endif
770 int CWindowCanvas::do_mask(int &redraw, 
771                 int &rerender, 
772                 int button_press, 
773                 int cursor_motion,
774                 int draw)
776 // Retrieve points from top recordable track
777 //printf("CWindowCanvas::do_mask 1\n");
778         Track *track = gui->cwindow->calculate_affected_track();
779 //printf("CWindowCanvas::do_mask 2\n");
781         if(!track) return 0;
782 //printf("CWindowCanvas::do_mask 3\n");
784         MaskAutos *mask_autos = track->automation->mask_autos;
785         long position = track->to_units(mwindow->edl->local_session->selectionstart,
786                 0);
787         ArrayList<MaskPoint*> points;
788         mask_autos->get_points(&points, mwindow->edl->session->cwindow_mask,
789                 position, 
790                 PLAY_FORWARD);
791 //printf("CWindowCanvas::do_mask 4\n");
793 // Translate mask to projection
794         BezierAutos *projector_autos = track->automation->projector_autos;
795         FloatAutos *projector_zooms = track->automation->pzoom_autos;
796         BezierAuto *before = 0, *after = 0;
797         FloatAuto *zoom_before = 0, *zoom_after = 0;
798         float projector_x, projector_y, projector_z;
799 // Projector zooms relative to the center of the track output.
800         float half_track_w = (float)track->track_w / 2;
801         float half_track_h = (float)track->track_h / 2;
802         projector_autos->get_center(projector_x, 
803                         projector_y, 
804                         projector_z, 
805                         position, 
806                         PLAY_FORWARD, 
807                         &before, 
808                         &after);
809         projector_z = projector_zooms->get_value(position,
810                 PLAY_FORWARD,
811                 zoom_before,
812                 zoom_after);
813 // printf("CWindowCanvas::do_mask 1 %f %f %f\n", projector_x, 
814 //                      projector_y, 
815 //                      projector_z);
818 // Get position of cursor relative to mask
819         float mask_cursor_x = get_cursor_x();
820         float mask_cursor_y = get_cursor_y();
821         canvas_to_output(mwindow->edl, 0, mask_cursor_x, mask_cursor_y);
823         mask_cursor_x -= projector_x;
824         mask_cursor_y -= projector_y;
825         mask_cursor_x = half_track_w + (mask_cursor_x - half_track_w) / projector_z;
826         mask_cursor_y = half_track_h + (mask_cursor_y - half_track_h) / projector_z;
828 // Fix cursor origin
829         if(button_press)
830         {
831                 gui->x_origin = mask_cursor_x;
832                 gui->y_origin = mask_cursor_y;
833         }
835         int result = 0;
836 // Points of closest line
837         int shortest_point1 = -1;
838         int shortest_point2 = -1;
839 // Closest point
840         int shortest_point = -1;
841 // Distance to closest line
842         float shortest_line_distance = BC_INFINITY;
843 // Distance to closest point
844         float shortest_point_distance = BC_INFINITY;
845         int selected_point = -1;
846         int selected_control_point = -1;
847         float selected_control_point_distance = BC_INFINITY;
848         ArrayList<int> x_points;
849         ArrayList<int> y_points;
851         if(!cursor_motion)
852         {
853                 if(draw)
854                 {
855                         canvas->set_color(WHITE);
856                         canvas->set_inverse();
857                 }
858 //printf("CWindowCanvas::do_mask 1 %d\n", points.total);
860 // Never draw closed polygon and a closed
861 // polygon is harder to add points to.
862                 for(int i = 0; i < points.total && !result; i++)
863                 {
864                         MaskPoint *point1 = points.values[i];
865                         MaskPoint *point2 = (i >= points.total - 1) ? 
866                                 points.values[0] : 
867                                 points.values[i + 1];
868                         float x0, x1, x2, x3;
869                         float y0, y1, y2, y3;
870                         float old_x, old_y, x, y;
871                         int segments = (int)(sqrt(SQR(point1->x - point2->x) + SQR(point1->y - point2->y)));
873 //printf("CWindowCanvas::do_mask 1 %f, %f -> %f, %f projectorz=%f\n",
874 //point1->x, point1->y, point2->x, point2->y, projector_z);
875                         for(int j = 0; j <= segments && !result; j++)
876                         {
877 //printf("CWindowCanvas::do_mask 1 %f, %f -> %f, %f\n", x0, y0, x3, y3);
878                                 x0 = point1->x;
879                                 y0 = point1->y;
880                                 x1 = point1->x + point1->control_x2;
881                                 y1 = point1->y + point1->control_y2;
882                                 x2 = point2->x + point2->control_x1;
883                                 y2 = point2->y + point2->control_y1;
884                                 x3 = point2->x;
885                                 y3 = point2->y;
887                                 float t = (float)j / segments;
888                                 float tpow2 = t * t;
889                                 float tpow3 = t * t * t;
890                                 float invt = 1 - t;
891                                 float invtpow2 = invt * invt;
892                                 float invtpow3 = invt * invt * invt;
894                                 x = (        invtpow3 * x0
895                                         + 3 * t     * invtpow2 * x1
896                                         + 3 * tpow2 * invt     * x2 
897                                         +     tpow3            * x3);
898                                 y = (        invtpow3 * y0 
899                                         + 3 * t     * invtpow2 * y1
900                                         + 3 * tpow2 * invt     * y2 
901                                         +     tpow3            * y3);
903                                 x = half_track_w + (x - half_track_w) * projector_z + projector_x;
904                                 y = half_track_h + (y - half_track_h) * projector_z + projector_y;
907 // Test new point addition
908                                 if(button_press)
909                                 {
910                                         float line_distance = 
911                                                 sqrt(SQR(x - mask_cursor_x) + SQR(y - mask_cursor_y));
913 //printf("CWindowCanvas::do_mask 1 x=%f mask_cursor_x=%f y=%f mask_cursor_y=%f %f %f %d, %d\n", 
914 //x, mask_cursor_x, y, mask_cursor_y, line_distance, shortest_line_distance, shortest_point1, shortest_point2);
915                                         if(line_distance < shortest_line_distance || 
916                                                 shortest_point1 < 0)
917                                         {
918                                                 shortest_line_distance = line_distance;
919                                                 shortest_point1 = i;
920                                                 shortest_point2 = (i >= points.total - 1) ? 0 : (i + 1);
921 //printf("CWindowCanvas::do_mask 2 %f %f %d, %d\n", line_distance, shortest_line_distance, shortest_point1, shortest_point2);
922                                         }
925                                         float point_distance1 = 
926                                                 sqrt(SQR(point1->x - mask_cursor_x) + SQR(point1->y - mask_cursor_y));
927                                         float point_distance2 = 
928                                                 sqrt(SQR(point2->x - mask_cursor_x) + SQR(point2->y - mask_cursor_y));
930                                         if(point_distance1 < shortest_point_distance || 
931                                                 shortest_point < 0)
932                                         {
933                                                 shortest_point_distance = point_distance1;
934                                                 shortest_point = i;
935                                         }
937                                         if(point_distance2 < shortest_point_distance || 
938                                                 shortest_point < 0)
939                                         {
940                                                 shortest_point_distance = point_distance2;
941                                                 shortest_point = (i >= points.total - 1) ? 0 : (i + 1);
942                                         }
943                                 }
945                                 output_to_canvas(mwindow->edl, 0, x, y);
948 #define TEST_BOX(cursor_x, cursor_y, target_x, target_y) \
949         (cursor_x >= target_x - CONTROL_W / 2 && \
950         cursor_x < target_x + CONTROL_W / 2 && \
951         cursor_y >= target_y - CONTROL_H / 2 && \
952         cursor_y < target_y + CONTROL_H / 2)
954 // Test existing point selection
955                                 if(button_press)
956                                 {
957                                         float canvas_x = half_track_w + (x0 - half_track_w) * projector_z + projector_x;
958                                         float canvas_y = half_track_h + (y0 - half_track_h) * projector_z + projector_y;
959                                         int cursor_x = get_cursor_x();
960                                         int cursor_y = get_cursor_y();
962 // Test first point
963                                         if(gui->shift_down())
964                                         {
965                                                 float control_x = half_track_w + (x1 - half_track_w) * projector_z + projector_x;
966                                                 float control_y = half_track_h + (y1 - half_track_h) * projector_z + projector_y;
967                                                 output_to_canvas(mwindow->edl, 0, control_x, control_y);
969                                                 float distance = 
970                                                         sqrt(SQR(control_x - cursor_x) + SQR(control_y - cursor_y));
972                                                 if(distance < selected_control_point_distance)
973                                                 {
974                                                         selected_point = i;
975                                                         selected_control_point = 1;
976                                                         selected_control_point_distance = distance;
977                                                 }
978                                         }
979                                         else
980                                         {
981                                                 output_to_canvas(mwindow->edl, 0, canvas_x, canvas_y);
982                                                 if(!gui->ctrl_down())
983                                                 {
984                                                         if(TEST_BOX(cursor_x, cursor_y, canvas_x, canvas_y))
985                                                         {
986                                                                 selected_point = i;
987                                                         }
988                                                 }
989                                                 else
990                                                 {
991                                                         selected_point = shortest_point;
992                                                 }
993                                         }
995 // Test second point
996                                         canvas_x = half_track_w + (x3 - half_track_w) * projector_z + projector_x;
997                                         canvas_y = half_track_h + (y3 - half_track_h) * projector_z + projector_y;
998                                         if(gui->shift_down())
999                                         {
1000                                                 float control_x = half_track_w + (x2 - half_track_w) * projector_z + projector_x;
1001                                                 float control_y = half_track_h + (y2 - half_track_h) * projector_z + projector_y;
1002                                                 output_to_canvas(mwindow->edl, 0, control_x, control_y);
1004                                                 float distance = 
1005                                                         sqrt(SQR(control_x - cursor_x) + SQR(control_y - cursor_y));
1007 //printf("CWindowCanvas::do_mask %d %f %f\n", i, distance, selected_control_point_distance);
1008                                                 if(distance < selected_control_point_distance)
1009                                                 {
1010                                                         selected_point = (i < points.total - 1 ? i + 1 : 0);
1011                                                         selected_control_point = 0;
1012                                                         selected_control_point_distance = distance;
1013                                                 }
1014                                         }
1015                                         else
1016                                         if(i < points.total - 1)
1017                                         {
1018                                                 output_to_canvas(mwindow->edl, 0, canvas_x, canvas_y);
1019                                                 if(!gui->ctrl_down())
1020                                                 {
1021                                                         if(TEST_BOX(cursor_x, cursor_y, canvas_x, canvas_y))
1022                                                         {
1023                                                                 selected_point = (i < points.total - 1 ? i + 1 : 0);
1024                                                         }
1025                                                 }
1026                                                 else
1027                                                 {
1028                                                         selected_point = shortest_point;
1029                                                 }
1030                                         }
1031                                 }
1035                                 if(j > 0)
1036                                 {
1037 // Draw joining line
1038                                         if(draw)
1039                                         {
1040                                                 x_points.append((int)x);
1041                                                 y_points.append((int)y);
1042                                         }
1044                                         if(j == segments)
1045                                         {
1050                                                 if(draw)
1051                                                 {
1052 // Draw second anchor
1053                                                         if(i < points.total - 1)
1054                                                         {
1055                                                                 if(i == gui->affected_point - 1)
1056                                                                         canvas->draw_disc((int)x - CONTROL_W / 2, 
1057                                                                                 (int)y - CONTROL_W / 2, 
1058                                                                                 CONTROL_W, 
1059                                                                                 CONTROL_W);
1060                                                                 else
1061                                                                         canvas->draw_circle((int)x - CONTROL_W / 2, 
1062                                                                                 (int)y - CONTROL_W / 2, 
1063                                                                                 CONTROL_W, 
1064                                                                                 CONTROL_W);
1065 // char string[BCTEXTLEN];
1066 // sprintf(string, "%d", (i < points.total - 1 ? i + 1 : 0));
1067 // canvas->draw_text((int)x + CONTROL_W, (int)y + CONTROL_W, string);
1068                                                         }
1070 // Draw second control point.  Discard x2 and y2 after this.
1071                                                         x2 = half_track_w + (x2 - half_track_w) * projector_z + projector_x;
1072                                                         y2 = half_track_h + (y2 - half_track_h) * projector_z + projector_y;
1073                                                         output_to_canvas(mwindow->edl, 0, x2, y2);
1074                                                         canvas->draw_line((int)x, (int)y, (int)x2, (int)y2);
1075                                                         canvas->draw_rectangle((int)x2 - CONTROL_W / 2,
1076                                                                 (int)y2 - CONTROL_H / 2,
1077                                                                 CONTROL_W,
1078                                                                 CONTROL_H);
1079                                                 }
1080                                         }
1081                                 }
1082                                 else
1083                                 {
1086 // Draw first anchor
1087                                         if(i == 0 && draw)
1088                                         {
1089                                                 canvas->draw_disc((int)x - FIRST_CONTROL_W / 2, 
1090                                                         (int)y - FIRST_CONTROL_H / 2, 
1091                                                         FIRST_CONTROL_W, 
1092                                                         FIRST_CONTROL_H);
1093                                         }
1095 // Draw first control point.  Discard x1 and y1 after this.
1096                                         if(draw)
1097                                         {
1098                                                 x1 = half_track_w + (x1 - half_track_w) * projector_z + projector_x;
1099                                                 y1 = half_track_h + (y1 - half_track_h) * projector_z + projector_y;
1100                                                 output_to_canvas(mwindow->edl, 0, x1, y1);
1101                                                 canvas->draw_line((int)x, (int)y, (int)x1, (int)y1);
1102                                                 canvas->draw_rectangle((int)x1 - CONTROL_W / 2,
1103                                                         (int)y1 - CONTROL_H / 2,
1104                                                         CONTROL_W,
1105                                                         CONTROL_H);
1106                                         
1107                                                 x_points.append((int)x);
1108                                                 y_points.append((int)y);
1109                                         }
1110                                 }
1111 //printf("CWindowCanvas::do_mask 1\n");
1113                                 old_x = x;
1114                                 old_y = y;
1115                         }
1116                 }
1117 //printf("CWindowCanvas::do_mask 1\n");
1119                 if(draw)
1120                 {
1121                         canvas->draw_polygon(&x_points, &y_points);
1122                         canvas->set_opaque();
1123                 }
1124 //printf("CWindowCanvas::do_mask 1\n");
1125         }
1133         if(button_press && !result)
1134         {
1135                 gui->affected_track = gui->cwindow->calculate_affected_track();
1136 // Get current keyframe
1137                 if(gui->affected_track)
1138                         gui->affected_auto = 
1139                                 gui->cwindow->calculate_affected_auto(gui->affected_track->automation->mask_autos);
1141                 MaskAuto *keyframe = (MaskAuto*)gui->affected_auto;
1142                 SubMask *mask = keyframe->get_submask(mwindow->edl->session->cwindow_mask);
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                         }
1189 // printf("CWindowGUI::do_mask 40\n");
1190 // mwindow->edl->dump();
1191 // printf("CWindowGUI::do_mask 50\n");
1195 //printf("CWindowCanvas::do_mask 1 %f %f %d %d\n", 
1196 //      shortest_line_distance, shortest_point_distance, shortest_point1, shortest_point2);
1197 //printf("CWindowCanvas::do_mask %d %d\n", shortest_point1, shortest_point2);
1199 // Append to end of list
1200                         if(labs(shortest_point1 - shortest_point2) > 1)
1201                         {
1202 // Need to apply the new point to every keyframe
1203                                 for(MaskAuto *current = (MaskAuto*)mask_autos->default_auto;
1204                                         current; )
1205                                 {
1206                                         SubMask *submask = current->get_submask(mwindow->edl->session->cwindow_mask);
1207                                         MaskPoint *new_point = new MaskPoint;
1208                                         submask->points.append(new_point);
1209                                         *new_point = *point;
1210                                         if(current == (MaskAuto*)mask_autos->default_auto)
1211                                                 current = (MaskAuto*)mask_autos->first;
1212                                         else
1213                                                 current = (MaskAuto*)NEXT;
1214                                 }
1216                                 gui->affected_point = mask->points.total - 1;
1217                                 result = 1;
1218                         }
1219                         else
1220 // Insert between 2 points, shifting back point 2
1221                         if(shortest_point1 >= 0 && shortest_point2 >= 0)
1222                         {
1223                                 for(MaskAuto *current = (MaskAuto*)mask_autos->default_auto;
1224                                         current; )
1225                                 {
1226                                         SubMask *submask = current->get_submask(mwindow->edl->session->cwindow_mask);
1227 // In case the keyframe point count isn't synchronized with the rest of the keyframes,
1228 // avoid a crash.
1229                                         if(submask->points.total >= shortest_point2)
1230                                         {
1231                                                 MaskPoint *new_point = new MaskPoint;
1232                                                 submask->points.append(0);
1233                                                 for(int i = submask->points.total - 1; 
1234                                                         i > shortest_point2; 
1235                                                         i--)
1236                                                         submask->points.values[i] = submask->points.values[i - 1];
1237                                                 submask->points.values[shortest_point2] = new_point;
1239                                                 *new_point = *point;
1240                                         }
1242                                         if(current == (MaskAuto*)mask_autos->default_auto)
1243                                                 current = (MaskAuto*)mask_autos->first;
1244                                         else
1245                                                 current = (MaskAuto*)NEXT;
1246                                 }
1249                                 gui->affected_point = shortest_point2;
1250                                 result = 1;
1251                         }
1254 // printf("CWindowGUI::do_mask 20\n");
1255 // mwindow->edl->dump();
1256 // printf("CWindowGUI::do_mask 30\n");
1261 // Create the first point.
1262                         if(!result)
1263                         {
1264 //printf("CWindowCanvas::do_mask 1\n");
1265                                 for(MaskAuto *current = (MaskAuto*)mask_autos->default_auto;
1266                                         current; )
1267                                 {
1268                                         SubMask *submask = current->get_submask(mwindow->edl->session->cwindow_mask);
1269                                         MaskPoint *new_point = new MaskPoint;
1270                                         submask->points.append(new_point);
1271                                         *new_point = *point;
1272                                         if(current == (MaskAuto*)mask_autos->default_auto)
1273                                                 current = (MaskAuto*)mask_autos->first;
1274                                         else
1275                                                 current = (MaskAuto*)NEXT;
1276                                 }
1278 //printf("CWindowCanvas::do_mask 2\n");
1279 // Create a second point if none existed before
1280                                 if(mask->points.total < 2)
1281                                 {
1282                                         for(MaskAuto *current = (MaskAuto*)mask_autos->default_auto;
1283                                                 current; )
1284                                         {
1285                                                 SubMask *submask = current->get_submask(mwindow->edl->session->cwindow_mask);
1286                                                 MaskPoint *new_point = new MaskPoint;
1287                                                 submask->points.append(new_point);
1288                                                 *new_point = *point;
1289                                                 if(current == (MaskAuto*)mask_autos->default_auto)
1290                                                         current = (MaskAuto*)mask_autos->first;
1291                                                 else
1292                                                         current = (MaskAuto*)NEXT;
1293                                         }
1294                                 }
1295                                 gui->affected_point = mask->points.total - 1;
1296 //printf("CWindowCanvas::do_mask 3 %d\n", mask->points.total);
1297                         }
1301                         gui->current_operation = mwindow->edl->session->cwindow_operation;
1302 // Delete the template
1303                         delete point;
1304 //printf("CWindowGUI::do_mask 1\n");
1305                         mwindow->undo->update_undo_after();
1306 //printf("CWindowGUI::do_mask 10\n");
1308                 }
1310                 result = 1;
1311                 rerender = 1;
1312                 redraw = 1;
1313         }
1315         if(button_press && result)
1316         {
1317                 MaskAuto *keyframe = (MaskAuto*)gui->affected_auto;
1318                 SubMask *mask = keyframe->get_submask(mwindow->edl->session->cwindow_mask);
1319                 MaskPoint *point = mask->points.values[gui->affected_point];
1320                 gui->center_x = point->x;
1321                 gui->center_y = point->y;
1322                 gui->control_in_x = point->control_x1;
1323                 gui->control_in_y = point->control_y1;
1324                 gui->control_out_x = point->control_x2;
1325                 gui->control_out_y = point->control_y2;
1326 // printf("CWindowCanvas::do_mask 1 %p %p %d\n", 
1327 //      gui->affected_auto, 
1328 //      gui->affected_point,
1329 //      gui->current_operation);
1330         }
1332 //printf("CWindowCanvas::do_mask 8\n");
1333         if(cursor_motion)
1334         {
1335                 MaskAuto *keyframe = (MaskAuto*)gui->affected_auto;
1336                 SubMask *mask = keyframe->get_submask(mwindow->edl->session->cwindow_mask);
1337                 if(gui->affected_point < mask->points.total)
1338                 {
1339                         MaskPoint *point = mask->points.values[gui->affected_point];
1340 //                      float cursor_x = get_cursor_x();
1341 //                      float cursor_y = get_cursor_y();
1342 //                      canvas_to_output(mwindow->edl, 0, cursor_x, cursor_y);
1343                         float cursor_x = mask_cursor_x;
1344                         float cursor_y = mask_cursor_y;
1345 //printf("CWindowCanvas::do_mask 9 %d %d\n", mask->points.total, gui->affected_point);
1347                         float last_x = point->x;
1348                         float last_y = point->y;
1349                         float last_control_x1 = point->control_x1;
1350                         float last_control_y1 = point->control_y1;
1351                         float last_control_x2 = point->control_x2;
1352                         float last_control_y2 = point->control_y2;
1355                         switch(gui->current_operation)
1356                         {
1357                                 case CWINDOW_MASK:
1358                                         point->x = cursor_x - gui->x_origin + gui->center_x;
1359                                         point->y = cursor_y - gui->y_origin + gui->center_y;
1360                                         break;
1362                                 case CWINDOW_MASK_CONTROL_IN:
1363                                         point->control_x1 = cursor_x - gui->x_origin + gui->control_in_x;
1364                                         point->control_y1 = cursor_y - gui->y_origin + gui->control_in_y;
1365                                         break;
1367                                 case CWINDOW_MASK_CONTROL_OUT:
1368                                         point->control_x2 = cursor_x - gui->x_origin + gui->control_out_x;
1369                                         point->control_y2 = cursor_y - gui->y_origin + gui->control_out_y;
1370                                         break;
1372                                 case CWINDOW_MASK_TRANSLATE:
1373                                         for(int i = 0; i < mask->points.total; i++)
1374                                         {
1375                                                 mask->points.values[i]->x += cursor_x - gui->x_origin;
1376                                                 mask->points.values[i]->y += cursor_y - gui->y_origin;
1377                                         }
1378                                         gui->x_origin = cursor_x;
1379                                         gui->y_origin = cursor_y;
1380                                         break;
1381                         }
1384                         if( !EQUIV(last_x, point->x) ||
1385                                 !EQUIV(last_y, point->y) ||
1386                                 !EQUIV(last_control_x1, point->control_x1) ||
1387                                 !EQUIV(last_control_y1, point->control_y1) ||
1388                                 !EQUIV(last_control_x2, point->control_x2) ||
1389                                 !EQUIV(last_control_y2, point->control_y2))
1390                         {
1391                                 mwindow->undo->update_undo_before(_("tweek"), LOAD_AUTOMATION);
1392                                 rerender = 1;
1393                                 redraw = 1;
1394                         }
1395                 }
1396                 result = 1;
1397         }
1398 //printf("CWindowCanvas::do_mask 2 %d %d %d\n", result, rerender, redraw);
1400         points.remove_all_objects();
1401 //printf("CWindowCanvas::do_mask 20\n");
1402         return result;
1405 void CWindowCanvas::draw_overlays()
1407 //printf("CWindowCanvas::draw_overlays 1\n");
1408         if(mwindow->edl->session->safe_regions)
1409         {
1410                 draw_safe_regions();
1411         }
1413         if(mwindow->edl->session->cwindow_scrollbars)
1414         {
1415 // Always draw output rectangle
1416                 float x1, y1, x2, y2;
1417                 x1 = 0;
1418                 x2 = mwindow->edl->session->output_w;
1419                 y1 = 0;
1420                 y2 = mwindow->edl->session->output_h;
1421                 output_to_canvas(mwindow->edl, 0, x1, y1);
1422                 output_to_canvas(mwindow->edl, 0, x2, y2);
1424                 canvas->set_inverse();
1425                 canvas->set_color(WHITE);
1427                 canvas->draw_rectangle((int)x1, 
1428                                 (int)y1, 
1429                                 (int)(x2 - x1), 
1430                                 (int)(y2 - y1));
1432                 canvas->set_opaque();
1433         }
1435         if(mwindow->session->ccanvas_highlighted)
1436         {
1437                 canvas->set_color(WHITE);
1438                 canvas->set_inverse();
1439                 canvas->draw_rectangle(0, 0, canvas->get_w(), canvas->get_h());
1440                 canvas->draw_rectangle(1, 1, canvas->get_w() - 2, canvas->get_h() - 2);
1441                 canvas->set_opaque();
1442         }
1444         int temp1 = 0, temp2 = 0;
1445 //printf("CWindowCanvas::draw_overlays 1 %d\n", mwindow->edl->session->cwindow_operation);
1446         switch(mwindow->edl->session->cwindow_operation)
1447         {
1448                 case CWINDOW_CAMERA:
1449                         draw_bezier(1);
1450                         break;
1452                 case CWINDOW_PROJECTOR:
1453                         draw_bezier(0);
1454                         break;
1456                 case CWINDOW_CROP:
1457                         draw_crop();
1458                         break;
1460                 case CWINDOW_MASK:
1461                         do_mask(temp1, temp2, 0, 0, 1);
1462                         break;
1463         }
1464 //printf("CWindowCanvas::draw_overlays 2\n");
1467 void CWindowCanvas::draw_safe_regions()
1469         float action_x1, action_x2, action_y1, action_y2;
1470         float title_x1, title_x2, title_y1, title_y2;
1472         action_x1 = mwindow->edl->session->output_w / 2 - mwindow->edl->session->output_w / 2 * 0.9;
1473         action_x2 = mwindow->edl->session->output_w / 2 + mwindow->edl->session->output_w / 2 * 0.9;
1474         action_y1 = mwindow->edl->session->output_h / 2 - mwindow->edl->session->output_h / 2 * 0.9;
1475         action_y2 = mwindow->edl->session->output_h / 2 + mwindow->edl->session->output_h / 2 * 0.9;
1476         title_x1 = mwindow->edl->session->output_w / 2 - mwindow->edl->session->output_w / 2 * 0.8;
1477         title_x2 = mwindow->edl->session->output_w / 2 + mwindow->edl->session->output_w / 2 * 0.8;
1478         title_y1 = mwindow->edl->session->output_h / 2 - mwindow->edl->session->output_h / 2 * 0.8;
1479         title_y2 = mwindow->edl->session->output_h / 2 + mwindow->edl->session->output_h / 2 * 0.8;
1481         output_to_canvas(mwindow->edl, 0, action_x1, action_y1);
1482         output_to_canvas(mwindow->edl, 0, action_x2, action_y2);
1483         output_to_canvas(mwindow->edl, 0, title_x1, title_y1);
1484         output_to_canvas(mwindow->edl, 0, title_x2, title_y2);
1486         canvas->set_inverse();
1487         canvas->set_color(WHITE);
1489         canvas->draw_rectangle((int)action_x1, 
1490                         (int)action_y1, 
1491                         (int)(action_x2 - action_x1), 
1492                         (int)(action_y2 - action_y1));
1493         canvas->draw_rectangle((int)title_x1, 
1494                         (int)title_y1, 
1495                         (int)(title_x2 - title_x1), 
1496                         (int)(title_y2 - title_y1));
1498         canvas->set_opaque();
1501 void CWindowCanvas::reset_keyframe(int do_camera)
1503         BezierAuto *translate_keyframe = 0;
1504         FloatAuto *zoom_keyframe = 0;
1505         Track *affected_track = 0;
1507         affected_track = gui->cwindow->calculate_affected_track();
1509         if(affected_track)
1510         {
1511                 if(do_camera)
1512                 {
1513                         translate_keyframe = (BezierAuto*)gui->cwindow->calculate_affected_auto(
1514                                 affected_track->automation->camera_autos);
1515                         zoom_keyframe = (FloatAuto*)gui->cwindow->calculate_affected_auto(
1516                                 affected_track->automation->czoom_autos);
1517                 }
1518                 else
1519                 {
1520                         translate_keyframe = (BezierAuto*)gui->cwindow->calculate_affected_auto(
1521                                 affected_track->automation->projector_autos);
1522                         zoom_keyframe = (FloatAuto*)gui->cwindow->calculate_affected_auto(
1523                                 affected_track->automation->pzoom_autos);
1524                 }
1526                 translate_keyframe->center_x = 0;
1527                 translate_keyframe->center_y = 0;
1528                 translate_keyframe->center_z = 1;
1529                 zoom_keyframe->value = 1;
1531                 mwindow->sync_parameters(CHANGE_PARAMS);
1532                 gui->update_tool();
1533 //              gui->cwindow->playback_engine->que->send_command(CURRENT_FRAME, 
1534 //                      CHANGE_NONE,
1535 //                      mwindow->edl,
1536 //                      1);
1537         }
1540 void CWindowCanvas::reset_camera()
1542         reset_keyframe(1);
1545 void CWindowCanvas::reset_projector()
1547         reset_keyframe(0);
1550 int CWindowCanvas::test_crop(int button_press, int &redraw)
1552         int result = 0;
1553         int handle_selected = -1;
1554         float x1 = mwindow->edl->session->crop_x1;
1555         float y1 = mwindow->edl->session->crop_y1;
1556         float x2 = mwindow->edl->session->crop_x2;
1557         float y2 = mwindow->edl->session->crop_y2;
1558         float cursor_x = get_cursor_x();
1559         float cursor_y = get_cursor_y();
1560         float canvas_x1 = x1;
1561         float canvas_y1 = y1;
1562         float canvas_x2 = x2;
1563         float canvas_y2 = y2;
1564         float canvas_cursor_x = cursor_x;
1565         float canvas_cursor_y = cursor_y;
1567         canvas_to_output(mwindow->edl, 0, cursor_x, cursor_y);
1568 // Use screen normalized coordinates for hot spot tests.
1569         output_to_canvas(mwindow->edl, 0, canvas_x1, canvas_y1);
1570         output_to_canvas(mwindow->edl, 0, canvas_x2, canvas_y2);
1573         if(gui->current_operation == CWINDOW_CROP)
1574         {
1575                 handle_selected = gui->crop_handle;
1576         }
1577         else
1578         if(canvas_cursor_x >= canvas_x1 && canvas_cursor_x < canvas_x1 + CROPHANDLE_W &&
1579                 canvas_cursor_y >= canvas_y1 && canvas_cursor_y < canvas_y1 + CROPHANDLE_H)
1580         {
1581                 handle_selected = 0;
1582                 gui->crop_origin_x = x1;
1583                 gui->crop_origin_y = y1;
1584         }
1585         else
1586         if(canvas_cursor_x >= canvas_x2 - CROPHANDLE_W && canvas_cursor_x < canvas_x2 &&
1587                 canvas_cursor_y >= canvas_y1 && canvas_cursor_y < canvas_y1 + CROPHANDLE_H)
1588         {
1589                 handle_selected = 1;
1590                 gui->crop_origin_x = x2;
1591                 gui->crop_origin_y = y1;
1592         }
1593         else
1594         if(canvas_cursor_x >= canvas_x1 && canvas_cursor_x < canvas_x1 + CROPHANDLE_W &&
1595                 canvas_cursor_y >= canvas_y2 - CROPHANDLE_H && canvas_cursor_y < canvas_y2)
1596         {
1597                 handle_selected = 2;
1598                 gui->crop_origin_x = x1;
1599                 gui->crop_origin_y = y2;
1600         }
1601         else
1602         if(canvas_cursor_x >= canvas_x2 - CROPHANDLE_W && canvas_cursor_x < canvas_x2 &&
1603                 canvas_cursor_y >= canvas_y2 - CROPHANDLE_H && canvas_cursor_y < canvas_y2)
1604         {
1605                 handle_selected = 3;
1606                 gui->crop_origin_x = x2;
1607                 gui->crop_origin_y = y2;
1608         }
1609         else
1610 // Start new box
1611         {
1612                 gui->crop_origin_x = cursor_x;
1613                 gui->crop_origin_y = cursor_y;
1614         }
1616 // printf("test crop %d %d\n", 
1617 //      gui->current_operation,
1618 //      handle_selected);
1620 // Start dragging.
1621         if(button_press)
1622         {
1623                 gui->current_operation = CWINDOW_CROP;
1624                 gui->crop_handle = handle_selected;
1625                 gui->x_origin = cursor_x;
1626                 gui->y_origin = cursor_y;
1627                 result = 1;
1629                 if(handle_selected < 0) 
1630                 {
1631                         x2 = x1 = cursor_x;
1632                         y2 = y1 = cursor_y;
1633                         mwindow->edl->session->crop_x1 = (int)x1;
1634                         mwindow->edl->session->crop_y1 = (int)y1;
1635                         mwindow->edl->session->crop_x2 = (int)x2;
1636                         mwindow->edl->session->crop_y2 = (int)y2;
1637                         redraw = 1;
1638                 }
1639         }
1640     else
1641 // Update dragging
1642         if(gui->current_operation == CWINDOW_CROP)
1643         {
1644                 float x_difference, y_difference;
1645                 if(gui->crop_handle >= 0)
1646                 {
1647                         float zoom_x, zoom_y, conformed_w, conformed_h;
1648                         get_zooms(mwindow->edl, 0, zoom_x, zoom_y, conformed_w, conformed_h);
1649                         x_difference = cursor_x - gui->x_origin;
1650                 }
1652                 switch(gui->crop_handle)
1653                 {
1654                         case -1:
1655                                 x1 = gui->crop_origin_x;
1656                                 y1 = gui->crop_origin_y;
1657                                 x2 = gui->crop_origin_x;
1658                                 y2 = gui->crop_origin_y;
1659                                 if(cursor_x < gui->x_origin)
1660                                 {
1661                                         if(cursor_y < gui->y_origin)
1662                                         {
1663                                                 x1 = cursor_x;
1664                                                 y1 = cursor_y;
1665                                         }
1666                                         else
1667                                         if(cursor_y >= gui->y_origin)
1668                                         {
1669                                                 x1 = cursor_x;
1670                                                 y2 = cursor_y;
1671                                         }
1672                                 }
1673                                 else
1674                                 if(cursor_x  >= gui->x_origin)
1675                                 {
1676                                         if(cursor_y < gui->y_origin)
1677                                         {
1678                                                 y1 = cursor_y;
1679                                                 x2 = cursor_x;
1680                                         }
1681                                         else
1682                                         if(cursor_y >= gui->y_origin)
1683                                         {
1684                                                 x2 = cursor_x;
1685                                                 y2 = cursor_y;
1686                                         }
1687                                 }
1689 // printf("test crop %d %d %d %d\n", 
1690 //      mwindow->edl->session->crop_x1,
1691 //      mwindow->edl->session->crop_y1,
1692 //      mwindow->edl->session->crop_x2,
1693 //      mwindow->edl->session->crop_y2);
1694                                 break;
1695                         case 0:
1696                                 x1 = cursor_x - gui->x_origin + gui->crop_origin_x;
1697                                 y1 = cursor_y - gui->y_origin + gui->crop_origin_y;
1698                                 break;
1699                         case 1:
1700                                 x2 = cursor_x - gui->x_origin + gui->crop_origin_x;
1701                                 y1 = cursor_y - gui->y_origin + gui->crop_origin_y;
1702                                 break;
1703                         case 2:
1704                                 x1 = cursor_x - gui->x_origin + gui->crop_origin_x;
1705                                 y2 = cursor_y - gui->y_origin + gui->crop_origin_y;
1706                                 break;
1707                         case 3:
1708                                 x2 = cursor_x - gui->x_origin + gui->crop_origin_x;
1709                                 y2 = cursor_y - gui->y_origin + gui->crop_origin_y;
1710                                 break;
1711                 }
1713                 if(!EQUIV(mwindow->edl->session->crop_x1, x1) ||
1714                         !EQUIV(mwindow->edl->session->crop_x2, x2) ||
1715                         !EQUIV(mwindow->edl->session->crop_y1, y1) ||
1716                         !EQUIV(mwindow->edl->session->crop_y2, y2))
1717                 {
1718                         if (x1 > x2) 
1719                         {
1720                                 float tmp = x1;
1721                                 x1 = x2;
1722                                 x2 = tmp;
1723                                 switch (gui->crop_handle) 
1724                                 {
1725                                         case 0: gui->crop_handle = 1; break;
1726                                         case 1: gui->crop_handle = 0; break;
1727                                         case 2: gui->crop_handle = 3; break;
1728                                         case 3: gui->crop_handle = 2; break;
1729                                         default: break;
1730                                 }
1732                         }
1733                         if (y1 > y2) 
1734                         {
1735                                 float tmp = y1;
1736                                 y1 = y2;
1737                                 y2 = tmp;
1738                                 switch (gui->crop_handle) 
1739                                 {
1740                                         case 0: gui->crop_handle = 2; break;
1741                                         case 1: gui->crop_handle = 3; break;
1742                                         case 2: gui->crop_handle = 0; break;
1743                                         case 3: gui->crop_handle = 1; break;
1744                                         default: break;
1745                                 }
1746                         }
1748                         mwindow->edl->session->crop_x1 = (int)x1;
1749                         mwindow->edl->session->crop_y1 = (int)y1;
1750                         mwindow->edl->session->crop_x2 = (int)x2;
1751                         mwindow->edl->session->crop_y2 = (int)y2;
1752                         result = 1;
1753                         redraw = 1;
1754                 }
1755         }
1756         else
1757 // Update cursor font
1758         if(handle_selected >= 0)
1759         {
1760                 switch(handle_selected)
1761                 {
1762                         case 0:
1763                                 set_cursor(UPLEFT_RESIZE);
1764                                 break;
1765                         case 1:
1766                                 set_cursor(UPRIGHT_RESIZE);
1767                                 break;
1768                         case 2:
1769                                 set_cursor(DOWNLEFT_RESIZE);
1770                                 break;
1771                         case 3:
1772                                 set_cursor(DOWNRIGHT_RESIZE);
1773                                 break;
1774                 }
1775                 result = 1;
1776         }
1777         else
1778         {
1779                 set_cursor(ARROW_CURSOR);
1780         }
1781 #define CLAMP(x, y, z) ((x) = ((x) < (y) ? (y) : ((x) > (z) ? (z) : (x))))
1782         
1783         if(redraw)
1784         {
1785                 CLAMP(mwindow->edl->session->crop_x1, 0, mwindow->edl->calculate_output_w(0));
1786                 CLAMP(mwindow->edl->session->crop_x2, 0, mwindow->edl->calculate_output_w(0));
1787                 CLAMP(mwindow->edl->session->crop_y1, 0, mwindow->edl->calculate_output_h(0));
1788                 CLAMP(mwindow->edl->session->crop_y2, 0, mwindow->edl->calculate_output_h(0));
1789 // printf("CWindowCanvas::test_crop %d %d %d %d\n", 
1790 //      mwindow->edl->session->crop_x2,
1791 //      mwindow->edl->session->crop_y2,
1792 //      mwindow->edl->calculate_output_w(0), 
1793 //      mwindow->edl->calculate_output_h(0));
1794         }
1795         return result;
1799 void CWindowCanvas::draw_crop()
1801         canvas->set_inverse();
1802         canvas->set_color(WHITE);
1804         float x1 = mwindow->edl->session->crop_x1;
1805         float y1 = mwindow->edl->session->crop_y1;
1806         float x2 = mwindow->edl->session->crop_x2;
1807         float y2 = mwindow->edl->session->crop_y2;
1809         output_to_canvas(mwindow->edl, 0, x1, y1);
1810         output_to_canvas(mwindow->edl, 0, x2, y2);
1812         if(x2 - x1 && y2 - y1)
1813                 canvas->draw_rectangle((int)x1, 
1814                         (int)y1, 
1815                         (int)(x2 - x1), 
1816                         (int)(y2 - y1));
1818         draw_crophandle((int)x1, (int)y1);
1819         draw_crophandle((int)x2 - CROPHANDLE_W, (int)y1);
1820         draw_crophandle((int)x1, (int)y2 - CROPHANDLE_H);
1821         draw_crophandle((int)x2 - CROPHANDLE_W, (int)y2 - CROPHANDLE_H);
1822         canvas->set_opaque();
1827 #define BEZIER_W 20
1828 #define BEZIER_H 20
1830 int CWindowCanvas::do_bezier_center(BezierAuto *current, 
1831         BezierAutos *camera_autos,
1832         BezierAutos *projector_autos, 
1833         FloatAutos *czoom_autos,
1834         FloatAutos *pzoom_autos,
1835         int camera, 
1836         int draw)
1838         float center_x = 0, center_y = 0, center_z = 0;
1839         BezierAuto *before = 0, *after = 0;
1840         FloatAuto *previous = 0, *next = 0;
1841         VTrack *track = (VTrack*)current->autos->track;
1842         long position = track->to_units(
1843                                 mwindow->edl->local_session->selectionstart, 
1844                                 0);
1846 // Get center of current frame.  Draw everything relative to this.
1847         if(camera)
1848         {
1849                 camera_autos->get_center(center_x, 
1850                         center_y, 
1851                         center_z, 
1852                         (float)position,
1853                         PLAY_FORWARD, 
1854                         &before, 
1855                         &after);
1856                 center_z = czoom_autos->get_value(position,
1857                         PLAY_FORWARD,
1858                         previous,
1859                         next);
1861                 float projector_x, projector_y, projector_z;
1862                 before = after = 0;
1863                 projector_autos->get_center(projector_x, 
1864                         projector_y, 
1865                         projector_z,
1866                         (float)position,
1867                         PLAY_FORWARD,
1868                         &before,
1869                         &after);
1870                 previous = next = 0;
1871                 projector_z = pzoom_autos->get_value(position,
1872                         PLAY_FORWARD,
1873                         previous,
1874                         next);
1876                 center_x -= projector_x;
1877                 center_y -= projector_y;
1878                 center_z = projector_z;
1879 //printf("CWindowCanvas::do_bezier_center 1 %p %f %f\n", 
1880 //current, projector_y, center_y);
1881         }
1882         else
1883         {
1884                 center_z = pzoom_autos->get_value(current->position,
1885                         PLAY_FORWARD,
1886                         previous,
1887                         next);
1888         }
1892         float auto_x = current->center_x - center_x + mwindow->edl->session->output_w / 2;
1893         float auto_y = current->center_y - center_y + mwindow->edl->session->output_h / 2;
1894         float track_x1 = auto_x - track->track_w / 2 * center_z;
1895         float track_y1 = auto_y - track->track_h / 2 * center_z;
1896         float track_x2 = track_x1 + track->track_w * center_z;
1897         float track_y2 = track_y1 + track->track_h * center_z;
1898         float control_in_x = auto_x + current->control_in_x;
1899         float control_in_y = auto_y + current->control_in_y;
1900         float control_out_x = auto_x + current->control_out_x;
1901         float control_out_y = auto_y + current->control_out_y;
1902         int control_point = 0;
1905         output_to_canvas(mwindow->edl, 0, auto_x, auto_y);
1906         output_to_canvas(mwindow->edl, 0, control_out_x, control_out_y);
1907         output_to_canvas(mwindow->edl, 0, control_in_x, control_in_y);
1908         output_to_canvas(mwindow->edl, 0, track_x1, track_y1);
1909         output_to_canvas(mwindow->edl, 0, track_x2, track_y2);
1911 #define DRAW_THING(offset) \
1912         canvas->draw_line((int)control_in_x + offset,  \
1913                 (int)control_in_y + offset,  \
1914                 (int)auto_x + offset,  \
1915                 (int)auto_y + offset); \
1916         canvas->draw_line((int)control_out_x + offset,  \
1917                 (int)control_out_y + offset,  \
1918                 (int)auto_x + offset,  \
1919                 (int)auto_y + offset); \
1920         canvas->draw_rectangle((int)control_in_x - CONTROL_W / 2 + offset,  \
1921                 (int)control_in_y - CONTROL_H / 2 + offset, \
1922                 CONTROL_W, \
1923                 CONTROL_H); \
1924         canvas->draw_rectangle((int)control_out_x - CONTROL_W / 2 + offset,  \
1925                 (int)control_out_y - CONTROL_H / 2 + offset, \
1926                 CONTROL_W, \
1927                 CONTROL_H); \
1929         if(0) \
1930         { \
1931                 canvas->draw_line((int)auto_x - BEZIER_W / 2,  \
1932                         (int)auto_y - BEZIER_H / 2 + offset, \
1933                         (int)auto_x + BEZIER_W / 2, \
1934                         (int)auto_y + BEZIER_H / 2 + offset); \
1935                 canvas->draw_line((int)auto_x - BEZIER_W / 2,  \
1936                         (int)auto_y + BEZIER_H / 2 + offset, \
1937                         (int)auto_x + BEZIER_W / 2, \
1938                         (int)auto_y - BEZIER_H / 2 + offset); \
1939         } \
1940         else \
1941         { \
1942                 canvas->draw_rectangle((int)track_x1 + offset, \
1943                         (int)track_y1 + offset, \
1944                         (int)(track_x2 - track_x1), \
1945                         (int)(track_y2 - track_y1)); \
1946                 canvas->draw_line((int)track_x1 + offset,  \
1947                         (int)track_y1 + offset, \
1948                         (int)track_x2 + offset, \
1949                         (int)track_y2 + offset); \
1950                 canvas->draw_line((int)track_x2 + offset,  \
1951                         (int)track_y1 + offset, \
1952                         (int)track_x1 + offset, \
1953                         (int)track_y2 + offset); \
1954         }
1956         if(draw)
1957         {
1958 // Drop shadow
1959                 canvas->set_color(BLACK);
1960                 DRAW_THING(1);
1962                 canvas->set_inverse();
1963                 if(current->position > position)
1964                         canvas->set_color(GREEN);
1965                 else
1966                         canvas->set_color(RED);
1968                 DRAW_THING(0);
1969                 canvas->set_opaque();
1970 // printf("CWindowCanvas::do_bezier_center 2 %f,%f %f,%f\n", 
1971 // control_in_x, 
1972 // control_in_y, 
1973 // control_out_x,
1974 // control_out_y);
1975         }
1976         else
1977         {
1978                 int cursor_x = get_cursor_x();
1979                 int cursor_y = get_cursor_y();
1980                 
1981 #ifndef SQR
1982 #define SQR(x) ((x) * (x))
1983 #endif
1985                 float distance1 = sqrt(SQR(cursor_x - control_in_x) + 
1986                         SQR(cursor_y - control_in_y));
1987                 float distance2 = sqrt(SQR(cursor_x - control_out_x) + 
1988                         SQR(cursor_y - control_out_y));
1989 // printf("CWindowCanvas::do_bezier_center 3 %f,%f %f,%f\n", 
1990 // control_in_x, 
1991 // control_in_y, 
1992 // control_out_x,
1993 // control_out_y);
1995                 control_point = distance2 < distance1;
1996         }
1997         
1998         return control_point;
2003 void CWindowCanvas::draw_bezier_joining(BezierAuto *first, 
2004         BezierAuto *last, 
2005         BezierAutos *camera_autos,
2006         BezierAutos *projector_autos, 
2007         FloatAutos *czoom_autos,
2008         FloatAutos *pzoom_autos,
2009         int camera)
2011         if(first == last) return;
2012         
2013         float center_x = 0, center_y = 0, center_z = 0;
2014         BezierAuto *before = 0, *after = 0;
2015         long position = first->autos->track->to_units(
2016                                         mwindow->edl->local_session->selectionstart, 
2017                                         0);
2019 // Get center of current position.  Draw everything relative to this.
2020         if(camera)
2021         {
2022                 camera_autos->get_center(center_x, 
2023                                 center_y, 
2024                                 center_z, 
2025                                 (float)position, 
2026                                 PLAY_FORWARD, 
2027                                 &before, 
2028                                 &after);
2030                 float projector_x, projector_y, projector_z;
2031                 before = after = 0;
2032                 projector_autos->get_center(projector_x, 
2033                         projector_y, 
2034                         projector_z,
2035                         (float)position,
2036                         PLAY_FORWARD,
2037                         &before,
2038                         &after);
2040                 center_x -= projector_x;
2041                 center_y -= projector_y;
2042         }
2044 //      int segments = 10;
2045         int segments = MAX(canvas->get_w(), canvas->get_h());
2046         int step = (last->position - first->position) / segments;
2047         float old_x, old_y;
2048         if(step < 1) step = 1;
2050         for(long frame = first->position; 
2051                 frame < last->position; 
2052                 frame += step)
2053         {
2054                 float new_x, new_y, new_z;
2055                 float x1, y1, x2, y2;
2057                 ((BezierAutos*)(first->autos))->get_center(new_x, 
2058                         new_y, 
2059                         new_z, 
2060                         frame, 
2061                         PLAY_FORWARD, 
2062                         &before, 
2063                         &after);
2065                 if(frame == first->position)
2066                 {
2067                         old_x = new_x;
2068                         old_y = new_y;
2069                 }
2071                 x1 = old_x - center_x + mwindow->edl->session->output_w / 2;
2072                 y1 = old_y - center_y + mwindow->edl->session->output_h / 2;
2073                 x2 = new_x - center_x + mwindow->edl->session->output_w / 2;
2074                 y2 = new_y - center_y + mwindow->edl->session->output_h / 2;
2075                 output_to_canvas(mwindow->edl, 0, x1, y1);
2076                 output_to_canvas(mwindow->edl, 0, x2, y2);
2078 // Drop shadow
2079 //              canvas->set_color(BLACK);
2080 //              canvas->draw_line((int)x1 + 1, (int)y1 + 1, (int)x2 + 1, (int)y2 + 1);
2082                 if(frame >= position)
2083                         canvas->set_color(GREEN);
2084                 else
2085                         canvas->set_color(RED);
2087                 canvas->set_inverse();
2088                 canvas->draw_line((int)x1, (int)y1, (int)x2, (int)y2);
2089                 canvas->set_opaque();
2090                 old_x = new_x;
2091                 old_y = new_y;
2092         }
2097 void CWindowCanvas::draw_bezier(int do_camera)
2099         Track *track = gui->cwindow->calculate_affected_track();
2100         BezierAutos *autos, *camera_autos, *projector_autos;
2101         BezierAuto *first = 0, *mid = 0, *last = 0;
2102         BezierAuto *before = 0, *after = 0;
2103         FloatAutos *czoom_autos, *pzoom_autos;
2105 // No track at initialization
2106         if(!track) return;
2108         camera_autos = track->automation->camera_autos;
2109         projector_autos = track->automation->projector_autos;
2110         czoom_autos = track->automation->czoom_autos;
2111         pzoom_autos = track->automation->pzoom_autos;
2113         if(do_camera)
2114                 autos = track->automation->camera_autos;
2115         else
2116                 autos = track->automation->projector_autos;
2119         long position = track->to_units(mwindow->edl->local_session->selectionstart, 
2120                                         0);
2123 // Rules for which autos to draw:
2125 // No automation besides default:
2126 //     mid = default
2128 // Automation on or after current position only
2129 //     mid = first, last = next
2131 // Automation before current position only
2132 //     mid = last, first = previous
2133 // 
2134 // Automation on current position only
2135 //     mid = first
2137 // Automation before and after current position
2138 //     first = previous, mid = next, last = next->next
2140         for(first = (BezierAuto*)autos->last; 
2141                 first; 
2142                 first = (BezierAuto*)first->previous)
2143                 if(first->position < position)
2144                         break;
2146         if(first)
2147         {
2148                 mid = (BezierAuto*)first->next;
2149                 if(!mid)
2150                 {
2151                         mid = first;
2152                         first = (BezierAuto*)first->previous;
2153                 }
2154         }
2155         else
2156                 mid = (BezierAuto*)autos->first;
2158         if(mid)
2159                 last = (BezierAuto*)mid->next;
2160         else
2161                 mid = (BezierAuto*)autos->default_auto;
2163         if(!last)
2164         {
2165                 last = mid;
2166                 mid = first;
2167                 if(mid) first = (BezierAuto*)mid->previous;
2168         }
2169         
2170         if(!first)
2171         {
2172                 first = mid;
2173                 mid = last;
2174                 if(mid) last = (BezierAuto*)mid->next;
2175         }
2177 //printf("draw_bezier 1 %p %p %p\n", first, mid, last);
2181 // Draw joining lines
2182         if(first && mid)
2183                 draw_bezier_joining(first, 
2184                         mid, 
2185                         camera_autos, 
2186                         projector_autos, 
2187                         czoom_autos,
2188                         pzoom_autos,
2189                         do_camera);
2191         if(mid && last)
2192                 draw_bezier_joining(mid, 
2193                         last, 
2194                         camera_autos, 
2195                         projector_autos, 
2196                         czoom_autos,
2197                         pzoom_autos,
2198                         do_camera);
2200 //printf("draw_bezier 2 %p %p %p\n", first, mid, last);
2203 // Draw centers of autos
2204         if(first) 
2205                 do_bezier_center(first, 
2206                         camera_autos, 
2207                         projector_autos, 
2208                         czoom_autos,
2209                         pzoom_autos,
2210                         do_camera, 
2211                         1);
2212         if(mid) 
2213                 do_bezier_center(mid, 
2214                         camera_autos, 
2215                         projector_autos, 
2216                         czoom_autos,
2217                         pzoom_autos,
2218                         do_camera, 
2219                         1);
2220         if(last) 
2221                 do_bezier_center(last, 
2222                         camera_autos, 
2223                         projector_autos, 
2224                         czoom_autos,
2225                         pzoom_autos,
2226                         do_camera, 
2227                         1);
2229 //printf("draw_bezier 3 %p %p %p\n", first, mid, last);
2237 int CWindowCanvas::test_bezier(int button_press, 
2238         int &redraw, 
2239         int &redraw_canvas,
2240         int &rerender,
2241         int do_camera)
2243         int result = 0;
2245 // Processing drag operation.
2246 // Create keyframe during first cursor motion.
2247         if(!button_press)
2248         {
2250                 float cursor_x = get_cursor_x();
2251                 float cursor_y = get_cursor_y();
2252                 canvas_to_output(mwindow->edl, 0, cursor_x, cursor_y);
2254                 if(gui->current_operation == CWINDOW_CAMERA ||
2255                         gui->current_operation == CWINDOW_PROJECTOR)
2256                 {
2257                         if(!gui->ctrl_down() && gui->shift_down() && !gui->translating_zoom)
2258                         {
2259                                 gui->translating_zoom = 1;
2260                                 gui->affected_auto = 0;
2261                         }
2262                         else
2263                         if(!gui->ctrl_down() && !gui->shift_down() && gui->translating_zoom)
2264                         {
2265                                 gui->translating_zoom = 0;
2266                                 gui->affected_auto = 0;
2267                         }
2269 // Get target keyframe
2270                         BezierAutos *camera_autos = gui->affected_track->automation->camera_autos;
2271                         BezierAutos *projector_autos = gui->affected_track->automation->projector_autos;
2272                         FloatAutos *czoom_autos = gui->affected_track->automation->czoom_autos;
2273                         FloatAutos *pzoom_autos = gui->affected_track->automation->pzoom_autos;
2274                         float last_center_x;
2275                         float last_center_y;
2276                         float last_center_z;
2279                         if(!gui->affected_auto)
2280                         {
2281                                 mwindow->undo->update_undo_before(_("keyframe"), LOAD_AUTOMATION);
2282                                 if(mwindow->edl->session->cwindow_operation == CWINDOW_CAMERA)
2283                                 {
2284                                         if(gui->translating_zoom)
2285                                         {
2286                                                 gui->affected_auto = 
2287                                                         gui->cwindow->calculate_affected_auto((Autos*)czoom_autos, 1);
2288                                         }
2289                                         else
2290                                                 gui->affected_auto = 
2291                                                         gui->cwindow->calculate_affected_auto((Autos*)camera_autos, 1);
2292                                 }
2293                                 else
2294                                 if(mwindow->edl->session->cwindow_operation == CWINDOW_PROJECTOR)
2295                                 {
2296                                         if(gui->translating_zoom)
2297                                         {
2298                                                 gui->affected_auto = 
2299                                                         gui->cwindow->calculate_affected_auto((Autos*)pzoom_autos, 1);
2300                                         }
2301                                         else
2302                                                 gui->affected_auto = 
2303                                                         gui->cwindow->calculate_affected_auto((Autos*)projector_autos, 1);
2304                                 }
2306                                 calculate_origin();
2307                                 
2308                                 if(gui->translating_zoom)
2309                                 {
2310                                         gui->center_z = ((FloatAuto*)gui->affected_auto)->value;
2311                                 }
2312                                 else
2313                                 {
2314                                         gui->center_x = ((BezierAuto*)gui->affected_auto)->center_x;
2315                                         gui->center_y = ((BezierAuto*)gui->affected_auto)->center_y;
2316                                 }
2318                                 rerender = 1;
2319                                 redraw = 1;
2320                         }
2322                         BezierAuto *bezier_keyframe = (BezierAuto*)gui->affected_auto;
2323                         FloatAuto *zoom_keyframe = (FloatAuto*)gui->affected_auto;
2325                         if(gui->translating_zoom)
2326                         {
2327                                 last_center_z = zoom_keyframe->value;
2328                         }
2329                         else
2330                         {
2331                                 last_center_x = bezier_keyframe->center_x;
2332                                 last_center_y = bezier_keyframe->center_y;
2333                         }
2335                         if(gui->translating_zoom)
2336                         {
2337                                 zoom_keyframe->value = gui->center_z + (cursor_y - gui->y_origin) / 128;
2338                                 if(!EQUIV(last_center_z, zoom_keyframe->value))
2339                                 {
2340                                         mwindow->undo->update_undo_before(_("tweek"), LOAD_AUTOMATION);
2341                                         rerender = 1;
2342                                         redraw = 1;
2343                                         redraw_canvas = 1;
2344                                 }
2345                         }
2346                         else
2347                         {
2348                                 bezier_keyframe->center_x = gui->center_x + cursor_x - gui->x_origin;
2349                                 bezier_keyframe->center_y = gui->center_y + cursor_y - gui->y_origin;
2350                                 if(!EQUIV(last_center_x,  bezier_keyframe->center_x) ||
2351                                         !EQUIV(last_center_y, bezier_keyframe->center_y))
2352                                 {
2353                                         mwindow->undo->update_undo_before(_("tweek"), LOAD_AUTOMATION);
2354                                         rerender = 1;
2355                                         redraw = 1;
2356                                 }
2357                         }
2358                 }
2359                 else
2360                 if(gui->current_operation == CWINDOW_CAMERA_CONTROL_IN ||
2361                         gui->current_operation == CWINDOW_PROJECTOR_CONTROL_IN)
2362                 {
2363                         BezierAuto *bezier_keyframe = (BezierAuto*)gui->affected_auto;
2364                         float last_control_in_x = bezier_keyframe->control_in_x;
2365                         float last_control_in_y = bezier_keyframe->control_in_y;
2366                         bezier_keyframe->control_in_x = gui->control_in_x + cursor_x - gui->x_origin;
2367                         bezier_keyframe->control_in_y = gui->control_in_y + cursor_y - gui->y_origin;
2369                         if(!EQUIV(last_control_in_x, bezier_keyframe->control_in_x) ||
2370                                 !EQUIV(last_control_in_y, bezier_keyframe->control_in_y))
2371                         {
2372                                 mwindow->undo->update_undo_before(_("tweek"), LOAD_AUTOMATION);
2373                                 rerender = 1;
2374                                 redraw = 1;
2375                         }
2376                 }
2377                 else
2378                 if(gui->current_operation == CWINDOW_CAMERA_CONTROL_OUT ||
2379                         gui->current_operation == CWINDOW_PROJECTOR_CONTROL_OUT)
2380                 {
2381                         BezierAuto *bezier_keyframe = (BezierAuto*)gui->affected_auto;
2382                         float last_control_out_x = bezier_keyframe->control_out_x;
2383                         float last_control_out_y = bezier_keyframe->control_out_y;
2384                         bezier_keyframe->control_out_x = gui->control_out_x + cursor_x - gui->x_origin;
2385                         bezier_keyframe->control_out_y = gui->control_out_y + cursor_y - gui->y_origin;
2387                         if(!EQUIV(last_control_out_x, bezier_keyframe->control_out_x) ||
2388                                 !EQUIV(last_control_out_y, bezier_keyframe->control_out_y))
2389                         {
2390                                 mwindow->undo->update_undo_before(_("tweek"), LOAD_AUTOMATION);
2391                                 rerender = 1;
2392                                 redraw = 1;
2393                         }
2394                 }
2396                 result = 1;
2397         }
2398         else
2399 // Begin drag operation.  Don't create keyframe here.
2400         {
2401 // Get affected track off of the first recordable video track.
2402 // Calculating based on the alpha channel would require rendering
2403 // each layer and its effects and trapping the result in VirtualVNode before
2404 // compositing onto the output.
2405                 gui->affected_track = gui->cwindow->calculate_affected_track();
2406                 gui->affected_auto = 0;
2408                 if(gui->affected_track)
2409                 {
2410                         BezierAutos *camera_autos = gui->affected_track->automation->camera_autos;
2411                         BezierAutos *projector_autos = gui->affected_track->automation->projector_autos;
2412                         FloatAutos *czoom_autos = gui->affected_track->automation->czoom_autos;
2413                         FloatAutos *pzoom_autos = gui->affected_track->automation->pzoom_autos;
2416                         if(!gui->ctrl_down())
2417                         {
2418                                 gui->current_operation = 
2419                                         mwindow->edl->session->cwindow_operation;
2420                                 gui->affected_auto = 0;
2421                         }
2422                         else
2423                         {
2424 // Get nearest control point
2425                                 if(mwindow->edl->session->cwindow_operation == CWINDOW_CAMERA)
2426                                         gui->affected_auto = 
2427                                                 gui->cwindow->calculate_affected_auto(camera_autos, 0);
2428                                 else
2429                                 if(mwindow->edl->session->cwindow_operation == CWINDOW_PROJECTOR)
2430                                         gui->affected_auto = 
2431                                                 gui->cwindow->calculate_affected_auto(projector_autos, 0);
2433 //printf("CWindowCanvas::test_bezier 1 %d\n", gui->current_operation);
2434                                 int control_point = do_bezier_center(
2435                                         (BezierAuto*)gui->affected_auto, 
2436                                         camera_autos,
2437                                         projector_autos,
2438                                         czoom_autos,
2439                                         pzoom_autos,
2440                                         mwindow->edl->session->cwindow_operation == CWINDOW_CAMERA,
2441                                         0);
2443 //printf("CWindowCanvas::test_bezier 2 %d\n", control_point);
2444                                 if(control_point == 0)
2445                                 {
2446                                         if(mwindow->edl->session->cwindow_operation == CWINDOW_CAMERA)
2447                                                 gui->current_operation = CWINDOW_CAMERA_CONTROL_IN;
2448                                         else
2449                                                 gui->current_operation = CWINDOW_PROJECTOR_CONTROL_IN;
2450                                 }
2451                                 else
2452                                 {
2453                                         if(mwindow->edl->session->cwindow_operation == CWINDOW_CAMERA)
2454                                                 gui->current_operation = CWINDOW_CAMERA_CONTROL_OUT;
2455                                         else
2456                                                 gui->current_operation = CWINDOW_PROJECTOR_CONTROL_OUT;
2457                                 }
2459                                 BezierAuto *keyframe = (BezierAuto*)gui->affected_auto;
2460                                 gui->center_x = keyframe->center_x;
2461                                 gui->center_y = keyframe->center_y;
2462                                 gui->center_z = keyframe->center_z;
2463                                 gui->control_in_x = keyframe->control_in_x;
2464                                 gui->control_in_y = keyframe->control_in_y;
2465                                 gui->control_out_x = keyframe->control_out_x;
2466                                 gui->control_out_y = keyframe->control_out_y;
2467                         }
2470                         result = 1;
2471                 }
2472         }
2473         
2474         return result;
2477 int CWindowCanvas::test_zoom(int &redraw)
2479         int result = 0;
2480         float zoom = get_zoom();
2481         float x;
2482         float y;
2484         if(!mwindow->edl->session->cwindow_scrollbars)
2485         {
2486                 mwindow->edl->session->cwindow_scrollbars = 1;
2487                 zoom = 1.0;
2488                 x = 0;
2489                 y = 0;
2490         }
2491         else
2492         {
2493                 x = get_cursor_x();
2494                 y = get_cursor_y();
2495                 canvas_to_output(mwindow->edl, 
2496                                 0, 
2497                                 x, 
2498                                 y);
2500 //printf("CWindowCanvas::test_zoom 1 %f %f\n", x, y);
2502 // Zoom out
2503                 if(get_buttonpress() == 5 ||
2504                         gui->ctrl_down() || 
2505                         gui->shift_down())
2506                 {
2507                         if(zoom > MIN_ZOOM)
2508                         {
2509                                 zoom /= 2;
2510                                 x -= w_visible * 2 / 2;
2511                                 y -= h_visible * 2 / 2;
2512                         }
2513                         else
2514                         {
2515                                 x -= w_visible / 2;
2516                                 y -= h_visible / 2;
2517                         }
2518                 }
2519                 else
2520 // Zoom in
2521                 {
2522                         if(zoom < MAX_ZOOM)
2523                         {
2524                                 zoom *= 2;
2525                                 x -= w_visible / 2 / 2;
2526                                 y -= h_visible / 2 / 2;
2527                         }
2528                         else
2529                         {
2530                                 x -= w_visible / 2;
2531                                 y -= h_visible / 2;
2532                         }
2533                 }
2534         }
2536         int x_i = (int)x;
2537         int y_i = (int)y;
2538 //      check_boundaries(mwindow->edl, x_i, y_i, zoom);
2540 //printf("CWindowCanvas::test_zoom 2 %d %d\n", x_i, y_i);
2542         update_zoom(x_i, 
2543                         y_i, 
2544                         zoom);
2545         reposition_window(mwindow->edl, 
2546                         mwindow->theme->ccanvas_x,
2547                         mwindow->theme->ccanvas_y,
2548                         mwindow->theme->ccanvas_w,
2549                         mwindow->theme->ccanvas_h);
2550         redraw = 1;
2551         result = 1;
2553         
2554         gui->zoom_panel->update(zoom);
2555         
2556         return result;
2560 void CWindowCanvas::calculate_origin()
2562         gui->x_origin = get_cursor_x();
2563         gui->y_origin = get_cursor_y();
2564 //printf("CWindowCanvas::calculate_origin 1 %f %f\n", gui->x_origin, gui->y_origin);
2565         canvas_to_output(mwindow->edl, 0, gui->x_origin, gui->y_origin);
2566 //printf("CWindowCanvas::calculate_origin 2 %f %f\n", gui->x_origin, gui->y_origin);
2570 int CWindowCanvas::cursor_leave_event()
2572         set_cursor(ARROW_CURSOR);
2573         return 1;
2576 int CWindowCanvas::cursor_enter_event()
2578         int redraw = 0;
2579         switch(mwindow->edl->session->cwindow_operation)
2580         {
2581                 case CWINDOW_CAMERA:
2582                 case CWINDOW_PROJECTOR:
2583                         set_cursor(MOVE_CURSOR);
2584                         break;
2585                 case CWINDOW_ZOOM:
2586                         set_cursor(MOVE_CURSOR);
2587                         break;
2588                 case CWINDOW_CROP:
2589                         test_crop(0, redraw);
2590                         break;
2591                 case CWINDOW_PROTECT:
2592                         set_cursor(ARROW_CURSOR);
2593                         break;
2594                 case CWINDOW_MASK:
2595                         set_cursor(CROSS_CURSOR);
2596                         break;
2597         }
2598         return 1;
2601 int CWindowCanvas::cursor_motion_event()
2603         int redraw = 0, result = 0, rerender = 0, redraw_canvas = 0;
2606         switch(gui->current_operation)
2607         {
2608                 case CWINDOW_SCROLL:
2609                 {
2610                         float zoom = get_zoom();
2611                         float cursor_x = get_cursor_x();
2612                         float cursor_y = get_cursor_y();
2614                         float zoom_x, zoom_y, conformed_w, conformed_h;
2615                         get_zooms(mwindow->edl, 0, zoom_x, zoom_y, conformed_w, conformed_h);
2616                         cursor_x = (float)cursor_x / zoom_x + gui->x_offset;
2617                         cursor_y = (float)cursor_y / zoom_y + gui->y_offset;
2621                         int x = (int)(gui->x_origin - cursor_x + gui->x_offset);
2622                         int y = (int)(gui->y_origin - cursor_y + gui->y_offset);
2624                         update_zoom(x, 
2625                                 y, 
2626                                 zoom);
2627                         update_scrollbars();
2628                         redraw = 1;
2629                         result = 1;
2630                         break;
2631                 }
2633                 case CWINDOW_CAMERA:
2634                 case CWINDOW_CAMERA_CONTROL_IN:
2635                 case CWINDOW_CAMERA_CONTROL_OUT:
2636                         result = test_bezier(0, redraw, redraw_canvas, rerender, 1);
2637                         break;
2639                 case CWINDOW_PROJECTOR:
2640                 case CWINDOW_PROJECTOR_CONTROL_IN:
2641                 case CWINDOW_PROJECTOR_CONTROL_OUT:
2642                         result = test_bezier(0, redraw, redraw_canvas, rerender, 0);
2643                         break;
2646                 case CWINDOW_CROP:
2647 //printf("CWindowCanvas::cursor_motion_event 1 %d %d\n", x, y);
2648                         result = test_crop(0, redraw);
2649                         break;
2651                 case CWINDOW_MASK:
2652                 case CWINDOW_MASK_CONTROL_IN:
2653                 case CWINDOW_MASK_CONTROL_OUT:
2654                 case CWINDOW_MASK_TRANSLATE:
2655                         result = do_mask(redraw, 
2656                                 rerender, 
2657                                 0, 
2658                                 1,
2659                                 0);
2660                         break;
2661         }
2665         if(!result)
2666         {
2667                 switch(mwindow->edl->session->cwindow_operation)
2668                 {
2669                         case CWINDOW_CROP:
2670                                 result = test_crop(0, redraw);
2671                                 break;
2672                 }
2673         }
2676 // If the window is never unlocked before calling send_command the
2677 // display shouldn't get stuck on the old video frame although it will
2678 // flicker between the old video frame and the new video frame.
2680         if(redraw)
2681         {
2682                 draw_refresh();
2683                 gui->update_tool();
2684         }
2686         if(redraw_canvas)
2687         {
2688                 mwindow->gui->lock_window("CWindowCanvas::cursor_motion_event 1");
2689                 mwindow->gui->canvas->draw_overlays();
2690                 mwindow->gui->canvas->flash();
2691                 mwindow->gui->unlock_window();
2692         }
2694         if(rerender)
2695         {
2696                 mwindow->restart_brender();
2697                 mwindow->sync_parameters(CHANGE_PARAMS);
2698                 gui->cwindow->playback_engine->que->send_command(CURRENT_FRAME, 
2699                         CHANGE_NONE,
2700                         mwindow->edl,
2701                         1);
2702                 if(!redraw) gui->update_tool();
2703         }
2704         return result;
2707 int CWindowCanvas::button_press_event()
2709         int result = 0;
2710         int redraw = 0;
2711         int redraw_canvas = 0;
2712         int rerender = 0;
2714         if(Canvas::button_press_event()) return 1;
2716         gui->translating_zoom = gui->shift_down(); 
2718         calculate_origin();
2719 //printf("CWindowCanvas::button_press_event 2 %f %f\n", gui->x_origin, gui->y_origin, gui->x_origin, gui->y_origin);
2721         float zoom_x, zoom_y, conformed_w, conformed_h;
2722         get_zooms(mwindow->edl, 0, zoom_x, zoom_y, conformed_w, conformed_h);
2723         gui->x_offset = get_x_offset(mwindow->edl, 0, zoom_x, conformed_w, conformed_h);
2724         gui->y_offset = get_y_offset(mwindow->edl, 0, zoom_y, conformed_w, conformed_h);
2726 // Scroll view
2727         if(get_buttonpress() == 2)
2728         {
2729                 gui->current_operation = CWINDOW_SCROLL;
2730                 result = 1;
2731         }
2732         else
2733 // Adjust parameter
2734         {
2735                 switch(mwindow->edl->session->cwindow_operation)
2736                 {
2737                         case CWINDOW_CAMERA:
2738                                 result = test_bezier(1, redraw, redraw_canvas, rerender, 1);
2739                                 break;
2741                         case CWINDOW_PROJECTOR:
2742                                 result = test_bezier(1, redraw, redraw_canvas, rerender, 0);
2743                                 break;
2745                         case CWINDOW_ZOOM:
2746                                 result = test_zoom(redraw);
2747                                 break;
2749                         case CWINDOW_CROP:
2750                                 result = test_crop(1, redraw);
2751                                 break;
2753                         case CWINDOW_MASK:
2754                                 if(get_buttonpress() == 1)
2755                                         result = do_mask(redraw, rerender, 1, 0, 0);
2756                                 break;
2757                 }
2758         }
2760         if(redraw)
2761         {
2762                 draw_refresh();
2763                 gui->update_tool();
2764         }
2766         if(rerender) /* rerendering can also be caused by press event */
2767         {
2768                 mwindow->restart_brender();
2769                 mwindow->sync_parameters(CHANGE_PARAMS);
2770                 gui->cwindow->playback_engine->que->send_command(CURRENT_FRAME, 
2771                         CHANGE_NONE,
2772                         mwindow->edl,
2773                         1);
2774                 if(!redraw) gui->update_tool();
2775         }
2776         return result;
2779 int CWindowCanvas::button_release_event()
2781         int result = 0;
2783         switch(gui->current_operation)
2784         {
2785                 case CWINDOW_SCROLL:
2786                         result = 1;
2787                         break;
2788         }
2790         gui->current_operation = CWINDOW_NONE;
2791         mwindow->undo->update_undo_after();
2792 //printf("CWindowCanvas::button_release_event %d\n", result);
2793         return result;
2796 void CWindowCanvas::zoom_resize_window(float percentage)
2798         int canvas_w, canvas_h;
2799         calculate_sizes(mwindow->edl->get_aspect_ratio(), 
2800                 mwindow->edl->calculate_output_w(0), 
2801                 mwindow->edl->calculate_output_h(0), 
2802                 percentage,
2803                 canvas_w,
2804                 canvas_h);
2805         int new_w, new_h;
2806         new_w = canvas_w + (gui->get_w() - mwindow->theme->ccanvas_w);
2807         new_h = canvas_h + (gui->get_h() - mwindow->theme->ccanvas_h);
2808         gui->resize_window(new_w, new_h);
2809         gui->resize_event(new_w, new_h);
2812 void CWindowCanvas::toggle_controls()
2814         mwindow->session->cwindow_controls = !mwindow->session->cwindow_controls;
2815         gui->resize_event(gui->get_w(), gui->get_h());
2818 int CWindowCanvas::get_cwindow_controls()
2820         return mwindow->session->cwindow_controls;