r690: Fixed that dragging mask points would not be an undoable operation.
[cinelerra_cv.git] / cinelerra / cwindowgui.C
blobcaa8befc34553c833f4f12fc4194f29c719c903e
1 #include "automation.h"
2 #include "autos.h"
3 #include "bcsignals.h"
4 #include "canvas.h"
5 #include "clip.h"
6 #include "cpanel.h"
7 #include "cplayback.h"
8 #include "ctimebar.h"
9 #include "cursors.h"
10 #include "cwindowgui.h"
11 #include "cwindow.h"
12 #include "cwindowtool.h"
13 #include "editpanel.h"
14 #include "edl.h"
15 #include "edlsession.h"
16 #include "floatauto.h"
17 #include "floatautos.h"
18 #include "language.h"
19 #include "localsession.h"
20 #include "mainclock.h"
21 #include "mainmenu.h"
22 #include "mainundo.h"
23 #include "mainsession.h"
24 #include "maskauto.h"
25 #include "maskautos.h"
26 #include "meterpanel.h"
27 #include "mwindowgui.h"
28 #include "mwindow.h"
29 #include "mwindow.h"
30 #include "playtransport.h"
31 #include "theme.h"
32 #include "trackcanvas.h"
33 #include "tracks.h"
34 #include "transportque.h"
35 #include "vtrack.h"
38 static double my_zoom_table[] = 
40         0.25,
41         0.33,
42         0.50,
43         0.75,
44         1.0,
45         1.5,
46         2.0,
47         3.0,
48         4.0
51 static int total_zooms = sizeof(my_zoom_table) / sizeof(double);
54 CWindowGUI::CWindowGUI(MWindow *mwindow, CWindow *cwindow)
55  : BC_Window(PROGRAM_NAME ": Compositor",
56         mwindow->session->cwindow_x, 
57     mwindow->session->cwindow_y, 
58     mwindow->session->cwindow_w, 
59     mwindow->session->cwindow_h,
60     100,
61     100,
62     1,
63     1,
64     1,
65         BC_WindowBase::get_resources()->bg_color,
66         mwindow->edl->session->get_cwindow_display())
68         this->mwindow = mwindow;
69     this->cwindow = cwindow;
70         affected_track = 0;
71         affected_x = 0;
72         affected_y = 0;
73         affected_z = 0;
74         affected_keyframe = 0;
75         affected_point = 0;
76         x_offset = 0;
77         y_offset = 0;
78         x_origin = 0;
79         y_origin = 0;
80         current_operation = CWINDOW_NONE;
81         tool_panel = 0;
82         translating_zoom = 0;
83         active = 0;
84         inactive = 0;
85         crop_translate = 0;
88 CWindowGUI::~CWindowGUI()
90         if(tool_panel) delete tool_panel;
91         delete meters;
92         delete composite_panel;
93         delete canvas;
94         delete transport;
95         delete edit_panel;
96         delete zoom_panel;
97         delete active;
98         delete inactive;
101 int CWindowGUI::create_objects()
103 SET_TRACE
104         set_icon(mwindow->theme->get_image("cwindow_icon"));
106         active = new BC_Pixmap(this, mwindow->theme->get_image("cwindow_active"));
107         inactive = new BC_Pixmap(this, mwindow->theme->get_image("cwindow_inactive"));
109 SET_TRACE
110         mwindow->theme->get_cwindow_sizes(this, mwindow->session->cwindow_controls);
111 SET_TRACE
112         mwindow->theme->draw_cwindow_bg(this);
113 SET_TRACE
114         flash();
115 SET_TRACE
117 // Meters required by composite panel
118         meters = new CWindowMeters(mwindow, 
119                 this,
120                 mwindow->theme->cmeter_x,
121                 mwindow->theme->cmeter_y,
122                 mwindow->theme->cmeter_h);
123         meters->create_objects();
124 SET_TRACE
127         composite_panel = new CPanel(mwindow, 
128                 this, 
129                 mwindow->theme->ccomposite_x,
130                 mwindow->theme->ccomposite_y,
131                 mwindow->theme->ccomposite_w,
132                 mwindow->theme->ccomposite_h);
133         composite_panel->create_objects();
135 SET_TRACE
136         canvas = new CWindowCanvas(mwindow, this);
137         canvas->create_objects(mwindow->edl);
138 SET_TRACE
141         add_subwindow(timebar = new CTimeBar(mwindow,
142                 this,
143                 mwindow->theme->ctimebar_x,
144                 mwindow->theme->ctimebar_y,
145                 mwindow->theme->ctimebar_w, 
146                 mwindow->theme->ctimebar_h));
147         timebar->create_objects();
149 SET_TRACE
150         add_subwindow(slider = new CWindowSlider(mwindow, 
151                 cwindow, 
152                 mwindow->theme->cslider_x,
153                 mwindow->theme->cslider_y, 
154                 mwindow->theme->cslider_w));
156         transport = new CWindowTransport(mwindow, 
157                 this, 
158                 mwindow->theme->ctransport_x, 
159                 mwindow->theme->ctransport_y);
160         transport->create_objects();
161         transport->set_slider(slider);
163 SET_TRACE
164         edit_panel = new CWindowEditing(mwindow, cwindow);
165 SET_TRACE
166         edit_panel->set_meters(meters);
167 SET_TRACE
168         edit_panel->create_objects();
169 SET_TRACE
171 //      add_subwindow(clock = new MainClock(mwindow, 
172 //              mwindow->theme->ctime_x, 
173 //              mwindow->theme->ctime_y));
175         zoom_panel = new CWindowZoom(mwindow, 
176                 this, 
177                 mwindow->theme->czoom_x, 
178                 mwindow->theme->czoom_y);
179         zoom_panel->create_objects();
180         zoom_panel->zoom_text->add_item(new BC_MenuItem(AUTO_ZOOM));
181         if(!mwindow->edl->session->cwindow_scrollbars) zoom_panel->set_text(AUTO_ZOOM);
183 //      destination = new CWindowDestination(mwindow, 
184 //              this, 
185 //              mwindow->theme->cdest_x,
186 //              mwindow->theme->cdest_y);
187 //      destination->create_objects();
189 // Must create after meter panel
190         tool_panel = new CWindowTool(mwindow, this);
191         tool_panel->Thread::start();
192         
193         set_operation(mwindow->edl->session->cwindow_operation);
196         canvas->draw_refresh();
198         draw_status();
200 SET_TRACE
201         return 0;
204 int CWindowGUI::translation_event()
206         mwindow->session->cwindow_x = get_x();
207         mwindow->session->cwindow_y = get_y();
208         return 0;
211 int CWindowGUI::resize_event(int w, int h)
213         mwindow->session->cwindow_x = get_x();
214         mwindow->session->cwindow_y = get_y();
215         mwindow->session->cwindow_w = w;
216         mwindow->session->cwindow_h = h;
218         mwindow->theme->get_cwindow_sizes(this, mwindow->session->cwindow_controls);
219         mwindow->theme->draw_cwindow_bg(this);
220         flash();
222         composite_panel->reposition_buttons(mwindow->theme->ccomposite_x,
223                 mwindow->theme->ccomposite_y);
225         canvas->reposition_window(mwindow->edl,
226                 mwindow->theme->ccanvas_x,
227                 mwindow->theme->ccanvas_y,
228                 mwindow->theme->ccanvas_w,
229                 mwindow->theme->ccanvas_h);
231         timebar->resize_event();
233         slider->reposition_window(mwindow->theme->cslider_x,
234                 mwindow->theme->cslider_y, 
235                 mwindow->theme->cslider_w);
236 // Recalibrate pointer motion range
237         slider->set_position();
239         transport->reposition_buttons(mwindow->theme->ctransport_x, 
240                 mwindow->theme->ctransport_y);
242         edit_panel->reposition_buttons(mwindow->theme->cedit_x, 
243                 mwindow->theme->cedit_y);
245 //      clock->reposition_window(mwindow->theme->ctime_x, 
246 //              mwindow->theme->ctime_y);
248         zoom_panel->reposition_window(mwindow->theme->czoom_x, 
249                 mwindow->theme->czoom_y);
251 //      destination->reposition_window(mwindow->theme->cdest_x,
252 //              mwindow->theme->cdest_y);
254         meters->reposition_window(mwindow->theme->cmeter_x,
255                 mwindow->theme->cmeter_y,
256                 mwindow->theme->cmeter_h);
258         draw_status();
260         BC_WindowBase::resize_event(w, h);
261         return 1;
265 void CWindowGUI::draw_status()
267         if(canvas->canvas && 
268                 canvas->canvas->get_video_on() ||
269                 canvas->is_processing)
270                 draw_pixmap(active, 
271                         mwindow->theme->cstatus_x, 
272                         mwindow->theme->cstatus_y);
273         else
274                 draw_pixmap(inactive, 
275                         mwindow->theme->cstatus_x, 
276                         mwindow->theme->cstatus_y);
277         flash(mwindow->theme->cstatus_x,
278                 mwindow->theme->cstatus_y,
279                 active->get_w(),
280                 active->get_h());
285 // TODO
286 // Don't refresh the canvas in a load file operation which is going to
287 // refresh it anyway.
288 void CWindowGUI::set_operation(int value)
290         mwindow->edl->session->cwindow_operation = value;
292         composite_panel->set_operation(value);
293         edit_panel->update();
295         tool_panel->start_tool(value);
296         canvas->draw_refresh();
299 void CWindowGUI::update_tool()
301         tool_panel->update_values();
304 int CWindowGUI::close_event()
306         cwindow->hide_window();
307         return 1;
311 int CWindowGUI::keypress_event()
313         int result = 0;
315         switch(get_keypress())
316         {
317                 case 'w':
318                 case 'W':
319                         close_event();
320                         result = 1;
321                         break;
322                 case '+':
323                 case '=':
324                         keyboard_zoomin();
325                         result = 1;
326                         break;
327                 case '-':
328                         keyboard_zoomout();
329                         result = 1;
330                         break;
331         }
333         if(!result) result = transport->keypress_event();
335         return result;
339 void CWindowGUI::reset_affected()
341         affected_x = 0;
342         affected_y = 0;
343         affected_z = 0;
346 void CWindowGUI::keyboard_zoomin()
348 //      if(mwindow->edl->session->cwindow_scrollbars)
349 //      {
350                 zoom_panel->zoom_tumbler->handle_up_event();
351 //      }
352 //      else
353 //      {
354 //      }
357 void CWindowGUI::keyboard_zoomout()
359 //      if(mwindow->edl->session->cwindow_scrollbars)
360 //      {
361                 zoom_panel->zoom_tumbler->handle_down_event();
362 //      }
363 //      else
364 //      {
365 //      }
369 void CWindowGUI::drag_motion()
371         if(get_hidden()) return;
373         if(mwindow->session->current_operation == DRAG_ASSET ||
374                 mwindow->session->current_operation == DRAG_VTRANSITION ||
375                 mwindow->session->current_operation == DRAG_VEFFECT)
376         {
377                 int old_status = mwindow->session->ccanvas_highlighted;
378                 int cursor_x = get_relative_cursor_x();
379                 int cursor_y = get_relative_cursor_y();
381                 mwindow->session->ccanvas_highlighted = get_cursor_over_window() &&
382                         cursor_x >= canvas->x &&
383                         cursor_x < canvas->x + canvas->w &&
384                         cursor_y >= canvas->y &&
385                         cursor_y < canvas->y + canvas->h;
388                 if(old_status != mwindow->session->ccanvas_highlighted)
389                         canvas->draw_refresh();
390         }
393 int CWindowGUI::drag_stop()
395         int result = 0;
396         if(get_hidden()) return 0;
398         if((mwindow->session->current_operation == DRAG_ASSET ||
399                 mwindow->session->current_operation == DRAG_VTRANSITION ||
400                 mwindow->session->current_operation == DRAG_VEFFECT) &&
401                 mwindow->session->ccanvas_highlighted)
402         {
403 // Hide highlighting
404                 mwindow->session->ccanvas_highlighted = 0;
405                 canvas->draw_refresh();
406                 result = 1;
407         }
408         else
409                 return 0;
411         if(mwindow->session->current_operation == DRAG_ASSET)
412         {
413                 if(mwindow->session->drag_assets->total)
414                 {
415                         mwindow->gui->lock_window("CWindowGUI::drag_stop 1");
416                         mwindow->clear(0);
417                         mwindow->load_assets(mwindow->session->drag_assets, 
418                                 mwindow->edl->local_session->get_selectionstart(), 
419                                 LOAD_PASTE,
420                                 mwindow->session->track_highlighted,
421                                 0,
422                                 mwindow->edl->session->labels_follow_edits, 
423                                 mwindow->edl->session->plugins_follow_edits);
424                 }
426                 if(mwindow->session->drag_clips->total)
427                 {
428                         mwindow->gui->lock_window("CWindowGUI::drag_stop 2");
429                         mwindow->clear(0);
430                         mwindow->paste_edls(mwindow->session->drag_clips, 
431                                 LOAD_PASTE, 
432                                 mwindow->session->track_highlighted,
433                                 mwindow->edl->local_session->get_selectionstart(),
434                                 mwindow->edl->session->labels_follow_edits, 
435                                 mwindow->edl->session->plugins_follow_edits);
436                 }
438                 if(mwindow->session->drag_assets->total ||
439                         mwindow->session->drag_clips->total)
440                 {
441                         mwindow->save_backup();
442                         mwindow->restart_brender();
443                         mwindow->gui->update(1, 1, 1, 1, 0, 1, 0);
444                         mwindow->undo->update_undo(_("insert assets"), LOAD_ALL);
445                         mwindow->gui->unlock_window();
446                         mwindow->sync_parameters(LOAD_ALL);
447                 }
448         }
450         if(mwindow->session->current_operation == DRAG_VEFFECT)
451         {
452 //printf("CWindowGUI::drag_stop 1\n");
453                 Track *affected_track = cwindow->calculate_affected_track();
454 //printf("CWindowGUI::drag_stop 2\n");
456                 mwindow->gui->lock_window("CWindowGUI::drag_stop 3");
457                 mwindow->insert_effects_cwindow(affected_track);
458                 mwindow->session->current_operation = NO_OPERATION;
459                 mwindow->gui->unlock_window();
460         }
462         if(mwindow->session->current_operation == DRAG_VTRANSITION)
463         {
464                 Track *affected_track = cwindow->calculate_affected_track();
465                 mwindow->gui->lock_window("CWindowGUI::drag_stop 4");
466                 mwindow->paste_transition_cwindow(affected_track);
467                 mwindow->session->current_operation = NO_OPERATION;
468                 mwindow->gui->unlock_window();
469         }
471         return result;
475 CWindowEditing::CWindowEditing(MWindow *mwindow, CWindow *cwindow)
476  : EditPanel(mwindow, 
477                 cwindow->gui, 
478                 mwindow->theme->cedit_x, 
479                 mwindow->theme->cedit_y,
480                 mwindow->edl->session->editing_mode, 
481                 0,
482                 1,
483                 0, 
484                 0,
485                 1,
486                 1,
487                 1,
488                 1,
489                 1,
490                 0,
491                 1,
492                 1,
493                 1,
494                 0,
495                 1)
497         this->mwindow = mwindow;
498         this->cwindow = cwindow;
501 void CWindowEditing::set_inpoint()
503         mwindow->set_inpoint(0);
506 void CWindowEditing::set_outpoint()
508         mwindow->set_outpoint(0);
515 CWindowMeters::CWindowMeters(MWindow *mwindow, CWindowGUI *gui, int x, int y, int h)
516  : MeterPanel(mwindow, 
517                 gui,
518                 x,
519                 y,
520                 h,
521                 mwindow->edl->session->audio_channels,
522                 mwindow->edl->session->cwindow_meter)
524         this->mwindow = mwindow;
525         this->gui = gui;
528 CWindowMeters::~CWindowMeters()
532 int CWindowMeters::change_status_event()
534         mwindow->edl->session->cwindow_meter = use_meters;
535         mwindow->theme->get_cwindow_sizes(gui, mwindow->session->cwindow_controls);
536         gui->resize_event(gui->get_w(), gui->get_h());
537         return 1;
543 CWindowZoom::CWindowZoom(MWindow *mwindow, CWindowGUI *gui, int x, int y)
544  : ZoomPanel(mwindow, 
545         gui, 
546         (double)mwindow->edl->session->cwindow_zoom, 
547         x, 
548         y,
549         80, 
550         my_zoom_table, 
551         total_zooms, 
552         ZOOM_PERCENTAGE)
554         this->mwindow = mwindow;
555         this->gui = gui;
558 CWindowZoom::~CWindowZoom()
562 int CWindowZoom::handle_event()
564         if(!strcasecmp(AUTO_ZOOM, get_text()))
565         {
566                 mwindow->edl->session->cwindow_scrollbars = 0;
567         }
568         else
569         {
570                 mwindow->edl->session->cwindow_scrollbars = 1;
571         }
573         float old_zoom = mwindow->edl->session->cwindow_zoom;
574         float new_zoom = get_value();
575         float x = gui->canvas->w / 2;
576         float y = gui->canvas->h / 2;
577         gui->canvas->canvas_to_output(mwindow->edl, 
578                                 0, 
579                                 x, 
580                                 y);
581         x -= gui->canvas->w_visible / 2 * old_zoom / new_zoom;
582         y -= gui->canvas->h_visible / 2 * old_zoom / new_zoom;
583         gui->canvas->update_zoom((int)x, 
584                 (int)y, 
585                 new_zoom);
586         gui->canvas->reposition_window(mwindow->edl, 
587                 mwindow->theme->ccanvas_x,
588                 mwindow->theme->ccanvas_y,
589                 mwindow->theme->ccanvas_w,
590                 mwindow->theme->ccanvas_h);
591         gui->canvas->draw_refresh();
592         return 1;
597 CWindowSlider::CWindowSlider(MWindow *mwindow, CWindow *cwindow, int x, int y, int pixels)
598  : BC_PercentageSlider(x, 
599                         y,
600                         0,
601                         pixels, 
602                         pixels, 
603                         0, 
604                         1, 
605                         0)
607         this->mwindow = mwindow;
608         this->cwindow = cwindow;
609         set_precision(0.00001);
612 CWindowSlider::~CWindowSlider()
616 int CWindowSlider::handle_event()
618         unlock_window();
619         cwindow->playback_engine->interrupt_playback(1);
620         lock_window("CWindowSlider::handle_event 1");
621         
622         mwindow->gui->lock_window("CWindowSlider::handle_event 2");
623         mwindow->select_point((double)get_value());
624         mwindow->gui->unlock_window();
625         return 1;
628 void CWindowSlider::set_position()
630         double new_length = mwindow->edl->tracks->total_playable_length();
631         if(mwindow->edl->local_session->preview_end <= 0 ||
632                 mwindow->edl->local_session->preview_end > new_length)
633                 mwindow->edl->local_session->preview_end = new_length;
634         if(mwindow->edl->local_session->preview_start > 
635                 mwindow->edl->local_session->preview_end)
636                 mwindow->edl->local_session->preview_start = 0;
640         update(mwindow->theme->cslider_w, 
641                 mwindow->edl->local_session->get_selectionstart(1), 
642                 mwindow->edl->local_session->preview_start, 
643                 mwindow->edl->local_session->preview_end);
647 int CWindowSlider::increase_value()
649         unlock_window();
650         cwindow->gui->transport->handle_transport(SINGLE_FRAME_FWD);
651         lock_window("CWindowSlider::increase_value");
652         return 1;
655 int CWindowSlider::decrease_value()
657         unlock_window();
658         cwindow->gui->transport->handle_transport(SINGLE_FRAME_REWIND);
659         lock_window("CWindowSlider::decrease_value");
660         return 1;
664 // CWindowDestination::CWindowDestination(MWindow *mwindow, CWindowGUI *cwindow, int x, int y)
665 //  : BC_PopupTextBox(cwindow, 
666 //      &cwindow->destinations, 
667 //      cwindow->destinations.values[cwindow->cwindow->destination]->get_text(),
668 //      x, 
669 //      y, 
670 //      70, 
671 //      200)
672 // {
673 //      this->mwindow = mwindow;
674 //      this->cwindow = cwindow;
675 // }
676 // 
677 // CWindowDestination::~CWindowDestination()
678 // {
679 // }
680 // 
681 // int CWindowDestination::handle_event()
682 // {
683 //      return 1;
684 // }
687 CWindowTransport::CWindowTransport(MWindow *mwindow, 
688         CWindowGUI *gui, 
689         int x, 
690         int y)
691  : PlayTransport(mwindow, 
692         gui, 
693         x, 
694         y)
696         this->gui = gui;
699 EDL* CWindowTransport::get_edl()
701         return mwindow->edl;
704 void CWindowTransport::goto_start()
706         gui->unlock_window();
707         handle_transport(REWIND, 1);
709         mwindow->gui->lock_window("CWindowTransport::goto_start 1");
710         mwindow->goto_start();
711         mwindow->gui->unlock_window();
713         gui->lock_window("CWindowTransport::goto_start 2");
716 void CWindowTransport::goto_end()
718         gui->unlock_window();
719         handle_transport(GOTO_END, 1);
721         mwindow->gui->lock_window("CWindowTransport::goto_end 1");
722         mwindow->goto_end();
723         mwindow->gui->unlock_window();
725         gui->lock_window("CWindowTransport::goto_end 2");
730 CWindowCanvas::CWindowCanvas(MWindow *mwindow, CWindowGUI *gui)
731  : Canvas(gui,
732                 mwindow->theme->ccanvas_x,
733                 mwindow->theme->ccanvas_y,
734                 mwindow->theme->ccanvas_w,
735                 mwindow->theme->ccanvas_h,
736                 0,
737                 0,
738                 mwindow->edl->session->cwindow_scrollbars,
739                 1)
741         this->mwindow = mwindow;
742         this->gui = gui;
745 void CWindowCanvas::status_event()
747         gui->draw_status();
750 void CWindowCanvas::update_zoom(int x, int y, float zoom)
752         use_scrollbars = mwindow->edl->session->cwindow_scrollbars;
754         mwindow->edl->session->cwindow_xscroll = x;
755         mwindow->edl->session->cwindow_yscroll = y;
756         mwindow->edl->session->cwindow_zoom = zoom;
759 int CWindowCanvas::get_xscroll()
761         return mwindow->edl->session->cwindow_xscroll;
764 int CWindowCanvas::get_yscroll()
766         return mwindow->edl->session->cwindow_yscroll;
770 float CWindowCanvas::get_zoom()
772         return mwindow->edl->session->cwindow_zoom;
775 void CWindowCanvas::draw_refresh()
777         if(!canvas->video_is_on())
778         {
779 //printf("CWindowCanvas::draw_refresh 1 %f\n", mwindow->edl->session->cwindow_zoom);
780                 canvas->clear_box(0, 0, canvas->get_w(), canvas->get_h());
781 //printf("CWindowCanvas::draw_refresh 2\n");
783                 if(refresh_frame)
784                 {
785                         int in_x, in_y, in_w, in_h, out_x, out_y, out_w, out_h;
786 //printf("CWindowCanvas::draw_refresh 3 %d\n", refresh_frame->get_color_model());
787                         get_transfers(mwindow->edl, 
788                                 in_x, 
789                                 in_y, 
790                                 in_w, 
791                                 in_h, 
792                                 out_x, 
793                                 out_y, 
794                                 out_w, 
795                                 out_h);
798 // printf("CWindowCanvas::draw_refresh %d %d %d %d -> %d %d %d %d\n", 
799 // in_x, in_y, in_w, in_h, out_x, out_y, out_w, out_h);
800 //canvas->clear_box(0, 0, canvas->get_w(), canvas->get_h());
803 //printf("CWindowCanvas::draw_refresh 5\n");
804                         if(out_w > 0 && out_h > 0 && in_w > 0 && in_h > 0)
805                                 canvas->draw_vframe(refresh_frame,
806                                                 out_x, 
807                                                 out_y, 
808                                                 out_w, 
809                                                 out_h,
810                                                 in_x, 
811                                                 in_y, 
812                                                 in_w, 
813                                                 in_h,
814                                                 0);
815 //printf("CWindowCanvas::draw_refresh 6\n");
816                 }
817                 else
818                 {
819 //printf("CWindowCanvas::draw_refresh 7\n");
820                         canvas->clear_box(0, 0, canvas->get_w(), canvas->get_h());
821 //printf("CWindowCanvas::draw_refresh 8\n");
822                 }
824 //printf("CWindowCanvas::draw_refresh 9\n");
825                 draw_overlays();
826                 canvas->flash();
827                 canvas->flush();
828 //printf("CWindowCanvas::draw_refresh 10\n");
829         }
832 #define CROPHANDLE_W 10
833 #define CROPHANDLE_H 10
835 void CWindowCanvas::draw_crophandle(int x, int y)
837         canvas->draw_box(x, y, CROPHANDLE_W, CROPHANDLE_H);
840 #define CONTROL_W 10
841 #define CONTROL_H 10
842 #define FIRST_CONTROL_W 20
843 #define FIRST_CONTROL_H 20
844 #undef BC_INFINITY
845 #define BC_INFINITY 65536
846 #ifndef SQR
847 #define SQR(x) ((x) * (x))
848 #endif
850 int CWindowCanvas::do_mask(int &redraw, 
851                 int &rerender, 
852                 int button_press, 
853                 int cursor_motion,
854                 int draw)
856 // Retrieve points from top recordable track
857 //printf("CWindowCanvas::do_mask 1\n");
858         Track *track = gui->cwindow->calculate_affected_track();
859 //printf("CWindowCanvas::do_mask 2\n");
861         if(!track) return 0;
862 //printf("CWindowCanvas::do_mask 3\n");
864         MaskAutos *mask_autos = (MaskAutos*)track->automation->autos[AUTOMATION_MASK];
865         int64_t position = track->to_units(
866                 mwindow->edl->local_session->get_selectionstart(1),
867                 0);
868         ArrayList<MaskPoint*> points;
869         mask_autos->get_points(&points, mwindow->edl->session->cwindow_mask,
870                 position, 
871                 PLAY_FORWARD);
872 //printf("CWindowCanvas::do_mask 4\n");
874 // Projector zooms relative to the center of the track output.
875         float half_track_w = (float)track->track_w / 2;
876         float half_track_h = (float)track->track_h / 2;
877 // Translate mask to projection
878         float projector_x, projector_y, projector_z;
879         track->automation->get_projector(&projector_x,
880                 &projector_y,
881                 &projector_z,
882                 position,
883                 PLAY_FORWARD);
886 // Get position of cursor relative to mask
887         float mask_cursor_x = get_cursor_x();
888         float mask_cursor_y = get_cursor_y();
889         canvas_to_output(mwindow->edl, 0, mask_cursor_x, mask_cursor_y);
891         projector_x += mwindow->edl->session->output_w / 2;
892         projector_y += mwindow->edl->session->output_h / 2;
894         mask_cursor_x -= projector_x;
895         mask_cursor_y -= projector_y;
896         mask_cursor_x = mask_cursor_x / projector_z + half_track_w;
897         mask_cursor_y = mask_cursor_y / projector_z + half_track_h;
899 // Fix cursor origin
900         if(button_press)
901         {
902                 gui->x_origin = mask_cursor_x;
903                 gui->y_origin = mask_cursor_y;
904         }
906         int result = 0;
907 // Points of closest line
908         int shortest_point1 = -1;
909         int shortest_point2 = -1;
910 // Closest point
911         int shortest_point = -1;
912 // Distance to closest line
913         float shortest_line_distance = BC_INFINITY;
914 // Distance to closest point
915         float shortest_point_distance = BC_INFINITY;
916         int selected_point = -1;
917         int selected_control_point = -1;
918         float selected_control_point_distance = BC_INFINITY;
919         ArrayList<int> x_points;
920         ArrayList<int> y_points;
922         if(!cursor_motion)
923         {
924                 if(draw)
925                 {
926                         canvas->set_color(WHITE);
927                         canvas->set_inverse();
928                 }
929 //printf("CWindowCanvas::do_mask 1 %d\n", points.total);
931 // Never draw closed polygon and a closed
932 // polygon is harder to add points to.
933                 for(int i = 0; i < points.total && !result; i++)
934                 {
935                         MaskPoint *point1 = points.values[i];
936                         MaskPoint *point2 = (i >= points.total - 1) ? 
937                                 points.values[0] : 
938                                 points.values[i + 1];
939                         float x0, x1, x2, x3;
940                         float y0, y1, y2, y3;
941                         float old_x, old_y, x, y;
942                         int segments = (int)(sqrt(SQR(point1->x - point2->x) + SQR(point1->y - point2->y)));
944 //printf("CWindowCanvas::do_mask 1 %f, %f -> %f, %f projectorz=%f\n",
945 //point1->x, point1->y, point2->x, point2->y, projector_z);
946                         for(int j = 0; j <= segments && !result; j++)
947                         {
948 //printf("CWindowCanvas::do_mask 1 %f, %f -> %f, %f\n", x0, y0, x3, y3);
949                                 x0 = point1->x;
950                                 y0 = point1->y;
951                                 x1 = point1->x + point1->control_x2;
952                                 y1 = point1->y + point1->control_y2;
953                                 x2 = point2->x + point2->control_x1;
954                                 y2 = point2->y + point2->control_y1;
955                                 x3 = point2->x;
956                                 y3 = point2->y;
958                                 float t = (float)j / segments;
959                                 float tpow2 = t * t;
960                                 float tpow3 = t * t * t;
961                                 float invt = 1 - t;
962                                 float invtpow2 = invt * invt;
963                                 float invtpow3 = invt * invt * invt;
965                                 x = (        invtpow3 * x0
966                                         + 3 * t     * invtpow2 * x1
967                                         + 3 * tpow2 * invt     * x2 
968                                         +     tpow3            * x3);
969                                 y = (        invtpow3 * y0 
970                                         + 3 * t     * invtpow2 * y1
971                                         + 3 * tpow2 * invt     * y2 
972                                         +     tpow3            * y3);
974                                 x = (x - half_track_w) * projector_z + projector_x;
975                                 y = (y - half_track_h) * projector_z + projector_y;
978 // Test new point addition
979                                 if(button_press)
980                                 {
981                                         float line_distance = 
982                                                 sqrt(SQR(x - mask_cursor_x) + SQR(y - mask_cursor_y));
984 //printf("CWindowCanvas::do_mask 1 x=%f mask_cursor_x=%f y=%f mask_cursor_y=%f %f %f %d, %d\n", 
985 //x, mask_cursor_x, y, mask_cursor_y, line_distance, shortest_line_distance, shortest_point1, shortest_point2);
986                                         if(line_distance < shortest_line_distance || 
987                                                 shortest_point1 < 0)
988                                         {
989                                                 shortest_line_distance = line_distance;
990                                                 shortest_point1 = i;
991                                                 shortest_point2 = (i >= points.total - 1) ? 0 : (i + 1);
992 //printf("CWindowCanvas::do_mask 2 %f %f %d, %d\n", line_distance, shortest_line_distance, shortest_point1, shortest_point2);
993                                         }
996                                         float point_distance1 = 
997                                                 sqrt(SQR(point1->x - mask_cursor_x) + SQR(point1->y - mask_cursor_y));
998                                         float point_distance2 = 
999                                                 sqrt(SQR(point2->x - mask_cursor_x) + SQR(point2->y - mask_cursor_y));
1001                                         if(point_distance1 < shortest_point_distance || 
1002                                                 shortest_point < 0)
1003                                         {
1004                                                 shortest_point_distance = point_distance1;
1005                                                 shortest_point = i;
1006                                         }
1008                                         if(point_distance2 < shortest_point_distance || 
1009                                                 shortest_point < 0)
1010                                         {
1011                                                 shortest_point_distance = point_distance2;
1012                                                 shortest_point = (i >= points.total - 1) ? 0 : (i + 1);
1013                                         }
1014                                 }
1016                                 output_to_canvas(mwindow->edl, 0, x, y);
1019 #define TEST_BOX(cursor_x, cursor_y, target_x, target_y) \
1020         (cursor_x >= target_x - CONTROL_W / 2 && \
1021         cursor_x < target_x + CONTROL_W / 2 && \
1022         cursor_y >= target_y - CONTROL_H / 2 && \
1023         cursor_y < target_y + CONTROL_H / 2)
1025 // Test existing point selection
1026                                 if(button_press)
1027                                 {
1028                                         float canvas_x = (x0 - half_track_w) * projector_z + projector_x;
1029                                         float canvas_y = (y0 - half_track_h) * projector_z + projector_y;
1030                                         int cursor_x = get_cursor_x();
1031                                         int cursor_y = get_cursor_y();
1033 // Test first point
1034                                         if(gui->shift_down())
1035                                         {
1036                                                 float control_x = (x1 - half_track_w) * projector_z + projector_x;
1037                                                 float control_y = (y1 - half_track_h) * projector_z + projector_y;
1038                                                 output_to_canvas(mwindow->edl, 0, control_x, control_y);
1040                                                 float distance = 
1041                                                         sqrt(SQR(control_x - cursor_x) + SQR(control_y - cursor_y));
1043                                                 if(distance < selected_control_point_distance)
1044                                                 {
1045                                                         selected_point = i;
1046                                                         selected_control_point = 1;
1047                                                         selected_control_point_distance = distance;
1048                                                 }
1049                                         }
1050                                         else
1051                                         {
1052                                                 output_to_canvas(mwindow->edl, 0, canvas_x, canvas_y);
1053                                                 if(!gui->ctrl_down())
1054                                                 {
1055                                                         if(TEST_BOX(cursor_x, cursor_y, canvas_x, canvas_y))
1056                                                         {
1057                                                                 selected_point = i;
1058                                                         }
1059                                                 }
1060                                                 else
1061                                                 {
1062                                                         selected_point = shortest_point;
1063                                                 }
1064                                         }
1066 // Test second point
1067                                         canvas_x = (x3 - half_track_w) * projector_z + projector_x;
1068                                         canvas_y = (y3 - half_track_h) * projector_z + projector_y;
1069                                         if(gui->shift_down())
1070                                         {
1071                                                 float control_x = (x2 - half_track_w) * projector_z + projector_x;
1072                                                 float control_y = (y2 - half_track_h) * projector_z + projector_y;
1073                                                 output_to_canvas(mwindow->edl, 0, control_x, control_y);
1075                                                 float distance = 
1076                                                         sqrt(SQR(control_x - cursor_x) + SQR(control_y - cursor_y));
1078 //printf("CWindowCanvas::do_mask %d %f %f\n", i, distance, selected_control_point_distance);
1079                                                 if(distance < selected_control_point_distance)
1080                                                 {
1081                                                         selected_point = (i < points.total - 1 ? i + 1 : 0);
1082                                                         selected_control_point = 0;
1083                                                         selected_control_point_distance = distance;
1084                                                 }
1085                                         }
1086                                         else
1087                                         if(i < points.total - 1)
1088                                         {
1089                                                 output_to_canvas(mwindow->edl, 0, canvas_x, canvas_y);
1090                                                 if(!gui->ctrl_down())
1091                                                 {
1092                                                         if(TEST_BOX(cursor_x, cursor_y, canvas_x, canvas_y))
1093                                                         {
1094                                                                 selected_point = (i < points.total - 1 ? i + 1 : 0);
1095                                                         }
1096                                                 }
1097                                                 else
1098                                                 {
1099                                                         selected_point = shortest_point;
1100                                                 }
1101                                         }
1102                                 }
1106                                 if(j > 0)
1107                                 {
1108 // Draw joining line
1109                                         if(draw)
1110                                         {
1111                                                 x_points.append((int)x);
1112                                                 y_points.append((int)y);
1113                                         }
1115                                         if(j == segments)
1116                                         {
1121                                                 if(draw)
1122                                                 {
1123 // Draw second anchor
1124                                                         if(i < points.total - 1)
1125                                                         {
1126                                                                 if(i == gui->affected_point - 1)
1127                                                                         canvas->draw_disc((int)x - CONTROL_W / 2, 
1128                                                                                 (int)y - CONTROL_W / 2, 
1129                                                                                 CONTROL_W, 
1130                                                                                 CONTROL_W);
1131                                                                 else
1132                                                                         canvas->draw_circle((int)x - CONTROL_W / 2, 
1133                                                                                 (int)y - CONTROL_W / 2, 
1134                                                                                 CONTROL_W, 
1135                                                                                 CONTROL_W);
1136 // char string[BCTEXTLEN];
1137 // sprintf(string, "%d", (i < points.total - 1 ? i + 1 : 0));
1138 // canvas->draw_text((int)x + CONTROL_W, (int)y + CONTROL_W, string);
1139                                                         }
1141 // Draw second control point.  Discard x2 and y2 after this.
1142                                                         x2 = (x2 - half_track_w) * projector_z + projector_x;
1143                                                         y2 = (y2 - half_track_h) * projector_z + projector_y;
1144                                                         output_to_canvas(mwindow->edl, 0, x2, y2);
1145                                                         canvas->draw_line((int)x, (int)y, (int)x2, (int)y2);
1146                                                         canvas->draw_rectangle((int)x2 - CONTROL_W / 2,
1147                                                                 (int)y2 - CONTROL_H / 2,
1148                                                                 CONTROL_W,
1149                                                                 CONTROL_H);
1150                                                 }
1151                                         }
1152                                 }
1153                                 else
1154                                 {
1157 // Draw first anchor
1158                                         if(i == 0 && draw)
1159                                         {
1160                                                 canvas->draw_disc((int)x - FIRST_CONTROL_W / 2, 
1161                                                         (int)y - FIRST_CONTROL_H / 2, 
1162                                                         FIRST_CONTROL_W, 
1163                                                         FIRST_CONTROL_H);
1164                                         }
1166 // Draw first control point.  Discard x1 and y1 after this.
1167                                         if(draw)
1168                                         {
1169                                                 x1 = (x1 - half_track_w) * projector_z + projector_x;
1170                                                 y1 = (y1 - half_track_h) * projector_z + projector_y;
1171                                                 output_to_canvas(mwindow->edl, 0, x1, y1);
1172                                                 canvas->draw_line((int)x, (int)y, (int)x1, (int)y1);
1173                                                 canvas->draw_rectangle((int)x1 - CONTROL_W / 2,
1174                                                         (int)y1 - CONTROL_H / 2,
1175                                                         CONTROL_W,
1176                                                         CONTROL_H);
1177                                         
1178                                                 x_points.append((int)x);
1179                                                 y_points.append((int)y);
1180                                         }
1181                                 }
1182 //printf("CWindowCanvas::do_mask 1\n");
1184                                 old_x = x;
1185                                 old_y = y;
1186                         }
1187                 }
1188 //printf("CWindowCanvas::do_mask 1\n");
1190                 if(draw)
1191                 {
1192                         canvas->draw_polygon(&x_points, &y_points);
1193                         canvas->set_opaque();
1194                 }
1195 //printf("CWindowCanvas::do_mask 1\n");
1196         }
1204         if(button_press && !result)
1205         {
1206                 gui->affected_track = gui->cwindow->calculate_affected_track();
1207 // Get current keyframe
1208                 if(gui->affected_track)
1209                         gui->affected_keyframe = 
1210                                 gui->cwindow->calculate_affected_auto(
1211                                         gui->affected_track->automation->autos[AUTOMATION_MASK],
1212                                         1);
1214                 MaskAuto *keyframe = (MaskAuto*)gui->affected_keyframe;
1215                 SubMask *mask = keyframe->get_submask(mwindow->edl->session->cwindow_mask);
1218 // Translate entire keyframe
1219                 if(gui->alt_down() && mask->points.total)
1220                 {
1221                         gui->current_operation = CWINDOW_MASK_TRANSLATE;
1222                         gui->affected_point = 0;
1223                 }
1224                 else
1225 // Existing point or control point was selected
1226                 if(selected_point >= 0)
1227                 {
1228                         gui->affected_point = selected_point;
1230                         if(selected_control_point == 0)
1231                                 gui->current_operation = CWINDOW_MASK_CONTROL_IN;
1232                         else
1233                         if(selected_control_point == 1)
1234                                 gui->current_operation = CWINDOW_MASK_CONTROL_OUT;
1235                         else
1236                                 gui->current_operation = mwindow->edl->session->cwindow_operation;
1237                 }
1238                 else
1239 // No existing point or control point was selected so create a new one
1240                 if(!gui->shift_down() && !gui->alt_down())
1241                 {
1242 // Create the template
1243                         MaskPoint *point = new MaskPoint;
1244                         point->x = mask_cursor_x;
1245                         point->y = mask_cursor_y;
1246                         point->control_x1 = 0;
1247                         point->control_y1 = 0;
1248                         point->control_x2 = 0;
1249                         point->control_y2 = 0;
1252                         if(shortest_point2 < shortest_point1)
1253                         {
1254                                 shortest_point2 ^= shortest_point1;
1255                                 shortest_point1 ^= shortest_point2;
1256                                 shortest_point2 ^= shortest_point1;
1257                         }
1261 // printf("CWindowGUI::do_mask 40\n");
1262 // mwindow->edl->dump();
1263 // printf("CWindowGUI::do_mask 50\n");
1267 //printf("CWindowCanvas::do_mask 1 %f %f %d %d\n", 
1268 //      shortest_line_distance, shortest_point_distance, shortest_point1, shortest_point2);
1269 //printf("CWindowCanvas::do_mask %d %d\n", shortest_point1, shortest_point2);
1271 // Append to end of list
1272                         if(labs(shortest_point1 - shortest_point2) > 1)
1273                         {
1274 // Need to apply the new point to every keyframe
1275                                 for(MaskAuto *current = (MaskAuto*)mask_autos->default_auto;
1276                                         current; )
1277                                 {
1278                                         SubMask *submask = current->get_submask(mwindow->edl->session->cwindow_mask);
1279                                         MaskPoint *new_point = new MaskPoint;
1280                                         submask->points.append(new_point);
1281                                         *new_point = *point;
1282                                         if(current == (MaskAuto*)mask_autos->default_auto)
1283                                                 current = (MaskAuto*)mask_autos->first;
1284                                         else
1285                                                 current = (MaskAuto*)NEXT;
1286                                 }
1288                                 gui->affected_point = mask->points.total - 1;
1289                                 result = 1;
1290                         }
1291                         else
1292 // Insert between 2 points, shifting back point 2
1293                         if(shortest_point1 >= 0 && shortest_point2 >= 0)
1294                         {
1295                                 for(MaskAuto *current = (MaskAuto*)mask_autos->default_auto;
1296                                         current; )
1297                                 {
1298                                         SubMask *submask = current->get_submask(mwindow->edl->session->cwindow_mask);
1299 // In case the keyframe point count isn't synchronized with the rest of the keyframes,
1300 // avoid a crash.
1301                                         if(submask->points.total >= shortest_point2)
1302                                         {
1303                                                 MaskPoint *new_point = new MaskPoint;
1304                                                 submask->points.append(0);
1305                                                 for(int i = submask->points.total - 1; 
1306                                                         i > shortest_point2; 
1307                                                         i--)
1308                                                         submask->points.values[i] = submask->points.values[i - 1];
1309                                                 submask->points.values[shortest_point2] = new_point;
1311                                                 *new_point = *point;
1312                                         }
1314                                         if(current == (MaskAuto*)mask_autos->default_auto)
1315                                                 current = (MaskAuto*)mask_autos->first;
1316                                         else
1317                                                 current = (MaskAuto*)NEXT;
1318                                 }
1321                                 gui->affected_point = shortest_point2;
1322                                 result = 1;
1323                         }
1326 // printf("CWindowGUI::do_mask 20\n");
1327 // mwindow->edl->dump();
1328 // printf("CWindowGUI::do_mask 30\n");
1333 // Create the first point.
1334                         if(!result)
1335                         {
1336 //printf("CWindowCanvas::do_mask 1\n");
1337                                 for(MaskAuto *current = (MaskAuto*)mask_autos->default_auto;
1338                                         current; )
1339                                 {
1340                                         SubMask *submask = current->get_submask(mwindow->edl->session->cwindow_mask);
1341                                         MaskPoint *new_point = new MaskPoint;
1342                                         submask->points.append(new_point);
1343                                         *new_point = *point;
1344                                         if(current == (MaskAuto*)mask_autos->default_auto)
1345                                                 current = (MaskAuto*)mask_autos->first;
1346                                         else
1347                                                 current = (MaskAuto*)NEXT;
1348                                 }
1350 //printf("CWindowCanvas::do_mask 2\n");
1351 // Create a second point if none existed before
1352                                 if(mask->points.total < 2)
1353                                 {
1354                                         for(MaskAuto *current = (MaskAuto*)mask_autos->default_auto;
1355                                                 current; )
1356                                         {
1357                                                 SubMask *submask = current->get_submask(mwindow->edl->session->cwindow_mask);
1358                                                 MaskPoint *new_point = new MaskPoint;
1359                                                 submask->points.append(new_point);
1360                                                 *new_point = *point;
1361                                                 if(current == (MaskAuto*)mask_autos->default_auto)
1362                                                         current = (MaskAuto*)mask_autos->first;
1363                                                 else
1364                                                         current = (MaskAuto*)NEXT;
1365                                         }
1366                                 }
1367                                 gui->affected_point = mask->points.total - 1;
1368 //printf("CWindowCanvas::do_mask 3 %d\n", mask->points.total);
1369                         }
1373                         gui->current_operation = mwindow->edl->session->cwindow_operation;
1374 // Delete the template
1375                         delete point;
1376 //printf("CWindowGUI::do_mask 1\n");
1377                         mwindow->undo->update_undo(_("mask point"), LOAD_AUTOMATION);
1378 //printf("CWindowGUI::do_mask 10\n");
1380                 }
1382                 result = 1;
1383                 rerender = 1;
1384                 redraw = 1;
1385         }
1387         if(button_press && result)
1388         {
1389                 MaskAuto *keyframe = (MaskAuto*)gui->affected_keyframe;
1390                 SubMask *mask = keyframe->get_submask(mwindow->edl->session->cwindow_mask);
1391                 MaskPoint *point = mask->points.values[gui->affected_point];
1392                 gui->center_x = point->x;
1393                 gui->center_y = point->y;
1394                 gui->control_in_x = point->control_x1;
1395                 gui->control_in_y = point->control_y1;
1396                 gui->control_out_x = point->control_x2;
1397                 gui->control_out_y = point->control_y2;
1398         }
1400 //printf("CWindowCanvas::do_mask 8\n");
1401         if(cursor_motion)
1402         {
1403                 MaskAuto *keyframe = (MaskAuto*)gui->affected_keyframe;
1404                 SubMask *mask = keyframe->get_submask(mwindow->edl->session->cwindow_mask);
1405                 if(gui->affected_point < mask->points.total)
1406                 {
1407                         MaskPoint *point = mask->points.values[gui->affected_point];
1408 //                      float cursor_x = get_cursor_x();
1409 //                      float cursor_y = get_cursor_y();
1410 //                      canvas_to_output(mwindow->edl, 0, cursor_x, cursor_y);
1411                         float cursor_x = mask_cursor_x;
1412                         float cursor_y = mask_cursor_y;
1413 //printf("CWindowCanvas::do_mask 9 %d %d\n", mask->points.total, gui->affected_point);
1415                         float last_x = point->x;
1416                         float last_y = point->y;
1417                         float last_control_x1 = point->control_x1;
1418                         float last_control_y1 = point->control_y1;
1419                         float last_control_x2 = point->control_x2;
1420                         float last_control_y2 = point->control_y2;
1423                         switch(gui->current_operation)
1424                         {
1425                                 case CWINDOW_MASK:
1426                                         point->x = cursor_x - gui->x_origin + gui->center_x;
1427                                         point->y = cursor_y - gui->y_origin + gui->center_y;
1428                                         break;
1430                                 case CWINDOW_MASK_CONTROL_IN:
1431                                         point->control_x1 = cursor_x - gui->x_origin + gui->control_in_x;
1432                                         point->control_y1 = cursor_y - gui->y_origin + gui->control_in_y;
1433                                         break;
1435                                 case CWINDOW_MASK_CONTROL_OUT:
1436                                         point->control_x2 = cursor_x - gui->x_origin + gui->control_out_x;
1437                                         point->control_y2 = cursor_y - gui->y_origin + gui->control_out_y;
1438                                         break;
1440                                 case CWINDOW_MASK_TRANSLATE:
1441                                         for(int i = 0; i < mask->points.total; i++)
1442                                         {
1443                                                 mask->points.values[i]->x += cursor_x - gui->x_origin;
1444                                                 mask->points.values[i]->y += cursor_y - gui->y_origin;
1445                                         }
1446                                         gui->x_origin = cursor_x;
1447                                         gui->y_origin = cursor_y;
1448                                         break;
1449                         }
1452                         if( !EQUIV(last_x, point->x) ||
1453                                 !EQUIV(last_y, point->y) ||
1454                                 !EQUIV(last_control_x1, point->control_x1) ||
1455                                 !EQUIV(last_control_y1, point->control_y1) ||
1456                                 !EQUIV(last_control_x2, point->control_x2) ||
1457                                 !EQUIV(last_control_y2, point->control_y2))
1458                         {
1459                                 rerender = 1;
1460                                 redraw = 1;
1461                         }
1462                 }
1463                 result = 1;
1464         }
1465 //printf("CWindowCanvas::do_mask 2 %d %d %d\n", result, rerender, redraw);
1467         points.remove_all_objects();
1468 //printf("CWindowCanvas::do_mask 20\n");
1469         return result;
1473 int CWindowCanvas::do_eyedrop(int &rerender, int button_press)
1475         int result = 0;
1476         float cursor_x = get_cursor_x();
1477         float cursor_y = get_cursor_y();
1480         if(button_press)
1481         {
1482                 gui->current_operation = CWINDOW_EYEDROP;
1483         }
1485         if(gui->current_operation == CWINDOW_EYEDROP)
1486         {
1487 SET_TRACE
1488                 canvas_to_output(mwindow->edl, 0, cursor_x, cursor_y);
1489 SET_TRACE
1491 // Get color out of frame.
1492 // Doesn't work during playback because that bypasses the refresh frame.
1493                 if(refresh_frame)
1494                 {
1495                         CLAMP(cursor_x, 0, refresh_frame->get_w() - 1);
1496                         CLAMP(cursor_y, 0, refresh_frame->get_h() - 1);
1498 // Decompression coefficients straight out of jpeglib
1499 #define V_TO_R    1.40200
1500 #define V_TO_G    -0.71414
1502 #define U_TO_G    -0.34414
1503 #define U_TO_B    1.77200
1505 #define GET_COLOR(type, components, max, do_yuv) \
1506 { \
1507         type *row = (type*)(refresh_frame->get_rows()[(int)cursor_y]) + \
1508                 (int)cursor_x * components; \
1509         float red = (float)*row++ / max; \
1510         float green = (float)*row++ / max; \
1511         float blue = (float)*row++ / max; \
1512         if(do_yuv) \
1513         { \
1514                 mwindow->edl->local_session->red = red + V_TO_R * (blue - 0.5); \
1515                 mwindow->edl->local_session->green = red + U_TO_G * (green - 0.5) + V_TO_G * (blue - 0.5); \
1516                 mwindow->edl->local_session->blue = red + U_TO_B * (green - 0.5); \
1517         } \
1518         else \
1519         { \
1520                 mwindow->edl->local_session->red = red; \
1521                 mwindow->edl->local_session->green = green; \
1522                 mwindow->edl->local_session->blue = blue; \
1523         } \
1526 SET_TRACE
1527                         switch(refresh_frame->get_color_model())
1528                         {
1529                                 case BC_YUV888:
1530                                         GET_COLOR(unsigned char, 3, 0xff, 1);
1531                                         break;
1532                                 case BC_YUVA8888:
1533                                         GET_COLOR(unsigned char, 4, 0xff, 1);
1534                                         break;
1535                                 case BC_YUV161616:
1536                                         GET_COLOR(uint16_t, 3, 0xffff, 1);
1537                                         break;
1538                                 case BC_YUVA16161616:
1539                                         GET_COLOR(uint16_t, 4, 0xffff, 1);
1540                                         break;
1541                                 case BC_RGB888:
1542                                         GET_COLOR(unsigned char, 3, 0xff, 0);
1543                                         break;
1544                                 case BC_RGBA8888:
1545                                         GET_COLOR(unsigned char, 4, 0xff, 0);
1546                                         break;
1547                                 case BC_RGB_FLOAT:
1548                                         GET_COLOR(float, 3, 1.0, 0);
1549                                         break;
1550                                 case BC_RGBA_FLOAT:
1551                                         GET_COLOR(float, 4, 1.0, 0);
1552                                         break;
1553                         }
1554 SET_TRACE
1555                 }
1556                 else
1557                 {
1558                         mwindow->edl->local_session->red = 0;
1559                         mwindow->edl->local_session->green = 0;
1560                         mwindow->edl->local_session->blue = 0;
1561                 }
1563 SET_TRACE
1565                 gui->update_tool();             
1568 SET_TRACE
1570                 result = 1;
1571 // Can't rerender since the color value is from the output of any effect it
1572 // goes into.
1573 //              rerender = 1;
1574         }
1576         return result;
1579 void CWindowCanvas::draw_overlays()
1581 //printf("CWindowCanvas::draw_overlays 1\n");
1582         if(mwindow->edl->session->safe_regions)
1583         {
1584                 draw_safe_regions();
1585         }
1587         if(mwindow->edl->session->cwindow_scrollbars)
1588         {
1589 // Always draw output rectangle
1590                 float x1, y1, x2, y2;
1591                 x1 = 0;
1592                 x2 = mwindow->edl->session->output_w;
1593                 y1 = 0;
1594                 y2 = mwindow->edl->session->output_h;
1595                 output_to_canvas(mwindow->edl, 0, x1, y1);
1596                 output_to_canvas(mwindow->edl, 0, x2, y2);
1598                 canvas->set_inverse();
1599                 canvas->set_color(WHITE);
1601                 canvas->draw_rectangle((int)x1, 
1602                                 (int)y1, 
1603                                 (int)(x2 - x1), 
1604                                 (int)(y2 - y1));
1606                 canvas->set_opaque();
1607         }
1609         if(mwindow->session->ccanvas_highlighted)
1610         {
1611                 canvas->set_color(WHITE);
1612                 canvas->set_inverse();
1613                 canvas->draw_rectangle(0, 0, canvas->get_w(), canvas->get_h());
1614                 canvas->draw_rectangle(1, 1, canvas->get_w() - 2, canvas->get_h() - 2);
1615                 canvas->set_opaque();
1616         }
1618         int temp1 = 0, temp2 = 0;
1619 //printf("CWindowCanvas::draw_overlays 1 %d\n", mwindow->edl->session->cwindow_operation);
1620         switch(mwindow->edl->session->cwindow_operation)
1621         {
1622                 case CWINDOW_CAMERA:
1623                         draw_bezier(1);
1624                         break;
1626                 case CWINDOW_PROJECTOR:
1627                         draw_bezier(0);
1628                         break;
1630                 case CWINDOW_CROP:
1631                         draw_crop();
1632                         break;
1634                 case CWINDOW_MASK:
1635                         do_mask(temp1, temp2, 0, 0, 1);
1636                         break;
1637         }
1638 //printf("CWindowCanvas::draw_overlays 2\n");
1641 void CWindowCanvas::draw_safe_regions()
1643         float action_x1, action_x2, action_y1, action_y2;
1644         float title_x1, title_x2, title_y1, title_y2;
1646         action_x1 = mwindow->edl->session->output_w / 2 - mwindow->edl->session->output_w / 2 * 0.9;
1647         action_x2 = mwindow->edl->session->output_w / 2 + mwindow->edl->session->output_w / 2 * 0.9;
1648         action_y1 = mwindow->edl->session->output_h / 2 - mwindow->edl->session->output_h / 2 * 0.9;
1649         action_y2 = mwindow->edl->session->output_h / 2 + mwindow->edl->session->output_h / 2 * 0.9;
1650         title_x1 = mwindow->edl->session->output_w / 2 - mwindow->edl->session->output_w / 2 * 0.8;
1651         title_x2 = mwindow->edl->session->output_w / 2 + mwindow->edl->session->output_w / 2 * 0.8;
1652         title_y1 = mwindow->edl->session->output_h / 2 - mwindow->edl->session->output_h / 2 * 0.8;
1653         title_y2 = mwindow->edl->session->output_h / 2 + mwindow->edl->session->output_h / 2 * 0.8;
1655         output_to_canvas(mwindow->edl, 0, action_x1, action_y1);
1656         output_to_canvas(mwindow->edl, 0, action_x2, action_y2);
1657         output_to_canvas(mwindow->edl, 0, title_x1, title_y1);
1658         output_to_canvas(mwindow->edl, 0, title_x2, title_y2);
1660         canvas->set_inverse();
1661         canvas->set_color(WHITE);
1663         canvas->draw_rectangle((int)action_x1, 
1664                         (int)action_y1, 
1665                         (int)(action_x2 - action_x1), 
1666                         (int)(action_y2 - action_y1));
1667         canvas->draw_rectangle((int)title_x1, 
1668                         (int)title_y1, 
1669                         (int)(title_x2 - title_x1), 
1670                         (int)(title_y2 - title_y1));
1672         canvas->set_opaque();
1675 void CWindowCanvas::reset_keyframe(int do_camera)
1677         FloatAuto *x_keyframe = 0;
1678         FloatAuto *y_keyframe = 0;
1679         FloatAuto *z_keyframe = 0;
1680         Track *affected_track = 0;
1682         affected_track = gui->cwindow->calculate_affected_track();
1684         if(affected_track)
1685         {
1686                 gui->cwindow->calculate_affected_autos(&x_keyframe,
1687                         &y_keyframe,
1688                         &z_keyframe,
1689                         affected_track,
1690                         do_camera,
1691                         1,
1692                         1,
1693                         1);
1695                 x_keyframe->value = 0;
1696                 y_keyframe->value = 0;
1697                 z_keyframe->value = 1;
1699                 mwindow->sync_parameters(CHANGE_PARAMS);
1700                 gui->update_tool();
1701         }
1704 void CWindowCanvas::reset_camera()
1706         reset_keyframe(1);
1709 void CWindowCanvas::reset_projector()
1711         reset_keyframe(0);
1714 int CWindowCanvas::test_crop(int button_press, int &redraw)
1716         int result = 0;
1717         int handle_selected = -1;
1718         float x1 = mwindow->edl->session->crop_x1;
1719         float y1 = mwindow->edl->session->crop_y1;
1720         float x2 = mwindow->edl->session->crop_x2;
1721         float y2 = mwindow->edl->session->crop_y2;
1722         float cursor_x = get_cursor_x();
1723         float cursor_y = get_cursor_y();
1724         float canvas_x1 = x1;
1725         float canvas_y1 = y1;
1726         float canvas_x2 = x2;
1727         float canvas_y2 = y2;
1728         float canvas_cursor_x = cursor_x;
1729         float canvas_cursor_y = cursor_y;
1731         canvas_to_output(mwindow->edl, 0, cursor_x, cursor_y);
1732 // Use screen normalized coordinates for hot spot tests.
1733         output_to_canvas(mwindow->edl, 0, canvas_x1, canvas_y1);
1734         output_to_canvas(mwindow->edl, 0, canvas_x2, canvas_y2);
1737         if(gui->current_operation == CWINDOW_CROP)
1738         {
1739                 handle_selected = gui->crop_handle;
1740         }
1741         else
1742         if(canvas_cursor_x >= canvas_x1 && canvas_cursor_x < canvas_x1 + CROPHANDLE_W &&
1743                 canvas_cursor_y >= canvas_y1 && canvas_cursor_y < canvas_y1 + CROPHANDLE_H)
1744         {
1745                 handle_selected = 0;
1746                 gui->crop_origin_x = x1;
1747                 gui->crop_origin_y = y1;
1748         }
1749         else
1750         if(canvas_cursor_x >= canvas_x2 - CROPHANDLE_W && canvas_cursor_x < canvas_x2 &&
1751                 canvas_cursor_y >= canvas_y1 && canvas_cursor_y < canvas_y1 + CROPHANDLE_H)
1752         {
1753                 handle_selected = 1;
1754                 gui->crop_origin_x = x2;
1755                 gui->crop_origin_y = y1;
1756         }
1757         else
1758         if(canvas_cursor_x >= canvas_x1 && canvas_cursor_x < canvas_x1 + CROPHANDLE_W &&
1759                 canvas_cursor_y >= canvas_y2 - CROPHANDLE_H && canvas_cursor_y < canvas_y2)
1760         {
1761                 handle_selected = 2;
1762                 gui->crop_origin_x = x1;
1763                 gui->crop_origin_y = y2;
1764         }
1765         else
1766         if(canvas_cursor_x >= canvas_x2 - CROPHANDLE_W && canvas_cursor_x < canvas_x2 &&
1767                 canvas_cursor_y >= canvas_y2 - CROPHANDLE_H && canvas_cursor_y < canvas_y2)
1768         {
1769                 handle_selected = 3;
1770                 gui->crop_origin_x = x2;
1771                 gui->crop_origin_y = y2;
1772         }
1773         else
1774 // Start new box
1775         {
1776                 gui->crop_origin_x = cursor_x;
1777                 gui->crop_origin_y = cursor_y;
1778         }
1780 // printf("test crop %d %d\n", 
1781 //      gui->current_operation,
1782 //      handle_selected);
1784 // Start dragging.
1785         if(button_press)
1786         {
1787                 if(gui->alt_down())
1788                 {
1789                         gui->crop_translate = 1;
1790                         gui->crop_origin_x1 = x1;
1791                         gui->crop_origin_y1 = y1;
1792                         gui->crop_origin_x2 = x2;
1793                         gui->crop_origin_y2 = y2;
1794                 }
1795                 else
1796                         gui->crop_translate = 0;
1798                 gui->current_operation = CWINDOW_CROP;
1799                 gui->crop_handle = handle_selected;
1800                 gui->x_origin = cursor_x;
1801                 gui->y_origin = cursor_y;
1802                 result = 1;
1804                 if(handle_selected < 0 && !gui->crop_translate) 
1805                 {
1806                         x2 = x1 = cursor_x;
1807                         y2 = y1 = cursor_y;
1808                         mwindow->edl->session->crop_x1 = (int)x1;
1809                         mwindow->edl->session->crop_y1 = (int)y1;
1810                         mwindow->edl->session->crop_x2 = (int)x2;
1811                         mwindow->edl->session->crop_y2 = (int)y2;
1812                         redraw = 1;
1813                 }
1814         }
1815     else
1816 // Translate all 4 points
1817         if(gui->current_operation == CWINDOW_CROP && gui->crop_translate)
1818         {
1819                 x1 = cursor_x - gui->x_origin + gui->crop_origin_x1;
1820                 y1 = cursor_y - gui->y_origin + gui->crop_origin_y1;
1821                 x2 = cursor_x - gui->x_origin + gui->crop_origin_x2;
1822                 y2 = cursor_y - gui->y_origin + gui->crop_origin_y2;
1824                 mwindow->edl->session->crop_x1 = (int)x1;
1825                 mwindow->edl->session->crop_y1 = (int)y1;
1826                 mwindow->edl->session->crop_x2 = (int)x2;
1827                 mwindow->edl->session->crop_y2 = (int)y2;
1828                 result = 1;
1829                 redraw = 1;
1830         }
1831         else
1832 // Update dragging
1833         if(gui->current_operation == CWINDOW_CROP)
1834         {
1835                 switch(gui->crop_handle)
1836                 {
1837                         case -1:
1838                                 x1 = gui->crop_origin_x;
1839                                 y1 = gui->crop_origin_y;
1840                                 x2 = gui->crop_origin_x;
1841                                 y2 = gui->crop_origin_y;
1842                                 if(cursor_x < gui->x_origin)
1843                                 {
1844                                         if(cursor_y < gui->y_origin)
1845                                         {
1846                                                 x1 = cursor_x;
1847                                                 y1 = cursor_y;
1848                                         }
1849                                         else
1850                                         if(cursor_y >= gui->y_origin)
1851                                         {
1852                                                 x1 = cursor_x;
1853                                                 y2 = cursor_y;
1854                                         }
1855                                 }
1856                                 else
1857                                 if(cursor_x  >= gui->x_origin)
1858                                 {
1859                                         if(cursor_y < gui->y_origin)
1860                                         {
1861                                                 y1 = cursor_y;
1862                                                 x2 = cursor_x;
1863                                         }
1864                                         else
1865                                         if(cursor_y >= gui->y_origin)
1866                                         {
1867                                                 x2 = cursor_x;
1868                                                 y2 = cursor_y;
1869                                         }
1870                                 }
1872 // printf("test crop %d %d %d %d\n", 
1873 //      mwindow->edl->session->crop_x1,
1874 //      mwindow->edl->session->crop_y1,
1875 //      mwindow->edl->session->crop_x2,
1876 //      mwindow->edl->session->crop_y2);
1877                                 break;
1878                         case 0:
1879                                 x1 = cursor_x - gui->x_origin + gui->crop_origin_x;
1880                                 y1 = cursor_y - gui->y_origin + gui->crop_origin_y;
1881                                 break;
1882                         case 1:
1883                                 x2 = cursor_x - gui->x_origin + gui->crop_origin_x;
1884                                 y1 = cursor_y - gui->y_origin + gui->crop_origin_y;
1885                                 break;
1886                         case 2:
1887                                 x1 = cursor_x - gui->x_origin + gui->crop_origin_x;
1888                                 y2 = cursor_y - gui->y_origin + gui->crop_origin_y;
1889                                 break;
1890                         case 3:
1891                                 x2 = cursor_x - gui->x_origin + gui->crop_origin_x;
1892                                 y2 = cursor_y - gui->y_origin + gui->crop_origin_y;
1893                                 break;
1894                 }
1896                 if(!EQUIV(mwindow->edl->session->crop_x1, x1) ||
1897                         !EQUIV(mwindow->edl->session->crop_x2, x2) ||
1898                         !EQUIV(mwindow->edl->session->crop_y1, y1) ||
1899                         !EQUIV(mwindow->edl->session->crop_y2, y2))
1900                 {
1901                         if (x1 > x2) 
1902                         {
1903                                 float tmp = x1;
1904                                 x1 = x2;
1905                                 x2 = tmp;
1906                                 switch (gui->crop_handle) 
1907                                 {
1908                                         case 0: gui->crop_handle = 1; break;
1909                                         case 1: gui->crop_handle = 0; break;
1910                                         case 2: gui->crop_handle = 3; break;
1911                                         case 3: gui->crop_handle = 2; break;
1912                                         default: break;
1913                                 }
1915                         }
1916                         if (y1 > y2) 
1917                         {
1918                                 float tmp = y1;
1919                                 y1 = y2;
1920                                 y2 = tmp;
1921                                 switch (gui->crop_handle) 
1922                                 {
1923                                         case 0: gui->crop_handle = 2; break;
1924                                         case 1: gui->crop_handle = 3; break;
1925                                         case 2: gui->crop_handle = 0; break;
1926                                         case 3: gui->crop_handle = 1; break;
1927                                         default: break;
1928                                 }
1929                         }
1931                         mwindow->edl->session->crop_x1 = (int)x1;
1932                         mwindow->edl->session->crop_y1 = (int)y1;
1933                         mwindow->edl->session->crop_x2 = (int)x2;
1934                         mwindow->edl->session->crop_y2 = (int)y2;
1935                         result = 1;
1936                         redraw = 1;
1937                 }
1938         }
1939         else
1940 // Update cursor font
1941         if(handle_selected >= 0)
1942         {
1943                 switch(handle_selected)
1944                 {
1945                         case 0:
1946                                 set_cursor(UPLEFT_RESIZE);
1947                                 break;
1948                         case 1:
1949                                 set_cursor(UPRIGHT_RESIZE);
1950                                 break;
1951                         case 2:
1952                                 set_cursor(DOWNLEFT_RESIZE);
1953                                 break;
1954                         case 3:
1955                                 set_cursor(DOWNRIGHT_RESIZE);
1956                                 break;
1957                 }
1958                 result = 1;
1959         }
1960         else
1961         {
1962                 set_cursor(ARROW_CURSOR);
1963         }
1964 #define CLAMP(x, y, z) ((x) = ((x) < (y) ? (y) : ((x) > (z) ? (z) : (x))))
1965         
1966         if(redraw)
1967         {
1968                 CLAMP(mwindow->edl->session->crop_x1, 0, mwindow->edl->session->output_w);
1969                 CLAMP(mwindow->edl->session->crop_x2, 0, mwindow->edl->session->output_w);
1970                 CLAMP(mwindow->edl->session->crop_y1, 0, mwindow->edl->session->output_h);
1971                 CLAMP(mwindow->edl->session->crop_y2, 0, mwindow->edl->session->output_h);
1972 // printf("CWindowCanvas::test_crop %d %d %d %d\n", 
1973 //      mwindow->edl->session->crop_x2,
1974 //      mwindow->edl->session->crop_y2,
1975 //      mwindow->edl->calculate_output_w(0), 
1976 //      mwindow->edl->calculate_output_h(0));
1977         }
1978         return result;
1982 void CWindowCanvas::draw_crop()
1984         canvas->set_inverse();
1985         canvas->set_color(WHITE);
1987         float x1 = mwindow->edl->session->crop_x1;
1988         float y1 = mwindow->edl->session->crop_y1;
1989         float x2 = mwindow->edl->session->crop_x2;
1990         float y2 = mwindow->edl->session->crop_y2;
1992         output_to_canvas(mwindow->edl, 0, x1, y1);
1993         output_to_canvas(mwindow->edl, 0, x2, y2);
1995         if(x2 - x1 && y2 - y1)
1996                 canvas->draw_rectangle((int)x1, 
1997                         (int)y1, 
1998                         (int)(x2 - x1), 
1999                         (int)(y2 - y1));
2001         draw_crophandle((int)x1, (int)y1);
2002         draw_crophandle((int)x2 - CROPHANDLE_W, (int)y1);
2003         draw_crophandle((int)x1, (int)y2 - CROPHANDLE_H);
2004         draw_crophandle((int)x2 - CROPHANDLE_W, (int)y2 - CROPHANDLE_H);
2005         canvas->set_opaque();
2015 void CWindowCanvas::draw_bezier(int do_camera)
2017         Track *track = gui->cwindow->calculate_affected_track();
2018         
2019         if(!track) return;
2021         float center_x;
2022         float center_y;
2023         float center_z;
2024         int64_t position = track->to_units(
2025                 mwindow->edl->local_session->get_selectionstart(1), 
2026                 0);
2028         track->automation->get_projector(&center_x, 
2029                 &center_y, 
2030                 &center_z, 
2031                 position,
2032                 PLAY_FORWARD);
2034 //      center_x += track->track_w / 2;
2035 //      center_y += track->track_h / 2;
2036         center_x += mwindow->edl->session->output_w / 2;
2037         center_y += mwindow->edl->session->output_h / 2;
2038         float track_x1 = center_x - track->track_w / 2 * center_z;
2039         float track_y1 = center_y - track->track_h / 2 * center_z;
2040         float track_x2 = track_x1 + track->track_w * center_z;
2041         float track_y2 = track_y1 + track->track_h * center_z;
2043         output_to_canvas(mwindow->edl, 0, track_x1, track_y1);
2044         output_to_canvas(mwindow->edl, 0, track_x2, track_y2);
2046 #define DRAW_PROJECTION(offset) \
2047         canvas->draw_rectangle((int)track_x1 + offset, \
2048                 (int)track_y1 + offset, \
2049                 (int)(track_x2 - track_x1), \
2050                 (int)(track_y2 - track_y1)); \
2051         canvas->draw_line((int)track_x1 + offset,  \
2052                 (int)track_y1 + offset, \
2053                 (int)track_x2 + offset, \
2054                 (int)track_y2 + offset); \
2055         canvas->draw_line((int)track_x2 + offset,  \
2056                 (int)track_y1 + offset, \
2057                 (int)track_x1 + offset, \
2058                 (int)track_y2 + offset); \
2061 // Drop shadow
2062         canvas->set_color(BLACK);
2063         DRAW_PROJECTION(1);
2065 //      canvas->set_inverse();
2066         if(do_camera)
2067                 canvas->set_color(GREEN);
2068         else
2069                 canvas->set_color(RED);
2071         DRAW_PROJECTION(0);
2072 //      canvas->set_opaque();
2078 int CWindowCanvas::test_bezier(int button_press, 
2079         int &redraw, 
2080         int &redraw_canvas,
2081         int &rerender,
2082         int do_camera)
2084         int result = 0;
2086 // Processing drag operation.
2087 // Create keyframe during first cursor motion.
2088         if(!button_press)
2089         {
2091                 float cursor_x = get_cursor_x();
2092                 float cursor_y = get_cursor_y();
2093                 canvas_to_output(mwindow->edl, 0, cursor_x, cursor_y);
2095                 if(gui->current_operation == CWINDOW_CAMERA ||
2096                         gui->current_operation == CWINDOW_PROJECTOR)
2097                 {
2098                         if(!gui->ctrl_down() && gui->shift_down() && !gui->translating_zoom)
2099                         {
2100                                 gui->translating_zoom = 1;
2101                                 gui->reset_affected();
2102                         }
2103                         else
2104                         if(!gui->ctrl_down() && !gui->shift_down() && gui->translating_zoom)
2105                         {
2106                                 gui->translating_zoom = 0;
2107                                 gui->reset_affected();
2108                         }
2110 // Get target keyframe
2111                         float last_center_x;
2112                         float last_center_y;
2113                         float last_center_z;
2116                         if(!gui->affected_x && !gui->affected_y && !gui->affected_z)
2117                         {
2118                                 Autos *affected_x_autos;
2119                                 Autos *affected_y_autos;
2120                                 Autos *affected_z_autos;
2121                                 if(!gui->affected_track) return 0;
2122                                 if(mwindow->edl->session->cwindow_operation == CWINDOW_CAMERA)
2123                                 {
2124                                         affected_x_autos = gui->affected_track->automation->autos[AUTOMATION_CAMERA_X];
2125                                         affected_y_autos = gui->affected_track->automation->autos[AUTOMATION_CAMERA_Y];
2126                                         affected_z_autos = gui->affected_track->automation->autos[AUTOMATION_CAMERA_Z];
2127                                 }
2128                                 else
2129                                 {
2130                                         affected_x_autos = gui->affected_track->automation->autos[AUTOMATION_PROJECTOR_X];
2131                                         affected_y_autos = gui->affected_track->automation->autos[AUTOMATION_PROJECTOR_Y];
2132                                         affected_z_autos = gui->affected_track->automation->autos[AUTOMATION_PROJECTOR_Z];
2133                                 }
2135                                 if(gui->translating_zoom)
2136                                 {
2137                                         gui->affected_z = 
2138                                                 (FloatAuto*)gui->cwindow->calculate_affected_auto(
2139                                                         affected_z_autos, 1);
2140                                 }
2141                                 else
2142                                 {
2143                                         gui->affected_x = 
2144                                                 (FloatAuto*)gui->cwindow->calculate_affected_auto(
2145                                                         affected_x_autos, 1);
2146                                         gui->affected_y = 
2147                                                 (FloatAuto*)gui->cwindow->calculate_affected_auto(
2148                                                         affected_y_autos, 1);
2149                                 }
2151                                 calculate_origin();
2153                                 if(gui->translating_zoom)
2154                                 {
2155                                         gui->center_z = gui->affected_z->value;
2156                                 }
2157                                 else
2158                                 {
2159                                         gui->center_x = gui->affected_x->value;
2160                                         gui->center_y = gui->affected_y->value;
2161                                 }
2163                                 rerender = 1;
2164                                 redraw = 1;
2165                         }
2168                         if(gui->translating_zoom)
2169                         {
2170                                 last_center_z = gui->affected_z->value;
2171                         }
2172                         else
2173                         {
2174                                 last_center_x = gui->affected_x->value;
2175                                 last_center_y = gui->affected_y->value;
2176                         }
2178                         if(gui->translating_zoom)
2179                         {
2180                                 gui->affected_z->value = gui->center_z + 
2181                                         (cursor_y - gui->y_origin) / 128;
2182                                 if(!EQUIV(last_center_z, gui->affected_z->value))
2183                                 {
2184                                         rerender = 1;
2185                                         redraw = 1;
2186                                         redraw_canvas = 1;
2187                                 }
2188                         }
2189                         else
2190                         {
2191                                 gui->affected_x->value = gui->center_x + cursor_x - gui->x_origin;
2192                                 gui->affected_y->value = gui->center_y + cursor_y - gui->y_origin;
2193                                 if(!EQUIV(last_center_x,  gui->affected_x->value) ||
2194                                         !EQUIV(last_center_y, gui->affected_y->value))
2195                                 {
2196                                         rerender = 1;
2197                                         redraw = 1;
2198                                         redraw_canvas = 1;
2199                                 }
2200                         }
2201                 }
2203                 result = 1;
2204         }
2205         else
2206 // Begin drag operation.  Don't create keyframe here.
2207         {
2208 // Get affected track off of the first recordable video track.
2209 // Calculating based on the alpha channel would require recording what layer
2210 // each output pixel belongs to as they're rendered and stacked.  Forget it.
2211                 gui->affected_track = gui->cwindow->calculate_affected_track();
2212                 gui->reset_affected();
2214                 if(gui->affected_track)
2215                 {
2216                         gui->current_operation = 
2217                                 mwindow->edl->session->cwindow_operation;
2218                         result = 1;
2219                 }
2220         }
2221         
2222         return result;
2225 int CWindowCanvas::test_zoom(int &redraw)
2227         int result = 0;
2228         float zoom = get_zoom();
2229         float x;
2230         float y;
2232         if(!mwindow->edl->session->cwindow_scrollbars)
2233         {
2234                 mwindow->edl->session->cwindow_scrollbars = 1;
2235                 zoom = 1.0;
2236                 x = mwindow->edl->session->output_w / 2;
2237                 y = mwindow->edl->session->output_h / 2;
2238         }
2239         else
2240         {
2241                 x = get_cursor_x();
2242                 y = get_cursor_y();
2243                 canvas_to_output(mwindow->edl, 
2244                                 0, 
2245                                 x, 
2246                                 y);
2248 //printf("CWindowCanvas::test_zoom 1 %f %f\n", x, y);
2250 // Find current zoom in table
2251                 int current_index = 0;
2252                 for(current_index = 0 ; current_index < total_zooms; current_index++)
2253                         if(EQUIV(my_zoom_table[current_index], zoom)) break;
2256 // Zoom out
2257                 if(get_buttonpress() == 5 ||
2258                         gui->ctrl_down() || 
2259                         gui->shift_down())
2260                 {
2261                         current_index--;
2262                 }
2263                 else
2264 // Zoom in
2265                 {
2266                         current_index++;
2267                 }
2268                 CLAMP(current_index, 0, total_zooms - 1);
2269                 zoom = my_zoom_table[current_index];
2270         }
2272         x = x - w / zoom / 2;
2273         y = y - h / zoom / 2;
2276         int x_i = (int)x;
2277         int y_i = (int)y;
2278 //      check_boundaries(mwindow->edl, x_i, y_i, zoom);
2280 //printf("CWindowCanvas::test_zoom 2 %d %d\n", x_i, y_i);
2282         update_zoom(x_i, 
2283                         y_i, 
2284                         zoom);
2285         reposition_window(mwindow->edl, 
2286                         mwindow->theme->ccanvas_x,
2287                         mwindow->theme->ccanvas_y,
2288                         mwindow->theme->ccanvas_w,
2289                         mwindow->theme->ccanvas_h);
2290         redraw = 1;
2291         result = 1;
2293         
2294         gui->zoom_panel->update(zoom);
2295         
2296         return result;
2300 void CWindowCanvas::calculate_origin()
2302         gui->x_origin = get_cursor_x();
2303         gui->y_origin = get_cursor_y();
2304 //printf("CWindowCanvas::calculate_origin 1 %f %f\n", gui->x_origin, gui->y_origin);
2305         canvas_to_output(mwindow->edl, 0, gui->x_origin, gui->y_origin);
2306 //printf("CWindowCanvas::calculate_origin 2 %f %f\n", gui->x_origin, gui->y_origin);
2310 int CWindowCanvas::cursor_leave_event()
2312         set_cursor(ARROW_CURSOR);
2313         return 1;
2316 int CWindowCanvas::cursor_enter_event()
2318         int redraw = 0;
2319         switch(mwindow->edl->session->cwindow_operation)
2320         {
2321                 case CWINDOW_CAMERA:
2322                 case CWINDOW_PROJECTOR:
2323                         set_cursor(MOVE_CURSOR);
2324                         break;
2325                 case CWINDOW_ZOOM:
2326                         set_cursor(MOVE_CURSOR);
2327                         break;
2328                 case CWINDOW_CROP:
2329                         test_crop(0, redraw);
2330                         break;
2331                 case CWINDOW_PROTECT:
2332                         set_cursor(ARROW_CURSOR);
2333                         break;
2334                 case CWINDOW_MASK:
2335                         set_cursor(CROSS_CURSOR);
2336                         break;
2337                 case CWINDOW_EYEDROP:
2338                         set_cursor(CROSS_CURSOR);
2339                         break;
2340         }
2341         return 1;
2344 int CWindowCanvas::cursor_motion_event()
2346         int redraw = 0, result = 0, rerender = 0, redraw_canvas = 0;
2349         switch(gui->current_operation)
2350         {
2351                 case CWINDOW_SCROLL:
2352                 {
2353                         float zoom = get_zoom();
2354                         float cursor_x = get_cursor_x();
2355                         float cursor_y = get_cursor_y();
2357                         float zoom_x, zoom_y, conformed_w, conformed_h;
2358                         get_zooms(mwindow->edl, 0, zoom_x, zoom_y, conformed_w, conformed_h);
2359                         cursor_x = (float)cursor_x / zoom_x + gui->x_offset;
2360                         cursor_y = (float)cursor_y / zoom_y + gui->y_offset;
2364                         int x = (int)(gui->x_origin - cursor_x + gui->x_offset);
2365                         int y = (int)(gui->y_origin - cursor_y + gui->y_offset);
2367                         update_zoom(x, 
2368                                 y, 
2369                                 zoom);
2370                         update_scrollbars();
2371                         redraw = 1;
2372                         result = 1;
2373                         break;
2374                 }
2376                 case CWINDOW_CAMERA:
2377                         result = test_bezier(0, redraw, redraw_canvas, rerender, 1);
2378                         break;
2380                 case CWINDOW_PROJECTOR:
2381                         result = test_bezier(0, redraw, redraw_canvas, rerender, 0);
2382                         break;
2385                 case CWINDOW_CROP:
2386 //printf("CWindowCanvas::cursor_motion_event 1 %d %d\n", x, y);
2387                         result = test_crop(0, redraw);
2388                         break;
2390                 case CWINDOW_MASK:
2391                 case CWINDOW_MASK_CONTROL_IN:
2392                 case CWINDOW_MASK_CONTROL_OUT:
2393                 case CWINDOW_MASK_TRANSLATE:
2394                         result = do_mask(redraw, 
2395                                 rerender, 
2396                                 0, 
2397                                 1,
2398                                 0);
2399                         break;
2401                 case CWINDOW_EYEDROP:
2402                         result = do_eyedrop(rerender, 0);
2403                         break;
2405         }
2409         if(!result)
2410         {
2411                 switch(mwindow->edl->session->cwindow_operation)
2412                 {
2413                         case CWINDOW_CROP:
2414                                 result = test_crop(0, redraw);
2415                                 break;
2416                 }
2417         }
2420 // If the window is never unlocked before calling send_command the
2421 // display shouldn't get stuck on the old video frame although it will
2422 // flicker between the old video frame and the new video frame.
2424         if(redraw)
2425         {
2426                 draw_refresh();
2427                 gui->update_tool();
2428         }
2430         if(redraw_canvas)
2431         {
2432                 mwindow->gui->lock_window("CWindowCanvas::cursor_motion_event 1");
2433                 mwindow->gui->canvas->draw_overlays();
2434                 mwindow->gui->canvas->flash();
2435                 mwindow->gui->unlock_window();
2436         }
2438         if(rerender)
2439         {
2440                 mwindow->restart_brender();
2441                 mwindow->sync_parameters(CHANGE_PARAMS);
2442                 gui->cwindow->playback_engine->que->send_command(CURRENT_FRAME, 
2443                         CHANGE_NONE,
2444                         mwindow->edl,
2445                         1);
2446                 if(!redraw) gui->update_tool();
2447         }
2448         return result;
2451 int CWindowCanvas::button_press_event()
2453         int result = 0;
2454         int redraw = 0;
2455         int redraw_canvas = 0;
2456         int rerender = 0;
2458         if(Canvas::button_press_event()) return 1;
2460         gui->translating_zoom = gui->shift_down(); 
2462         calculate_origin();
2463 //printf("CWindowCanvas::button_press_event 2 %f %f\n", gui->x_origin, gui->y_origin, gui->x_origin, gui->y_origin);
2465         float zoom_x, zoom_y, conformed_w, conformed_h;
2466         get_zooms(mwindow->edl, 0, zoom_x, zoom_y, conformed_w, conformed_h);
2467         gui->x_offset = get_x_offset(mwindow->edl, 0, zoom_x, conformed_w, conformed_h);
2468         gui->y_offset = get_y_offset(mwindow->edl, 0, zoom_y, conformed_w, conformed_h);
2470 // Scroll view
2471         if(get_buttonpress() == 2)
2472         {
2473                 gui->current_operation = CWINDOW_SCROLL;
2474                 result = 1;
2475         }
2476         else
2477 // Adjust parameter
2478         {
2479                 switch(mwindow->edl->session->cwindow_operation)
2480                 {
2481                         case CWINDOW_CAMERA:
2482                                 result = test_bezier(1, redraw, redraw_canvas, rerender, 1);
2483                                 break;
2485                         case CWINDOW_PROJECTOR:
2486                                 result = test_bezier(1, redraw, redraw_canvas, rerender, 0);
2487                                 break;
2489                         case CWINDOW_ZOOM:
2490                                 result = test_zoom(redraw);
2491                                 break;
2493                         case CWINDOW_CROP:
2494                                 result = test_crop(1, redraw);
2495                                 break;
2497                         case CWINDOW_MASK:
2498                                 if(get_buttonpress() == 1)
2499                                         result = do_mask(redraw, rerender, 1, 0, 0);
2500                                 break;
2502                         case CWINDOW_EYEDROP:
2503                                 result = do_eyedrop(rerender, 1);
2504                                 break;
2505                 }
2506         }
2508         if(redraw)
2509         {
2510                 draw_refresh();
2511                 gui->update_tool();
2512         }
2514 // rerendering can also be caused by press event
2515         if(rerender) 
2516         {
2517                 mwindow->restart_brender();
2518                 mwindow->sync_parameters(CHANGE_PARAMS);
2519                 gui->cwindow->playback_engine->que->send_command(CURRENT_FRAME, 
2520                         CHANGE_NONE,
2521                         mwindow->edl,
2522                         1);
2523                 if(!redraw) gui->update_tool();
2524         }
2525         return result;
2528 int CWindowCanvas::button_release_event()
2530         int result = 0;
2532         switch(gui->current_operation)
2533         {
2534                 case CWINDOW_SCROLL:
2535                         result = 1;
2536                         break;
2538                 case CWINDOW_CAMERA:
2539                         mwindow->undo->update_undo(_("camera"), LOAD_AUTOMATION);
2540                         break;
2542                 case CWINDOW_PROJECTOR:
2543                         mwindow->undo->update_undo(_("projector"), LOAD_AUTOMATION);
2544                         break;
2546                 case CWINDOW_MASK:
2547                 case CWINDOW_MASK_CONTROL_IN:
2548                 case CWINDOW_MASK_CONTROL_OUT:
2549                 case CWINDOW_MASK_TRANSLATE:
2550                         mwindow->undo->update_undo(_("mask point"), LOAD_AUTOMATION);
2551                         break;
2552         }
2554         gui->current_operation = CWINDOW_NONE;
2555         return result;
2558 void CWindowCanvas::zoom_resize_window(float percentage)
2560         int canvas_w, canvas_h;
2561         calculate_sizes(mwindow->edl->get_aspect_ratio(), 
2562                 mwindow->edl->session->output_w, 
2563                 mwindow->edl->session->output_h, 
2564                 percentage,
2565                 canvas_w,
2566                 canvas_h);
2567         int new_w, new_h;
2568         new_w = canvas_w + (gui->get_w() - mwindow->theme->ccanvas_w);
2569         new_h = canvas_h + (gui->get_h() - mwindow->theme->ccanvas_h);
2570         gui->resize_window(new_w, new_h);
2571         gui->resize_event(new_w, new_h);
2574 void CWindowCanvas::toggle_controls()
2576         mwindow->session->cwindow_controls = !mwindow->session->cwindow_controls;
2577         gui->resize_event(gui->get_w(), gui->get_h());
2580 int CWindowCanvas::get_cwindow_controls()
2582         return mwindow->session->cwindow_controls;