prevent popup deactivation while button_down
[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                                 gui->update_tool();
1095                         }
1096                         else
1097                         switch(gui->ruler_handle)
1098                         {
1099                                 case 0:
1100                                         do_ruler(1, 0, 0, 0);
1101                                         mwindow->edl->session->ruler_x1 = output_x - gui->x_origin + gui->ruler_origin_x;
1102                                         mwindow->edl->session->ruler_y1 = output_y - gui->y_origin + gui->ruler_origin_y;
1103                                         if(gui->alt_down() || gui->ctrl_down()) 
1104                                         {
1105                                                 double angle_value = fabs(atan((mwindow->edl->session->ruler_y2 - mwindow->edl->session->ruler_y1) /
1106                                                         (mwindow->edl->session->ruler_x2 - mwindow->edl->session->ruler_x1)) * 
1107                                                         360 /
1108                                                         2 / 
1109                                                         M_PI);
1110                                                 double distance_value = 
1111                                                         sqrt(SQR(mwindow->edl->session->ruler_x2 - mwindow->edl->session->ruler_x1) +
1112                                                         SQR(mwindow->edl->session->ruler_y2 - mwindow->edl->session->ruler_y1));
1113                                                 if(angle_value < 22)
1114                                                         mwindow->edl->session->ruler_y1 = mwindow->edl->session->ruler_y2;
1115                                                 else
1116                                                 if(angle_value > 67)
1117                                                         mwindow->edl->session->ruler_x1 = mwindow->edl->session->ruler_x2;
1118                                                 else
1119                                                 if(mwindow->edl->session->ruler_x1 < mwindow->edl->session->ruler_x2 && 
1120                                                         mwindow->edl->session->ruler_y1 < mwindow->edl->session->ruler_y2)
1121                                                 {
1122                                                         mwindow->edl->session->ruler_x1 = mwindow->edl->session->ruler_x2 - distance_value / 1.414214;
1123                                                         mwindow->edl->session->ruler_y1 = mwindow->edl->session->ruler_y2 - distance_value / 1.414214;
1124                                                 }
1125                                                 else
1126                                                 if(mwindow->edl->session->ruler_x1 < mwindow->edl->session->ruler_x2 && mwindow->edl->session->ruler_y1 > mwindow->edl->session->ruler_y2)
1127                                                 {
1128                                                         mwindow->edl->session->ruler_x1 = mwindow->edl->session->ruler_x2 - distance_value / 1.414214;
1129                                                         mwindow->edl->session->ruler_y1 = mwindow->edl->session->ruler_y2 + distance_value / 1.414214;
1130                                                 }
1131                                                 else
1132                                                 if(mwindow->edl->session->ruler_x1 > mwindow->edl->session->ruler_x2 && 
1133                                                         mwindow->edl->session->ruler_y1 < mwindow->edl->session->ruler_y2)
1134                                                 {
1135                                                         mwindow->edl->session->ruler_x1 = mwindow->edl->session->ruler_x2 + distance_value / 1.414214;
1136                                                         mwindow->edl->session->ruler_y1 = mwindow->edl->session->ruler_y2 - distance_value / 1.414214;
1137                                                 }
1138                                                 else
1139                                                 {
1140                                                         mwindow->edl->session->ruler_x1 = mwindow->edl->session->ruler_x2 + distance_value / 1.414214;
1141                                                         mwindow->edl->session->ruler_y1 = mwindow->edl->session->ruler_y2 + distance_value / 1.414214;
1142                                                 }
1143                                         }
1144                                         do_ruler(1, 0, 0, 0);
1145                                         get_canvas()->flash();
1146                                         gui->update_tool();
1147                                         break;
1148
1149                                 case 1:
1150                                         do_ruler(1, 0, 0, 0);
1151                                         mwindow->edl->session->ruler_x2 = output_x - gui->x_origin + gui->ruler_origin_x;
1152                                         mwindow->edl->session->ruler_y2 = output_y - gui->y_origin + gui->ruler_origin_y;
1153                                         if(gui->alt_down() || gui->ctrl_down()) 
1154                                         {
1155                                                 double angle_value = fabs(atan((mwindow->edl->session->ruler_y2 - mwindow->edl->session->ruler_y1) /
1156                                                         (mwindow->edl->session->ruler_x2 - mwindow->edl->session->ruler_x1)) * 
1157                                                         360 /
1158                                                         2 / 
1159                                                         M_PI);
1160                                                 double distance_value = 
1161                                                         sqrt(SQR(mwindow->edl->session->ruler_x2 - mwindow->edl->session->ruler_x1) +
1162                                                         SQR(mwindow->edl->session->ruler_y2 - mwindow->edl->session->ruler_y1));
1163                                                 if(angle_value < 22)
1164                                                         mwindow->edl->session->ruler_y2 = mwindow->edl->session->ruler_y1;
1165                                                 else
1166                                                 if(angle_value > 67)
1167                                                         mwindow->edl->session->ruler_x2 = mwindow->edl->session->ruler_x1;
1168                                                 else
1169                                                 if(mwindow->edl->session->ruler_x2 < mwindow->edl->session->ruler_x1 && 
1170                                                         mwindow->edl->session->ruler_y2 < mwindow->edl->session->ruler_y1)
1171                                                 {
1172                                                         mwindow->edl->session->ruler_x2 = mwindow->edl->session->ruler_x1 - distance_value / 1.414214;
1173                                                         mwindow->edl->session->ruler_y2 = mwindow->edl->session->ruler_y1 - distance_value / 1.414214;
1174                                                 }
1175                                                 else
1176                                                 if(mwindow->edl->session->ruler_x2 < mwindow->edl->session->ruler_x1 && 
1177                                                         mwindow->edl->session->ruler_y2 > mwindow->edl->session->ruler_y1)
1178                                                 {
1179                                                         mwindow->edl->session->ruler_x2 = mwindow->edl->session->ruler_x1 - distance_value / 1.414214;
1180                                                         mwindow->edl->session->ruler_y2 = mwindow->edl->session->ruler_y1 + distance_value / 1.414214;
1181                                                 }
1182                                                 else
1183                                                 if(mwindow->edl->session->ruler_x2 > mwindow->edl->session->ruler_x1 && mwindow->edl->session->ruler_y2 < mwindow->edl->session->ruler_y1)
1184                                                 {
1185                                                         mwindow->edl->session->ruler_x2 = mwindow->edl->session->ruler_x1 + distance_value / 1.414214;
1186                                                         mwindow->edl->session->ruler_y2 = mwindow->edl->session->ruler_y1 - distance_value / 1.414214;
1187                                                 }
1188                                                 else
1189                                                 {
1190                                                         mwindow->edl->session->ruler_x2 = mwindow->edl->session->ruler_x1 + distance_value / 1.414214;
1191                                                         mwindow->edl->session->ruler_y2 = mwindow->edl->session->ruler_y1 + distance_value / 1.414214;
1192                                                 }
1193                                         }
1194                                         do_ruler(1, 0, 0, 0);
1195                                         get_canvas()->flash();
1196                                         gui->update_tool();
1197                                         break;
1198                         }
1199 //printf("CWindowCanvas::do_ruler 2 %f %f %f %f\n", gui->ruler_x1, gui->ruler_y1, gui->ruler_x2, gui->ruler_y2);
1200                 }
1201                 else
1202                 {
1203 // printf("CWindowCanvas::do_ruler 2 %f %f %f %f\n", 
1204 // canvas_cursor_x, 
1205 // canvas_cursor_y,
1206 // canvas_x1,
1207 // canvas_y1);
1208                         if(canvas_cursor_x >= canvas_x1 - RULERHANDLE_W / 2 && 
1209                                 canvas_cursor_x < canvas_x1 + RULERHANDLE_W / 2 && 
1210                                 canvas_cursor_y >= canvas_y1 - RULERHANDLE_W && 
1211                                 canvas_cursor_y < canvas_y1 + RULERHANDLE_H / 2)
1212                         {
1213                                 set_cursor(UPRIGHT_ARROW_CURSOR);
1214                         }
1215                         else
1216                         if(canvas_cursor_x >= canvas_x2 - RULERHANDLE_W / 2 && 
1217                                 canvas_cursor_x < canvas_x2 + RULERHANDLE_W / 2 && 
1218                                 canvas_cursor_y >= canvas_y2 - RULERHANDLE_W && 
1219                                 canvas_cursor_y < canvas_y2 + RULERHANDLE_H / 2)
1220                         {
1221                                 set_cursor(UPRIGHT_ARROW_CURSOR);
1222                         }
1223                         else
1224                                 set_cursor(CROSS_CURSOR);
1225
1226 // Update current position
1227                         gui->update_tool();
1228                 }
1229         }
1230
1231 // Assume no ruler measurement if 0 length
1232         if(draw && (x2 - x1 || y2 - y1))
1233         {
1234                 get_canvas()->set_inverse();
1235                 get_canvas()->set_color(WHITE);
1236                 get_canvas()->draw_line((int)canvas_x1, 
1237                         (int)canvas_y1, 
1238                         (int)canvas_x2, 
1239                         (int)canvas_y2);
1240                 get_canvas()->draw_line((int)canvas_x1 - RULERHANDLE_W / 2, 
1241                         (int)canvas_y1, 
1242                         (int)canvas_x1 + RULERHANDLE_W / 2, 
1243                         (int)canvas_y1);
1244                 get_canvas()->draw_line((int)canvas_x1, 
1245                         (int)canvas_y1 - RULERHANDLE_H / 2, 
1246                         (int)canvas_x1, 
1247                         (int)canvas_y1 + RULERHANDLE_H / 2);
1248                 get_canvas()->draw_line((int)canvas_x2 - RULERHANDLE_W / 2, 
1249                         (int)canvas_y2, 
1250                         (int)canvas_x2 + RULERHANDLE_W / 2, 
1251                         (int)canvas_y2);
1252                 get_canvas()->draw_line((int)canvas_x2, 
1253                         (int)canvas_y2 - RULERHANDLE_H / 2, 
1254                         (int)canvas_x2, 
1255                         (int)canvas_y2 + RULERHANDLE_H / 2);
1256                 get_canvas()->set_opaque();
1257         }
1258
1259         return result;
1260 }
1261
1262
1263 int CWindowCanvas::do_mask(int &redraw, 
1264                 int &rerender, 
1265                 int button_press, 
1266                 int cursor_motion,
1267                 int draw)
1268 {
1269 // Retrieve points from top recordable track
1270 //printf("CWindowCanvas::do_mask 1\n");
1271         Track *track = gui->cwindow->calculate_affected_track();
1272 //printf("CWindowCanvas::do_mask 2\n");
1273
1274         if(!track) return 0;
1275 //printf("CWindowCanvas::do_mask 3\n");
1276
1277         MaskAutos *mask_autos = (MaskAutos*)track->automation->autos[AUTOMATION_MASK];
1278         int64_t position = track->to_units(
1279                 mwindow->edl->local_session->get_selectionstart(1),
1280                 0);
1281         ArrayList<MaskPoint*> points;
1282
1283 // Determine the points based on whether
1284 // new keyframes will be generated or drawing is performed.
1285 // If keyframe generation occurs, use the interpolated mask.
1286 // If no keyframe generation occurs, use the previous mask.
1287         int use_interpolated = 0;
1288         if(button_press || cursor_motion)
1289         {
1290 #ifdef USE_KEYFRAME_SPANNING
1291                 double selection_start = mwindow->edl->local_session->get_selectionstart(0);
1292                 double selection_end = mwindow->edl->local_session->get_selectionend(0);
1293
1294                 Auto *first = 0;
1295                 mask_autos->get_prev_auto(track->to_units(selection_start, 0),
1296                         PLAY_FORWARD,
1297                         first,
1298                         1);
1299                 Auto *last = 0;
1300                 mask_autos->get_prev_auto(track->to_units(selection_end, 0),
1301                         PLAY_FORWARD,
1302                         last,
1303                         1);
1304
1305                 if(last == first && (!mwindow->edl->session->auto_keyframes))
1306                         use_interpolated = 0;
1307                 else
1308 // If keyframe spanning occurs, use the interpolated points.
1309 // If new keyframe is generated, use the interpolated points.
1310                         use_interpolated = 1;
1311                 
1312 #else
1313                 if(mwindow->edl->session->auto_keyframes)
1314                         use_interpolated = 1;
1315 #endif
1316         }
1317         else
1318                 use_interpolated = 1;
1319
1320         if(use_interpolated)
1321         {
1322 // Interpolate the points to get exactly what is being rendered at this position.
1323                 mask_autos->get_points(&points, 
1324                         mwindow->edl->session->cwindow_mask,
1325                         position, 
1326                         PLAY_FORWARD);
1327         }
1328         else
1329 // Use the prev mask
1330         {
1331                 Auto *prev = 0;
1332                 mask_autos->get_prev_auto(position,
1333                         PLAY_FORWARD,
1334                         prev,
1335                         1);
1336                 ((MaskAuto*)prev)->get_points(&points, 
1337                         mwindow->edl->session->cwindow_mask);
1338         }
1339
1340 // Projector zooms relative to the center of the track output.
1341         float half_track_w = (float)track->track_w / 2;
1342         float half_track_h = (float)track->track_h / 2;
1343 // Translate mask to projection
1344         float projector_x, projector_y, projector_z;
1345         track->automation->get_projector(&projector_x,
1346                 &projector_y,
1347                 &projector_z,
1348                 position,
1349                 PLAY_FORWARD);
1350
1351
1352 // Get position of cursor relative to mask
1353         float mask_cursor_x = get_cursor_x();
1354         float mask_cursor_y = get_cursor_y();
1355         canvas_to_output(mwindow->edl, 0, mask_cursor_x, mask_cursor_y);
1356
1357         projector_x += mwindow->edl->session->output_w / 2;
1358         projector_y += mwindow->edl->session->output_h / 2;
1359
1360         mask_cursor_x -= projector_x;
1361         mask_cursor_y -= projector_y;
1362         mask_cursor_x = mask_cursor_x / projector_z + half_track_w;
1363         mask_cursor_y = mask_cursor_y / projector_z + half_track_h;
1364
1365 // Fix cursor origin
1366         if(button_press)
1367         {
1368                 gui->x_origin = mask_cursor_x;
1369                 gui->y_origin = mask_cursor_y;
1370         }
1371
1372         int result = 0;
1373 // Points of closest line
1374         int shortest_point1 = -1;
1375         int shortest_point2 = -1;
1376 // Closest point
1377         int shortest_point = -1;
1378 // Distance to closest line
1379         float shortest_line_distance = BC_INFINITY;
1380 // Distance to closest point
1381         float shortest_point_distance = BC_INFINITY;
1382         int selected_point = -1;
1383         int selected_control_point = -1;
1384         float selected_control_point_distance = BC_INFINITY;
1385         ArrayList<int> x_points;
1386         ArrayList<int> y_points;
1387
1388         if(!cursor_motion)
1389         {
1390                 if(draw)
1391                 {
1392                         get_canvas()->set_color(WHITE);
1393                         get_canvas()->set_inverse();
1394                 }
1395 //printf("CWindowCanvas::do_mask 1 %d\n", points.size());
1396
1397 // Never draw closed polygon and a closed
1398 // polygon is harder to add points to.
1399                 for(int i = 0; i < points.size() && !result; i++)
1400                 {
1401                         MaskPoint *point1 = points.get(i);
1402                         MaskPoint *point2 = (i >= points.size() - 1) ? 
1403                                 points.get(0) : 
1404                                 points.get(i + 1);
1405                         float x0, x1, x2, x3;
1406                         float y0, y1, y2, y3;
1407                         float x, y;
1408                         int segments = (int)(sqrt(SQR(point1->x - point2->x) + SQR(point1->y - point2->y)));
1409
1410 //printf("CWindowCanvas::do_mask 1 %f, %f -> %f, %f projectorz=%f\n",
1411 //point1->x, point1->y, point2->x, point2->y, projector_z);
1412                         for(int j = 0; j <= segments && !result; j++)
1413                         {
1414 //printf("CWindowCanvas::do_mask 1 %f, %f -> %f, %f\n", x0, y0, x3, y3);
1415                                 x0 = point1->x;
1416                                 y0 = point1->y;
1417                                 x1 = point1->x + point1->control_x2;
1418                                 y1 = point1->y + point1->control_y2;
1419                                 x2 = point2->x + point2->control_x1;
1420                                 y2 = point2->y + point2->control_y1;
1421                                 x3 = point2->x;
1422                                 y3 = point2->y;
1423
1424                                 float t = (float)j / segments;
1425                                 float tpow2 = t * t;
1426                                 float tpow3 = t * t * t;
1427                                 float invt = 1 - t;
1428                                 float invtpow2 = invt * invt;
1429                                 float invtpow3 = invt * invt * invt;
1430
1431                                 x = (        invtpow3 * x0
1432                                         + 3 * t     * invtpow2 * x1
1433                                         + 3 * tpow2 * invt     * x2 
1434                                         +     tpow3            * x3);
1435                                 y = (        invtpow3 * y0 
1436                                         + 3 * t     * invtpow2 * y1
1437                                         + 3 * tpow2 * invt     * y2 
1438                                         +     tpow3            * y3);
1439
1440                                 x = (x - half_track_w) * projector_z + projector_x;
1441                                 y = (y - half_track_h) * projector_z + projector_y;
1442
1443
1444 // Test new point addition
1445                                 if(button_press)
1446                                 {
1447                                         float line_distance = 
1448                                                 sqrt(SQR(x - mask_cursor_x) + SQR(y - mask_cursor_y));
1449
1450 //printf("CWindowCanvas::do_mask 1 x=%f mask_cursor_x=%f y=%f mask_cursor_y=%f %f %f %d, %d\n", 
1451 //x, mask_cursor_x, y, mask_cursor_y, line_distance, shortest_line_distance, shortest_point1, shortest_point2);
1452                                         if(line_distance < shortest_line_distance || 
1453                                                 shortest_point1 < 0)
1454                                         {
1455                                                 shortest_line_distance = line_distance;
1456                                                 shortest_point1 = i;
1457                                                 shortest_point2 = (i >= points.size() - 1) ? 0 : (i + 1);
1458 //printf("CWindowCanvas::do_mask 2 %f %f %d, %d\n", line_distance, shortest_line_distance, shortest_point1, shortest_point2);
1459                                         }
1460
1461
1462                                         float point_distance1 = 
1463                                                 sqrt(SQR(point1->x - mask_cursor_x) + SQR(point1->y - mask_cursor_y));
1464                                         float point_distance2 = 
1465                                                 sqrt(SQR(point2->x - mask_cursor_x) + SQR(point2->y - mask_cursor_y));
1466
1467                                         if(point_distance1 < shortest_point_distance || 
1468                                                 shortest_point < 0)
1469                                         {
1470                                                 shortest_point_distance = point_distance1;
1471                                                 shortest_point = i;
1472                                         }
1473
1474                                         if(point_distance2 < shortest_point_distance || 
1475                                                 shortest_point < 0)
1476                                         {
1477                                                 shortest_point_distance = point_distance2;
1478                                                 shortest_point = (i >= points.size() - 1) ? 0 : (i + 1);
1479                                         }
1480                                 }
1481
1482                                 output_to_canvas(mwindow->edl, 0, x, y);
1483
1484
1485 #define TEST_BOX(cursor_x, cursor_y, target_x, target_y) \
1486         (cursor_x >= target_x - CONTROL_W / 2 && \
1487         cursor_x < target_x + CONTROL_W / 2 && \
1488         cursor_y >= target_y - CONTROL_H / 2 && \
1489         cursor_y < target_y + CONTROL_H / 2)
1490
1491 // Test existing point selection
1492                                 if(button_press)
1493                                 {
1494                                         float canvas_x = (x0 - half_track_w) * projector_z + projector_x;
1495                                         float canvas_y = (y0 - half_track_h) * projector_z + projector_y;
1496                                         int cursor_x = get_cursor_x();
1497                                         int cursor_y = get_cursor_y();
1498
1499 // Test first point
1500                                         if(gui->shift_down())
1501                                         {
1502                                                 float control_x = (x1 - half_track_w) * projector_z + projector_x;
1503                                                 float control_y = (y1 - half_track_h) * projector_z + projector_y;
1504                                                 output_to_canvas(mwindow->edl, 0, control_x, control_y);
1505
1506                                                 float distance = 
1507                                                         sqrt(SQR(control_x - cursor_x) + SQR(control_y - cursor_y));
1508
1509                                                 if(distance < selected_control_point_distance)
1510                                                 {
1511                                                         selected_point = i;
1512                                                         selected_control_point = 1;
1513                                                         selected_control_point_distance = distance;
1514                                                 }
1515                                         }
1516                                         else
1517                                         {
1518                                                 output_to_canvas(mwindow->edl, 0, canvas_x, canvas_y);
1519                                                 if(!gui->ctrl_down())
1520                                                 {
1521                                                         if(TEST_BOX(cursor_x, cursor_y, canvas_x, canvas_y))
1522                                                         {
1523                                                                 selected_point = i;
1524                                                         }
1525                                                 }
1526                                                 else
1527                                                 {
1528                                                         selected_point = shortest_point;
1529                                                 }
1530                                         }
1531
1532 // Test second point
1533                                         canvas_x = (x3 - half_track_w) * projector_z + projector_x;
1534                                         canvas_y = (y3 - half_track_h) * projector_z + projector_y;
1535                                         if(gui->shift_down())
1536                                         {
1537                                                 float control_x = (x2 - half_track_w) * projector_z + projector_x;
1538                                                 float control_y = (y2 - half_track_h) * projector_z + projector_y;
1539                                                 output_to_canvas(mwindow->edl, 0, control_x, control_y);
1540
1541                                                 float distance = 
1542                                                         sqrt(SQR(control_x - cursor_x) + SQR(control_y - cursor_y));
1543
1544 //printf("CWindowCanvas::do_mask %d %f %f\n", i, distance, selected_control_point_distance);
1545                                                 if(distance < selected_control_point_distance)
1546                                                 {
1547                                                         selected_point = (i < points.size() - 1 ? i + 1 : 0);
1548                                                         selected_control_point = 0;
1549                                                         selected_control_point_distance = distance;
1550                                                 }
1551                                         }
1552                                         else
1553                                         if(i < points.size() - 1)
1554                                         {
1555                                                 output_to_canvas(mwindow->edl, 0, canvas_x, canvas_y);
1556                                                 if(!gui->ctrl_down())
1557                                                 {
1558                                                         if(TEST_BOX(cursor_x, cursor_y, canvas_x, canvas_y))
1559                                                         {
1560                                                                 selected_point = (i < points.size() - 1 ? i + 1 : 0);
1561                                                         }
1562                                                 }
1563                                                 else
1564                                                 {
1565                                                         selected_point = shortest_point;
1566                                                 }
1567                                         }
1568                                 }
1569
1570
1571
1572                                 if(j > 0)
1573                                 {
1574 // Draw joining line
1575                                         if(draw)
1576                                         {
1577                                                 x_points.append((int)x);
1578                                                 y_points.append((int)y);
1579                                         }
1580
1581                                         if(j == segments)
1582                                         {
1583
1584
1585
1586
1587                                                 if(draw)
1588                                                 {
1589 // Draw second anchor
1590                                                         if(i < points.size() - 1)
1591                                                         {
1592                                                                 if(i == gui->affected_point - 1)
1593                                                                         get_canvas()->draw_disc((int)x - CONTROL_W / 2, 
1594                                                                                 (int)y - CONTROL_W / 2, 
1595                                                                                 CONTROL_W, 
1596                                                                                 CONTROL_W);
1597                                                                 else
1598                                                                         get_canvas()->draw_circle((int)x - CONTROL_W / 2, 
1599                                                                                 (int)y - CONTROL_W / 2, 
1600                                                                                 CONTROL_W, 
1601                                                                                 CONTROL_W);
1602 // char string[BCTEXTLEN];
1603 // sprintf(string, "%d", (i < points.size() - 1 ? i + 1 : 0));
1604 // canvas->draw_text((int)x + CONTROL_W, (int)y + CONTROL_W, string);
1605                                                         }
1606
1607 // Draw second control point.  Discard x2 and y2 after this.
1608                                                         x2 = (x2 - half_track_w) * projector_z + projector_x;
1609                                                         y2 = (y2 - half_track_h) * projector_z + projector_y;
1610                                                         output_to_canvas(mwindow->edl, 0, x2, y2);
1611                                                         get_canvas()->draw_line((int)x, (int)y, (int)x2, (int)y2);
1612                                                         get_canvas()->draw_rectangle((int)x2 - CONTROL_W / 2,
1613                                                                 (int)y2 - CONTROL_H / 2,
1614                                                                 CONTROL_W,
1615                                                                 CONTROL_H);
1616                                                 }
1617                                         }
1618                                 }
1619                                 else
1620                                 {
1621
1622
1623 // Draw first anchor
1624                                         if(i == 0 && draw)
1625                                         {
1626                                                 get_canvas()->draw_disc((int)x - FIRST_CONTROL_W / 2, 
1627                                                         (int)y - FIRST_CONTROL_H / 2, 
1628                                                         FIRST_CONTROL_W, 
1629                                                         FIRST_CONTROL_H);
1630                                         }
1631
1632 // Draw first control point.  Discard x1 and y1 after this.
1633                                         if(draw)
1634                                         {
1635                                                 x1 = (x1 - half_track_w) * projector_z + projector_x;
1636                                                 y1 = (y1 - half_track_h) * projector_z + projector_y;
1637                                                 output_to_canvas(mwindow->edl, 0, x1, y1);
1638                                                 get_canvas()->draw_line((int)x, (int)y, (int)x1, (int)y1);
1639                                                 get_canvas()->draw_rectangle((int)x1 - CONTROL_W / 2,
1640                                                         (int)y1 - CONTROL_H / 2,
1641                                                         CONTROL_W,
1642                                                         CONTROL_H);
1643                                         
1644                                                 x_points.append((int)x);
1645                                                 y_points.append((int)y);
1646                                         }
1647                                 }
1648 //printf("CWindowCanvas::do_mask 1\n");
1649
1650                         }
1651                 }
1652 //printf("CWindowCanvas::do_mask 1\n");
1653
1654                 if(draw)
1655                 {
1656                         get_canvas()->draw_polygon(&x_points, &y_points);
1657                         get_canvas()->set_opaque();
1658                 }
1659 //printf("CWindowCanvas::do_mask 1\n");
1660         }
1661
1662
1663
1664
1665
1666
1667
1668         if(button_press && !result)
1669         {
1670                 gui->affected_track = gui->cwindow->calculate_affected_track();
1671
1672 // Get keyframe outside the EDL to edit.  This must be rendered
1673 // instead of the EDL keyframes when it exists.  Then it must be
1674 // applied to the EDL keyframes on buttonrelease.
1675                 if(gui->affected_track)
1676                 {
1677 #ifdef USE_KEYFRAME_SPANNING
1678 // Make copy of current parameters in local keyframe
1679                         gui->mask_keyframe = 
1680                                 (MaskAuto*)gui->cwindow->calculate_affected_auto(
1681                                         mask_autos,
1682                                         0);
1683                         gui->orig_mask_keyframe->copy_data(gui->mask_keyframe);
1684 #else
1685
1686                         gui->mask_keyframe = 
1687                                 (MaskAuto*)gui->cwindow->calculate_affected_auto(
1688                                         mask_autos,
1689                                         1);
1690 #endif
1691                 }
1692                 SubMask *mask = gui->mask_keyframe->get_submask(mwindow->edl->session->cwindow_mask);
1693
1694
1695 // Translate entire keyframe
1696                 if(gui->alt_down() && mask->points.size())
1697                 {
1698                         mwindow->undo->update_undo_before(_("mask translate"), 0);
1699                         gui->current_operation = CWINDOW_MASK_TRANSLATE;
1700                         gui->affected_point = 0;
1701                 }
1702                 else
1703 // Existing point or control point was selected
1704                 if(selected_point >= 0)
1705                 {
1706                         mwindow->undo->update_undo_before(_("mask adjust"), 0);
1707                         gui->affected_point = selected_point;
1708
1709                         if(selected_control_point == 0)
1710                                 gui->current_operation = CWINDOW_MASK_CONTROL_IN;
1711                         else
1712                         if(selected_control_point == 1)
1713                                 gui->current_operation = CWINDOW_MASK_CONTROL_OUT;
1714                         else
1715                                 gui->current_operation = mwindow->edl->session->cwindow_operation;
1716                 }
1717                 else
1718 // No existing point or control point was selected so create a new one
1719                 if(!gui->shift_down() && !gui->alt_down())
1720                 {
1721                         mwindow->undo->update_undo_before(_("mask point"), 0);
1722 // Create the template
1723                         MaskPoint *point = new MaskPoint;
1724                         point->x = mask_cursor_x;
1725                         point->y = mask_cursor_y;
1726                         point->control_x1 = 0;
1727                         point->control_y1 = 0;
1728                         point->control_x2 = 0;
1729                         point->control_y2 = 0;
1730
1731
1732                         if(shortest_point2 < shortest_point1)
1733                         {
1734                                 shortest_point2 ^= shortest_point1;
1735                                 shortest_point1 ^= shortest_point2;
1736                                 shortest_point2 ^= shortest_point1;
1737                         }
1738
1739
1740
1741 // printf("CWindowGUI::do_mask 40\n");
1742 // mwindow->edl->dump();
1743 // printf("CWindowGUI::do_mask 50\n");
1744
1745
1746
1747 //printf("CWindowCanvas::do_mask 1 %f %f %d %d\n", 
1748 //      shortest_line_distance, shortest_point_distance, shortest_point1, shortest_point2);
1749 //printf("CWindowCanvas::do_mask %d %d\n", shortest_point1, shortest_point2);
1750
1751 // Append to end of list
1752                         if(labs(shortest_point1 - shortest_point2) > 1)
1753                         {
1754 #ifdef USE_KEYFRAME_SPANNING
1755
1756                                 MaskPoint *new_point = new MaskPoint;
1757                                 points.append(new_point);
1758                                 *new_point = *point;
1759                                 gui->affected_point = points.size() - 1;
1760
1761 #else
1762
1763 // Need to apply the new point to every keyframe
1764                                 for(MaskAuto *current = (MaskAuto*)mask_autos->default_auto;
1765                                         current; )
1766                                 {
1767                                         SubMask *submask = current->get_submask(mwindow->edl->session->cwindow_mask);
1768                                         MaskPoint *new_point = new MaskPoint;
1769                                         submask->points.append(new_point);
1770                                         *new_point = *point;
1771                                         if(current == (MaskAuto*)mask_autos->default_auto)
1772                                                 current = (MaskAuto*)mask_autos->first;
1773                                         else
1774                                                 current = (MaskAuto*)NEXT;
1775                                 }
1776                                 gui->affected_point = mask->points.size() - 1;
1777 #endif
1778
1779                                 result = 1;
1780                         }
1781                         else
1782 // Insert between 2 points, shifting back point 2
1783                         if(shortest_point1 >= 0 && shortest_point2 >= 0)
1784                         {
1785
1786 #ifdef USE_KEYFRAME_SPANNING
1787 // In case the keyframe point count isn't synchronized with the rest of the keyframes,
1788 // avoid a crash.
1789                                 if(points.size() >= shortest_point2)
1790                                 {
1791                                         MaskPoint *new_point = new MaskPoint;
1792                                         points.append(0);
1793                                         for(int i = points.size() - 1; 
1794                                                 i > shortest_point2; 
1795                                                 i--)
1796                                                 points.values[i] = points.values[i - 1];
1797                                         points.values[shortest_point2] = new_point;
1798
1799                                         *new_point = *point;
1800                                 }
1801
1802 #else
1803
1804                                 for(MaskAuto *current = (MaskAuto*)mask_autos->default_auto;
1805                                         current; )
1806                                 {
1807                                         SubMask *submask = current->get_submask(mwindow->edl->session->cwindow_mask);
1808 // In case the keyframe point count isn't synchronized with the rest of the keyframes,
1809 // avoid a crash.
1810                                         if(submask->points.size() >= shortest_point2)
1811                                         {
1812                                                 MaskPoint *new_point = new MaskPoint;
1813                                                 submask->points.append(0);
1814                                                 for(int i = submask->points.size() - 1; 
1815                                                         i > shortest_point2; 
1816                                                         i--)
1817                                                         submask->points.values[i] = submask->points.values[i - 1];
1818                                                 submask->points.values[shortest_point2] = new_point;
1819
1820                                                 *new_point = *point;
1821                                         }
1822
1823                                         if(current == (MaskAuto*)mask_autos->default_auto)
1824                                                 current = (MaskAuto*)mask_autos->first;
1825                                         else
1826                                                 current = (MaskAuto*)NEXT;
1827                                 }
1828 #endif
1829
1830
1831                                 gui->affected_point = shortest_point2;
1832                                 result = 1;
1833                         }
1834
1835
1836 // printf("CWindowGUI::do_mask 20\n");
1837 // mwindow->edl->dump();
1838 // printf("CWindowGUI::do_mask 30\n");
1839
1840
1841
1842
1843                         if(!result)
1844                         {
1845 //printf("CWindowCanvas::do_mask 1\n");
1846 // Create the first point.
1847 #ifdef USE_KEYFRAME_SPANNING
1848                                 MaskPoint *new_point = new MaskPoint;
1849                                 points.append(new_point);
1850                                 *new_point = *point;
1851 #else
1852                                 for(MaskAuto *current = (MaskAuto*)mask_autos->default_auto;
1853                                         current; )
1854                                 {
1855                                         SubMask *submask = current->get_submask(mwindow->edl->session->cwindow_mask);
1856                                         MaskPoint *new_point = new MaskPoint;
1857                                         submask->points.append(new_point);
1858                                         *new_point = *point;
1859                                         if(current == (MaskAuto*)mask_autos->default_auto)
1860                                                 current = (MaskAuto*)mask_autos->first;
1861                                         else
1862                                                 current = (MaskAuto*)NEXT;
1863                                 }
1864 #endif
1865
1866 //printf("CWindowCanvas::do_mask 2\n");
1867 // Create a second point if none existed before
1868 #ifdef USE_KEYFRAME_SPANNING
1869                                 if(points.size() < 2)
1870                                 {
1871
1872                                         MaskPoint *new_point = new MaskPoint;
1873                                         points.append(new_point);
1874                                         *new_point = *point;
1875                                 }
1876
1877                                 gui->affected_point = points.size() - 1;
1878 #else
1879                                 if(mask->points.size() < 2)
1880                                 {
1881
1882                                         for(MaskAuto *current = (MaskAuto*)mask_autos->default_auto;
1883                                                 current; )
1884                                         {
1885                                                 SubMask *submask = current->get_submask(mwindow->edl->session->cwindow_mask);
1886                                                 MaskPoint *new_point = new MaskPoint;
1887                                                 submask->points.append(new_point);
1888                                                 *new_point = *point;
1889                                                 if(current == (MaskAuto*)mask_autos->default_auto)
1890                                                         current = (MaskAuto*)mask_autos->first;
1891                                                 else
1892                                                         current = (MaskAuto*)NEXT;
1893                                         }
1894                                 }
1895
1896                                 gui->affected_point = mask->points.size() - 1;
1897 #endif
1898
1899 //printf("CWindowCanvas::do_mask 3 %d\n", mask->points.size());
1900                         }
1901
1902
1903
1904                         gui->current_operation = mwindow->edl->session->cwindow_operation;
1905 // Delete the template
1906                         delete point;
1907
1908                 }
1909
1910                 result = 1;
1911                 rerender = 1;
1912                 redraw = 1;
1913         }
1914
1915         if(button_press && result)
1916         {
1917 #ifdef USE_KEYFRAME_SPANNING
1918                 MaskPoint *point = points.values[gui->affected_point];
1919                 gui->center_x = point->x;
1920                 gui->center_y = point->y;
1921                 gui->control_in_x = point->control_x1;
1922                 gui->control_in_y = point->control_y1;
1923                 gui->control_out_x = point->control_x2;
1924                 gui->control_out_y = point->control_y2;
1925                 gui->tool_panel->raise_window();
1926 #else
1927                 SubMask *mask = gui->mask_keyframe->get_submask(mwindow->edl->session->cwindow_mask);
1928                 MaskPoint *point = mask->points.values[gui->affected_point];
1929                 gui->center_x = point->x;
1930                 gui->center_y = point->y;
1931                 gui->control_in_x = point->control_x1;
1932                 gui->control_in_y = point->control_y1;
1933                 gui->control_out_x = point->control_x2;
1934                 gui->control_out_y = point->control_y2;
1935                 gui->tool_panel->raise_window();
1936 #endif
1937         }
1938
1939 //printf("CWindowCanvas::do_mask 8\n");
1940         if(cursor_motion)
1941         {
1942
1943 #ifdef USE_KEYFRAME_SPANNING
1944 // Must update the reference keyframes for every cursor motion
1945                 gui->mask_keyframe = 
1946                         (MaskAuto*)gui->cwindow->calculate_affected_auto(
1947                                 mask_autos,
1948                                 0);
1949                 gui->orig_mask_keyframe->copy_data(gui->mask_keyframe);
1950 #endif
1951
1952 //printf("CWindowCanvas::do_mask %d %d\n", __LINE__, gui->affected_point);
1953
1954                 SubMask *mask = gui->mask_keyframe->get_submask(mwindow->edl->session->cwindow_mask);
1955                 if(gui->affected_point < mask->points.size() &&
1956                         gui->current_operation != CWINDOW_NONE)
1957                 {
1958 //                      mwindow->undo->update_undo_before(_("mask point"), this);
1959 #ifdef USE_KEYFRAME_SPANNING
1960                         MaskPoint *point = points.get(gui->affected_point);
1961 #else
1962                         MaskPoint *point = mask->points.get(gui->affected_point);
1963 #endif
1964 //                      float cursor_x = get_cursor_x();
1965 //                      float cursor_y = get_cursor_y();
1966 //                      canvas_to_output(mwindow->edl, 0, cursor_x, cursor_y);
1967                         float cursor_x = mask_cursor_x;
1968                         float cursor_y = mask_cursor_y;
1969 //printf("CWindowCanvas::do_mask 9 %d %d\n", mask->points.size(), gui->affected_point);
1970
1971                         float last_x = point->x;
1972                         float last_y = point->y;
1973                         float last_control_x1 = point->control_x1;
1974                         float last_control_y1 = point->control_y1;
1975                         float last_control_x2 = point->control_x2;
1976                         float last_control_y2 = point->control_y2;
1977
1978
1979                         switch(gui->current_operation)
1980                         {
1981                                 case CWINDOW_MASK:
1982 //printf("CWindowCanvas::do_mask %d %d\n", __LINE__, gui->affected_point);
1983                                         point->x = cursor_x - gui->x_origin + gui->center_x;
1984                                         point->y = cursor_y - gui->y_origin + gui->center_y;
1985                                         break;
1986
1987                                 case CWINDOW_MASK_CONTROL_IN:
1988                                         point->control_x1 = cursor_x - gui->x_origin + gui->control_in_x;
1989                                         point->control_y1 = cursor_y - gui->y_origin + gui->control_in_y;
1990                                         break;
1991
1992                                 case CWINDOW_MASK_CONTROL_OUT:
1993                                         point->control_x2 = cursor_x - gui->x_origin + gui->control_out_x;
1994                                         point->control_y2 = cursor_y - gui->y_origin + gui->control_out_y;
1995                                         break;
1996
1997                                 case CWINDOW_MASK_TRANSLATE:
1998 #ifdef USE_KEYFRAME_SPANNING
1999                                         for(int i = 0; i < points.size(); i++)
2000                                         {
2001                                                 points.values[i]->x += cursor_x - gui->x_origin;
2002                                                 points.values[i]->y += cursor_y - gui->y_origin;
2003                                         }
2004 #else
2005                                         for(int i = 0; i < mask->points.size(); i++)
2006                                         {
2007                                                 mask->points.values[i]->x += cursor_x - gui->x_origin;
2008                                                 mask->points.values[i]->y += cursor_y - gui->y_origin;
2009                                         }
2010 #endif
2011                                         gui->x_origin = cursor_x;
2012                                         gui->y_origin = cursor_y;
2013                                         break;
2014                         }
2015
2016
2017                         if( !EQUIV(last_x, point->x) ||
2018                                 !EQUIV(last_y, point->y) ||
2019                                 !EQUIV(last_control_x1, point->control_x1) ||
2020                                 !EQUIV(last_control_y1, point->control_y1) ||
2021                                 !EQUIV(last_control_x2, point->control_x2) ||
2022                                 !EQUIV(last_control_y2, point->control_y2))
2023                         {
2024                                 rerender = 1;
2025                                 redraw = 1;
2026                         }
2027                 }
2028                 else
2029                 if(gui->current_operation == CWINDOW_NONE)
2030                 {
2031 //                      printf("CWindowCanvas::do_mask %d\n", __LINE__);
2032                         int over_point = 0;
2033                         for(int i = 0; i < points.size() && !over_point; i++)
2034                         {
2035                                 MaskPoint *point = points.get(i);
2036                                 float x0 = point->x;
2037                                 float y0 = point->y;
2038                                 float x1 = point->x + point->control_x1;
2039                                 float y1 = point->y + point->control_y1;
2040                                 float x2 = point->x + point->control_x2;
2041                                 float y2 = point->y + point->control_y2;
2042                                 float canvas_x = (x0 - half_track_w) * projector_z + projector_x;
2043                                 float canvas_y = (y0 - half_track_h) * projector_z + projector_y;
2044                                 int cursor_x = get_cursor_x();
2045                                 int cursor_y = get_cursor_y();
2046                                 
2047                                 output_to_canvas(mwindow->edl, 0, canvas_x, canvas_y);
2048                                 if(TEST_BOX(cursor_x, cursor_y, canvas_x, canvas_y))
2049                                 {
2050                                         over_point = 1;
2051                                 }
2052                                 
2053                                 
2054                                 if(!over_point && gui->shift_down())
2055                                 {
2056                                         canvas_x = (x1 - half_track_w) * projector_z + projector_x;
2057                                         canvas_y = (y1 - half_track_h) * projector_z + projector_y;
2058                                         output_to_canvas(mwindow->edl, 0, canvas_x, canvas_y);
2059                                         if(TEST_BOX(cursor_x, cursor_y, canvas_x, canvas_y))
2060                                         {
2061                                                 over_point = 1;
2062                                         }
2063                                         else
2064                                         {
2065                                                 canvas_x = (x2 - half_track_w) * projector_z + projector_x;
2066                                                 canvas_y = (y2 - half_track_h) * projector_z + projector_y;
2067                                                 output_to_canvas(mwindow->edl, 0, canvas_x, canvas_y);
2068                                                 if(TEST_BOX(cursor_x, cursor_y, canvas_x, canvas_y))
2069                                                 {
2070                                                         over_point = 1;
2071                                                 }
2072                                         }
2073                                 }
2074                         }
2075                         
2076                         if(over_point)
2077                         {
2078                                 set_cursor(ARROW_CURSOR);
2079                         }
2080                         else
2081                         {
2082                                 set_cursor(CROSS_CURSOR);
2083                         }
2084                 }
2085                 
2086                 result = 1;
2087         }
2088 //printf("CWindowCanvas::do_mask 2 %d %d %d\n", result, rerender, redraw);
2089
2090
2091 #ifdef USE_KEYFRAME_SPANNING
2092 // Must commit change after operation.
2093         if(rerender && track)
2094         {
2095 // Swap EDL keyframe with original.
2096 // Apply new values to keyframe span
2097                 MaskAuto temp_keyframe(mwindow->edl, mask_autos);
2098                 temp_keyframe.copy_data(gui->mask_keyframe);
2099 // Apply interpolated points back to keyframe
2100                 temp_keyframe.set_points(&points, mwindow->edl->session->cwindow_mask);
2101                 gui->mask_keyframe->copy_data(gui->orig_mask_keyframe);
2102                 mask_autos->update_parameter(&temp_keyframe);
2103         }
2104 #endif
2105
2106         points.remove_all_objects();
2107 //printf("CWindowCanvas::do_mask 20\n");
2108         return result;
2109 }
2110
2111
2112 int CWindowCanvas::do_eyedrop(int &rerender, int button_press, int draw)
2113 {
2114         int result = 0;
2115         int radius = mwindow->edl->session->eyedrop_radius;
2116         int row1 = 0;
2117         int row2 = 0;
2118         int column1 = 0;
2119         int column2 = 0;
2120
2121
2122
2123         if(refresh_frame && refresh_frame->get_w()>0 && refresh_frame->get_h()>0)
2124         {
2125
2126                 if(draw)
2127                 {
2128                         row1 = gui->eyedrop_y - radius;
2129                         row2 = gui->eyedrop_y + radius;
2130                         column1 = gui->eyedrop_x - radius;
2131                         column2 = gui->eyedrop_x + radius;
2132
2133                         CLAMP(row1, 0, refresh_frame->get_h() - 1);
2134                         CLAMP(row2, 0, refresh_frame->get_h() - 1);
2135                         CLAMP(column1, 0, refresh_frame->get_w() - 1);
2136                         CLAMP(column2, 0, refresh_frame->get_w() - 1);
2137
2138                         if(row2 <= row1) row2 = row1 + 1;
2139                         if(column2 <= column1) column2 = column1 + 1;
2140
2141                         float x1 = column1;
2142                         float y1 = row1;
2143                         float x2 = column2;
2144                         float y2 = row2;
2145
2146                         output_to_canvas(mwindow->edl, 0, x1, y1);
2147                         output_to_canvas(mwindow->edl, 0, x2, y2);
2148 //printf("CWindowCanvas::do_eyedrop %d %f %f %f %f\n", __LINE__, x1, x2, y1, y2);
2149
2150                         if(x2 - x1 >= 1 && y2 - y1 >= 1)
2151                         {
2152                                 get_canvas()->set_inverse();
2153                                 get_canvas()->set_color(WHITE);
2154
2155                                 get_canvas()->draw_rectangle((int)x1, 
2156                                         (int)y1, 
2157                                         (int)(x2 - x1), 
2158                                         (int)(y2 - y1));
2159
2160                                 get_canvas()->set_opaque();
2161                                 get_canvas()->flash();
2162                         }
2163                         return 0;
2164                 }
2165         }
2166
2167         if(button_press)
2168         {
2169                 gui->current_operation = CWINDOW_EYEDROP;
2170                 gui->tool_panel->raise_window();
2171         }
2172
2173         if(gui->current_operation == CWINDOW_EYEDROP)
2174         {
2175                 mwindow->undo->update_undo_before(_("Eyedrop"), this);
2176
2177 // Get color out of frame.
2178 // Doesn't work during playback because that bypasses the refresh frame.
2179                 if(refresh_frame && refresh_frame->get_w()>0 && refresh_frame->get_h()>0)
2180                 {
2181                         float cursor_x = get_cursor_x();
2182                         float cursor_y = get_cursor_y();
2183                         canvas_to_output(mwindow->edl, 0, cursor_x, cursor_y);
2184                         CLAMP(cursor_x, 0, refresh_frame->get_w() - 1);
2185                         CLAMP(cursor_y, 0, refresh_frame->get_h() - 1);
2186
2187                         row1 = cursor_y - radius;
2188                         row2 = cursor_y + radius;
2189                         column1 = cursor_x - radius;
2190                         column2 = cursor_x + radius;
2191                         CLAMP(row1, 0, refresh_frame->get_h() - 1);
2192                         CLAMP(row2, 0, refresh_frame->get_h() - 1);
2193                         CLAMP(column1, 0, refresh_frame->get_w() - 1);
2194                         CLAMP(column2, 0, refresh_frame->get_w() - 1);
2195                         if(row2 <= row1) row2 = row1 + 1;
2196                         if(column2 <= column1) column2 = column1 + 1;
2197
2198
2199 // hide it
2200                         if(gui->eyedrop_visible)
2201                         {
2202                                 int temp;
2203                                 do_eyedrop(temp, 0, 1);
2204                                 gui->eyedrop_visible = 0;
2205                         }
2206
2207                         gui->eyedrop_x = cursor_x;
2208                         gui->eyedrop_y = cursor_y;
2209
2210 // show it
2211                         {
2212                                 int temp;
2213                                 do_eyedrop(temp, 0, 1);
2214                                 gui->eyedrop_visible = 1;
2215                         }
2216
2217 // Decompression coefficients straight out of jpeglib
2218 #define V_TO_R    1.40200
2219 #define V_TO_G    -0.71414
2220
2221 #define U_TO_G    -0.34414
2222 #define U_TO_B    1.77200
2223
2224 #define GET_COLOR(type, components, max, do_yuv) \
2225 { \
2226         type *row = (type*)(refresh_frame->get_rows()[i]) + \
2227                 j * components; \
2228         float red = (float)*row++ / max; \
2229         float green = (float)*row++ / max; \
2230         float blue = (float)*row++ / max; \
2231         if(do_yuv) \
2232         { \
2233                 mwindow->edl->local_session->red += red + V_TO_R * (blue - 0.5); \
2234                 mwindow->edl->local_session->green += red + U_TO_G * (green - 0.5) + V_TO_G * (blue - 0.5); \
2235                 mwindow->edl->local_session->blue += red + U_TO_B * (green - 0.5); \
2236         } \
2237         else \
2238         { \
2239                 mwindow->edl->local_session->red += red; \
2240                 mwindow->edl->local_session->green += green; \
2241                 mwindow->edl->local_session->blue += blue; \
2242         } \
2243 }
2244
2245
2246
2247                         mwindow->edl->local_session->red = 0;
2248                         mwindow->edl->local_session->green = 0;
2249                         mwindow->edl->local_session->blue = 0;
2250                         for(int i = row1; i < row2; i++)
2251                         {
2252                                 for(int j = column1; j < column2; j++)
2253                                 {
2254                                         switch(refresh_frame->get_color_model())
2255                                         {
2256                                                 case BC_YUV888:
2257                                                         GET_COLOR(unsigned char, 3, 0xff, 1);
2258                                                         break;
2259                                                 case BC_YUVA8888:
2260                                                         GET_COLOR(unsigned char, 4, 0xff, 1);
2261                                                         break;
2262                                                 case BC_YUV161616:
2263                                                         GET_COLOR(uint16_t, 3, 0xffff, 1);
2264                                                         break;
2265                                                 case BC_YUVA16161616:
2266                                                         GET_COLOR(uint16_t, 4, 0xffff, 1);
2267                                                         break;
2268                                                 case BC_RGB888:
2269                                                         GET_COLOR(unsigned char, 3, 0xff, 0);
2270                                                         break;
2271                                                 case BC_RGBA8888:
2272                                                         GET_COLOR(unsigned char, 4, 0xff, 0);
2273                                                         break;
2274                                                 case BC_RGB_FLOAT:
2275                                                         GET_COLOR(float, 3, 1.0, 0);
2276                                                         break;
2277                                                 case BC_RGBA_FLOAT:
2278                                                         GET_COLOR(float, 4, 1.0, 0);
2279                                                         break;
2280                                         }
2281                                 }
2282                         }
2283                         
2284                         mwindow->edl->local_session->red /= (row2 - row1) * (column2 - column1);
2285                         mwindow->edl->local_session->green /= (row2 - row1) * (column2 - column1);
2286                         mwindow->edl->local_session->blue /= (row2 - row1) * (column2 - column1);
2287
2288                 }
2289                 else
2290                 {
2291                         mwindow->edl->local_session->red = 0;
2292                         mwindow->edl->local_session->green = 0;
2293                         mwindow->edl->local_session->blue = 0;
2294                         gui->eyedrop_visible = 0;
2295                 }
2296
2297
2298                 gui->update_tool();             
2299
2300
2301
2302                 result = 1;
2303 // Can't rerender since the color value is from the output of any effect it
2304 // goes into.
2305 //              rerender = 1;
2306                 mwindow->undo->update_undo_after(_("Eyedrop"), LOAD_SESSION);
2307         }
2308
2309         return result;
2310 }
2311
2312 void CWindowCanvas::draw_overlays()
2313 {
2314         if(mwindow->edl->session->safe_regions)
2315         {
2316                 draw_safe_regions();
2317         }
2318
2319         if(mwindow->edl->session->cwindow_scrollbars)
2320         {
2321 // Always draw output rectangle
2322                 float x1, y1, x2, y2;
2323                 x1 = 0;
2324                 x2 = mwindow->edl->session->output_w;
2325                 y1 = 0;
2326                 y2 = mwindow->edl->session->output_h;
2327                 output_to_canvas(mwindow->edl, 0, x1, y1);
2328                 output_to_canvas(mwindow->edl, 0, x2, y2);
2329
2330                 get_canvas()->set_inverse();
2331                 get_canvas()->set_color(WHITE);
2332
2333                 get_canvas()->draw_rectangle((int)x1, 
2334                                 (int)y1, 
2335                                 (int)(x2 - x1), 
2336                                 (int)(y2 - y1));
2337
2338                 get_canvas()->set_opaque();
2339         }
2340
2341         if(mwindow->session->ccanvas_highlighted)
2342         {
2343                 get_canvas()->set_color(WHITE);
2344                 get_canvas()->set_inverse();
2345                 get_canvas()->draw_rectangle(0, 0, get_canvas()->get_w(), get_canvas()->get_h());
2346                 get_canvas()->draw_rectangle(1, 1, get_canvas()->get_w() - 2, get_canvas()->get_h() - 2);
2347                 get_canvas()->set_opaque();
2348         }
2349
2350         int temp1 = 0, temp2 = 0;
2351 //printf("CWindowCanvas::draw_overlays 1 %d\n", mwindow->edl->session->cwindow_operation);
2352         switch(mwindow->edl->session->cwindow_operation)
2353         {
2354                 case CWINDOW_CAMERA:
2355                         draw_bezier(1);
2356                         break;
2357
2358                 case CWINDOW_PROJECTOR:
2359                         draw_bezier(0);
2360                         break;
2361
2362                 case CWINDOW_CROP:
2363                         draw_crop();
2364                         break;
2365
2366                 case CWINDOW_MASK:
2367                         do_mask(temp1, temp2, 0, 0, 1);
2368                         break;
2369
2370                 case CWINDOW_RULER:
2371                         do_ruler(1, 0, 0, 0);
2372                         break;
2373
2374                 case CWINDOW_EYEDROP:
2375                 if(gui->eyedrop_visible)
2376                 {
2377                         int rerender;
2378                         do_eyedrop(rerender, 0, 1);
2379                         gui->eyedrop_visible = 1;
2380                         break;
2381                 }
2382         }
2383 }
2384
2385 void CWindowCanvas::draw_safe_regions()
2386 {
2387         float action_x1, action_x2, action_y1, action_y2;
2388         float title_x1, title_x2, title_y1, title_y2;
2389
2390         action_x1 = mwindow->edl->session->output_w / 2 - mwindow->edl->session->output_w / 2 * 0.9;
2391         action_x2 = mwindow->edl->session->output_w / 2 + mwindow->edl->session->output_w / 2 * 0.9;
2392         action_y1 = mwindow->edl->session->output_h / 2 - mwindow->edl->session->output_h / 2 * 0.9;
2393         action_y2 = mwindow->edl->session->output_h / 2 + mwindow->edl->session->output_h / 2 * 0.9;
2394         title_x1 = mwindow->edl->session->output_w / 2 - mwindow->edl->session->output_w / 2 * 0.8;
2395         title_x2 = mwindow->edl->session->output_w / 2 + mwindow->edl->session->output_w / 2 * 0.8;
2396         title_y1 = mwindow->edl->session->output_h / 2 - mwindow->edl->session->output_h / 2 * 0.8;
2397         title_y2 = mwindow->edl->session->output_h / 2 + mwindow->edl->session->output_h / 2 * 0.8;
2398
2399         output_to_canvas(mwindow->edl, 0, action_x1, action_y1);
2400         output_to_canvas(mwindow->edl, 0, action_x2, action_y2);
2401         output_to_canvas(mwindow->edl, 0, title_x1, title_y1);
2402         output_to_canvas(mwindow->edl, 0, title_x2, title_y2);
2403
2404         get_canvas()->set_inverse();
2405         get_canvas()->set_color(WHITE);
2406
2407         get_canvas()->draw_rectangle((int)action_x1, 
2408                         (int)action_y1, 
2409                         (int)(action_x2 - action_x1), 
2410                         (int)(action_y2 - action_y1));
2411         get_canvas()->draw_rectangle((int)title_x1, 
2412                         (int)title_y1, 
2413                         (int)(title_x2 - title_x1), 
2414                         (int)(title_y2 - title_y1));
2415
2416         get_canvas()->set_opaque();
2417 }
2418
2419 void CWindowCanvas::reset_keyframe(int do_camera)
2420 {
2421         FloatAuto *x_keyframe = 0;
2422         FloatAuto *y_keyframe = 0;
2423         FloatAuto *z_keyframe = 0;
2424         Track *affected_track = 0;
2425
2426         affected_track = gui->cwindow->calculate_affected_track();
2427
2428         if(affected_track)
2429         {
2430                 gui->cwindow->calculate_affected_autos(&x_keyframe,
2431                         &y_keyframe,
2432                         &z_keyframe,
2433                         affected_track,
2434                         do_camera,
2435                         1,
2436                         1,
2437                         1);
2438
2439                 x_keyframe->value = 0;
2440                 y_keyframe->value = 0;
2441                 z_keyframe->value = 1;
2442
2443                 mwindow->sync_parameters(CHANGE_PARAMS);
2444                 gui->update_tool();
2445         }
2446 }
2447
2448 void CWindowCanvas::reset_camera()
2449 {
2450         reset_keyframe(1);
2451 }
2452
2453 void CWindowCanvas::reset_projector()
2454 {
2455         reset_keyframe(0);
2456 }
2457
2458 int CWindowCanvas::test_crop(int button_press, int &redraw)
2459 {
2460         int result = 0;
2461         int handle_selected = -1;
2462         float x1 = mwindow->edl->session->crop_x1;
2463         float y1 = mwindow->edl->session->crop_y1;
2464         float x2 = mwindow->edl->session->crop_x2;
2465         float y2 = mwindow->edl->session->crop_y2;
2466         float cursor_x = get_cursor_x();
2467         float cursor_y = get_cursor_y();
2468         float canvas_x1 = x1;
2469         float canvas_y1 = y1;
2470         float canvas_x2 = x2;
2471         float canvas_y2 = y2;
2472         float canvas_cursor_x = cursor_x;
2473         float canvas_cursor_y = cursor_y;
2474
2475         canvas_to_output(mwindow->edl, 0, cursor_x, cursor_y);
2476 // Use screen normalized coordinates for hot spot tests.
2477         output_to_canvas(mwindow->edl, 0, canvas_x1, canvas_y1);
2478         output_to_canvas(mwindow->edl, 0, canvas_x2, canvas_y2);
2479
2480
2481         if(gui->current_operation == CWINDOW_CROP)
2482         {
2483                 handle_selected = gui->crop_handle;
2484         }
2485         else
2486         if(canvas_cursor_x >= canvas_x1 && canvas_cursor_x < canvas_x1 + CROPHANDLE_W &&
2487                 canvas_cursor_y >= canvas_y1 && canvas_cursor_y < canvas_y1 + CROPHANDLE_H)
2488         {
2489                 handle_selected = 0;
2490                 gui->crop_origin_x = x1;
2491                 gui->crop_origin_y = y1;
2492         }
2493         else
2494         if(canvas_cursor_x >= canvas_x2 - CROPHANDLE_W && canvas_cursor_x < canvas_x2 &&
2495                 canvas_cursor_y >= canvas_y1 && canvas_cursor_y < canvas_y1 + CROPHANDLE_H)
2496         {
2497                 handle_selected = 1;
2498                 gui->crop_origin_x = x2;
2499                 gui->crop_origin_y = y1;
2500         }
2501         else
2502         if(canvas_cursor_x >= canvas_x1 && canvas_cursor_x < canvas_x1 + CROPHANDLE_W &&
2503                 canvas_cursor_y >= canvas_y2 - CROPHANDLE_H && canvas_cursor_y < canvas_y2)
2504         {
2505                 handle_selected = 2;
2506                 gui->crop_origin_x = x1;
2507                 gui->crop_origin_y = y2;
2508         }
2509         else
2510         if(canvas_cursor_x >= canvas_x2 - CROPHANDLE_W && canvas_cursor_x < canvas_x2 &&
2511                 canvas_cursor_y >= canvas_y2 - CROPHANDLE_H && canvas_cursor_y < canvas_y2)
2512         {
2513                 handle_selected = 3;
2514                 gui->crop_origin_x = x2;
2515                 gui->crop_origin_y = y2;
2516         }
2517         else
2518 // Start new box
2519         {
2520                 gui->crop_origin_x = cursor_x;
2521                 gui->crop_origin_y = cursor_y;
2522         }
2523
2524 // printf("test crop %d %d\n", 
2525 //      gui->current_operation,
2526 //      handle_selected);
2527
2528 // Start dragging.
2529         if(button_press)
2530         {
2531                 if(gui->alt_down())
2532                 {
2533                         gui->crop_translate = 1;
2534                         gui->crop_origin_x1 = x1;
2535                         gui->crop_origin_y1 = y1;
2536                         gui->crop_origin_x2 = x2;
2537                         gui->crop_origin_y2 = y2;
2538                 }
2539                 else
2540                         gui->crop_translate = 0;
2541
2542                 gui->current_operation = CWINDOW_CROP;
2543                 gui->crop_handle = handle_selected;
2544                 gui->x_origin = cursor_x;
2545                 gui->y_origin = cursor_y;
2546                 gui->tool_panel->raise_window();
2547                 result = 1;
2548
2549                 if(handle_selected < 0 && !gui->crop_translate) 
2550                 {
2551                         x2 = x1 = cursor_x;
2552                         y2 = y1 = cursor_y;
2553                         mwindow->edl->session->crop_x1 = (int)x1;
2554                         mwindow->edl->session->crop_y1 = (int)y1;
2555                         mwindow->edl->session->crop_x2 = (int)x2;
2556                         mwindow->edl->session->crop_y2 = (int)y2;
2557                         redraw = 1;
2558                 }
2559         }
2560     else
2561 // Translate all 4 points
2562         if(gui->current_operation == CWINDOW_CROP && gui->crop_translate)
2563         {
2564                 x1 = cursor_x - gui->x_origin + gui->crop_origin_x1;
2565                 y1 = cursor_y - gui->y_origin + gui->crop_origin_y1;
2566                 x2 = cursor_x - gui->x_origin + gui->crop_origin_x2;
2567                 y2 = cursor_y - gui->y_origin + gui->crop_origin_y2;
2568
2569                 mwindow->edl->session->crop_x1 = (int)x1;
2570                 mwindow->edl->session->crop_y1 = (int)y1;
2571                 mwindow->edl->session->crop_x2 = (int)x2;
2572                 mwindow->edl->session->crop_y2 = (int)y2;
2573                 result = 1;
2574                 redraw = 1;
2575         }
2576         else
2577 // Update dragging
2578         if(gui->current_operation == CWINDOW_CROP)
2579         {
2580                 switch(gui->crop_handle)
2581                 {
2582                         case -1:
2583                                 x1 = gui->crop_origin_x;
2584                                 y1 = gui->crop_origin_y;
2585                                 x2 = gui->crop_origin_x;
2586                                 y2 = gui->crop_origin_y;
2587                                 if(cursor_x < gui->x_origin)
2588                                 {
2589                                         if(cursor_y < gui->y_origin)
2590                                         {
2591                                                 x1 = cursor_x;
2592                                                 y1 = cursor_y;
2593                                         }
2594                                         else
2595                                         if(cursor_y >= gui->y_origin)
2596                                         {
2597                                                 x1 = cursor_x;
2598                                                 y2 = cursor_y;
2599                                         }
2600                                 }
2601                                 else
2602                                 if(cursor_x  >= gui->x_origin)
2603                                 {
2604                                         if(cursor_y < gui->y_origin)
2605                                         {
2606                                                 y1 = cursor_y;
2607                                                 x2 = cursor_x;
2608                                         }
2609                                         else
2610                                         if(cursor_y >= gui->y_origin)
2611                                         {
2612                                                 x2 = cursor_x;
2613                                                 y2 = cursor_y;
2614                                         }
2615                                 }
2616
2617 // printf("test crop %d %d %d %d\n", 
2618 //      mwindow->edl->session->crop_x1,
2619 //      mwindow->edl->session->crop_y1,
2620 //      mwindow->edl->session->crop_x2,
2621 //      mwindow->edl->session->crop_y2);
2622                                 break;
2623                         case 0:
2624                                 x1 = cursor_x - gui->x_origin + gui->crop_origin_x;
2625                                 y1 = cursor_y - gui->y_origin + gui->crop_origin_y;
2626                                 break;
2627                         case 1:
2628                                 x2 = cursor_x - gui->x_origin + gui->crop_origin_x;
2629                                 y1 = cursor_y - gui->y_origin + gui->crop_origin_y;
2630                                 break;
2631                         case 2:
2632                                 x1 = cursor_x - gui->x_origin + gui->crop_origin_x;
2633                                 y2 = cursor_y - gui->y_origin + gui->crop_origin_y;
2634                                 break;
2635                         case 3:
2636                                 x2 = cursor_x - gui->x_origin + gui->crop_origin_x;
2637                                 y2 = cursor_y - gui->y_origin + gui->crop_origin_y;
2638                                 break;
2639                 }
2640
2641                 if(!EQUIV(mwindow->edl->session->crop_x1, x1) ||
2642                         !EQUIV(mwindow->edl->session->crop_x2, x2) ||
2643                         !EQUIV(mwindow->edl->session->crop_y1, y1) ||
2644                         !EQUIV(mwindow->edl->session->crop_y2, y2))
2645                 {
2646                         if (x1 > x2)
2647                         {
2648                                 float tmp = x1;
2649                                 x1 = x2;
2650                                 x2 = tmp;
2651                                 switch (gui->crop_handle) 
2652                                 {
2653                                         case 0: gui->crop_handle = 1; break;
2654                                         case 1: gui->crop_handle = 0; break;
2655                                         case 2: gui->crop_handle = 3; break;
2656                                         case 3: gui->crop_handle = 2; break;
2657                                         default: break;
2658                                 }
2659                         }
2660
2661                         if (y1 > y2) 
2662                         {
2663                                 float tmp = y1;
2664                                 y1 = y2;
2665                                 y2 = tmp;
2666                                 switch (gui->crop_handle) 
2667                                 {
2668                                         case 0: gui->crop_handle = 2; break;
2669                                         case 1: gui->crop_handle = 3; break;
2670                                         case 2: gui->crop_handle = 0; break;
2671                                         case 3: gui->crop_handle = 1; break;
2672                                         default: break;
2673                                 }
2674                         }
2675
2676                         mwindow->edl->session->crop_x1 = (int)x1;
2677                         mwindow->edl->session->crop_y1 = (int)y1;
2678                         mwindow->edl->session->crop_x2 = (int)x2;
2679                         mwindow->edl->session->crop_y2 = (int)y2;
2680                         result = 1;
2681                         redraw = 1;
2682                 }
2683         }
2684         else
2685 // Update cursor font
2686         if(handle_selected >= 0)
2687         {
2688                 switch(handle_selected)
2689                 {
2690                         case 0:
2691                                 set_cursor(UPLEFT_RESIZE);
2692                                 break;
2693                         case 1:
2694                                 set_cursor(UPRIGHT_RESIZE);
2695                                 break;
2696                         case 2:
2697                                 set_cursor(DOWNLEFT_RESIZE);
2698                                 break;
2699                         case 3:
2700                                 set_cursor(DOWNRIGHT_RESIZE);
2701                                 break;
2702                 }
2703                 result = 1;
2704         }
2705         else
2706         {
2707                 set_cursor(ARROW_CURSOR);
2708         }
2709 #define CLAMP(x, y, z) ((x) = ((x) < (y) ? (y) : ((x) > (z) ? (z) : (x))))
2710         
2711         if(redraw)
2712         {
2713                 CLAMP(mwindow->edl->session->crop_x1, 0, mwindow->edl->session->output_w);
2714                 CLAMP(mwindow->edl->session->crop_x2, 0, mwindow->edl->session->output_w);
2715                 CLAMP(mwindow->edl->session->crop_y1, 0, mwindow->edl->session->output_h);
2716                 CLAMP(mwindow->edl->session->crop_y2, 0, mwindow->edl->session->output_h);
2717 // printf("CWindowCanvas::test_crop %d %d %d %d\n", 
2718 //      mwindow->edl->session->crop_x2,
2719 //      mwindow->edl->session->crop_y2,
2720 //      mwindow->edl->calculate_output_w(0), 
2721 //      mwindow->edl->calculate_output_h(0));
2722         }
2723         return result;
2724 }
2725
2726
2727 void CWindowCanvas::draw_crop()
2728 {
2729         get_canvas()->set_inverse();
2730         get_canvas()->set_color(WHITE);
2731
2732         float x1 = mwindow->edl->session->crop_x1;
2733         float y1 = mwindow->edl->session->crop_y1;
2734         float x2 = mwindow->edl->session->crop_x2;
2735         float y2 = mwindow->edl->session->crop_y2;
2736
2737         output_to_canvas(mwindow->edl, 0, x1, y1);
2738         output_to_canvas(mwindow->edl, 0, x2, y2);
2739
2740         if(x2 - x1 && y2 - y1)
2741                 get_canvas()->draw_rectangle((int)x1, 
2742                         (int)y1, 
2743                         (int)(x2 - x1), 
2744                         (int)(y2 - y1));
2745
2746         draw_crophandle((int)x1, (int)y1);
2747         draw_crophandle((int)x2 - CROPHANDLE_W, (int)y1);
2748         draw_crophandle((int)x1, (int)y2 - CROPHANDLE_H);
2749         draw_crophandle((int)x2 - CROPHANDLE_W, (int)y2 - CROPHANDLE_H);
2750         get_canvas()->set_opaque();
2751 }
2752
2753
2754
2755
2756
2757
2758
2759
2760 void CWindowCanvas::draw_bezier(int do_camera)
2761 {
2762         Track *track = gui->cwindow->calculate_affected_track();
2763         
2764         if(!track) return;
2765
2766         float center_x;
2767         float center_y;
2768         float center_z;
2769         int64_t position = track->to_units(
2770                 mwindow->edl->local_session->get_selectionstart(1), 
2771                 0);
2772
2773         track->automation->get_projector(&center_x, 
2774                 &center_y, 
2775                 &center_z, 
2776                 position,
2777                 PLAY_FORWARD);
2778
2779 //      center_x += track->track_w / 2;
2780 //      center_y += track->track_h / 2;
2781         center_x += mwindow->edl->session->output_w / 2;
2782         center_y += mwindow->edl->session->output_h / 2;
2783         float track_x1 = center_x - track->track_w / 2 * center_z;
2784         float track_y1 = center_y - track->track_h / 2 * center_z;
2785         float track_x2 = track_x1 + track->track_w * center_z;
2786         float track_y2 = track_y1 + track->track_h * center_z;
2787
2788         output_to_canvas(mwindow->edl, 0, track_x1, track_y1);
2789         output_to_canvas(mwindow->edl, 0, track_x2, track_y2);
2790
2791 #define DRAW_PROJECTION(offset) \
2792         get_canvas()->draw_rectangle((int)track_x1 + offset, \
2793                 (int)track_y1 + offset, \
2794                 (int)(track_x2 - track_x1), \
2795                 (int)(track_y2 - track_y1)); \
2796         get_canvas()->draw_line((int)track_x1 + offset,  \
2797                 (int)track_y1 + offset, \
2798                 (int)track_x2 + offset, \
2799                 (int)track_y2 + offset); \
2800         get_canvas()->draw_line((int)track_x2 + offset,  \
2801                 (int)track_y1 + offset, \
2802                 (int)track_x1 + offset, \
2803                 (int)track_y2 + offset); \
2804
2805
2806 // Drop shadow
2807         get_canvas()->set_color(BLACK);
2808         DRAW_PROJECTION(1);
2809
2810 //      canvas->set_inverse();
2811         if(do_camera)
2812                 get_canvas()->set_color(GREEN);
2813         else
2814                 get_canvas()->set_color(RED);
2815
2816         DRAW_PROJECTION(0);
2817 //      canvas->set_opaque();
2818
2819 }
2820
2821
2822
2823 int CWindowCanvas::test_bezier(int button_press, 
2824         int &redraw, 
2825         int &redraw_canvas,
2826         int &rerender,
2827         int do_camera)
2828 {
2829         int result = 0;
2830
2831 // Processing drag operation.
2832 // Create keyframe during first cursor motion.
2833         if(!button_press)
2834         {
2835
2836                 float cursor_x = get_cursor_x();
2837                 float cursor_y = get_cursor_y();
2838                 canvas_to_output(mwindow->edl, 0, cursor_x, cursor_y);
2839
2840                 if(gui->current_operation == CWINDOW_CAMERA ||
2841                         gui->current_operation == CWINDOW_PROJECTOR)
2842                 {
2843                         if(!gui->ctrl_down() && gui->shift_down() && !gui->translating_zoom)
2844                         {
2845                                 gui->translating_zoom = 1;
2846                                 gui->reset_affected();
2847                         }
2848                         else
2849                         if(!gui->ctrl_down() && !gui->shift_down() && gui->translating_zoom)
2850                         {
2851                                 gui->translating_zoom = 0;
2852                                 gui->reset_affected();
2853                         }
2854
2855 // Get target keyframe
2856                         float last_center_x;
2857                         float last_center_y;
2858                         float last_center_z;
2859                         int created;
2860
2861                         if(!gui->affected_x && !gui->affected_y && !gui->affected_z)
2862                         {
2863                                 FloatAutos *affected_x_autos;
2864                                 FloatAutos *affected_y_autos;
2865                                 FloatAutos *affected_z_autos;
2866                                 if(!gui->affected_track) return 0;
2867                                 double position = mwindow->edl->local_session->get_selectionstart(1);
2868                                 int64_t track_position = gui->affected_track->to_units(position, 0);
2869
2870                                 if(mwindow->edl->session->cwindow_operation == CWINDOW_CAMERA)
2871                                 {
2872                                         affected_x_autos = (FloatAutos*)gui->affected_track->automation->autos[AUTOMATION_CAMERA_X];
2873                                         affected_y_autos = (FloatAutos*)gui->affected_track->automation->autos[AUTOMATION_CAMERA_Y];
2874                                         affected_z_autos = (FloatAutos*)gui->affected_track->automation->autos[AUTOMATION_CAMERA_Z];
2875                                 }
2876                                 else
2877                                 {
2878                                         affected_x_autos = (FloatAutos*)gui->affected_track->automation->autos[AUTOMATION_PROJECTOR_X];
2879                                         affected_y_autos = (FloatAutos*)gui->affected_track->automation->autos[AUTOMATION_PROJECTOR_Y];
2880                                         affected_z_autos = (FloatAutos*)gui->affected_track->automation->autos[AUTOMATION_PROJECTOR_Z];
2881                                 }
2882
2883
2884                                 if(gui->translating_zoom)
2885                                 {
2886                                         FloatAuto *previous = 0;
2887                                         FloatAuto *next = 0;
2888                                         float new_z = affected_z_autos->get_value(
2889                                                 track_position, 
2890                                                 PLAY_FORWARD,
2891                                                 previous,
2892                                                 next);
2893                                         gui->affected_z = 
2894                                                 (FloatAuto*)gui->cwindow->calculate_affected_auto(
2895                                                         affected_z_autos, 1, &created, 0);
2896                                         if(created) 
2897                                         {
2898                                                 gui->affected_z->value = new_z;
2899                                                 gui->affected_z->control_in_value = 0;
2900                                                 gui->affected_z->control_out_value = 0;
2901 //                                              gui->affected_z->control_in_position = 0;
2902 //                                              gui->affected_z->control_out_position = 0;
2903                                                 redraw_canvas = 1;
2904                                         }
2905                                 }
2906                                 else
2907                                 {
2908                                         FloatAuto *previous = 0;
2909                                         FloatAuto *next = 0;
2910                                         float new_x = affected_x_autos->get_value(
2911                                                 track_position, 
2912                                                 PLAY_FORWARD,
2913                                                 previous,
2914                                                 next);
2915                                         previous = 0;
2916                                         next = 0;
2917                                         float new_y = affected_y_autos->get_value(
2918                                                 track_position, 
2919                                                 PLAY_FORWARD,
2920                                                 previous,
2921                                                 next);
2922                                         gui->affected_x = 
2923                                                 (FloatAuto*)gui->cwindow->calculate_affected_auto(
2924                                                         affected_x_autos, 1, &created, 0);
2925                                         if(created) 
2926                                         {
2927                                                 gui->affected_x->value = new_x;
2928                                                 gui->affected_x->control_in_value = 0;
2929                                                 gui->affected_x->control_out_value = 0;
2930 //                                              gui->affected_x->control_in_position = 0;
2931 //                                              gui->affected_x->control_out_position = 0;
2932                                                 redraw_canvas = 1;
2933                                         }
2934                                         gui->affected_y = 
2935                                                 (FloatAuto*)gui->cwindow->calculate_affected_auto(
2936                                                         affected_y_autos, 1, &created, 0);
2937                                         if(created) 
2938                                         {
2939                                                 gui->affected_y->value = new_y;
2940                                                 gui->affected_y->control_in_value = 0;
2941                                                 gui->affected_y->control_out_value = 0;
2942 //                                              gui->affected_y->control_in_position = 0;
2943 //                                              gui->affected_y->control_out_position = 0;
2944                                                 redraw_canvas = 1;
2945                                         }
2946                                 }
2947
2948                                 calculate_origin();
2949
2950                                 if(gui->translating_zoom)
2951                                 {
2952                                         gui->center_z = gui->affected_z->value;
2953                                 }
2954                                 else
2955                                 {
2956                                         gui->center_x = gui->affected_x->value;
2957                                         gui->center_y = gui->affected_y->value;
2958                                 }
2959
2960                                 rerender = 1;
2961                                 redraw = 1;
2962                         }
2963
2964
2965                         if(gui->translating_zoom)
2966                         {
2967                                 last_center_z = gui->affected_z->value;
2968                         }
2969                         else
2970                         {
2971                                 last_center_x = gui->affected_x->value;
2972                                 last_center_y = gui->affected_y->value;
2973                         }
2974
2975                         if(gui->translating_zoom)
2976                         {
2977                                 gui->affected_z->value = gui->center_z + 
2978                                         (cursor_y - gui->y_origin) / 128;
2979
2980                                 if(gui->affected_z->value < 0) gui->affected_z->value = 0;
2981                                 if(!EQUIV(last_center_z, gui->affected_z->value))
2982                                 {
2983                                         rerender = 1;
2984                                         redraw = 1;
2985                                         redraw_canvas = 1;
2986                                 }
2987                         }
2988                         else
2989                         {
2990                                 gui->affected_x->value = gui->center_x + cursor_x - gui->x_origin;
2991                                 gui->affected_y->value = gui->center_y + cursor_y - gui->y_origin;
2992                                 if(!EQUIV(last_center_x,  gui->affected_x->value) ||
2993                                         !EQUIV(last_center_y, gui->affected_y->value))
2994                                 {
2995                                         rerender = 1;
2996                                         redraw = 1;
2997                                         redraw_canvas = 1;
2998                                 }
2999                         }
3000                 }
3001
3002                 result = 1;
3003         }
3004         else
3005 // Begin drag operation.  Don't create keyframe here.
3006         {
3007 // Get affected track off of the first recordable video track.
3008 // Calculating based on the alpha channel would require recording what layer
3009 // each output pixel belongs to as they're rendered and stacked.  Forget it.
3010                 gui->affected_track = gui->cwindow->calculate_affected_track();
3011                 gui->reset_affected();
3012
3013                 if(gui->affected_track)
3014                 {
3015                         if(gui->current_operation == CWINDOW_CAMERA)
3016                                 mwindow->undo->update_undo_before(_("camera"), this);
3017                         else
3018                                 mwindow->undo->update_undo_before(_("projector"), this);
3019
3020                         gui->current_operation = 
3021                                 mwindow->edl->session->cwindow_operation;
3022                         gui->tool_panel->raise_window();
3023                         result = 1;
3024                 }
3025         }
3026         
3027         return result;
3028 }
3029
3030 int CWindowCanvas::test_zoom(int &redraw)
3031 {
3032         int result = 0;
3033         float zoom = get_zoom();
3034         float x;
3035         float y;
3036
3037         if(!mwindow->edl->session->cwindow_scrollbars)
3038         {
3039                 mwindow->edl->session->cwindow_scrollbars = 1;
3040                 zoom = 1.0;
3041                 x = mwindow->edl->session->output_w / 2;
3042                 y = mwindow->edl->session->output_h / 2;
3043                 x = x - w / zoom / 2;
3044                 y = y - h / zoom / 2;
3045         }
3046         else
3047         {
3048 // Cursor position relative to canvas
3049                 x = get_cursor_x();
3050                 y = get_cursor_y();
3051 // cursor position relative to output
3052                 float output_x = x;
3053                 float output_y = y;
3054                 canvas_to_output(mwindow->edl, 
3055                                 0, 
3056                                 output_x, 
3057                                 output_y);
3058
3059 //printf("CWindowCanvas::test_zoom 1 %f %f\n", x, y);
3060
3061 // Find current zoom in table
3062                 int current_index = 0;
3063                 for(current_index = 0 ; current_index < total_zooms; current_index++)
3064                         if(EQUIV(my_zoom_table[current_index], zoom)) break;
3065
3066
3067 // Zoom out
3068                 if(get_buttonpress() == 5 ||
3069                         gui->ctrl_down() || 
3070                         gui->shift_down())
3071                 {
3072                         current_index--;
3073                 }
3074                 else
3075 // Zoom in
3076                 {
3077                         current_index++;
3078                 }
3079                 
3080                 CLAMP(current_index, 0, total_zooms - 1);
3081                 zoom = my_zoom_table[current_index];
3082                 
3083                 x = output_x - x / zoom;
3084                 y = output_y - y / zoom;
3085
3086                 
3087         }
3088
3089
3090
3091         int x_i = (int)x;
3092         int y_i = (int)y;
3093 //      check_boundaries(mwindow->edl, x_i, y_i, zoom);
3094
3095 //printf("CWindowCanvas::test_zoom 2 %d %d\n", x_i, y_i);
3096
3097         update_zoom(x_i, 
3098                         y_i, 
3099                         zoom);
3100         reposition_window(mwindow->edl, 
3101                         mwindow->theme->ccanvas_x,
3102                         mwindow->theme->ccanvas_y,
3103                         mwindow->theme->ccanvas_w,
3104                         mwindow->theme->ccanvas_h);
3105         redraw = 1;
3106         result = 1;
3107
3108         
3109         gui->zoom_panel->update(zoom);
3110         
3111         return result;
3112 }
3113
3114
3115 void CWindowCanvas::calculate_origin()
3116 {
3117         gui->x_origin = get_cursor_x();
3118         gui->y_origin = get_cursor_y();
3119 //printf("CWindowCanvas::calculate_origin 1 %f %f\n", gui->x_origin, gui->y_origin);
3120         canvas_to_output(mwindow->edl, 0, gui->x_origin, gui->y_origin);
3121 //printf("CWindowCanvas::calculate_origin 2 %f %f\n", gui->x_origin, gui->y_origin);
3122 }
3123
3124
3125 int CWindowCanvas::cursor_leave_event()
3126 {
3127         set_cursor(ARROW_CURSOR);
3128         return 1;
3129 }
3130
3131 int CWindowCanvas::cursor_enter_event()
3132 {
3133         int redraw = 0;
3134         switch(mwindow->edl->session->cwindow_operation)
3135         {
3136                 case CWINDOW_CAMERA:
3137                 case CWINDOW_PROJECTOR:
3138                         set_cursor(MOVE_CURSOR);
3139                         break;
3140                 case CWINDOW_ZOOM:
3141                         set_cursor(MOVE_CURSOR);
3142                         break;
3143                 case CWINDOW_CROP:
3144                         test_crop(0, redraw);
3145                         break;
3146                 case CWINDOW_PROTECT:
3147                         set_cursor(ARROW_CURSOR);
3148                         break;
3149                 case CWINDOW_MASK:
3150                 case CWINDOW_RULER:
3151                         set_cursor(CROSS_CURSOR);
3152                         break;
3153                 case CWINDOW_EYEDROP:
3154                         set_cursor(CROSS_CURSOR);
3155                         break;
3156         }
3157         return 1;
3158 }
3159
3160 int CWindowCanvas::cursor_motion_event()
3161 {
3162         int redraw = 0, result = 0, rerender = 0, redraw_canvas = 0;
3163
3164
3165 //printf("CWindowCanvas::cursor_motion_event %d current_operation=%d\n", __LINE__, gui->current_operation);
3166         switch(gui->current_operation)
3167         {
3168                 case CWINDOW_SCROLL:
3169                 {
3170                         float zoom = get_zoom();
3171                         float cursor_x = get_cursor_x();
3172                         float cursor_y = get_cursor_y();
3173
3174                         float zoom_x, zoom_y, conformed_w, conformed_h;
3175                         get_zooms(mwindow->edl, 0, zoom_x, zoom_y, conformed_w, conformed_h);
3176                         cursor_x = (float)cursor_x / zoom_x + gui->x_offset;
3177                         cursor_y = (float)cursor_y / zoom_y + gui->y_offset;
3178
3179
3180
3181                         int x = (int)(gui->x_origin - cursor_x + gui->x_offset);
3182                         int y = (int)(gui->y_origin - cursor_y + gui->y_offset);
3183
3184                         update_zoom(x, 
3185                                 y, 
3186                                 zoom);
3187                         update_scrollbars(0);
3188                         redraw = 1;
3189                         result = 1;
3190                         break;
3191                 }
3192
3193                 case CWINDOW_RULER:
3194                         result = do_ruler(0, 1, 0, 0);
3195                         break;
3196
3197                 case CWINDOW_CAMERA:
3198                         result = test_bezier(0, redraw, redraw_canvas, rerender, 1);
3199                         break;
3200
3201                 case CWINDOW_PROJECTOR:
3202                         result = test_bezier(0, redraw, redraw_canvas, rerender, 0);
3203                         break;
3204
3205
3206                 case CWINDOW_CROP:
3207                         result = test_crop(0, redraw);
3208 // printf("CWindowCanvas::cursor_motion_event %d result=%d redraw=%d\n", 
3209 // __LINE__, 
3210 // result, 
3211 // redraw);
3212                         break;
3213
3214                 case CWINDOW_MASK:
3215                 case CWINDOW_MASK_CONTROL_IN:
3216                 case CWINDOW_MASK_CONTROL_OUT:
3217                 case CWINDOW_MASK_TRANSLATE:
3218
3219                         result = do_mask(redraw, 
3220                                 rerender, 
3221                                 0, 
3222                                 1,
3223                                 0);
3224                         break;
3225
3226                 case CWINDOW_EYEDROP:
3227                         result = do_eyedrop(rerender, 0, 0);
3228                         break;
3229
3230                 default:
3231                         break;
3232
3233         }
3234
3235
3236 // cursor font changes
3237         if(!result)
3238         {
3239 // printf("CWindowCanvas::cursor_motion_event %d cwindow_operation=%d\n", 
3240 // __LINE__, 
3241 // mwindow->edl->session->cwindow_operation);
3242                 switch(mwindow->edl->session->cwindow_operation)
3243                 {
3244                         case CWINDOW_CROP:
3245                                 result = test_crop(0, redraw);
3246                                 break;
3247                         case CWINDOW_RULER:
3248                                 result = do_ruler(0, 1, 0, 0);
3249                                 break;
3250                         case CWINDOW_MASK:
3251                                 result = do_mask(redraw, 
3252                                         rerender, 
3253                                         0, 
3254                                         1,
3255                                         0);
3256                                         break;
3257                 }
3258         }
3259
3260
3261 // If the window is never unlocked before calling send_command the
3262 // display shouldn't get stuck on the old video frame although it will
3263 // flicker between the old video frame and the new video frame.
3264
3265         if(redraw)
3266         {
3267                 draw_refresh();
3268                 gui->update_tool();
3269         }
3270
3271         if(redraw_canvas)
3272         {
3273                 gui->unlock_window();
3274         
3275         
3276                 mwindow->gui->lock_window("CWindowCanvas::cursor_motion_event 1");
3277                 mwindow->gui->draw_overlays(1);
3278                 mwindow->gui->unlock_window();
3279                 
3280                 gui->lock_window("CWindowCanvas::cursor_motion_event 1");
3281         }
3282
3283         if(rerender)
3284         {
3285                 gui->unlock_window();
3286                 mwindow->restart_brender();
3287                 mwindow->sync_parameters(CHANGE_PARAMS);
3288                 gui->cwindow->playback_engine->que->send_command(CURRENT_FRAME, 
3289                         CHANGE_NONE,
3290                         mwindow->edl,
3291                         1);
3292                 if(!redraw) gui->update_tool();
3293                 gui->lock_window("CWindowCanvas::cursor_motion_event 2");
3294         }
3295         return result;
3296 }
3297
3298 int CWindowCanvas::button_press_event()
3299 {
3300         int result = 0;
3301         int redraw = 0;
3302         int redraw_canvas = 0;
3303         int rerender = 0;
3304
3305         if(Canvas::button_press_event()) return 1;
3306
3307         gui->translating_zoom = gui->shift_down(); 
3308
3309         calculate_origin();
3310 //printf("CWindowCanvas::button_press_event 2 %f %f\n", gui->x_origin, gui->y_origin, gui->x_origin, gui->y_origin);
3311
3312         float zoom_x, zoom_y, conformed_w, conformed_h;
3313         get_zooms(mwindow->edl, 0, zoom_x, zoom_y, conformed_w, conformed_h);
3314         gui->x_offset = get_x_offset(mwindow->edl, 0, zoom_x, conformed_w, conformed_h);
3315         gui->y_offset = get_y_offset(mwindow->edl, 0, zoom_y, conformed_w, conformed_h);
3316
3317 // Scroll view
3318         if(get_buttonpress() == 2)
3319         {
3320                 gui->current_operation = CWINDOW_SCROLL;
3321                 result = 1;
3322         }
3323         else
3324 // Adjust parameter
3325         {
3326                 switch(mwindow->edl->session->cwindow_operation)
3327                 {
3328                         case CWINDOW_RULER:
3329                                 result = do_ruler(0, 0, 1, 0);
3330                                 break;
3331                 
3332                         case CWINDOW_CAMERA:
3333                                 result = test_bezier(1, redraw, redraw_canvas, rerender, 1);
3334                                 break;
3335
3336                         case CWINDOW_PROJECTOR:
3337                                 result = test_bezier(1, redraw, redraw_canvas, rerender, 0);
3338                                 break;
3339
3340                         case CWINDOW_ZOOM:
3341                                 result = test_zoom(redraw);
3342                                 break;
3343
3344                         case CWINDOW_CROP:
3345                                 result = test_crop(1, redraw);
3346                                 break;
3347
3348                         case CWINDOW_MASK:
3349                                 if(get_buttonpress() == 1)
3350                                         result = do_mask(redraw, rerender, 1, 0, 0);
3351                                 break;
3352
3353                         case CWINDOW_EYEDROP:
3354                                 result = do_eyedrop(rerender, 1, 0);
3355                                 break;
3356                 }
3357         }
3358
3359         if(redraw)
3360         {
3361                 draw_refresh();
3362                 gui->unlock_window();
3363         
3364         
3365                 mwindow->gui->lock_window("CWindowCanvas::button_press_event 1");
3366                 mwindow->gui->draw_overlays(1);
3367                 mwindow->gui->unlock_window();
3368                 gui->update_tool();
3369                 
3370                 gui->lock_window("CWindowCanvas::button_press_event 1");
3371         }
3372
3373 // rerendering can also be caused by press event
3374         if(rerender) 
3375         {
3376                 gui->unlock_window();
3377
3378                 mwindow->restart_brender();
3379                 mwindow->sync_parameters(CHANGE_PARAMS);
3380                 gui->cwindow->playback_engine->que->send_command(CURRENT_FRAME, 
3381                         CHANGE_NONE,
3382                         mwindow->edl,
3383                         1);
3384                 if(!redraw) gui->update_tool();
3385                 gui->lock_window("CWindowCanvas::button_press_event 2");
3386         }
3387         return result;
3388 }
3389
3390 int CWindowCanvas::button_release_event()
3391 {
3392         int result = 0;
3393
3394         switch(gui->current_operation)
3395         {
3396                 case CWINDOW_SCROLL:
3397                         result = 1;
3398                         break;
3399                         
3400                 case CWINDOW_RULER:
3401                         do_ruler(0, 0, 0, 1);
3402                         break;
3403
3404                 case CWINDOW_CAMERA:
3405                         mwindow->undo->update_undo_after(_("camera"), LOAD_AUTOMATION);
3406                         break;
3407
3408                 case CWINDOW_PROJECTOR:
3409                         mwindow->undo->update_undo_after(_("projector"), LOAD_AUTOMATION);
3410                         break;
3411
3412                 case CWINDOW_MASK:
3413                 case CWINDOW_MASK_CONTROL_IN:
3414                 case CWINDOW_MASK_CONTROL_OUT:
3415                 case CWINDOW_MASK_TRANSLATE:
3416 // Finish mask operation
3417                         gui->mask_keyframe = 0;
3418                         mwindow->undo->update_undo_after(_("mask"), LOAD_AUTOMATION);
3419                         break;
3420
3421         }
3422
3423         gui->current_operation = CWINDOW_NONE;
3424         return result;
3425 }
3426
3427 void CWindowCanvas::zoom_resize_window(float percentage)
3428 {
3429         int canvas_w, canvas_h;
3430         int new_w, new_h;
3431         
3432         
3433 // Get required canvas size
3434         calculate_sizes(mwindow->edl->get_aspect_ratio(), 
3435                 mwindow->edl->session->output_w, 
3436                 mwindow->edl->session->output_h, 
3437                 percentage,
3438                 canvas_w,
3439                 canvas_h);
3440
3441 // Estimate window size from current borders
3442         new_w = canvas_w + (gui->get_w() - mwindow->theme->ccanvas_w);
3443         new_h = canvas_h + (gui->get_h() - mwindow->theme->ccanvas_h);
3444
3445 //printf("CWindowCanvas::zoom_resize_window %d %d %d\n", __LINE__, new_w, new_h);
3446         mwindow->session->cwindow_w = new_w;
3447         mwindow->session->cwindow_h = new_h;
3448
3449         mwindow->theme->get_cwindow_sizes(gui, 
3450                 mwindow->session->cwindow_controls);
3451
3452 // Estimate again from new borders
3453         new_w = canvas_w + (mwindow->session->cwindow_w - mwindow->theme->ccanvas_w);
3454         new_h = canvas_h + (mwindow->session->cwindow_h - mwindow->theme->ccanvas_h);
3455 //printf("CWindowCanvas::zoom_resize_window %d %d %d\n", __LINE__, new_w, new_h);
3456
3457         gui->resize_window(new_w, new_h);
3458         gui->resize_event(new_w, new_h);
3459 }
3460
3461 void CWindowCanvas::toggle_controls()
3462 {
3463         mwindow->session->cwindow_controls = !mwindow->session->cwindow_controls;
3464         gui->resize_event(gui->get_w(), gui->get_h());
3465 }
3466
3467 int CWindowCanvas::get_cwindow_controls()
3468 {
3469         return mwindow->session->cwindow_controls;
3470 }
3471
3472
3473