initial commit
[goodguy/history.git] / cinelerra-5.0 / cinelerra / cwindowgui.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 1997-2014 Adam Williams <broadcast at earthling dot net>
5  * 
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * 
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  * 
20  */
21
22 #include "automation.h"
23 #include "autos.h"
24 #include "bcsignals.h"
25 #include "canvas.h"
26 #include "clip.h"
27 #include "cpanel.h"
28 #include "cplayback.h"
29 #include "ctimebar.h"
30 #include "cursors.h"
31 #include "cwindowgui.h"
32 #include "cwindow.h"
33 #include "cwindowtool.h"
34 #include "editpanel.h"
35 #include "edl.h"
36 #include "edlsession.h"
37 #include "floatauto.h"
38 #include "floatautos.h"
39 #include "keys.h"
40 #include "language.h"
41 #include "localsession.h"
42 #include "mainclock.h"
43 #include "mainmenu.h"
44 #include "mainundo.h"
45 #include "mainsession.h"
46 #include "maskauto.h"
47 #include "maskautos.h"
48 #include "mbuttons.h"
49 #include "meterpanel.h"
50 #include "mwindowgui.h"
51 #include "mwindow.h"
52 #include "mwindow.h"
53 #include "playback3d.h"
54 #include "playtransport.h"
55 #include "theme.h"
56 #include "trackcanvas.h"
57 #include "tracks.h"
58 #include "transportque.h"
59 #include "vtrack.h"
60
61
62 static double my_zoom_table[] = 
63 {
64         0.25,
65         0.33,
66         0.50,
67         0.75,
68         1.0,
69         1.5,
70         2.0,
71         3.0,
72         4.0
73 };
74
75 static int total_zooms = sizeof(my_zoom_table) / sizeof(double);
76
77
78 CWindowGUI::CWindowGUI(MWindow *mwindow, CWindow *cwindow)
79  : BC_Window(PROGRAM_NAME ": Compositor",
80         mwindow->session->cwindow_x, 
81     mwindow->session->cwindow_y, 
82     mwindow->session->cwindow_w, 
83     mwindow->session->cwindow_h,
84     100,
85     100,
86     1,
87     1,
88     1,
89         BLACK,
90         mwindow->get_cwindow_display())
91 {
92         this->mwindow = mwindow;
93     this->cwindow = cwindow;
94         affected_track = 0;
95         affected_x = 0;
96         affected_y = 0;
97         affected_z = 0;
98         mask_keyframe = 0;
99         orig_mask_keyframe = new MaskAuto(0, 0);
100         affected_point = 0;
101         x_offset = 0;
102         y_offset = 0;
103         x_origin = 0;
104         y_origin = 0;
105         current_operation = CWINDOW_NONE;
106         tool_panel = 0;
107         translating_zoom = 0;
108         active = 0;
109         inactive = 0;
110         crop_translate = 0;
111         eyedrop_visible = 0;
112 }
113
114 CWindowGUI::~CWindowGUI()
115 {
116         if(tool_panel) delete tool_panel;
117         delete meters;
118         delete composite_panel;
119         delete canvas;
120         delete transport;
121         delete edit_panel;
122         delete zoom_panel;
123         delete active;
124         delete inactive;
125 }
126
127 void CWindowGUI::create_objects()
128 {
129         lock_window("CWindowGUI::create_objects");
130         set_icon(mwindow->theme->get_image("cwindow_icon"));
131
132         active = new BC_Pixmap(this, mwindow->theme->get_image("cwindow_active"));
133         inactive = new BC_Pixmap(this, mwindow->theme->get_image("cwindow_inactive"));
134
135         mwindow->theme->get_cwindow_sizes(this, mwindow->session->cwindow_controls);
136         mwindow->theme->draw_cwindow_bg(this);
137         flash();
138
139 // Meters required by composite panel
140         meters = new CWindowMeters(mwindow, 
141                 this,
142                 mwindow->theme->cmeter_x,
143                 mwindow->theme->cmeter_y,
144                 mwindow->theme->cmeter_h);
145         meters->create_objects();
146
147
148         composite_panel = new CPanel(mwindow, 
149                 this, 
150                 mwindow->theme->ccomposite_x,
151                 mwindow->theme->ccomposite_y,
152                 mwindow->theme->ccomposite_w,
153                 mwindow->theme->ccomposite_h);
154         composite_panel->create_objects();
155
156         canvas = new CWindowCanvas(mwindow, this);
157
158         canvas->create_objects(mwindow->edl);
159         canvas->use_cwindow();
160
161
162         add_subwindow(timebar = new CTimeBar(mwindow,
163                 this,
164                 mwindow->theme->ctimebar_x,
165                 mwindow->theme->ctimebar_y,
166                 mwindow->theme->ctimebar_w, 
167                 mwindow->theme->ctimebar_h));
168         timebar->create_objects();
169
170
171         transport = new CWindowTransport(mwindow, 
172                 this, 
173                 mwindow->theme->ctransport_x, 
174                 mwindow->theme->ctransport_y);
175         transport->create_objects();
176
177         edit_panel = new CWindowEditing(mwindow, cwindow);
178         edit_panel->set_meters(meters);
179         edit_panel->create_objects();
180
181 //      add_subwindow(clock = new MainClock(mwindow, 
182 //              mwindow->theme->ctime_x, 
183 //              mwindow->theme->ctime_y));
184
185         zoom_panel = new CWindowZoom(mwindow, 
186                 this, 
187                 mwindow->theme->czoom_x, 
188                 mwindow->theme->czoom_y, 
189                 mwindow->theme->czoom_w);
190         zoom_panel->create_objects();
191         zoom_panel->zoom_text->add_item(new BC_MenuItem(AUTO_ZOOM));
192         if(!mwindow->edl->session->cwindow_scrollbars) zoom_panel->set_text(AUTO_ZOOM);
193
194 //      destination = new CWindowDestination(mwindow, 
195 //              this, 
196 //              mwindow->theme->cdest_x,
197 //              mwindow->theme->cdest_y);
198 //      destination->create_objects();
199
200 // Must create after meter panel
201         tool_panel = new CWindowTool(mwindow, this);
202         tool_panel->Thread::start();
203
204         
205         set_operation(mwindow->edl->session->cwindow_operation);
206
207
208
209         canvas->draw_refresh(0);
210
211
212         draw_status(0);
213         unlock_window();
214 }
215
216 int CWindowGUI::translation_event()
217 {
218         mwindow->session->cwindow_x = get_x();
219         mwindow->session->cwindow_y = get_y();
220         return 0;
221 }
222
223 int CWindowGUI::resize_event(int w, int h)
224 {
225         mwindow->session->cwindow_x = get_x();
226         mwindow->session->cwindow_y = get_y();
227         mwindow->session->cwindow_w = w;
228         mwindow->session->cwindow_h = h;
229
230         mwindow->theme->get_cwindow_sizes(this, mwindow->session->cwindow_controls);
231         mwindow->theme->draw_cwindow_bg(this);
232         flash(0);
233
234         composite_panel->reposition_buttons(mwindow->theme->ccomposite_x,
235                 mwindow->theme->ccomposite_y);
236
237         canvas->reposition_window(mwindow->edl,
238                 mwindow->theme->ccanvas_x,
239                 mwindow->theme->ccanvas_y,
240                 mwindow->theme->ccanvas_w,
241                 mwindow->theme->ccanvas_h);
242
243         timebar->resize_event();
244
245         transport->reposition_buttons(mwindow->theme->ctransport_x, 
246                 mwindow->theme->ctransport_y);
247
248         edit_panel->reposition_buttons(mwindow->theme->cedit_x, 
249                 mwindow->theme->cedit_y);
250
251 //      clock->reposition_window(mwindow->theme->ctime_x, 
252 //              mwindow->theme->ctime_y);
253
254         zoom_panel->reposition_window(mwindow->theme->czoom_x, 
255                 mwindow->theme->czoom_y);
256
257 //      destination->reposition_window(mwindow->theme->cdest_x,
258 //              mwindow->theme->cdest_y);
259
260         meters->reposition_window(mwindow->theme->cmeter_x,
261                 mwindow->theme->cmeter_y,
262                 -1,
263                 mwindow->theme->cmeter_h);
264
265         draw_status(0);
266
267         BC_WindowBase::resize_event(w, h);
268         return 1;
269 }
270
271 int CWindowGUI::button_press_event()
272 {
273         if(canvas->get_canvas())
274                 return canvas->button_press_event_base(canvas->get_canvas());
275         return 0;
276 }
277
278 int CWindowGUI::cursor_leave_event()
279 {
280         if(canvas->get_canvas())
281                 return canvas->cursor_leave_event_base(canvas->get_canvas());
282         return 0;
283 }
284
285 int CWindowGUI::cursor_enter_event()
286 {
287         if(canvas->get_canvas())
288                 return canvas->cursor_enter_event_base(canvas->get_canvas());
289         return 0;
290 }
291
292 int CWindowGUI::button_release_event()
293 {
294         if(canvas->get_canvas())
295                 return canvas->button_release_event();
296         return 0;
297 }
298
299 int CWindowGUI::cursor_motion_event()
300 {
301         if(canvas->get_canvas())
302         {
303                 canvas->get_canvas()->unhide_cursor();
304                 return canvas->cursor_motion_event();
305         }
306         return 0;
307 }
308
309
310
311
312
313
314
315 void CWindowGUI::draw_status(int flush)
316 {
317         if( (canvas->get_canvas() && canvas->get_canvas()->get_video_on()) ||
318                 canvas->is_processing )
319         {
320                 draw_pixmap(active, 
321                         mwindow->theme->cstatus_x, 
322                         mwindow->theme->cstatus_y);
323         }
324         else
325         {
326                 draw_pixmap(inactive, 
327                         mwindow->theme->cstatus_x, 
328                         mwindow->theme->cstatus_y);
329         }
330
331
332 // printf("CWindowGUI::draw_status %d %d %d\n", __LINE__, mwindow->theme->cstatus_x,
333 //              mwindow->theme->cstatus_y);
334         flash(mwindow->theme->cstatus_x,
335                 mwindow->theme->cstatus_y,
336                 active->get_w(),
337                 active->get_h(),
338                 flush);
339 }
340
341
342 void CWindowGUI::zoom_canvas(int do_auto, double value, int update_menu)
343 {
344         if(do_auto)
345                 mwindow->edl->session->cwindow_scrollbars = 0;
346         else
347                 mwindow->edl->session->cwindow_scrollbars = 1;
348
349         float old_zoom = mwindow->edl->session->cwindow_zoom;
350         float new_zoom = value;
351         float x = canvas->w / 2;
352         float y = canvas->h / 2;
353         canvas->canvas_to_output(mwindow->edl, 
354                                 0, 
355                                 x, 
356                                 y);
357         x -= canvas->w_visible / 2 * old_zoom / new_zoom;
358         y -= canvas->h_visible / 2 * old_zoom / new_zoom;
359         if(update_menu)
360         {
361                 if(do_auto)
362                 {
363                         zoom_panel->update(AUTO_ZOOM);
364                 }
365                 else
366                 {
367                         zoom_panel->update(value);
368                 }
369         }
370
371         canvas->update_zoom((int)x, 
372                 (int)y, 
373                 new_zoom);
374         canvas->reposition_window(mwindow->edl, 
375                 mwindow->theme->ccanvas_x,
376                 mwindow->theme->ccanvas_y,
377                 mwindow->theme->ccanvas_w,
378                 mwindow->theme->ccanvas_h);
379         canvas->draw_refresh();
380 }
381
382
383
384 void CWindowGUI::set_operation(int value)
385 {
386         mwindow->edl->session->cwindow_operation = value;
387
388         composite_panel->set_operation(value);
389         edit_panel->update();
390
391         tool_panel->start_tool(value);
392         canvas->draw_refresh();
393 }
394
395 void CWindowGUI::update_tool()
396 {
397         tool_panel->update_values();
398 }
399
400 int CWindowGUI::close_event()
401 {
402         cwindow->hide_window();
403         return 1;
404 }
405
406
407 int CWindowGUI::keypress_event()
408 {
409         int result = 0;
410
411         switch(get_keypress())
412         {
413                 case 'w':
414                 case 'W':
415                         close_event();
416                         result = 1;
417                         break;
418                 case '+':
419                 case '=':
420                         keyboard_zoomin();
421                         result = 1;
422                         break;
423                 case '-':
424                         keyboard_zoomout();
425                         result = 1;
426                         break;
427                 case 'f':
428                         unlock_window();
429                         if(mwindow->session->cwindow_fullscreen)
430                                 canvas->stop_fullscreen();
431                         else
432                                 canvas->start_fullscreen();
433                         lock_window("CWindowGUI::keypress_event 1");
434                         break;
435                 case 'x':
436                         unlock_window();
437                         mwindow->gui->lock_window("CWindowGUI::keypress_event 2");
438                         mwindow->cut();
439                         mwindow->gui->unlock_window();
440                         lock_window("CWindowGUI::keypress_event 2");
441                         break;
442                 case BACKSPACE:
443                         unlock_window();
444                         mwindow->gui->lock_window("CWindowGUI::keypress_event 2");
445                         mwindow->clear_entry();
446                         mwindow->gui->unlock_window();
447                         lock_window("CWindowGUI::keypress_event 3");
448                         break;
449                 case ESC:
450                         unlock_window();
451                         if(mwindow->session->cwindow_fullscreen)
452                                 canvas->stop_fullscreen();
453                         lock_window("CWindowGUI::keypress_event 4");
454                         break;
455                 case LEFT:
456                         if(!ctrl_down()) 
457                         { 
458                                 if (alt_down())
459                                 {
460                                         int shift_down = this->shift_down();
461                                         unlock_window();
462                                         mwindow->gui->mbuttons->transport->handle_transport(STOP, 1, 0, 0);
463
464                                         mwindow->gui->lock_window("CWindowGUI::keypress_event 2");
465                                         mwindow->prev_edit_handle(shift_down);
466                                         mwindow->gui->unlock_window();
467
468                                         lock_window("CWindowGUI::keypress_event 1");
469                                 }
470                                 else
471                                 {
472                                         unlock_window();
473                                         
474                                         mwindow->gui->lock_window("CWindowGUI::keypress_event 3");
475                                         mwindow->move_left(); 
476                                         mwindow->gui->unlock_window();
477
478                                         lock_window("CWindowGUI::keypress_event 2");
479                                 }
480                                 result = 1; 
481                         }
482                         break;
483                 case RIGHT:
484                         if(!ctrl_down()) 
485                         { 
486                                 if (alt_down())
487                                 {
488                                         int shift_down = this->shift_down();
489                                         unlock_window();
490                                         mwindow->gui->mbuttons->transport->handle_transport(STOP, 1, 0, 0);
491
492                                         mwindow->gui->lock_window("CWindowGUI::keypress_event 2");
493                                         mwindow->next_edit_handle(shift_down);
494                                         mwindow->gui->unlock_window();
495
496                                         lock_window("CWindowGUI::keypress_event 2");
497                                 }
498                                 else
499                                 {
500                                         unlock_window();
501
502                                         mwindow->gui->lock_window("CWindowGUI::keypress_event 4");
503                                         mwindow->move_right(); 
504                                         mwindow->gui->unlock_window();
505
506                                         lock_window("CWindowGUI::keypress_event 3");
507                                 }
508                                 result = 1; 
509                         }
510                         break;
511         }
512
513         if(!result) result = transport->keypress_event();
514
515         return result;
516 }
517
518
519 void CWindowGUI::reset_affected()
520 {
521         affected_x = 0;
522         affected_y = 0;
523         affected_z = 0;
524 }
525
526 void CWindowGUI::keyboard_zoomin()
527 {
528 //      if(mwindow->edl->session->cwindow_scrollbars)
529 //      {
530                 zoom_panel->zoom_tumbler->handle_up_event();
531 //      }
532 //      else
533 //      {
534 //      }
535 }
536
537 void CWindowGUI::keyboard_zoomout()
538 {
539 //      if(mwindow->edl->session->cwindow_scrollbars)
540 //      {
541                 zoom_panel->zoom_tumbler->handle_down_event();
542 //      }
543 //      else
544 //      {
545 //      }
546 }
547
548
549 void CWindowGUI::drag_motion()
550 {
551         if(get_hidden()) return;
552
553         if(mwindow->session->current_operation == DRAG_ASSET ||
554                 mwindow->session->current_operation == DRAG_VTRANSITION ||
555                 mwindow->session->current_operation == DRAG_VEFFECT)
556         {
557                 int old_status = mwindow->session->ccanvas_highlighted;
558                 int cursor_x = get_relative_cursor_x();
559                 int cursor_y = get_relative_cursor_y();
560
561                 mwindow->session->ccanvas_highlighted = get_cursor_over_window() &&
562                         cursor_x >= canvas->x &&
563                         cursor_x < canvas->x + canvas->w &&
564                         cursor_y >= canvas->y &&
565                         cursor_y < canvas->y + canvas->h;
566
567
568                 if(old_status != mwindow->session->ccanvas_highlighted)
569                         canvas->draw_refresh();
570         }
571 }
572
573 int CWindowGUI::drag_stop()
574 {
575         int result = 0;
576         if(get_hidden()) return 0;
577
578         if((mwindow->session->current_operation == DRAG_ASSET ||
579                 mwindow->session->current_operation == DRAG_VTRANSITION ||
580                 mwindow->session->current_operation == DRAG_VEFFECT) &&
581                 mwindow->session->ccanvas_highlighted)
582         {
583 // Hide highlighting
584                 mwindow->session->ccanvas_highlighted = 0;
585                 canvas->draw_refresh();
586                 result = 1;
587         }
588         else
589                 return 0;
590
591         if(mwindow->session->current_operation == DRAG_ASSET)
592         {
593                 if(mwindow->session->drag_assets->total ||
594                         mwindow->session->drag_clips->total)
595                 {
596                         mwindow->gui->lock_window("CWindowGUI::drag_stop 5");
597                         mwindow->undo->update_undo_before(_("insert assets"), 0);
598                         mwindow->gui->unlock_window();
599                 }
600
601                 if(mwindow->session->drag_assets->total)
602                 {
603                         mwindow->gui->lock_window("CWindowGUI::drag_stop 1");
604                         mwindow->clear(0);
605                         mwindow->load_assets(mwindow->session->drag_assets, 
606                                 mwindow->edl->local_session->get_selectionstart(), 
607                                 LOADMODE_PASTE,
608                                 mwindow->session->track_highlighted,
609                                 0,
610                                 mwindow->edl->session->labels_follow_edits, 
611                                 mwindow->edl->session->plugins_follow_edits,
612                                 mwindow->edl->session->autos_follow_edits);
613                 }
614
615                 if(mwindow->session->drag_clips->total)
616                 {
617                         mwindow->gui->lock_window("CWindowGUI::drag_stop 2");
618                         mwindow->clear(0);
619                         mwindow->paste_edls(mwindow->session->drag_clips, 
620                                 LOADMODE_PASTE, 
621                                 mwindow->session->track_highlighted,
622                                 mwindow->edl->local_session->get_selectionstart(),
623                                 mwindow->edl->session->labels_follow_edits, 
624                                 mwindow->edl->session->plugins_follow_edits,
625                                 mwindow->edl->session->autos_follow_edits);
626                 }
627
628                 if(mwindow->session->drag_assets->total ||
629                         mwindow->session->drag_clips->total)
630                 {
631                         mwindow->save_backup();
632                         mwindow->restart_brender();
633                         mwindow->gui->update(1, 1, 1, 1, 0, 1, 0);
634                         mwindow->undo->update_undo_after(_("insert assets"), LOAD_ALL);
635                         mwindow->gui->unlock_window();
636                         mwindow->sync_parameters(LOAD_ALL);
637                 }
638         }
639
640         if(mwindow->session->current_operation == DRAG_VEFFECT)
641         {
642 //printf("CWindowGUI::drag_stop 1\n");
643                 Track *affected_track = cwindow->calculate_affected_track();
644 //printf("CWindowGUI::drag_stop 2\n");
645
646                 mwindow->gui->lock_window("CWindowGUI::drag_stop 3");
647                 mwindow->insert_effects_cwindow(affected_track);
648                 mwindow->session->current_operation = NO_OPERATION;
649                 mwindow->gui->unlock_window();
650         }
651
652         if(mwindow->session->current_operation == DRAG_VTRANSITION)
653         {
654                 Track *affected_track = cwindow->calculate_affected_track();
655                 mwindow->gui->lock_window("CWindowGUI::drag_stop 4");
656                 mwindow->paste_transition_cwindow(affected_track);
657                 mwindow->session->current_operation = NO_OPERATION;
658                 mwindow->gui->unlock_window();
659         }
660
661         return result;
662 }
663
664 void CWindowGUI::update_meters()
665 {
666         if(mwindow->edl->session->cwindow_meter != meters->visible)
667         {
668                 meters->set_meters(meters->meter_count, mwindow->edl->session->cwindow_meter);
669                 mwindow->theme->get_cwindow_sizes(this, mwindow->session->cwindow_controls);
670                 resize_event(get_w(), get_h());
671         }
672 }
673
674
675 CWindowEditing::CWindowEditing(MWindow *mwindow, CWindow *cwindow)
676  : EditPanel(mwindow, 
677                 cwindow->gui, 
678                 mwindow->theme->cedit_x, 
679                 mwindow->theme->cedit_y,
680                 mwindow->edl->session->editing_mode, 
681                 0,
682                 1,
683                 0, 
684                 0,
685                 1,
686                 1,
687                 1,
688                 1,
689                 1,
690                 0,
691                 1,
692                 1,
693                 1,
694                 0,
695                 1,
696                 0)
697 {
698         this->mwindow = mwindow;
699         this->cwindow = cwindow;
700 }
701
702 #define CWrapper(fn) void CWindowEditing::fn() { \
703         mwindow->gui->lock_window("CWrapper::" #fn); \
704         EditPanel::fn(); \
705         mwindow->gui->unlock_window(); \
706 }
707
708 CWrapper(copy_selection)
709 CWrapper(splice_selection)
710 CWrapper(overwrite_selection)
711 CWrapper(set_inpoint)
712 CWrapper(set_outpoint)
713 CWrapper(clear_inpoint)
714 CWrapper(clear_outpoint)
715 CWrapper(to_clip)
716 CWrapper(toggle_label)
717 CWrapper(prev_label)
718 CWrapper(next_label)
719 CWrapper(prev_edit)
720 CWrapper(next_edit)
721
722
723
724 CWindowMeters::CWindowMeters(MWindow *mwindow, 
725         CWindowGUI *gui, 
726         int x, 
727         int y, 
728         int h)
729  : MeterPanel(mwindow, 
730                 gui,
731                 x,
732                 y,
733                 -1,
734                 h,
735                 mwindow->edl->session->audio_channels,
736                 mwindow->edl->session->cwindow_meter,
737                 0,
738                 0)
739 {
740         this->mwindow = mwindow;
741         this->gui = gui;
742 }
743
744 CWindowMeters::~CWindowMeters()
745 {
746 }
747
748 int CWindowMeters::change_status_event(int new_status)
749 {
750         mwindow->edl->session->cwindow_meter = new_status;
751         gui->update_meters();
752         return 1;
753 }
754
755
756
757
758 CWindowZoom::CWindowZoom(MWindow *mwindow, CWindowGUI *gui, int x, int y, int w)
759  : ZoomPanel(mwindow, 
760         gui, 
761         (double)mwindow->edl->session->cwindow_zoom, 
762         x, 
763         y,
764         w, 
765         my_zoom_table, 
766         total_zooms, 
767         ZOOM_PERCENTAGE)
768 {
769         this->mwindow = mwindow;
770         this->gui = gui;
771 }
772
773 CWindowZoom::~CWindowZoom()
774 {
775 }
776
777 int CWindowZoom::handle_event()
778 {
779         if(!strcasecmp(AUTO_ZOOM, get_text()))
780         {
781                 gui->zoom_canvas(1, get_value(), 0);
782         }
783         else
784         {
785                 gui->zoom_canvas(0, get_value(), 0);
786         }
787
788         return 1;
789 }
790
791
792
793
794
795
796 CWindowTransport::CWindowTransport(MWindow *mwindow, 
797         CWindowGUI *gui, 
798         int x, 
799         int y)
800  : PlayTransport(mwindow, 
801         gui, 
802         x, 
803         y)
804 {
805         this->gui = gui;
806 }
807
808 EDL* CWindowTransport::get_edl()
809 {
810         return mwindow->edl;
811 }
812
813 void CWindowTransport::goto_start()
814 {
815         gui->unlock_window();
816         handle_transport(REWIND, 1);
817
818         mwindow->gui->lock_window("CWindowTransport::goto_start 1");
819         mwindow->goto_start();
820         mwindow->gui->unlock_window();
821
822         gui->lock_window("CWindowTransport::goto_start 2");
823 }
824
825 void CWindowTransport::goto_end()
826 {
827         gui->unlock_window();
828         handle_transport(GOTO_END, 1);
829
830         mwindow->gui->lock_window("CWindowTransport::goto_end 1");
831         mwindow->goto_end();
832         mwindow->gui->unlock_window();
833
834         gui->lock_window("CWindowTransport::goto_end 2");
835 }
836
837
838
839 CWindowCanvas::CWindowCanvas(MWindow *mwindow, CWindowGUI *gui)
840  : Canvas(mwindow,
841         gui,
842         mwindow->theme->ccanvas_x,
843         mwindow->theme->ccanvas_y,
844         mwindow->theme->ccanvas_w,
845         mwindow->theme->ccanvas_h,
846         0,
847         0,
848         mwindow->edl->session->cwindow_scrollbars)
849 {
850         this->mwindow = mwindow;
851         this->gui = gui;
852 }
853
854 void CWindowCanvas::status_event()
855 {
856         gui->draw_status(1);
857 }
858
859 int CWindowCanvas::get_fullscreen()
860 {
861         return mwindow->session->cwindow_fullscreen;
862 }
863
864 void CWindowCanvas::set_fullscreen(int value)
865 {
866         mwindow->session->cwindow_fullscreen = value;
867 }
868
869
870 void CWindowCanvas::update_zoom(int x, int y, float zoom)
871 {
872         use_scrollbars = mwindow->edl->session->cwindow_scrollbars;
873
874         mwindow->edl->session->cwindow_xscroll = x;
875         mwindow->edl->session->cwindow_yscroll = y;
876         mwindow->edl->session->cwindow_zoom = zoom;
877 }
878
879 void CWindowCanvas::zoom_auto()
880 {
881         gui->zoom_canvas(1, 1.0, 1);
882 }
883
884 int CWindowCanvas::get_xscroll()
885 {
886         return mwindow->edl->session->cwindow_xscroll;
887 }
888
889 int CWindowCanvas::get_yscroll()
890 {
891         return mwindow->edl->session->cwindow_yscroll;
892 }
893
894
895 float CWindowCanvas::get_zoom()
896 {
897         return mwindow->edl->session->cwindow_zoom;
898 }
899
900 void CWindowCanvas::draw_refresh(int flush)
901 {
902         if(get_canvas() && !get_canvas()->get_video_on())
903         {
904
905                 if(refresh_frame)
906                 {
907                         float in_x1, in_y1, in_x2, in_y2;
908                         float out_x1, out_y1, out_x2, out_y2;
909                         get_transfers(mwindow->edl, 
910                                 in_x1, 
911                                 in_y1, 
912                                 in_x2, 
913                                 in_y2, 
914                                 out_x1, 
915                                 out_y1, 
916                                 out_x2, 
917                                 out_y2);
918
919                         if(!EQUIV(out_x1, 0) ||
920                                 !EQUIV(out_y1, 0) ||
921                                 !EQUIV(out_x2, get_canvas()->get_w()) ||
922                                 !EQUIV(out_y2, get_canvas()->get_h()))
923                         {
924                                 get_canvas()->clear_box(0, 
925                                         0, 
926                                         get_canvas()->get_w(), 
927                                         get_canvas()->get_h());
928                         }
929
930 //printf("CWindowCanvas::draw_refresh %.2f %.2f %.2f %.2f -> %.2f %.2f %.2f %.2f\n", 
931 //in_x1, in_y1, in_x2, in_y2, out_x1, out_y1, out_x2, out_y2);
932
933
934                         if(out_x2 > out_x1 && 
935                                 out_y2 > out_y1 && 
936                                 in_x2 > in_x1 && 
937                                 in_y2 > in_y1)
938                         {
939 // Can't use OpenGL here because it is called asynchronously of the
940 // playback operation.
941                                 get_canvas()->draw_vframe(refresh_frame,
942                                                 (int)out_x1, 
943                                                 (int)out_y1, 
944                                                 (int)(out_x2 - out_x1), 
945                                                 (int)(out_y2 - out_y1),
946                                                 (int)in_x1, 
947                                                 (int)in_y1, 
948                                                 (int)(in_x2 - in_x1), 
949                                                 (int)(in_y2 - in_y1),
950                                                 0);
951                         }
952                 }
953                 else
954                 {
955                         get_canvas()->clear_box(0, 
956                                 0, 
957                                 get_canvas()->get_w(), 
958                                 get_canvas()->get_h());
959                 }
960
961                 draw_overlays();
962                 get_canvas()->flash(flush);
963         }
964 //printf("CWindowCanvas::draw_refresh 10\n");
965 }
966
967 #define CROPHANDLE_W 10
968 #define CROPHANDLE_H 10
969
970 void CWindowCanvas::draw_crophandle(int x, int y)
971 {
972         get_canvas()->draw_box(x, y, CROPHANDLE_W, CROPHANDLE_H);
973 }
974
975
976
977
978
979
980 #define CONTROL_W 10
981 #define CONTROL_H 10
982 #define FIRST_CONTROL_W 20
983 #define FIRST_CONTROL_H 20
984 #undef BC_INFINITY
985 #define BC_INFINITY 65536
986
987 #define RULERHANDLE_W 16
988 #define RULERHANDLE_H 16
989
990
991
992 int CWindowCanvas::do_ruler(int draw, 
993         int motion, 
994         int button_press, 
995         int button_release)
996 {
997         int result = 0;
998         float x1 = mwindow->edl->session->ruler_x1;
999         float y1 = mwindow->edl->session->ruler_y1;
1000         float x2 = mwindow->edl->session->ruler_x2;
1001         float y2 = mwindow->edl->session->ruler_y2;
1002         float canvas_x1 = x1;
1003         float canvas_y1 = y1;
1004         float canvas_x2 = x2;
1005         float canvas_y2 = y2;
1006         float output_x = get_cursor_x();
1007         float output_y = get_cursor_y();
1008         float canvas_cursor_x = output_x;
1009         float canvas_cursor_y = output_y;
1010
1011         canvas_to_output(mwindow->edl, 0, output_x, output_y);
1012         output_to_canvas(mwindow->edl, 0, canvas_x1, canvas_y1);
1013         output_to_canvas(mwindow->edl, 0, canvas_x2, canvas_y2);
1014         mwindow->session->cwindow_output_x = (int)output_x;
1015         mwindow->session->cwindow_output_y = (int)output_y;
1016
1017         if(button_press && get_buttonpress() == 1)
1018         {
1019                 gui->ruler_handle = -1;
1020                 gui->ruler_translate = 0;
1021                 if(gui->alt_down())
1022                 {
1023                         gui->ruler_translate = 1;
1024                         gui->ruler_origin_x = x1;
1025                         gui->ruler_origin_y = y1;
1026                 }
1027                 else
1028                 if(canvas_cursor_x >= canvas_x1 - RULERHANDLE_W / 2 && 
1029                         canvas_cursor_x < canvas_x1 + RULERHANDLE_W / 2 && 
1030                         canvas_cursor_y >= canvas_y1 - RULERHANDLE_W && 
1031                         canvas_cursor_y < canvas_y1 + RULERHANDLE_H / 2)
1032                 {
1033                         gui->ruler_handle = 0;
1034                         gui->ruler_origin_x = x1;
1035                         gui->ruler_origin_y = y1;
1036                 }
1037                 else
1038                 if(canvas_cursor_x >= canvas_x2 - RULERHANDLE_W / 2 && 
1039                         canvas_cursor_x < canvas_x2 + RULERHANDLE_W / 2 && 
1040                         canvas_cursor_y >= canvas_y2 - RULERHANDLE_W && 
1041                         canvas_cursor_y < canvas_y2 + RULERHANDLE_H / 2)
1042                 {
1043                         gui->ruler_handle = 1;
1044                         gui->ruler_origin_x = x2;
1045                         gui->ruler_origin_y = y2;
1046                 }
1047
1048
1049 // Start new selection
1050                 if(!gui->ruler_translate && 
1051                         (gui->ruler_handle < 0 || 
1052                         (EQUIV(x2 - x1, 0.0) && 
1053                         EQUIV(y2 - y1, 0.0))))
1054                 {
1055 // Hide previous
1056                         do_ruler(1, 0, 0, 0);
1057                         get_canvas()->flash();
1058                         gui->ruler_handle = 1;
1059                         mwindow->edl->session->ruler_x1 = output_x;
1060                         mwindow->edl->session->ruler_y1 = output_y;
1061                         mwindow->edl->session->ruler_x2 = output_x;
1062                         mwindow->edl->session->ruler_y2 = output_y;
1063                         gui->ruler_origin_x = mwindow->edl->session->ruler_x2;
1064                         gui->ruler_origin_y = mwindow->edl->session->ruler_y2;
1065                 }
1066
1067                 gui->x_origin = output_x;
1068                 gui->y_origin = output_y;
1069                 gui->current_operation = CWINDOW_RULER;
1070                 gui->tool_panel->raise_window();
1071                 result = 1;
1072         }
1073
1074         if(motion)
1075         {
1076                 if(gui->current_operation == CWINDOW_RULER)
1077                 {
1078                         if(gui->ruler_translate)
1079                         {
1080 // Hide ruler
1081                                 do_ruler(1, 0, 0, 0);
1082                                 float x_difference = mwindow->edl->session->ruler_x1;
1083                                 float y_difference = mwindow->edl->session->ruler_y1;
1084                                 mwindow->edl->session->ruler_x1 = output_x - gui->x_origin + gui->ruler_origin_x;
1085                                 mwindow->edl->session->ruler_y1 = output_y - gui->y_origin + gui->ruler_origin_y;
1086                                 x_difference -= mwindow->edl->session->ruler_x1;
1087                                 y_difference -= mwindow->edl->session->ruler_y1;
1088                                 mwindow->edl->session->ruler_x2 -= x_difference;
1089                                 mwindow->edl->session->ruler_y2 -= y_difference;
1090 // Show ruler
1091                                 do_ruler(1, 0, 0, 0);
1092                                 get_canvas()->flash();
1093                         }
1094                         else
1095                         switch(gui->ruler_handle)
1096                         {
1097                                 case 0:
1098                                         do_ruler(1, 0, 0, 0);
1099                                         mwindow->edl->session->ruler_x1 = output_x - gui->x_origin + gui->ruler_origin_x;
1100                                         mwindow->edl->session->ruler_y1 = output_y - gui->y_origin + gui->ruler_origin_y;
1101                                         if(gui->alt_down() || gui->ctrl_down()) 
1102                                         {
1103                                                 double angle_value = fabs(atan((mwindow->edl->session->ruler_y2 - mwindow->edl->session->ruler_y1) /
1104                                                         (mwindow->edl->session->ruler_x2 - mwindow->edl->session->ruler_x1)) * 
1105                                                         360 /
1106                                                         2 / 
1107                                                         M_PI);
1108                                                 double distance_value = 
1109                                                         sqrt(SQR(mwindow->edl->session->ruler_x2 - mwindow->edl->session->ruler_x1) +
1110                                                         SQR(mwindow->edl->session->ruler_y2 - mwindow->edl->session->ruler_y1));
1111                                                 if(angle_value < 22)
1112                                                         mwindow->edl->session->ruler_y1 = mwindow->edl->session->ruler_y2;
1113                                                 else
1114                                                 if(angle_value > 67)
1115                                                         mwindow->edl->session->ruler_x1 = mwindow->edl->session->ruler_x2;
1116                                                 else
1117                                                 if(mwindow->edl->session->ruler_x1 < mwindow->edl->session->ruler_x2 && 
1118                                                         mwindow->edl->session->ruler_y1 < mwindow->edl->session->ruler_y2)
1119                                                 {
1120                                                         mwindow->edl->session->ruler_x1 = mwindow->edl->session->ruler_x2 - distance_value / 1.414214;
1121                                                         mwindow->edl->session->ruler_y1 = mwindow->edl->session->ruler_y2 - distance_value / 1.414214;
1122                                                 }
1123                                                 else
1124                                                 if(mwindow->edl->session->ruler_x1 < mwindow->edl->session->ruler_x2 && mwindow->edl->session->ruler_y1 > mwindow->edl->session->ruler_y2)
1125                                                 {
1126                                                         mwindow->edl->session->ruler_x1 = mwindow->edl->session->ruler_x2 - distance_value / 1.414214;
1127                                                         mwindow->edl->session->ruler_y1 = mwindow->edl->session->ruler_y2 + distance_value / 1.414214;
1128                                                 }
1129                                                 else
1130                                                 if(mwindow->edl->session->ruler_x1 > mwindow->edl->session->ruler_x2 && 
1131                                                         mwindow->edl->session->ruler_y1 < mwindow->edl->session->ruler_y2)
1132                                                 {
1133                                                         mwindow->edl->session->ruler_x1 = mwindow->edl->session->ruler_x2 + distance_value / 1.414214;
1134                                                         mwindow->edl->session->ruler_y1 = mwindow->edl->session->ruler_y2 - distance_value / 1.414214;
1135                                                 }
1136                                                 else
1137                                                 {
1138                                                         mwindow->edl->session->ruler_x1 = mwindow->edl->session->ruler_x2 + distance_value / 1.414214;
1139                                                         mwindow->edl->session->ruler_y1 = mwindow->edl->session->ruler_y2 + distance_value / 1.414214;
1140                                                 }
1141                                         }
1142                                         do_ruler(1, 0, 0, 0);
1143                                         get_canvas()->flash();
1144                                         gui->update_tool();
1145                                         break;
1146
1147                                 case 1:
1148                                         do_ruler(1, 0, 0, 0);
1149                                         mwindow->edl->session->ruler_x2 = output_x - gui->x_origin + gui->ruler_origin_x;
1150                                         mwindow->edl->session->ruler_y2 = output_y - gui->y_origin + gui->ruler_origin_y;
1151                                         if(gui->alt_down() || gui->ctrl_down()) 
1152                                         {
1153                                                 double angle_value = fabs(atan((mwindow->edl->session->ruler_y2 - mwindow->edl->session->ruler_y1) /
1154                                                         (mwindow->edl->session->ruler_x2 - mwindow->edl->session->ruler_x1)) * 
1155                                                         360 /
1156                                                         2 / 
1157                                                         M_PI);
1158                                                 double distance_value = 
1159                                                         sqrt(SQR(mwindow->edl->session->ruler_x2 - mwindow->edl->session->ruler_x1) +
1160                                                         SQR(mwindow->edl->session->ruler_y2 - mwindow->edl->session->ruler_y1));
1161                                                 if(angle_value < 22)
1162                                                         mwindow->edl->session->ruler_y2 = mwindow->edl->session->ruler_y1;
1163                                                 else
1164                                                 if(angle_value > 67)
1165                                                         mwindow->edl->session->ruler_x2 = mwindow->edl->session->ruler_x1;
1166                                                 else
1167                                                 if(mwindow->edl->session->ruler_x2 < mwindow->edl->session->ruler_x1 && 
1168                                                         mwindow->edl->session->ruler_y2 < mwindow->edl->session->ruler_y1)
1169                                                 {
1170                                                         mwindow->edl->session->ruler_x2 = mwindow->edl->session->ruler_x1 - distance_value / 1.414214;
1171                                                         mwindow->edl->session->ruler_y2 = mwindow->edl->session->ruler_y1 - distance_value / 1.414214;
1172                                                 }
1173                                                 else
1174                                                 if(mwindow->edl->session->ruler_x2 < mwindow->edl->session->ruler_x1 && 
1175                                                         mwindow->edl->session->ruler_y2 > mwindow->edl->session->ruler_y1)
1176                                                 {
1177                                                         mwindow->edl->session->ruler_x2 = mwindow->edl->session->ruler_x1 - distance_value / 1.414214;
1178                                                         mwindow->edl->session->ruler_y2 = mwindow->edl->session->ruler_y1 + distance_value / 1.414214;
1179                                                 }
1180                                                 else
1181                                                 if(mwindow->edl->session->ruler_x2 > mwindow->edl->session->ruler_x1 && mwindow->edl->session->ruler_y2 < mwindow->edl->session->ruler_y1)
1182                                                 {
1183                                                         mwindow->edl->session->ruler_x2 = mwindow->edl->session->ruler_x1 + distance_value / 1.414214;
1184                                                         mwindow->edl->session->ruler_y2 = mwindow->edl->session->ruler_y1 - distance_value / 1.414214;
1185                                                 }
1186                                                 else
1187                                                 {
1188                                                         mwindow->edl->session->ruler_x2 = mwindow->edl->session->ruler_x1 + distance_value / 1.414214;
1189                                                         mwindow->edl->session->ruler_y2 = mwindow->edl->session->ruler_y1 + distance_value / 1.414214;
1190                                                 }
1191                                         }
1192                                         do_ruler(1, 0, 0, 0);
1193                                         get_canvas()->flash();
1194                                         gui->update_tool();
1195                                         break;
1196                         }
1197 //printf("CWindowCanvas::do_ruler 2 %f %f %f %f\n", gui->ruler_x1, gui->ruler_y1, gui->ruler_x2, gui->ruler_y2);
1198                 }
1199                 else
1200                 {
1201 // printf("CWindowCanvas::do_ruler 2 %f %f %f %f\n", 
1202 // canvas_cursor_x, 
1203 // canvas_cursor_y,
1204 // canvas_x1,
1205 // canvas_y1);
1206                         if(canvas_cursor_x >= canvas_x1 - RULERHANDLE_W / 2 && 
1207                                 canvas_cursor_x < canvas_x1 + RULERHANDLE_W / 2 && 
1208                                 canvas_cursor_y >= canvas_y1 - RULERHANDLE_W && 
1209                                 canvas_cursor_y < canvas_y1 + RULERHANDLE_H / 2)
1210                         {
1211                                 set_cursor(UPRIGHT_ARROW_CURSOR);
1212                         }
1213                         else
1214                         if(canvas_cursor_x >= canvas_x2 - RULERHANDLE_W / 2 && 
1215                                 canvas_cursor_x < canvas_x2 + RULERHANDLE_W / 2 && 
1216                                 canvas_cursor_y >= canvas_y2 - RULERHANDLE_W && 
1217                                 canvas_cursor_y < canvas_y2 + RULERHANDLE_H / 2)
1218                         {
1219                                 set_cursor(UPRIGHT_ARROW_CURSOR);
1220                         }
1221                         else
1222                                 set_cursor(CROSS_CURSOR);
1223
1224 // Update current position
1225                         gui->update_tool();
1226                 }
1227         }
1228
1229 // Assume no ruler measurement if 0 length
1230         if(draw && (x2 - x1 || y2 - y1))
1231         {
1232                 get_canvas()->set_inverse();
1233                 get_canvas()->set_color(WHITE);
1234                 get_canvas()->draw_line((int)canvas_x1, 
1235                         (int)canvas_y1, 
1236                         (int)canvas_x2, 
1237                         (int)canvas_y2);
1238                 get_canvas()->draw_line((int)canvas_x1 - RULERHANDLE_W / 2, 
1239                         (int)canvas_y1, 
1240                         (int)canvas_x1 + RULERHANDLE_W / 2, 
1241                         (int)canvas_y1);
1242                 get_canvas()->draw_line((int)canvas_x1, 
1243                         (int)canvas_y1 - RULERHANDLE_H / 2, 
1244                         (int)canvas_x1, 
1245                         (int)canvas_y1 + RULERHANDLE_H / 2);
1246                 get_canvas()->draw_line((int)canvas_x2 - RULERHANDLE_W / 2, 
1247                         (int)canvas_y2, 
1248                         (int)canvas_x2 + RULERHANDLE_W / 2, 
1249                         (int)canvas_y2);
1250                 get_canvas()->draw_line((int)canvas_x2, 
1251                         (int)canvas_y2 - RULERHANDLE_H / 2, 
1252                         (int)canvas_x2, 
1253                         (int)canvas_y2 + RULERHANDLE_H / 2);
1254                 get_canvas()->set_opaque();
1255         }
1256
1257         return result;
1258 }
1259
1260
1261 int CWindowCanvas::do_mask(int &redraw, 
1262                 int &rerender, 
1263                 int button_press, 
1264                 int cursor_motion,
1265                 int draw)
1266 {
1267 // Retrieve points from top recordable track
1268 //printf("CWindowCanvas::do_mask 1\n");
1269         Track *track = gui->cwindow->calculate_affected_track();
1270 //printf("CWindowCanvas::do_mask 2\n");
1271
1272         if(!track) return 0;
1273 //printf("CWindowCanvas::do_mask 3\n");
1274
1275         MaskAutos *mask_autos = (MaskAutos*)track->automation->autos[AUTOMATION_MASK];
1276         int64_t position = track->to_units(
1277                 mwindow->edl->local_session->get_selectionstart(1),
1278                 0);
1279         ArrayList<MaskPoint*> points;
1280
1281 // Determine the points based on whether
1282 // new keyframes will be generated or drawing is performed.
1283 // If keyframe generation occurs, use the interpolated mask.
1284 // If no keyframe generation occurs, use the previous mask.
1285         int use_interpolated = 0;
1286         if(button_press || cursor_motion)
1287         {
1288 #ifdef USE_KEYFRAME_SPANNING
1289                 double selection_start = mwindow->edl->local_session->get_selectionstart(0);
1290                 double selection_end = mwindow->edl->local_session->get_selectionend(0);
1291
1292                 Auto *first = 0;
1293                 mask_autos->get_prev_auto(track->to_units(selection_start, 0),
1294                         PLAY_FORWARD,
1295                         first,
1296                         1);
1297                 Auto *last = 0;
1298                 mask_autos->get_prev_auto(track->to_units(selection_end, 0),
1299                         PLAY_FORWARD,
1300                         last,
1301                         1);
1302
1303                 if(last == first && (!mwindow->edl->session->auto_keyframes))
1304                         use_interpolated = 0;
1305                 else
1306 // If keyframe spanning occurs, use the interpolated points.
1307 // If new keyframe is generated, use the interpolated points.
1308                         use_interpolated = 1;
1309                 
1310 #else
1311                 if(mwindow->edl->session->auto_keyframes)
1312                         use_interpolated = 1;
1313 #endif
1314         }
1315         else
1316                 use_interpolated = 1;
1317
1318         if(use_interpolated)
1319         {
1320 // Interpolate the points to get exactly what is being rendered at this position.
1321                 mask_autos->get_points(&points, 
1322                         mwindow->edl->session->cwindow_mask,
1323                         position, 
1324                         PLAY_FORWARD);
1325         }
1326         else
1327 // Use the prev mask
1328         {
1329                 Auto *prev = 0;
1330                 mask_autos->get_prev_auto(position,
1331                         PLAY_FORWARD,
1332                         prev,
1333                         1);
1334                 ((MaskAuto*)prev)->get_points(&points, 
1335                         mwindow->edl->session->cwindow_mask);
1336         }
1337
1338 // Projector zooms relative to the center of the track output.
1339         float half_track_w = (float)track->track_w / 2;
1340         float half_track_h = (float)track->track_h / 2;
1341 // Translate mask to projection
1342         float projector_x, projector_y, projector_z;
1343         track->automation->get_projector(&projector_x,
1344                 &projector_y,
1345                 &projector_z,
1346                 position,
1347                 PLAY_FORWARD);
1348
1349
1350 // Get position of cursor relative to mask
1351         float mask_cursor_x = get_cursor_x();
1352         float mask_cursor_y = get_cursor_y();
1353         canvas_to_output(mwindow->edl, 0, mask_cursor_x, mask_cursor_y);
1354
1355         projector_x += mwindow->edl->session->output_w / 2;
1356         projector_y += mwindow->edl->session->output_h / 2;
1357
1358         mask_cursor_x -= projector_x;
1359         mask_cursor_y -= projector_y;
1360         mask_cursor_x = mask_cursor_x / projector_z + half_track_w;
1361         mask_cursor_y = mask_cursor_y / projector_z + half_track_h;
1362
1363 // Fix cursor origin
1364         if(button_press)
1365         {
1366                 gui->x_origin = mask_cursor_x;
1367                 gui->y_origin = mask_cursor_y;
1368         }
1369
1370         int result = 0;
1371 // Points of closest line
1372         int shortest_point1 = -1;
1373         int shortest_point2 = -1;
1374 // Closest point
1375         int shortest_point = -1;
1376 // Distance to closest line
1377         float shortest_line_distance = BC_INFINITY;
1378 // Distance to closest point
1379         float shortest_point_distance = BC_INFINITY;
1380         int selected_point = -1;
1381         int selected_control_point = -1;
1382         float selected_control_point_distance = BC_INFINITY;
1383         ArrayList<int> x_points;
1384         ArrayList<int> y_points;
1385
1386         if(!cursor_motion)
1387         {
1388                 if(draw)
1389                 {
1390                         get_canvas()->set_color(WHITE);
1391                         get_canvas()->set_inverse();
1392                 }
1393 //printf("CWindowCanvas::do_mask 1 %d\n", points.size());
1394
1395 // Never draw closed polygon and a closed
1396 // polygon is harder to add points to.
1397                 for(int i = 0; i < points.size() && !result; i++)
1398                 {
1399                         MaskPoint *point1 = points.get(i);
1400                         MaskPoint *point2 = (i >= points.size() - 1) ? 
1401                                 points.get(0) : 
1402                                 points.get(i + 1);
1403                         float x0, x1, x2, x3;
1404                         float y0, y1, y2, y3;
1405                         float x, y;
1406                         int segments = (int)(sqrt(SQR(point1->x - point2->x) + SQR(point1->y - point2->y)));
1407
1408 //printf("CWindowCanvas::do_mask 1 %f, %f -> %f, %f projectorz=%f\n",
1409 //point1->x, point1->y, point2->x, point2->y, projector_z);
1410                         for(int j = 0; j <= segments && !result; j++)
1411                         {
1412 //printf("CWindowCanvas::do_mask 1 %f, %f -> %f, %f\n", x0, y0, x3, y3);
1413                                 x0 = point1->x;
1414                                 y0 = point1->y;
1415                                 x1 = point1->x + point1->control_x2;
1416                                 y1 = point1->y + point1->control_y2;
1417                                 x2 = point2->x + point2->control_x1;
1418                                 y2 = point2->y + point2->control_y1;
1419                                 x3 = point2->x;
1420                                 y3 = point2->y;
1421
1422                                 float t = (float)j / segments;
1423                                 float tpow2 = t * t;
1424                                 float tpow3 = t * t * t;
1425                                 float invt = 1 - t;
1426                                 float invtpow2 = invt * invt;
1427                                 float invtpow3 = invt * invt * invt;
1428
1429                                 x = (        invtpow3 * x0
1430                                         + 3 * t     * invtpow2 * x1
1431                                         + 3 * tpow2 * invt     * x2 
1432                                         +     tpow3            * x3);
1433                                 y = (        invtpow3 * y0 
1434                                         + 3 * t     * invtpow2 * y1
1435                                         + 3 * tpow2 * invt     * y2 
1436                                         +     tpow3            * y3);
1437
1438                                 x = (x - half_track_w) * projector_z + projector_x;
1439                                 y = (y - half_track_h) * projector_z + projector_y;
1440
1441
1442 // Test new point addition
1443                                 if(button_press)
1444                                 {
1445                                         float line_distance = 
1446                                                 sqrt(SQR(x - mask_cursor_x) + SQR(y - mask_cursor_y));
1447
1448 //printf("CWindowCanvas::do_mask 1 x=%f mask_cursor_x=%f y=%f mask_cursor_y=%f %f %f %d, %d\n", 
1449 //x, mask_cursor_x, y, mask_cursor_y, line_distance, shortest_line_distance, shortest_point1, shortest_point2);
1450                                         if(line_distance < shortest_line_distance || 
1451                                                 shortest_point1 < 0)
1452                                         {
1453                                                 shortest_line_distance = line_distance;
1454                                                 shortest_point1 = i;
1455                                                 shortest_point2 = (i >= points.size() - 1) ? 0 : (i + 1);
1456 //printf("CWindowCanvas::do_mask 2 %f %f %d, %d\n", line_distance, shortest_line_distance, shortest_point1, shortest_point2);
1457                                         }
1458
1459
1460                                         float point_distance1 = 
1461                                                 sqrt(SQR(point1->x - mask_cursor_x) + SQR(point1->y - mask_cursor_y));
1462                                         float point_distance2 = 
1463                                                 sqrt(SQR(point2->x - mask_cursor_x) + SQR(point2->y - mask_cursor_y));
1464
1465                                         if(point_distance1 < shortest_point_distance || 
1466                                                 shortest_point < 0)
1467                                         {
1468                                                 shortest_point_distance = point_distance1;
1469                                                 shortest_point = i;
1470                                         }
1471
1472                                         if(point_distance2 < shortest_point_distance || 
1473                                                 shortest_point < 0)
1474                                         {
1475                                                 shortest_point_distance = point_distance2;
1476                                                 shortest_point = (i >= points.size() - 1) ? 0 : (i + 1);
1477                                         }
1478                                 }
1479
1480                                 output_to_canvas(mwindow->edl, 0, x, y);
1481
1482
1483 #define TEST_BOX(cursor_x, cursor_y, target_x, target_y) \
1484         (cursor_x >= target_x - CONTROL_W / 2 && \
1485         cursor_x < target_x + CONTROL_W / 2 && \
1486         cursor_y >= target_y - CONTROL_H / 2 && \
1487         cursor_y < target_y + CONTROL_H / 2)
1488
1489 // Test existing point selection
1490                                 if(button_press)
1491                                 {
1492                                         float canvas_x = (x0 - half_track_w) * projector_z + projector_x;
1493                                         float canvas_y = (y0 - half_track_h) * projector_z + projector_y;
1494                                         int cursor_x = get_cursor_x();
1495                                         int cursor_y = get_cursor_y();
1496
1497 // Test first point
1498                                         if(gui->shift_down())
1499                                         {
1500                                                 float control_x = (x1 - half_track_w) * projector_z + projector_x;
1501                                                 float control_y = (y1 - half_track_h) * projector_z + projector_y;
1502                                                 output_to_canvas(mwindow->edl, 0, control_x, control_y);
1503
1504                                                 float distance = 
1505                                                         sqrt(SQR(control_x - cursor_x) + SQR(control_y - cursor_y));
1506
1507                                                 if(distance < selected_control_point_distance)
1508                                                 {
1509                                                         selected_point = i;
1510                                                         selected_control_point = 1;
1511                                                         selected_control_point_distance = distance;
1512                                                 }
1513                                         }
1514                                         else
1515                                         {
1516                                                 output_to_canvas(mwindow->edl, 0, canvas_x, canvas_y);
1517                                                 if(!gui->ctrl_down())
1518                                                 {
1519                                                         if(TEST_BOX(cursor_x, cursor_y, canvas_x, canvas_y))
1520                                                         {
1521                                                                 selected_point = i;
1522                                                         }
1523                                                 }
1524                                                 else
1525                                                 {
1526                                                         selected_point = shortest_point;
1527                                                 }
1528                                         }
1529
1530 // Test second point
1531                                         canvas_x = (x3 - half_track_w) * projector_z + projector_x;
1532                                         canvas_y = (y3 - half_track_h) * projector_z + projector_y;
1533                                         if(gui->shift_down())
1534                                         {
1535                                                 float control_x = (x2 - half_track_w) * projector_z + projector_x;
1536                                                 float control_y = (y2 - half_track_h) * projector_z + projector_y;
1537                                                 output_to_canvas(mwindow->edl, 0, control_x, control_y);
1538
1539                                                 float distance = 
1540                                                         sqrt(SQR(control_x - cursor_x) + SQR(control_y - cursor_y));
1541
1542 //printf("CWindowCanvas::do_mask %d %f %f\n", i, distance, selected_control_point_distance);
1543                                                 if(distance < selected_control_point_distance)
1544                                                 {
1545                                                         selected_point = (i < points.size() - 1 ? i + 1 : 0);
1546                                                         selected_control_point = 0;
1547                                                         selected_control_point_distance = distance;
1548                                                 }
1549                                         }
1550                                         else
1551                                         if(i < points.size() - 1)
1552                                         {
1553                                                 output_to_canvas(mwindow->edl, 0, canvas_x, canvas_y);
1554                                                 if(!gui->ctrl_down())
1555                                                 {
1556                                                         if(TEST_BOX(cursor_x, cursor_y, canvas_x, canvas_y))
1557                                                         {
1558                                                                 selected_point = (i < points.size() - 1 ? i + 1 : 0);
1559                                                         }
1560                                                 }
1561                                                 else
1562                                                 {
1563                                                         selected_point = shortest_point;
1564                                                 }
1565                                         }
1566                                 }
1567
1568
1569
1570                                 if(j > 0)
1571                                 {
1572 // Draw joining line
1573                                         if(draw)
1574                                         {
1575                                                 x_points.append((int)x);
1576                                                 y_points.append((int)y);
1577                                         }
1578
1579                                         if(j == segments)
1580                                         {
1581
1582
1583
1584
1585                                                 if(draw)
1586                                                 {
1587 // Draw second anchor
1588                                                         if(i < points.size() - 1)
1589                                                         {
1590                                                                 if(i == gui->affected_point - 1)
1591                                                                         get_canvas()->draw_disc((int)x - CONTROL_W / 2, 
1592                                                                                 (int)y - CONTROL_W / 2, 
1593                                                                                 CONTROL_W, 
1594                                                                                 CONTROL_W);
1595                                                                 else
1596                                                                         get_canvas()->draw_circle((int)x - CONTROL_W / 2, 
1597                                                                                 (int)y - CONTROL_W / 2, 
1598                                                                                 CONTROL_W, 
1599                                                                                 CONTROL_W);
1600 // char string[BCTEXTLEN];
1601 // sprintf(string, "%d", (i < points.size() - 1 ? i + 1 : 0));
1602 // canvas->draw_text((int)x + CONTROL_W, (int)y + CONTROL_W, string);
1603                                                         }
1604
1605 // Draw second control point.  Discard x2 and y2 after this.
1606                                                         x2 = (x2 - half_track_w) * projector_z + projector_x;
1607                                                         y2 = (y2 - half_track_h) * projector_z + projector_y;
1608                                                         output_to_canvas(mwindow->edl, 0, x2, y2);
1609                                                         get_canvas()->draw_line((int)x, (int)y, (int)x2, (int)y2);
1610                                                         get_canvas()->draw_rectangle((int)x2 - CONTROL_W / 2,
1611                                                                 (int)y2 - CONTROL_H / 2,
1612                                                                 CONTROL_W,
1613                                                                 CONTROL_H);
1614                                                 }
1615                                         }
1616                                 }
1617                                 else
1618                                 {
1619
1620
1621 // Draw first anchor
1622                                         if(i == 0 && draw)
1623                                         {
1624                                                 get_canvas()->draw_disc((int)x - FIRST_CONTROL_W / 2, 
1625                                                         (int)y - FIRST_CONTROL_H / 2, 
1626                                                         FIRST_CONTROL_W, 
1627                                                         FIRST_CONTROL_H);
1628                                         }
1629
1630 // Draw first control point.  Discard x1 and y1 after this.
1631                                         if(draw)
1632                                         {
1633                                                 x1 = (x1 - half_track_w) * projector_z + projector_x;
1634                                                 y1 = (y1 - half_track_h) * projector_z + projector_y;
1635                                                 output_to_canvas(mwindow->edl, 0, x1, y1);
1636                                                 get_canvas()->draw_line((int)x, (int)y, (int)x1, (int)y1);
1637                                                 get_canvas()->draw_rectangle((int)x1 - CONTROL_W / 2,
1638                                                         (int)y1 - CONTROL_H / 2,
1639                                                         CONTROL_W,
1640                                                         CONTROL_H);
1641                                         
1642                                                 x_points.append((int)x);
1643                                                 y_points.append((int)y);
1644                                         }
1645                                 }
1646 //printf("CWindowCanvas::do_mask 1\n");
1647
1648                         }
1649                 }
1650 //printf("CWindowCanvas::do_mask 1\n");
1651
1652                 if(draw)
1653                 {
1654                         get_canvas()->draw_polygon(&x_points, &y_points);
1655                         get_canvas()->set_opaque();
1656                 }
1657 //printf("CWindowCanvas::do_mask 1\n");
1658         }
1659
1660
1661
1662
1663
1664
1665
1666         if(button_press && !result)
1667         {
1668                 gui->affected_track = gui->cwindow->calculate_affected_track();
1669
1670 // Get keyframe outside the EDL to edit.  This must be rendered
1671 // instead of the EDL keyframes when it exists.  Then it must be
1672 // applied to the EDL keyframes on buttonrelease.
1673                 if(gui->affected_track)
1674                 {
1675 #ifdef USE_KEYFRAME_SPANNING
1676 // Make copy of current parameters in local keyframe
1677                         gui->mask_keyframe = 
1678                                 (MaskAuto*)gui->cwindow->calculate_affected_auto(
1679                                         mask_autos,
1680                                         0);
1681                         gui->orig_mask_keyframe->copy_data(gui->mask_keyframe);
1682 #else
1683
1684                         gui->mask_keyframe = 
1685                                 (MaskAuto*)gui->cwindow->calculate_affected_auto(
1686                                         mask_autos,
1687                                         1);
1688 #endif
1689                 }
1690                 SubMask *mask = gui->mask_keyframe->get_submask(mwindow->edl->session->cwindow_mask);
1691
1692
1693 // Translate entire keyframe
1694                 if(gui->alt_down() && mask->points.size())
1695                 {
1696                         mwindow->undo->update_undo_before(_("mask translate"), 0);
1697                         gui->current_operation = CWINDOW_MASK_TRANSLATE;
1698                         gui->affected_point = 0;
1699                 }
1700                 else
1701 // Existing point or control point was selected
1702                 if(selected_point >= 0)
1703                 {
1704                         mwindow->undo->update_undo_before(_("mask adjust"), 0);
1705                         gui->affected_point = selected_point;
1706
1707                         if(selected_control_point == 0)
1708                                 gui->current_operation = CWINDOW_MASK_CONTROL_IN;
1709                         else
1710                         if(selected_control_point == 1)
1711                                 gui->current_operation = CWINDOW_MASK_CONTROL_OUT;
1712                         else
1713                                 gui->current_operation = mwindow->edl->session->cwindow_operation;
1714                 }
1715                 else
1716 // No existing point or control point was selected so create a new one
1717                 if(!gui->shift_down() && !gui->alt_down())
1718                 {
1719                         mwindow->undo->update_undo_before(_("mask point"), 0);
1720 // Create the template
1721                         MaskPoint *point = new MaskPoint;
1722                         point->x = mask_cursor_x;
1723                         point->y = mask_cursor_y;
1724                         point->control_x1 = 0;
1725                         point->control_y1 = 0;
1726                         point->control_x2 = 0;
1727                         point->control_y2 = 0;
1728
1729
1730                         if(shortest_point2 < shortest_point1)
1731                         {
1732                                 shortest_point2 ^= shortest_point1;
1733                                 shortest_point1 ^= shortest_point2;
1734                                 shortest_point2 ^= shortest_point1;
1735                         }
1736
1737
1738
1739 // printf("CWindowGUI::do_mask 40\n");
1740 // mwindow->edl->dump();
1741 // printf("CWindowGUI::do_mask 50\n");
1742
1743
1744
1745 //printf("CWindowCanvas::do_mask 1 %f %f %d %d\n", 
1746 //      shortest_line_distance, shortest_point_distance, shortest_point1, shortest_point2);
1747 //printf("CWindowCanvas::do_mask %d %d\n", shortest_point1, shortest_point2);
1748
1749 // Append to end of list
1750                         if(labs(shortest_point1 - shortest_point2) > 1)
1751                         {
1752 #ifdef USE_KEYFRAME_SPANNING
1753
1754                                 MaskPoint *new_point = new MaskPoint;
1755                                 points.append(new_point);
1756                                 *new_point = *point;
1757                                 gui->affected_point = points.size() - 1;
1758
1759 #else
1760
1761 // Need to apply the new point to every keyframe
1762                                 for(MaskAuto *current = (MaskAuto*)mask_autos->default_auto;
1763                                         current; )
1764                                 {
1765                                         SubMask *submask = current->get_submask(mwindow->edl->session->cwindow_mask);
1766                                         MaskPoint *new_point = new MaskPoint;
1767                                         submask->points.append(new_point);
1768                                         *new_point = *point;
1769                                         if(current == (MaskAuto*)mask_autos->default_auto)
1770                                                 current = (MaskAuto*)mask_autos->first;
1771                                         else
1772                                                 current = (MaskAuto*)NEXT;
1773                                 }
1774                                 gui->affected_point = mask->points.size() - 1;
1775 #endif
1776
1777                                 result = 1;
1778                         }
1779                         else
1780 // Insert between 2 points, shifting back point 2
1781                         if(shortest_point1 >= 0 && shortest_point2 >= 0)
1782                         {
1783
1784 #ifdef USE_KEYFRAME_SPANNING
1785 // In case the keyframe point count isn't synchronized with the rest of the keyframes,
1786 // avoid a crash.
1787                                 if(points.size() >= shortest_point2)
1788                                 {
1789                                         MaskPoint *new_point = new MaskPoint;
1790                                         points.append(0);
1791                                         for(int i = points.size() - 1; 
1792                                                 i > shortest_point2; 
1793                                                 i--)
1794                                                 points.values[i] = points.values[i - 1];
1795                                         points.values[shortest_point2] = new_point;
1796
1797                                         *new_point = *point;
1798                                 }
1799
1800 #else
1801
1802                                 for(MaskAuto *current = (MaskAuto*)mask_autos->default_auto;
1803                                         current; )
1804                                 {
1805                                         SubMask *submask = current->get_submask(mwindow->edl->session->cwindow_mask);
1806 // In case the keyframe point count isn't synchronized with the rest of the keyframes,
1807 // avoid a crash.
1808                                         if(submask->points.size() >= shortest_point2)
1809                                         {
1810                                                 MaskPoint *new_point = new MaskPoint;
1811                                                 submask->points.append(0);
1812                                                 for(int i = submask->points.size() - 1; 
1813                                                         i > shortest_point2; 
1814                                                         i--)
1815                                                         submask->points.values[i] = submask->points.values[i - 1];
1816                                                 submask->points.values[shortest_point2] = new_point;
1817
1818                                                 *new_point = *point;
1819                                         }
1820
1821                                         if(current == (MaskAuto*)mask_autos->default_auto)
1822                                                 current = (MaskAuto*)mask_autos->first;
1823                                         else
1824                                                 current = (MaskAuto*)NEXT;
1825                                 }
1826 #endif
1827
1828
1829                                 gui->affected_point = shortest_point2;
1830                                 result = 1;
1831                         }
1832
1833
1834 // printf("CWindowGUI::do_mask 20\n");
1835 // mwindow->edl->dump();
1836 // printf("CWindowGUI::do_mask 30\n");
1837
1838
1839
1840
1841                         if(!result)
1842                         {
1843 //printf("CWindowCanvas::do_mask 1\n");
1844 // Create the first point.
1845 #ifdef USE_KEYFRAME_SPANNING
1846                                 MaskPoint *new_point = new MaskPoint;
1847                                 points.append(new_point);
1848                                 *new_point = *point;
1849 #else
1850                                 for(MaskAuto *current = (MaskAuto*)mask_autos->default_auto;
1851                                         current; )
1852                                 {
1853                                         SubMask *submask = current->get_submask(mwindow->edl->session->cwindow_mask);
1854                                         MaskPoint *new_point = new MaskPoint;
1855                                         submask->points.append(new_point);
1856                                         *new_point = *point;
1857                                         if(current == (MaskAuto*)mask_autos->default_auto)
1858                                                 current = (MaskAuto*)mask_autos->first;
1859                                         else
1860                                                 current = (MaskAuto*)NEXT;
1861                                 }
1862 #endif
1863
1864 //printf("CWindowCanvas::do_mask 2\n");
1865 // Create a second point if none existed before
1866 #ifdef USE_KEYFRAME_SPANNING
1867                                 if(points.size() < 2)
1868                                 {
1869
1870                                         MaskPoint *new_point = new MaskPoint;
1871                                         points.append(new_point);
1872                                         *new_point = *point;
1873                                 }
1874
1875                                 gui->affected_point = points.size() - 1;
1876 #else
1877                                 if(mask->points.size() < 2)
1878                                 {
1879
1880                                         for(MaskAuto *current = (MaskAuto*)mask_autos->default_auto;
1881                                                 current; )
1882                                         {
1883                                                 SubMask *submask = current->get_submask(mwindow->edl->session->cwindow_mask);
1884                                                 MaskPoint *new_point = new MaskPoint;
1885                                                 submask->points.append(new_point);
1886                                                 *new_point = *point;
1887                                                 if(current == (MaskAuto*)mask_autos->default_auto)
1888                                                         current = (MaskAuto*)mask_autos->first;
1889                                                 else
1890                                                         current = (MaskAuto*)NEXT;
1891                                         }
1892                                 }
1893
1894                                 gui->affected_point = mask->points.size() - 1;
1895 #endif
1896
1897 //printf("CWindowCanvas::do_mask 3 %d\n", mask->points.size());
1898                         }
1899
1900
1901
1902                         gui->current_operation = mwindow->edl->session->cwindow_operation;
1903 // Delete the template
1904                         delete point;
1905
1906                 }
1907
1908                 result = 1;
1909                 rerender = 1;
1910                 redraw = 1;
1911         }
1912
1913         if(button_press && result)
1914         {
1915 #ifdef USE_KEYFRAME_SPANNING
1916                 MaskPoint *point = points.values[gui->affected_point];
1917                 gui->center_x = point->x;
1918                 gui->center_y = point->y;
1919                 gui->control_in_x = point->control_x1;
1920                 gui->control_in_y = point->control_y1;
1921                 gui->control_out_x = point->control_x2;
1922                 gui->control_out_y = point->control_y2;
1923                 gui->tool_panel->raise_window();
1924 #else
1925                 SubMask *mask = gui->mask_keyframe->get_submask(mwindow->edl->session->cwindow_mask);
1926                 MaskPoint *point = mask->points.values[gui->affected_point];
1927                 gui->center_x = point->x;
1928                 gui->center_y = point->y;
1929                 gui->control_in_x = point->control_x1;
1930                 gui->control_in_y = point->control_y1;
1931                 gui->control_out_x = point->control_x2;
1932                 gui->control_out_y = point->control_y2;
1933                 gui->tool_panel->raise_window();
1934 #endif
1935         }
1936
1937 //printf("CWindowCanvas::do_mask 8\n");
1938         if(cursor_motion)
1939         {
1940
1941 #ifdef USE_KEYFRAME_SPANNING
1942 // Must update the reference keyframes for every cursor motion
1943                 gui->mask_keyframe = 
1944                         (MaskAuto*)gui->cwindow->calculate_affected_auto(
1945                                 mask_autos,
1946                                 0);
1947                 gui->orig_mask_keyframe->copy_data(gui->mask_keyframe);
1948 #endif
1949
1950 //printf("CWindowCanvas::do_mask %d %d\n", __LINE__, gui->affected_point);
1951
1952                 SubMask *mask = gui->mask_keyframe->get_submask(mwindow->edl->session->cwindow_mask);
1953                 if(gui->affected_point < mask->points.size() &&
1954                         gui->current_operation != CWINDOW_NONE)
1955                 {
1956 //                      mwindow->undo->update_undo_before(_("mask point"), this);
1957 #ifdef USE_KEYFRAME_SPANNING
1958                         MaskPoint *point = points.get(gui->affected_point);
1959 #else
1960                         MaskPoint *point = mask->points.get(gui->affected_point);
1961 #endif
1962 //                      float cursor_x = get_cursor_x();
1963 //                      float cursor_y = get_cursor_y();
1964 //                      canvas_to_output(mwindow->edl, 0, cursor_x, cursor_y);
1965                         float cursor_x = mask_cursor_x;
1966                         float cursor_y = mask_cursor_y;
1967 //printf("CWindowCanvas::do_mask 9 %d %d\n", mask->points.size(), gui->affected_point);
1968
1969                         float last_x = point->x;
1970                         float last_y = point->y;
1971                         float last_control_x1 = point->control_x1;
1972                         float last_control_y1 = point->control_y1;
1973                         float last_control_x2 = point->control_x2;
1974                         float last_control_y2 = point->control_y2;
1975
1976
1977                         switch(gui->current_operation)
1978                         {
1979                                 case CWINDOW_MASK:
1980 //printf("CWindowCanvas::do_mask %d %d\n", __LINE__, gui->affected_point);
1981                                         point->x = cursor_x - gui->x_origin + gui->center_x;
1982                                         point->y = cursor_y - gui->y_origin + gui->center_y;
1983                                         break;
1984
1985                                 case CWINDOW_MASK_CONTROL_IN:
1986                                         point->control_x1 = cursor_x - gui->x_origin + gui->control_in_x;
1987                                         point->control_y1 = cursor_y - gui->y_origin + gui->control_in_y;
1988                                         break;
1989
1990                                 case CWINDOW_MASK_CONTROL_OUT:
1991                                         point->control_x2 = cursor_x - gui->x_origin + gui->control_out_x;
1992                                         point->control_y2 = cursor_y - gui->y_origin + gui->control_out_y;
1993                                         break;
1994
1995                                 case CWINDOW_MASK_TRANSLATE:
1996 #ifdef USE_KEYFRAME_SPANNING
1997                                         for(int i = 0; i < points.size(); i++)
1998                                         {
1999                                                 points.values[i]->x += cursor_x - gui->x_origin;
2000                                                 points.values[i]->y += cursor_y - gui->y_origin;
2001                                         }
2002 #else
2003                                         for(int i = 0; i < mask->points.size(); i++)
2004                                         {
2005                                                 mask->points.values[i]->x += cursor_x - gui->x_origin;
2006                                                 mask->points.values[i]->y += cursor_y - gui->y_origin;
2007                                         }
2008 #endif
2009                                         gui->x_origin = cursor_x;
2010                                         gui->y_origin = cursor_y;
2011                                         break;
2012                         }
2013
2014
2015                         if( !EQUIV(last_x, point->x) ||
2016                                 !EQUIV(last_y, point->y) ||
2017                                 !EQUIV(last_control_x1, point->control_x1) ||
2018                                 !EQUIV(last_control_y1, point->control_y1) ||
2019                                 !EQUIV(last_control_x2, point->control_x2) ||
2020                                 !EQUIV(last_control_y2, point->control_y2))
2021                         {
2022                                 rerender = 1;
2023                                 redraw = 1;
2024                         }
2025                 }
2026                 else
2027                 if(gui->current_operation == CWINDOW_NONE)
2028                 {
2029 //                      printf("CWindowCanvas::do_mask %d\n", __LINE__);
2030                         int over_point = 0;
2031                         for(int i = 0; i < points.size() && !over_point; i++)
2032                         {
2033                                 MaskPoint *point = points.get(i);
2034                                 float x0 = point->x;
2035                                 float y0 = point->y;
2036                                 float x1 = point->x + point->control_x1;
2037                                 float y1 = point->y + point->control_y1;
2038                                 float x2 = point->x + point->control_x2;
2039                                 float y2 = point->y + point->control_y2;
2040                                 float canvas_x = (x0 - half_track_w) * projector_z + projector_x;
2041                                 float canvas_y = (y0 - half_track_h) * projector_z + projector_y;
2042                                 int cursor_x = get_cursor_x();
2043                                 int cursor_y = get_cursor_y();
2044                                 
2045                                 output_to_canvas(mwindow->edl, 0, canvas_x, canvas_y);
2046                                 if(TEST_BOX(cursor_x, cursor_y, canvas_x, canvas_y))
2047                                 {
2048                                         over_point = 1;
2049                                 }
2050                                 
2051                                 
2052                                 if(!over_point && gui->shift_down())
2053                                 {
2054                                         canvas_x = (x1 - half_track_w) * projector_z + projector_x;
2055                                         canvas_y = (y1 - half_track_h) * projector_z + projector_y;
2056                                         output_to_canvas(mwindow->edl, 0, canvas_x, canvas_y);
2057                                         if(TEST_BOX(cursor_x, cursor_y, canvas_x, canvas_y))
2058                                         {
2059                                                 over_point = 1;
2060                                         }
2061                                         else
2062                                         {
2063                                                 canvas_x = (x2 - half_track_w) * projector_z + projector_x;
2064                                                 canvas_y = (y2 - half_track_h) * projector_z + projector_y;
2065                                                 output_to_canvas(mwindow->edl, 0, canvas_x, canvas_y);
2066                                                 if(TEST_BOX(cursor_x, cursor_y, canvas_x, canvas_y))
2067                                                 {
2068                                                         over_point = 1;
2069                                                 }
2070                                         }
2071                                 }
2072                         }
2073                         
2074                         if(over_point)
2075                         {
2076                                 set_cursor(ARROW_CURSOR);
2077                         }
2078                         else
2079                         {
2080                                 set_cursor(CROSS_CURSOR);
2081                         }
2082                 }
2083                 
2084                 result = 1;
2085         }
2086 //printf("CWindowCanvas::do_mask 2 %d %d %d\n", result, rerender, redraw);
2087
2088
2089 #ifdef USE_KEYFRAME_SPANNING
2090 // Must commit change after operation.
2091         if(rerender && track)
2092         {
2093 // Swap EDL keyframe with original.
2094 // Apply new values to keyframe span
2095                 MaskAuto temp_keyframe(mwindow->edl, mask_autos);
2096                 temp_keyframe.copy_data(gui->mask_keyframe);
2097 // Apply interpolated points back to keyframe
2098                 temp_keyframe.set_points(&points, mwindow->edl->session->cwindow_mask);
2099                 gui->mask_keyframe->copy_data(gui->orig_mask_keyframe);
2100                 mask_autos->update_parameter(&temp_keyframe);
2101         }
2102 #endif
2103
2104         points.remove_all_objects();
2105 //printf("CWindowCanvas::do_mask 20\n");
2106         return result;
2107 }
2108
2109
2110 int CWindowCanvas::do_eyedrop(int &rerender, int button_press, int draw)
2111 {
2112         int result = 0;
2113         int radius = mwindow->edl->session->eyedrop_radius;
2114         int row1 = 0;
2115         int row2 = 0;
2116         int column1 = 0;
2117         int column2 = 0;
2118
2119
2120
2121         if(refresh_frame)
2122         {
2123
2124                 if(draw)
2125                 {
2126                         row1 = gui->eyedrop_y - radius;
2127                         row2 = gui->eyedrop_y + radius;
2128                         column1 = gui->eyedrop_x - radius;
2129                         column2 = gui->eyedrop_x + radius;
2130
2131                         CLAMP(row1, 0, refresh_frame->get_h() - 1);
2132                         CLAMP(row2, 0, refresh_frame->get_h() - 1);
2133                         CLAMP(column1, 0, refresh_frame->get_w() - 1);
2134                         CLAMP(column2, 0, refresh_frame->get_w() - 1);
2135
2136                         if(row2 <= row1) row2 = row1 + 1;
2137                         if(column2 <= column1) column2 = column1 + 1;
2138
2139                         float x1 = column1;
2140                         float y1 = row1;
2141                         float x2 = column2;
2142                         float y2 = row2;
2143
2144                         output_to_canvas(mwindow->edl, 0, x1, y1);
2145                         output_to_canvas(mwindow->edl, 0, x2, y2);
2146 //printf("CWindowCanvas::do_eyedrop %d %f %f %f %f\n", __LINE__, x1, x2, y1, y2);
2147
2148                         if(x2 - x1 >= 1 && y2 - y1 >= 1)
2149                         {
2150                                 get_canvas()->set_inverse();
2151                                 get_canvas()->set_color(WHITE);
2152
2153                                 get_canvas()->draw_rectangle((int)x1, 
2154                                         (int)y1, 
2155                                         (int)(x2 - x1), 
2156                                         (int)(y2 - y1));
2157
2158                                 get_canvas()->set_opaque();
2159                                 get_canvas()->flash();
2160                         }
2161                         return 0;
2162                 }
2163         }
2164
2165         if(button_press)
2166         {
2167                 gui->current_operation = CWINDOW_EYEDROP;
2168                 gui->tool_panel->raise_window();
2169         }
2170
2171         if(gui->current_operation == CWINDOW_EYEDROP)
2172         {
2173                 mwindow->undo->update_undo_before(_("Eyedrop"), this);
2174
2175 // Get color out of frame.
2176 // Doesn't work during playback because that bypasses the refresh frame.
2177                 if(refresh_frame)
2178                 {
2179                         float cursor_x = get_cursor_x();
2180                         float cursor_y = get_cursor_y();
2181                         canvas_to_output(mwindow->edl, 0, cursor_x, cursor_y);
2182                         CLAMP(cursor_x, 0, refresh_frame->get_w() - 1);
2183                         CLAMP(cursor_y, 0, refresh_frame->get_h() - 1);
2184
2185                         row1 = cursor_y - radius;
2186                         row2 = cursor_y + radius;
2187                         column1 = cursor_x - radius;
2188                         column2 = cursor_x + radius;
2189                         CLAMP(row1, 0, refresh_frame->get_h() - 1);
2190                         CLAMP(row2, 0, refresh_frame->get_h() - 1);
2191                         CLAMP(column1, 0, refresh_frame->get_w() - 1);
2192                         CLAMP(column2, 0, refresh_frame->get_w() - 1);
2193                         if(row2 <= row1) row2 = row1 + 1;
2194                         if(column2 <= column1) column2 = column1 + 1;
2195
2196
2197 // hide it
2198                         if(gui->eyedrop_visible)
2199                         {
2200                                 int temp;
2201                                 do_eyedrop(temp, 0, 1);
2202                                 gui->eyedrop_visible = 0;
2203                         }
2204
2205                         gui->eyedrop_x = cursor_x;
2206                         gui->eyedrop_y = cursor_y;
2207
2208 // show it
2209                         {
2210                                 int temp;
2211                                 do_eyedrop(temp, 0, 1);
2212                                 gui->eyedrop_visible = 1;
2213                         }
2214
2215 // Decompression coefficients straight out of jpeglib
2216 #define V_TO_R    1.40200
2217 #define V_TO_G    -0.71414
2218
2219 #define U_TO_G    -0.34414
2220 #define U_TO_B    1.77200
2221
2222 #define GET_COLOR(type, components, max, do_yuv) \
2223 { \
2224         type *row = (type*)(refresh_frame->get_rows()[i]) + \
2225                 j * components; \
2226         float red = (float)*row++ / max; \
2227         float green = (float)*row++ / max; \
2228         float blue = (float)*row++ / max; \
2229         if(do_yuv) \
2230         { \
2231                 mwindow->edl->local_session->red += red + V_TO_R * (blue - 0.5); \
2232                 mwindow->edl->local_session->green += red + U_TO_G * (green - 0.5) + V_TO_G * (blue - 0.5); \
2233                 mwindow->edl->local_session->blue += red + U_TO_B * (green - 0.5); \
2234         } \
2235         else \
2236         { \
2237                 mwindow->edl->local_session->red += red; \
2238                 mwindow->edl->local_session->green += green; \
2239                 mwindow->edl->local_session->blue += blue; \
2240         } \
2241 }
2242
2243
2244
2245                         mwindow->edl->local_session->red = 0;
2246                         mwindow->edl->local_session->green = 0;
2247                         mwindow->edl->local_session->blue = 0;
2248                         for(int i = row1; i < row2; i++)
2249                         {
2250                                 for(int j = column1; j < column2; j++)
2251                                 {
2252                                         switch(refresh_frame->get_color_model())
2253                                         {
2254                                                 case BC_YUV888:
2255                                                         GET_COLOR(unsigned char, 3, 0xff, 1);
2256                                                         break;
2257                                                 case BC_YUVA8888:
2258                                                         GET_COLOR(unsigned char, 4, 0xff, 1);
2259                                                         break;
2260                                                 case BC_YUV161616:
2261                                                         GET_COLOR(uint16_t, 3, 0xffff, 1);
2262                                                         break;
2263                                                 case BC_YUVA16161616:
2264                                                         GET_COLOR(uint16_t, 4, 0xffff, 1);
2265                                                         break;
2266                                                 case BC_RGB888:
2267                                                         GET_COLOR(unsigned char, 3, 0xff, 0);
2268                                                         break;
2269                                                 case BC_RGBA8888:
2270                                                         GET_COLOR(unsigned char, 4, 0xff, 0);
2271                                                         break;
2272                                                 case BC_RGB_FLOAT:
2273                                                         GET_COLOR(float, 3, 1.0, 0);
2274                                                         break;
2275                                                 case BC_RGBA_FLOAT:
2276                                                         GET_COLOR(float, 4, 1.0, 0);
2277                                                         break;
2278                                         }
2279                                 }
2280                         }
2281                         
2282                         mwindow->edl->local_session->red /= (row2 - row1) * (column2 - column1);
2283                         mwindow->edl->local_session->green /= (row2 - row1) * (column2 - column1);
2284                         mwindow->edl->local_session->blue /= (row2 - row1) * (column2 - column1);
2285
2286                 }
2287                 else
2288                 {
2289                         mwindow->edl->local_session->red = 0;
2290                         mwindow->edl->local_session->green = 0;
2291                         mwindow->edl->local_session->blue = 0;
2292                         gui->eyedrop_visible = 0;
2293                 }
2294
2295
2296                 gui->update_tool();             
2297
2298
2299
2300                 result = 1;
2301 // Can't rerender since the color value is from the output of any effect it
2302 // goes into.
2303 //              rerender = 1;
2304                 mwindow->undo->update_undo_after(_("Eyedrop"), LOAD_SESSION);
2305         }
2306
2307         return result;
2308 }
2309
2310 void CWindowCanvas::draw_overlays()
2311 {
2312         if(mwindow->edl->session->safe_regions)
2313         {
2314                 draw_safe_regions();
2315         }
2316
2317         if(mwindow->edl->session->cwindow_scrollbars)
2318         {
2319 // Always draw output rectangle
2320                 float x1, y1, x2, y2;
2321                 x1 = 0;
2322                 x2 = mwindow->edl->session->output_w;
2323                 y1 = 0;
2324                 y2 = mwindow->edl->session->output_h;
2325                 output_to_canvas(mwindow->edl, 0, x1, y1);
2326                 output_to_canvas(mwindow->edl, 0, x2, y2);
2327
2328                 get_canvas()->set_inverse();
2329                 get_canvas()->set_color(WHITE);
2330
2331                 get_canvas()->draw_rectangle((int)x1, 
2332                                 (int)y1, 
2333                                 (int)(x2 - x1), 
2334                                 (int)(y2 - y1));
2335
2336                 get_canvas()->set_opaque();
2337         }
2338
2339         if(mwindow->session->ccanvas_highlighted)
2340         {
2341                 get_canvas()->set_color(WHITE);
2342                 get_canvas()->set_inverse();
2343                 get_canvas()->draw_rectangle(0, 0, get_canvas()->get_w(), get_canvas()->get_h());
2344                 get_canvas()->draw_rectangle(1, 1, get_canvas()->get_w() - 2, get_canvas()->get_h() - 2);
2345                 get_canvas()->set_opaque();
2346         }
2347
2348         int temp1 = 0, temp2 = 0;
2349 //printf("CWindowCanvas::draw_overlays 1 %d\n", mwindow->edl->session->cwindow_operation);
2350         switch(mwindow->edl->session->cwindow_operation)
2351         {
2352                 case CWINDOW_CAMERA:
2353                         draw_bezier(1);
2354                         break;
2355
2356                 case CWINDOW_PROJECTOR:
2357                         draw_bezier(0);
2358                         break;
2359
2360                 case CWINDOW_CROP:
2361                         draw_crop();
2362                         break;
2363
2364                 case CWINDOW_MASK:
2365                         do_mask(temp1, temp2, 0, 0, 1);
2366                         break;
2367
2368                 case CWINDOW_RULER:
2369                         do_ruler(1, 0, 0, 0);
2370                         break;
2371
2372                 case CWINDOW_EYEDROP:
2373                 if(gui->eyedrop_visible)
2374                 {
2375                         int rerender;
2376                         do_eyedrop(rerender, 0, 1);
2377                         gui->eyedrop_visible = 1;
2378                         break;
2379                 }
2380         }
2381 }
2382
2383 void CWindowCanvas::draw_safe_regions()
2384 {
2385         float action_x1, action_x2, action_y1, action_y2;
2386         float title_x1, title_x2, title_y1, title_y2;
2387
2388         action_x1 = mwindow->edl->session->output_w / 2 - mwindow->edl->session->output_w / 2 * 0.9;
2389         action_x2 = mwindow->edl->session->output_w / 2 + mwindow->edl->session->output_w / 2 * 0.9;
2390         action_y1 = mwindow->edl->session->output_h / 2 - mwindow->edl->session->output_h / 2 * 0.9;
2391         action_y2 = mwindow->edl->session->output_h / 2 + mwindow->edl->session->output_h / 2 * 0.9;
2392         title_x1 = mwindow->edl->session->output_w / 2 - mwindow->edl->session->output_w / 2 * 0.8;
2393         title_x2 = mwindow->edl->session->output_w / 2 + mwindow->edl->session->output_w / 2 * 0.8;
2394         title_y1 = mwindow->edl->session->output_h / 2 - mwindow->edl->session->output_h / 2 * 0.8;
2395         title_y2 = mwindow->edl->session->output_h / 2 + mwindow->edl->session->output_h / 2 * 0.8;
2396
2397         output_to_canvas(mwindow->edl, 0, action_x1, action_y1);
2398         output_to_canvas(mwindow->edl, 0, action_x2, action_y2);
2399         output_to_canvas(mwindow->edl, 0, title_x1, title_y1);
2400         output_to_canvas(mwindow->edl, 0, title_x2, title_y2);
2401
2402         get_canvas()->set_inverse();
2403         get_canvas()->set_color(WHITE);
2404
2405         get_canvas()->draw_rectangle((int)action_x1, 
2406                         (int)action_y1, 
2407                         (int)(action_x2 - action_x1), 
2408                         (int)(action_y2 - action_y1));
2409         get_canvas()->draw_rectangle((int)title_x1, 
2410                         (int)title_y1, 
2411                         (int)(title_x2 - title_x1), 
2412                         (int)(title_y2 - title_y1));
2413
2414         get_canvas()->set_opaque();
2415 }
2416
2417 void CWindowCanvas::reset_keyframe(int do_camera)
2418 {
2419         FloatAuto *x_keyframe = 0;
2420         FloatAuto *y_keyframe = 0;
2421         FloatAuto *z_keyframe = 0;
2422         Track *affected_track = 0;
2423
2424         affected_track = gui->cwindow->calculate_affected_track();
2425
2426         if(affected_track)
2427         {
2428                 gui->cwindow->calculate_affected_autos(&x_keyframe,
2429                         &y_keyframe,
2430                         &z_keyframe,
2431                         affected_track,
2432                         do_camera,
2433                         1,
2434                         1,
2435                         1);
2436
2437                 x_keyframe->value = 0;
2438                 y_keyframe->value = 0;
2439                 z_keyframe->value = 1;
2440
2441                 mwindow->sync_parameters(CHANGE_PARAMS);
2442                 gui->update_tool();
2443         }
2444 }
2445
2446 void CWindowCanvas::reset_camera()
2447 {
2448         reset_keyframe(1);
2449 }
2450
2451 void CWindowCanvas::reset_projector()
2452 {
2453         reset_keyframe(0);
2454 }
2455
2456 int CWindowCanvas::test_crop(int button_press, int &redraw)
2457 {
2458         int result = 0;
2459         int handle_selected = -1;
2460         float x1 = mwindow->edl->session->crop_x1;
2461         float y1 = mwindow->edl->session->crop_y1;
2462         float x2 = mwindow->edl->session->crop_x2;
2463         float y2 = mwindow->edl->session->crop_y2;
2464         float cursor_x = get_cursor_x();
2465         float cursor_y = get_cursor_y();
2466         float canvas_x1 = x1;
2467         float canvas_y1 = y1;
2468         float canvas_x2 = x2;
2469         float canvas_y2 = y2;
2470         float canvas_cursor_x = cursor_x;
2471         float canvas_cursor_y = cursor_y;
2472
2473         canvas_to_output(mwindow->edl, 0, cursor_x, cursor_y);
2474 // Use screen normalized coordinates for hot spot tests.
2475         output_to_canvas(mwindow->edl, 0, canvas_x1, canvas_y1);
2476         output_to_canvas(mwindow->edl, 0, canvas_x2, canvas_y2);
2477
2478
2479         if(gui->current_operation == CWINDOW_CROP)
2480         {
2481                 handle_selected = gui->crop_handle;
2482         }
2483         else
2484         if(canvas_cursor_x >= canvas_x1 && canvas_cursor_x < canvas_x1 + CROPHANDLE_W &&
2485                 canvas_cursor_y >= canvas_y1 && canvas_cursor_y < canvas_y1 + CROPHANDLE_H)
2486         {
2487                 handle_selected = 0;
2488                 gui->crop_origin_x = x1;
2489                 gui->crop_origin_y = y1;
2490         }
2491         else
2492         if(canvas_cursor_x >= canvas_x2 - CROPHANDLE_W && canvas_cursor_x < canvas_x2 &&
2493                 canvas_cursor_y >= canvas_y1 && canvas_cursor_y < canvas_y1 + CROPHANDLE_H)
2494         {
2495                 handle_selected = 1;
2496                 gui->crop_origin_x = x2;
2497                 gui->crop_origin_y = y1;
2498         }
2499         else
2500         if(canvas_cursor_x >= canvas_x1 && canvas_cursor_x < canvas_x1 + CROPHANDLE_W &&
2501                 canvas_cursor_y >= canvas_y2 - CROPHANDLE_H && canvas_cursor_y < canvas_y2)
2502         {
2503                 handle_selected = 2;
2504                 gui->crop_origin_x = x1;
2505                 gui->crop_origin_y = y2;
2506         }
2507         else
2508         if(canvas_cursor_x >= canvas_x2 - CROPHANDLE_W && canvas_cursor_x < canvas_x2 &&
2509                 canvas_cursor_y >= canvas_y2 - CROPHANDLE_H && canvas_cursor_y < canvas_y2)
2510         {
2511                 handle_selected = 3;
2512                 gui->crop_origin_x = x2;
2513                 gui->crop_origin_y = y2;
2514         }
2515         else
2516 // Start new box
2517         {
2518                 gui->crop_origin_x = cursor_x;
2519                 gui->crop_origin_y = cursor_y;
2520         }
2521
2522 // printf("test crop %d %d\n", 
2523 //      gui->current_operation,
2524 //      handle_selected);
2525
2526 // Start dragging.
2527         if(button_press)
2528         {
2529                 if(gui->alt_down())
2530                 {
2531                         gui->crop_translate = 1;
2532                         gui->crop_origin_x1 = x1;
2533                         gui->crop_origin_y1 = y1;
2534                         gui->crop_origin_x2 = x2;
2535                         gui->crop_origin_y2 = y2;
2536                 }
2537                 else
2538                         gui->crop_translate = 0;
2539
2540                 gui->current_operation = CWINDOW_CROP;
2541                 gui->crop_handle = handle_selected;
2542                 gui->x_origin = cursor_x;
2543                 gui->y_origin = cursor_y;
2544                 gui->tool_panel->raise_window();
2545                 result = 1;
2546
2547                 if(handle_selected < 0 && !gui->crop_translate) 
2548                 {
2549                         x2 = x1 = cursor_x;
2550                         y2 = y1 = cursor_y;
2551                         mwindow->edl->session->crop_x1 = (int)x1;
2552                         mwindow->edl->session->crop_y1 = (int)y1;
2553                         mwindow->edl->session->crop_x2 = (int)x2;
2554                         mwindow->edl->session->crop_y2 = (int)y2;
2555                         redraw = 1;
2556                 }
2557         }
2558     else
2559 // Translate all 4 points
2560         if(gui->current_operation == CWINDOW_CROP && gui->crop_translate)
2561         {
2562                 x1 = cursor_x - gui->x_origin + gui->crop_origin_x1;
2563                 y1 = cursor_y - gui->y_origin + gui->crop_origin_y1;
2564                 x2 = cursor_x - gui->x_origin + gui->crop_origin_x2;
2565                 y2 = cursor_y - gui->y_origin + gui->crop_origin_y2;
2566
2567                 mwindow->edl->session->crop_x1 = (int)x1;
2568                 mwindow->edl->session->crop_y1 = (int)y1;
2569                 mwindow->edl->session->crop_x2 = (int)x2;
2570                 mwindow->edl->session->crop_y2 = (int)y2;
2571                 result = 1;
2572                 redraw = 1;
2573         }
2574         else
2575 // Update dragging
2576         if(gui->current_operation == CWINDOW_CROP)
2577         {
2578                 switch(gui->crop_handle)
2579                 {
2580                         case -1:
2581                                 x1 = gui->crop_origin_x;
2582                                 y1 = gui->crop_origin_y;
2583                                 x2 = gui->crop_origin_x;
2584                                 y2 = gui->crop_origin_y;
2585                                 if(cursor_x < gui->x_origin)
2586                                 {
2587                                         if(cursor_y < gui->y_origin)
2588                                         {
2589                                                 x1 = cursor_x;
2590                                                 y1 = cursor_y;
2591                                         }
2592                                         else
2593                                         if(cursor_y >= gui->y_origin)
2594                                         {
2595                                                 x1 = cursor_x;
2596                                                 y2 = cursor_y;
2597                                         }
2598                                 }
2599                                 else
2600                                 if(cursor_x  >= gui->x_origin)
2601                                 {
2602                                         if(cursor_y < gui->y_origin)
2603                                         {
2604                                                 y1 = cursor_y;
2605                                                 x2 = cursor_x;
2606                                         }
2607                                         else
2608                                         if(cursor_y >= gui->y_origin)
2609                                         {
2610                                                 x2 = cursor_x;
2611                                                 y2 = cursor_y;
2612                                         }
2613                                 }
2614
2615 // printf("test crop %d %d %d %d\n", 
2616 //      mwindow->edl->session->crop_x1,
2617 //      mwindow->edl->session->crop_y1,
2618 //      mwindow->edl->session->crop_x2,
2619 //      mwindow->edl->session->crop_y2);
2620                                 break;
2621                         case 0:
2622                                 x1 = cursor_x - gui->x_origin + gui->crop_origin_x;
2623                                 y1 = cursor_y - gui->y_origin + gui->crop_origin_y;
2624                                 break;
2625                         case 1:
2626                                 x2 = cursor_x - gui->x_origin + gui->crop_origin_x;
2627                                 y1 = cursor_y - gui->y_origin + gui->crop_origin_y;
2628                                 break;
2629                         case 2:
2630                                 x1 = cursor_x - gui->x_origin + gui->crop_origin_x;
2631                                 y2 = cursor_y - gui->y_origin + gui->crop_origin_y;
2632                                 break;
2633                         case 3:
2634                                 x2 = cursor_x - gui->x_origin + gui->crop_origin_x;
2635                                 y2 = cursor_y - gui->y_origin + gui->crop_origin_y;
2636                                 break;
2637                 }
2638
2639                 if(!EQUIV(mwindow->edl->session->crop_x1, x1) ||
2640                         !EQUIV(mwindow->edl->session->crop_x2, x2) ||
2641                         !EQUIV(mwindow->edl->session->crop_y1, y1) ||
2642                         !EQUIV(mwindow->edl->session->crop_y2, y2))
2643                 {
2644                         if (x1 > x2)
2645                         {
2646                                 float tmp = x1;
2647                                 x1 = x2;
2648                                 x2 = tmp;
2649                                 switch (gui->crop_handle) 
2650                                 {
2651                                         case 0: gui->crop_handle = 1; break;
2652                                         case 1: gui->crop_handle = 0; break;
2653                                         case 2: gui->crop_handle = 3; break;
2654                                         case 3: gui->crop_handle = 2; break;
2655                                         default: break;
2656                                 }
2657                         }
2658
2659                         if (y1 > y2) 
2660                         {
2661                                 float tmp = y1;
2662                                 y1 = y2;
2663                                 y2 = tmp;
2664                                 switch (gui->crop_handle) 
2665                                 {
2666                                         case 0: gui->crop_handle = 2; break;
2667                                         case 1: gui->crop_handle = 3; break;
2668                                         case 2: gui->crop_handle = 0; break;
2669                                         case 3: gui->crop_handle = 1; break;
2670                                         default: break;
2671                                 }
2672                         }
2673
2674                         mwindow->edl->session->crop_x1 = (int)x1;
2675                         mwindow->edl->session->crop_y1 = (int)y1;
2676                         mwindow->edl->session->crop_x2 = (int)x2;
2677                         mwindow->edl->session->crop_y2 = (int)y2;
2678                         result = 1;
2679                         redraw = 1;
2680                 }
2681         }
2682         else
2683 // Update cursor font
2684         if(handle_selected >= 0)
2685         {
2686                 switch(handle_selected)
2687                 {
2688                         case 0:
2689                                 set_cursor(UPLEFT_RESIZE);
2690                                 break;
2691                         case 1:
2692                                 set_cursor(UPRIGHT_RESIZE);
2693                                 break;
2694                         case 2:
2695                                 set_cursor(DOWNLEFT_RESIZE);
2696                                 break;
2697                         case 3:
2698                                 set_cursor(DOWNRIGHT_RESIZE);
2699                                 break;
2700                 }
2701                 result = 1;
2702         }
2703         else
2704         {
2705                 set_cursor(ARROW_CURSOR);
2706         }
2707 #define CLAMP(x, y, z) ((x) = ((x) < (y) ? (y) : ((x) > (z) ? (z) : (x))))
2708         
2709         if(redraw)
2710         {
2711                 CLAMP(mwindow->edl->session->crop_x1, 0, mwindow->edl->session->output_w);
2712                 CLAMP(mwindow->edl->session->crop_x2, 0, mwindow->edl->session->output_w);
2713                 CLAMP(mwindow->edl->session->crop_y1, 0, mwindow->edl->session->output_h);
2714                 CLAMP(mwindow->edl->session->crop_y2, 0, mwindow->edl->session->output_h);
2715 // printf("CWindowCanvas::test_crop %d %d %d %d\n", 
2716 //      mwindow->edl->session->crop_x2,
2717 //      mwindow->edl->session->crop_y2,
2718 //      mwindow->edl->calculate_output_w(0), 
2719 //      mwindow->edl->calculate_output_h(0));
2720         }
2721         return result;
2722 }
2723
2724
2725 void CWindowCanvas::draw_crop()
2726 {
2727         get_canvas()->set_inverse();
2728         get_canvas()->set_color(WHITE);
2729
2730         float x1 = mwindow->edl->session->crop_x1;
2731         float y1 = mwindow->edl->session->crop_y1;
2732         float x2 = mwindow->edl->session->crop_x2;
2733         float y2 = mwindow->edl->session->crop_y2;
2734
2735         output_to_canvas(mwindow->edl, 0, x1, y1);
2736         output_to_canvas(mwindow->edl, 0, x2, y2);
2737
2738         if(x2 - x1 && y2 - y1)
2739                 get_canvas()->draw_rectangle((int)x1, 
2740                         (int)y1, 
2741                         (int)(x2 - x1), 
2742                         (int)(y2 - y1));
2743
2744         draw_crophandle((int)x1, (int)y1);
2745         draw_crophandle((int)x2 - CROPHANDLE_W, (int)y1);
2746         draw_crophandle((int)x1, (int)y2 - CROPHANDLE_H);
2747         draw_crophandle((int)x2 - CROPHANDLE_W, (int)y2 - CROPHANDLE_H);
2748         get_canvas()->set_opaque();
2749 }
2750
2751
2752
2753
2754
2755
2756
2757
2758 void CWindowCanvas::draw_bezier(int do_camera)
2759 {
2760         Track *track = gui->cwindow->calculate_affected_track();
2761         
2762         if(!track) return;
2763
2764         float center_x;
2765         float center_y;
2766         float center_z;
2767         int64_t position = track->to_units(
2768                 mwindow->edl->local_session->get_selectionstart(1), 
2769                 0);
2770
2771         track->automation->get_projector(&center_x, 
2772                 &center_y, 
2773                 &center_z, 
2774                 position,
2775                 PLAY_FORWARD);
2776
2777 //      center_x += track->track_w / 2;
2778 //      center_y += track->track_h / 2;
2779         center_x += mwindow->edl->session->output_w / 2;
2780         center_y += mwindow->edl->session->output_h / 2;
2781         float track_x1 = center_x - track->track_w / 2 * center_z;
2782         float track_y1 = center_y - track->track_h / 2 * center_z;
2783         float track_x2 = track_x1 + track->track_w * center_z;
2784         float track_y2 = track_y1 + track->track_h * center_z;
2785
2786         output_to_canvas(mwindow->edl, 0, track_x1, track_y1);
2787         output_to_canvas(mwindow->edl, 0, track_x2, track_y2);
2788
2789 #define DRAW_PROJECTION(offset) \
2790         get_canvas()->draw_rectangle((int)track_x1 + offset, \
2791                 (int)track_y1 + offset, \
2792                 (int)(track_x2 - track_x1), \
2793                 (int)(track_y2 - track_y1)); \
2794         get_canvas()->draw_line((int)track_x1 + offset,  \
2795                 (int)track_y1 + offset, \
2796                 (int)track_x2 + offset, \
2797                 (int)track_y2 + offset); \
2798         get_canvas()->draw_line((int)track_x2 + offset,  \
2799                 (int)track_y1 + offset, \
2800                 (int)track_x1 + offset, \
2801                 (int)track_y2 + offset); \
2802
2803
2804 // Drop shadow
2805         get_canvas()->set_color(BLACK);
2806         DRAW_PROJECTION(1);
2807
2808 //      canvas->set_inverse();
2809         if(do_camera)
2810                 get_canvas()->set_color(GREEN);
2811         else
2812                 get_canvas()->set_color(RED);
2813
2814         DRAW_PROJECTION(0);
2815 //      canvas->set_opaque();
2816
2817 }
2818
2819
2820
2821 int CWindowCanvas::test_bezier(int button_press, 
2822         int &redraw, 
2823         int &redraw_canvas,
2824         int &rerender,
2825         int do_camera)
2826 {
2827         int result = 0;
2828
2829 // Processing drag operation.
2830 // Create keyframe during first cursor motion.
2831         if(!button_press)
2832         {
2833
2834                 float cursor_x = get_cursor_x();
2835                 float cursor_y = get_cursor_y();
2836                 canvas_to_output(mwindow->edl, 0, cursor_x, cursor_y);
2837
2838                 if(gui->current_operation == CWINDOW_CAMERA ||
2839                         gui->current_operation == CWINDOW_PROJECTOR)
2840                 {
2841                         if(!gui->ctrl_down() && gui->shift_down() && !gui->translating_zoom)
2842                         {
2843                                 gui->translating_zoom = 1;
2844                                 gui->reset_affected();
2845                         }
2846                         else
2847                         if(!gui->ctrl_down() && !gui->shift_down() && gui->translating_zoom)
2848                         {
2849                                 gui->translating_zoom = 0;
2850                                 gui->reset_affected();
2851                         }
2852
2853 // Get target keyframe
2854                         float last_center_x;
2855                         float last_center_y;
2856                         float last_center_z;
2857                         int created;
2858
2859                         if(!gui->affected_x && !gui->affected_y && !gui->affected_z)
2860                         {
2861                                 FloatAutos *affected_x_autos;
2862                                 FloatAutos *affected_y_autos;
2863                                 FloatAutos *affected_z_autos;
2864                                 if(!gui->affected_track) return 0;
2865                                 double position = mwindow->edl->local_session->get_selectionstart(1);
2866                                 int64_t track_position = gui->affected_track->to_units(position, 0);
2867
2868                                 if(mwindow->edl->session->cwindow_operation == CWINDOW_CAMERA)
2869                                 {
2870                                         affected_x_autos = (FloatAutos*)gui->affected_track->automation->autos[AUTOMATION_CAMERA_X];
2871                                         affected_y_autos = (FloatAutos*)gui->affected_track->automation->autos[AUTOMATION_CAMERA_Y];
2872                                         affected_z_autos = (FloatAutos*)gui->affected_track->automation->autos[AUTOMATION_CAMERA_Z];
2873                                 }
2874                                 else
2875                                 {
2876                                         affected_x_autos = (FloatAutos*)gui->affected_track->automation->autos[AUTOMATION_PROJECTOR_X];
2877                                         affected_y_autos = (FloatAutos*)gui->affected_track->automation->autos[AUTOMATION_PROJECTOR_Y];
2878                                         affected_z_autos = (FloatAutos*)gui->affected_track->automation->autos[AUTOMATION_PROJECTOR_Z];
2879                                 }
2880
2881
2882                                 if(gui->translating_zoom)
2883                                 {
2884                                         FloatAuto *previous = 0;
2885                                         FloatAuto *next = 0;
2886                                         float new_z = affected_z_autos->get_value(
2887                                                 track_position, 
2888                                                 PLAY_FORWARD,
2889                                                 previous,
2890                                                 next);
2891                                         gui->affected_z = 
2892                                                 (FloatAuto*)gui->cwindow->calculate_affected_auto(
2893                                                         affected_z_autos, 1, &created, 0);
2894                                         if(created) 
2895                                         {
2896                                                 gui->affected_z->value = new_z;
2897                                                 gui->affected_z->control_in_value = 0;
2898                                                 gui->affected_z->control_out_value = 0;
2899 //                                              gui->affected_z->control_in_position = 0;
2900 //                                              gui->affected_z->control_out_position = 0;
2901                                                 redraw_canvas = 1;
2902                                         }
2903                                 }
2904                                 else
2905                                 {
2906                                         FloatAuto *previous = 0;
2907                                         FloatAuto *next = 0;
2908                                         float new_x = affected_x_autos->get_value(
2909                                                 track_position, 
2910                                                 PLAY_FORWARD,
2911                                                 previous,
2912                                                 next);
2913                                         previous = 0;
2914                                         next = 0;
2915                                         float new_y = affected_y_autos->get_value(
2916                                                 track_position, 
2917                                                 PLAY_FORWARD,
2918                                                 previous,
2919                                                 next);
2920                                         gui->affected_x = 
2921                                                 (FloatAuto*)gui->cwindow->calculate_affected_auto(
2922                                                         affected_x_autos, 1, &created, 0);
2923                                         if(created) 
2924                                         {
2925                                                 gui->affected_x->value = new_x;
2926                                                 gui->affected_x->control_in_value = 0;
2927                                                 gui->affected_x->control_out_value = 0;
2928 //                                              gui->affected_x->control_in_position = 0;
2929 //                                              gui->affected_x->control_out_position = 0;
2930                                                 redraw_canvas = 1;
2931                                         }
2932                                         gui->affected_y = 
2933                                                 (FloatAuto*)gui->cwindow->calculate_affected_auto(
2934                                                         affected_y_autos, 1, &created, 0);
2935                                         if(created) 
2936                                         {
2937                                                 gui->affected_y->value = new_y;
2938                                                 gui->affected_y->control_in_value = 0;
2939                                                 gui->affected_y->control_out_value = 0;
2940 //                                              gui->affected_y->control_in_position = 0;
2941 //                                              gui->affected_y->control_out_position = 0;
2942                                                 redraw_canvas = 1;
2943                                         }
2944                                 }
2945
2946                                 calculate_origin();
2947
2948                                 if(gui->translating_zoom)
2949                                 {
2950                                         gui->center_z = gui->affected_z->value;
2951                                 }
2952                                 else
2953                                 {
2954                                         gui->center_x = gui->affected_x->value;
2955                                         gui->center_y = gui->affected_y->value;
2956                                 }
2957
2958                                 rerender = 1;
2959                                 redraw = 1;
2960                         }
2961
2962
2963                         if(gui->translating_zoom)
2964                         {
2965                                 last_center_z = gui->affected_z->value;
2966                         }
2967                         else
2968                         {
2969                                 last_center_x = gui->affected_x->value;
2970                                 last_center_y = gui->affected_y->value;
2971                         }
2972
2973                         if(gui->translating_zoom)
2974                         {
2975                                 gui->affected_z->value = gui->center_z + 
2976                                         (cursor_y - gui->y_origin) / 128;
2977
2978                                 if(gui->affected_z->value < 0) gui->affected_z->value = 0;
2979                                 if(!EQUIV(last_center_z, gui->affected_z->value))
2980                                 {
2981                                         rerender = 1;
2982                                         redraw = 1;
2983                                         redraw_canvas = 1;
2984                                 }
2985                         }
2986                         else
2987                         {
2988                                 gui->affected_x->value = gui->center_x + cursor_x - gui->x_origin;
2989                                 gui->affected_y->value = gui->center_y + cursor_y - gui->y_origin;
2990                                 if(!EQUIV(last_center_x,  gui->affected_x->value) ||
2991                                         !EQUIV(last_center_y, gui->affected_y->value))
2992                                 {
2993                                         rerender = 1;
2994                                         redraw = 1;
2995                                         redraw_canvas = 1;
2996                                 }
2997                         }
2998                 }
2999
3000                 result = 1;
3001         }
3002         else
3003 // Begin drag operation.  Don't create keyframe here.
3004         {
3005 // Get affected track off of the first recordable video track.
3006 // Calculating based on the alpha channel would require recording what layer
3007 // each output pixel belongs to as they're rendered and stacked.  Forget it.
3008                 gui->affected_track = gui->cwindow->calculate_affected_track();
3009                 gui->reset_affected();
3010
3011                 if(gui->affected_track)
3012                 {
3013                         if(gui->current_operation == CWINDOW_CAMERA)
3014                                 mwindow->undo->update_undo_before(_("camera"), this);
3015                         else
3016                                 mwindow->undo->update_undo_before(_("projector"), this);
3017
3018                         gui->current_operation = 
3019                                 mwindow->edl->session->cwindow_operation;
3020                         gui->tool_panel->raise_window();
3021                         result = 1;
3022                 }
3023         }
3024         
3025         return result;
3026 }
3027
3028 int CWindowCanvas::test_zoom(int &redraw)
3029 {
3030         int result = 0;
3031         float zoom = get_zoom();
3032         float x;
3033         float y;
3034
3035         if(!mwindow->edl->session->cwindow_scrollbars)
3036         {
3037                 mwindow->edl->session->cwindow_scrollbars = 1;
3038                 zoom = 1.0;
3039                 x = mwindow->edl->session->output_w / 2;
3040                 y = mwindow->edl->session->output_h / 2;
3041                 x = x - w / zoom / 2;
3042                 y = y - h / zoom / 2;
3043         }
3044         else
3045         {
3046 // Cursor position relative to canvas
3047                 x = get_cursor_x();
3048                 y = get_cursor_y();
3049 // cursor position relative to output
3050                 float output_x = x;
3051                 float output_y = y;
3052                 canvas_to_output(mwindow->edl, 
3053                                 0, 
3054                                 output_x, 
3055                                 output_y);
3056
3057 //printf("CWindowCanvas::test_zoom 1 %f %f\n", x, y);
3058
3059 // Find current zoom in table
3060                 int current_index = 0;
3061                 for(current_index = 0 ; current_index < total_zooms; current_index++)
3062                         if(EQUIV(my_zoom_table[current_index], zoom)) break;
3063
3064
3065 // Zoom out
3066                 if(get_buttonpress() == 5 ||
3067                         gui->ctrl_down() || 
3068                         gui->shift_down())
3069                 {
3070                         current_index--;
3071                 }
3072                 else
3073 // Zoom in
3074                 {
3075                         current_index++;
3076                 }
3077                 
3078                 CLAMP(current_index, 0, total_zooms - 1);
3079                 zoom = my_zoom_table[current_index];
3080                 
3081                 x = output_x - x / zoom;
3082                 y = output_y - y / zoom;
3083
3084                 
3085         }
3086
3087
3088
3089         int x_i = (int)x;
3090         int y_i = (int)y;
3091 //      check_boundaries(mwindow->edl, x_i, y_i, zoom);
3092
3093 //printf("CWindowCanvas::test_zoom 2 %d %d\n", x_i, y_i);
3094
3095         update_zoom(x_i, 
3096                         y_i, 
3097                         zoom);
3098         reposition_window(mwindow->edl, 
3099                         mwindow->theme->ccanvas_x,
3100                         mwindow->theme->ccanvas_y,
3101                         mwindow->theme->ccanvas_w,
3102                         mwindow->theme->ccanvas_h);
3103         redraw = 1;
3104         result = 1;
3105
3106         
3107         gui->zoom_panel->update(zoom);
3108         
3109         return result;
3110 }
3111
3112
3113 void CWindowCanvas::calculate_origin()
3114 {
3115         gui->x_origin = get_cursor_x();
3116         gui->y_origin = get_cursor_y();
3117 //printf("CWindowCanvas::calculate_origin 1 %f %f\n", gui->x_origin, gui->y_origin);
3118         canvas_to_output(mwindow->edl, 0, gui->x_origin, gui->y_origin);
3119 //printf("CWindowCanvas::calculate_origin 2 %f %f\n", gui->x_origin, gui->y_origin);
3120 }
3121
3122
3123 int CWindowCanvas::cursor_leave_event()
3124 {
3125         set_cursor(ARROW_CURSOR);
3126         return 1;
3127 }
3128
3129 int CWindowCanvas::cursor_enter_event()
3130 {
3131         int redraw = 0;
3132         switch(mwindow->edl->session->cwindow_operation)
3133         {
3134                 case CWINDOW_CAMERA:
3135                 case CWINDOW_PROJECTOR:
3136                         set_cursor(MOVE_CURSOR);
3137                         break;
3138                 case CWINDOW_ZOOM:
3139                         set_cursor(MOVE_CURSOR);
3140                         break;
3141                 case CWINDOW_CROP:
3142                         test_crop(0, redraw);
3143                         break;
3144                 case CWINDOW_PROTECT:
3145                         set_cursor(ARROW_CURSOR);
3146                         break;
3147                 case CWINDOW_MASK:
3148                 case CWINDOW_RULER:
3149                         set_cursor(CROSS_CURSOR);
3150                         break;
3151                 case CWINDOW_EYEDROP:
3152                         set_cursor(CROSS_CURSOR);
3153                         break;
3154         }
3155         return 1;
3156 }
3157
3158 int CWindowCanvas::cursor_motion_event()
3159 {
3160         int redraw = 0, result = 0, rerender = 0, redraw_canvas = 0;
3161
3162
3163 //printf("CWindowCanvas::cursor_motion_event %d current_operation=%d\n", __LINE__, gui->current_operation);
3164         switch(gui->current_operation)
3165         {
3166                 case CWINDOW_SCROLL:
3167                 {
3168                         float zoom = get_zoom();
3169                         float cursor_x = get_cursor_x();
3170                         float cursor_y = get_cursor_y();
3171
3172                         float zoom_x, zoom_y, conformed_w, conformed_h;
3173                         get_zooms(mwindow->edl, 0, zoom_x, zoom_y, conformed_w, conformed_h);
3174                         cursor_x = (float)cursor_x / zoom_x + gui->x_offset;
3175                         cursor_y = (float)cursor_y / zoom_y + gui->y_offset;
3176
3177
3178
3179                         int x = (int)(gui->x_origin - cursor_x + gui->x_offset);
3180                         int y = (int)(gui->y_origin - cursor_y + gui->y_offset);
3181
3182                         update_zoom(x, 
3183                                 y, 
3184                                 zoom);
3185                         update_scrollbars(0);
3186                         redraw = 1;
3187                         result = 1;
3188                         break;
3189                 }
3190
3191                 case CWINDOW_RULER:
3192                         result = do_ruler(0, 1, 0, 0);
3193                         break;
3194
3195                 case CWINDOW_CAMERA:
3196                         result = test_bezier(0, redraw, redraw_canvas, rerender, 1);
3197                         break;
3198
3199                 case CWINDOW_PROJECTOR:
3200                         result = test_bezier(0, redraw, redraw_canvas, rerender, 0);
3201                         break;
3202
3203
3204                 case CWINDOW_CROP:
3205                         result = test_crop(0, redraw);
3206 // printf("CWindowCanvas::cursor_motion_event %d result=%d redraw=%d\n", 
3207 // __LINE__, 
3208 // result, 
3209 // redraw);
3210                         break;
3211
3212                 case CWINDOW_MASK:
3213                 case CWINDOW_MASK_CONTROL_IN:
3214                 case CWINDOW_MASK_CONTROL_OUT:
3215                 case CWINDOW_MASK_TRANSLATE:
3216
3217                         result = do_mask(redraw, 
3218                                 rerender, 
3219                                 0, 
3220                                 1,
3221                                 0);
3222                         break;
3223
3224                 case CWINDOW_EYEDROP:
3225                         result = do_eyedrop(rerender, 0, 0);
3226                         break;
3227
3228                 default:
3229                         break;
3230
3231         }
3232
3233
3234 // cursor font changes
3235         if(!result)
3236         {
3237 // printf("CWindowCanvas::cursor_motion_event %d cwindow_operation=%d\n", 
3238 // __LINE__, 
3239 // mwindow->edl->session->cwindow_operation);
3240                 switch(mwindow->edl->session->cwindow_operation)
3241                 {
3242                         case CWINDOW_CROP:
3243                                 result = test_crop(0, redraw);
3244                                 break;
3245                         case CWINDOW_RULER:
3246                                 result = do_ruler(0, 1, 0, 0);
3247                                 break;
3248                         case CWINDOW_MASK:
3249                                 result = do_mask(redraw, 
3250                                         rerender, 
3251                                         0, 
3252                                         1,
3253                                         0);
3254                                         break;
3255                 }
3256         }
3257
3258
3259 // If the window is never unlocked before calling send_command the
3260 // display shouldn't get stuck on the old video frame although it will
3261 // flicker between the old video frame and the new video frame.
3262
3263         if(redraw)
3264         {
3265                 draw_refresh();
3266                 gui->update_tool();
3267         }
3268
3269         if(redraw_canvas)
3270         {
3271                 gui->unlock_window();
3272         
3273         
3274                 mwindow->gui->lock_window("CWindowCanvas::cursor_motion_event 1");
3275                 mwindow->gui->draw_overlays(1);
3276                 mwindow->gui->unlock_window();
3277                 
3278                 gui->lock_window("CWindowCanvas::cursor_motion_event 1");
3279         }
3280
3281         if(rerender)
3282         {
3283                 gui->unlock_window();
3284                 mwindow->restart_brender();
3285                 mwindow->sync_parameters(CHANGE_PARAMS);
3286                 gui->cwindow->playback_engine->que->send_command(CURRENT_FRAME, 
3287                         CHANGE_NONE,
3288                         mwindow->edl,
3289                         1);
3290                 if(!redraw) gui->update_tool();
3291                 gui->lock_window("CWindowCanvas::cursor_motion_event 2");
3292         }
3293         return result;
3294 }
3295
3296 int CWindowCanvas::button_press_event()
3297 {
3298         int result = 0;
3299         int redraw = 0;
3300         int redraw_canvas = 0;
3301         int rerender = 0;
3302
3303         if(Canvas::button_press_event()) return 1;
3304
3305         gui->translating_zoom = gui->shift_down(); 
3306
3307         calculate_origin();
3308 //printf("CWindowCanvas::button_press_event 2 %f %f\n", gui->x_origin, gui->y_origin, gui->x_origin, gui->y_origin);
3309
3310         float zoom_x, zoom_y, conformed_w, conformed_h;
3311         get_zooms(mwindow->edl, 0, zoom_x, zoom_y, conformed_w, conformed_h);
3312         gui->x_offset = get_x_offset(mwindow->edl, 0, zoom_x, conformed_w, conformed_h);
3313         gui->y_offset = get_y_offset(mwindow->edl, 0, zoom_y, conformed_w, conformed_h);
3314
3315 // Scroll view
3316         if(get_buttonpress() == 2)
3317         {
3318                 gui->current_operation = CWINDOW_SCROLL;
3319                 result = 1;
3320         }
3321         else
3322 // Adjust parameter
3323         {
3324                 switch(mwindow->edl->session->cwindow_operation)
3325                 {
3326                         case CWINDOW_RULER:
3327                                 result = do_ruler(0, 0, 1, 0);
3328                                 break;
3329                 
3330                         case CWINDOW_CAMERA:
3331                                 result = test_bezier(1, redraw, redraw_canvas, rerender, 1);
3332                                 break;
3333
3334                         case CWINDOW_PROJECTOR:
3335                                 result = test_bezier(1, redraw, redraw_canvas, rerender, 0);
3336                                 break;
3337
3338                         case CWINDOW_ZOOM:
3339                                 result = test_zoom(redraw);
3340                                 break;
3341
3342                         case CWINDOW_CROP:
3343                                 result = test_crop(1, redraw);
3344                                 break;
3345
3346                         case CWINDOW_MASK:
3347                                 if(get_buttonpress() == 1)
3348                                         result = do_mask(redraw, rerender, 1, 0, 0);
3349                                 break;
3350
3351                         case CWINDOW_EYEDROP:
3352                                 result = do_eyedrop(rerender, 1, 0);
3353                                 break;
3354                 }
3355         }
3356
3357         if(redraw)
3358         {
3359                 draw_refresh();
3360                 gui->unlock_window();
3361         
3362         
3363                 mwindow->gui->lock_window("CWindowCanvas::button_press_event 1");
3364                 mwindow->gui->draw_overlays(1);
3365                 mwindow->gui->unlock_window();
3366                 gui->update_tool();
3367                 
3368                 gui->lock_window("CWindowCanvas::button_press_event 1");
3369         }
3370
3371 // rerendering can also be caused by press event
3372         if(rerender) 
3373         {
3374                 gui->unlock_window();
3375
3376                 mwindow->restart_brender();
3377                 mwindow->sync_parameters(CHANGE_PARAMS);
3378                 gui->cwindow->playback_engine->que->send_command(CURRENT_FRAME, 
3379                         CHANGE_NONE,
3380                         mwindow->edl,
3381                         1);
3382                 if(!redraw) gui->update_tool();
3383                 gui->lock_window("CWindowCanvas::button_press_event 2");
3384         }
3385         return result;
3386 }
3387
3388 int CWindowCanvas::button_release_event()
3389 {
3390         int result = 0;
3391
3392         switch(gui->current_operation)
3393         {
3394                 case CWINDOW_SCROLL:
3395                         result = 1;
3396                         break;
3397                         
3398                 case CWINDOW_RULER:
3399                         do_ruler(0, 0, 0, 1);
3400                         break;
3401
3402                 case CWINDOW_CAMERA:
3403                         mwindow->undo->update_undo_after(_("camera"), LOAD_AUTOMATION);
3404                         break;
3405
3406                 case CWINDOW_PROJECTOR:
3407                         mwindow->undo->update_undo_after(_("projector"), LOAD_AUTOMATION);
3408                         break;
3409
3410                 case CWINDOW_MASK:
3411                 case CWINDOW_MASK_CONTROL_IN:
3412                 case CWINDOW_MASK_CONTROL_OUT:
3413                 case CWINDOW_MASK_TRANSLATE:
3414 // Finish mask operation
3415                         gui->mask_keyframe = 0;
3416                         mwindow->undo->update_undo_after(_("mask"), LOAD_AUTOMATION);
3417                         break;
3418
3419         }
3420
3421         gui->current_operation = CWINDOW_NONE;
3422         return result;
3423 }
3424
3425 void CWindowCanvas::zoom_resize_window(float percentage)
3426 {
3427         int canvas_w, canvas_h;
3428         int new_w, new_h;
3429         
3430         
3431 // Get required canvas size
3432         calculate_sizes(mwindow->edl->get_aspect_ratio(), 
3433                 mwindow->edl->session->output_w, 
3434                 mwindow->edl->session->output_h, 
3435                 percentage,
3436                 canvas_w,
3437                 canvas_h);
3438
3439 // Estimate window size from current borders
3440         new_w = canvas_w + (gui->get_w() - mwindow->theme->ccanvas_w);
3441         new_h = canvas_h + (gui->get_h() - mwindow->theme->ccanvas_h);
3442
3443 //printf("CWindowCanvas::zoom_resize_window %d %d %d\n", __LINE__, new_w, new_h);
3444         mwindow->session->cwindow_w = new_w;
3445         mwindow->session->cwindow_h = new_h;
3446
3447         mwindow->theme->get_cwindow_sizes(gui, 
3448                 mwindow->session->cwindow_controls);
3449
3450 // Estimate again from new borders
3451         new_w = canvas_w + (mwindow->session->cwindow_w - mwindow->theme->ccanvas_w);
3452         new_h = canvas_h + (mwindow->session->cwindow_h - mwindow->theme->ccanvas_h);
3453 //printf("CWindowCanvas::zoom_resize_window %d %d %d\n", __LINE__, new_w, new_h);
3454
3455         gui->resize_window(new_w, new_h);
3456         gui->resize_event(new_w, new_h);
3457 }
3458
3459 void CWindowCanvas::toggle_controls()
3460 {
3461         mwindow->session->cwindow_controls = !mwindow->session->cwindow_controls;
3462         gui->resize_event(gui->get_w(), gui->get_h());
3463 }
3464
3465 int CWindowCanvas::get_cwindow_controls()
3466 {
3467         return mwindow->session->cwindow_controls;
3468 }
3469
3470
3471