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