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