4 * Copyright (C) 1997-2014 Adam Williams <broadcast at earthling dot net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "automation.h"
24 #include "bcsignals.h"
28 #include "cplayback.h"
31 #include "cwindowgui.h"
33 #include "cwindowtool.h"
34 #include "editpanel.h"
36 #include "edlsession.h"
37 #include "floatauto.h"
38 #include "floatautos.h"
41 #include "localsession.h"
42 #include "mainclock.h"
45 #include "mainsession.h"
47 #include "maskautos.h"
49 #include "meterpanel.h"
50 #include "mwindowgui.h"
53 #include "playback3d.h"
54 #include "playtransport.h"
56 #include "trackcanvas.h"
58 #include "transportque.h"
62 static double my_zoom_table[] =
75 static int total_zooms = sizeof(my_zoom_table) / sizeof(double);
78 CWindowGUI::CWindowGUI(MWindow *mwindow, CWindow *cwindow)
79 : BC_Window(_(PROGRAM_NAME ": Compositor"),
80 mwindow->session->cwindow_x,
81 mwindow->session->cwindow_y,
82 mwindow->session->cwindow_w,
83 mwindow->session->cwindow_h,
89 BC_WindowBase::get_resources()->bg_color,
90 mwindow->get_cwindow_display())
92 this->mwindow = mwindow;
93 this->cwindow = cwindow;
95 affected_x = affected_y = affected_z = 0;
97 orig_mask_keyframe = new MaskAuto(0, 0);
99 x_offset = y_offset = 0;
100 x_origin = y_origin = 0;
101 current_operation = CWINDOW_NONE;
105 crop_handle = -1; crop_translate = 0;
106 crop_origin_x = crop_origin_y = 0;
107 crop_origin_x1 = crop_origin_y1 = 0;
108 crop_origin_x2 = crop_origin_y2 = 0;
110 eyedrop_x = eyedrop_y = 0;
111 ruler_origin_x = ruler_origin_y = 0;
112 ruler_handle = -1; ruler_translate = 0;
113 center_x = center_y = center_z = 0;
114 control_in_x = control_in_y = 0;
115 control_out_x = control_out_y = 0;
116 translating_zoom = 0;
120 CWindowGUI::~CWindowGUI()
122 if(tool_panel) delete tool_panel;
124 delete composite_panel;
131 delete orig_mask_keyframe;
134 void CWindowGUI::create_objects()
136 lock_window("CWindowGUI::create_objects");
137 set_icon(mwindow->theme->get_image("cwindow_icon"));
139 active = new BC_Pixmap(this, mwindow->theme->get_image("cwindow_active"));
140 inactive = new BC_Pixmap(this, mwindow->theme->get_image("cwindow_inactive"));
142 mwindow->theme->get_cwindow_sizes(this, mwindow->session->cwindow_controls);
143 mwindow->theme->draw_cwindow_bg(this);
146 // Meters required by composite panel
147 meters = new CWindowMeters(mwindow,
149 mwindow->theme->cmeter_x,
150 mwindow->theme->cmeter_y,
151 mwindow->theme->cmeter_h);
152 meters->create_objects();
155 composite_panel = new CPanel(mwindow,
157 mwindow->theme->ccomposite_x,
158 mwindow->theme->ccomposite_y,
159 mwindow->theme->ccomposite_w,
160 mwindow->theme->ccomposite_h);
161 composite_panel->create_objects();
163 canvas = new CWindowCanvas(mwindow, this);
165 canvas->create_objects(mwindow->edl);
166 canvas->use_cwindow();
169 add_subwindow(timebar = new CTimeBar(mwindow,
171 mwindow->theme->ctimebar_x,
172 mwindow->theme->ctimebar_y,
173 mwindow->theme->ctimebar_w,
174 mwindow->theme->ctimebar_h));
175 timebar->create_objects();
178 add_subwindow(slider = new CWindowSlider(mwindow,
180 mwindow->theme->cslider_x,
181 mwindow->theme->cslider_y,
182 mwindow->theme->cslider_w));
185 transport = new CWindowTransport(mwindow,
187 mwindow->theme->ctransport_x,
188 mwindow->theme->ctransport_y);
189 transport->create_objects();
191 transport->set_slider(slider);
194 edit_panel = new CWindowEditing(mwindow, cwindow);
195 edit_panel->set_meters(meters);
196 edit_panel->create_objects();
198 // add_subwindow(clock = new MainClock(mwindow,
199 // mwindow->theme->ctime_x,
200 // mwindow->theme->ctime_y));
202 zoom_panel = new CWindowZoom(mwindow,
204 mwindow->theme->czoom_x,
205 mwindow->theme->czoom_y,
206 mwindow->theme->czoom_w);
207 zoom_panel->create_objects();
208 zoom_panel->zoom_text->add_item(new BC_MenuItem(auto_zoom = _(AUTO_ZOOM)));
209 if( !mwindow->edl->session->cwindow_scrollbars )
210 zoom_panel->set_text(auto_zoom);
212 // destination = new CWindowDestination(mwindow,
214 // mwindow->theme->cdest_x,
215 // mwindow->theme->cdest_y);
216 // destination->create_objects();
218 // Must create after meter panel
219 tool_panel = new CWindowTool(mwindow, this);
220 tool_panel->Thread::start();
223 set_operation(mwindow->edl->session->cwindow_operation);
227 canvas->draw_refresh(0);
234 int CWindowGUI::translation_event()
236 mwindow->session->cwindow_x = get_x();
237 mwindow->session->cwindow_y = get_y();
241 int CWindowGUI::resize_event(int w, int h)
243 mwindow->session->cwindow_x = get_x();
244 mwindow->session->cwindow_y = get_y();
245 mwindow->session->cwindow_w = w;
246 mwindow->session->cwindow_h = h;
248 mwindow->theme->get_cwindow_sizes(this, mwindow->session->cwindow_controls);
249 mwindow->theme->draw_cwindow_bg(this);
252 composite_panel->reposition_buttons(mwindow->theme->ccomposite_x,
253 mwindow->theme->ccomposite_y, mwindow->theme->ccomposite_h);
255 canvas->reposition_window(mwindow->edl,
256 mwindow->theme->ccanvas_x,
257 mwindow->theme->ccanvas_y,
258 mwindow->theme->ccanvas_w,
259 mwindow->theme->ccanvas_h);
261 timebar->resize_event();
264 slider->reposition_window(mwindow->theme->cslider_x,
265 mwindow->theme->cslider_y,
266 mwindow->theme->cslider_w);
267 // Recalibrate pointer motion range
268 slider->set_position();
271 transport->reposition_buttons(mwindow->theme->ctransport_x,
272 mwindow->theme->ctransport_y);
274 edit_panel->reposition_buttons(mwindow->theme->cedit_x,
275 mwindow->theme->cedit_y);
277 // clock->reposition_window(mwindow->theme->ctime_x,
278 // mwindow->theme->ctime_y);
280 zoom_panel->reposition_window(mwindow->theme->czoom_x,
281 mwindow->theme->czoom_y);
283 // destination->reposition_window(mwindow->theme->cdest_x,
284 // mwindow->theme->cdest_y);
286 meters->reposition_window(mwindow->theme->cmeter_x,
287 mwindow->theme->cmeter_y,
289 mwindow->theme->cmeter_h);
293 BC_WindowBase::resize_event(w, h);
297 int CWindowGUI::button_press_event()
299 if(canvas->get_canvas())
300 return canvas->button_press_event_base(canvas->get_canvas());
304 int CWindowGUI::cursor_leave_event()
306 if(canvas->get_canvas())
307 return canvas->cursor_leave_event_base(canvas->get_canvas());
311 int CWindowGUI::cursor_enter_event()
313 if(canvas->get_canvas())
314 return canvas->cursor_enter_event_base(canvas->get_canvas());
318 int CWindowGUI::button_release_event()
320 if(canvas->get_canvas())
321 return canvas->button_release_event();
325 int CWindowGUI::cursor_motion_event()
327 if(canvas->get_canvas())
329 canvas->get_canvas()->unhide_cursor();
330 return canvas->cursor_motion_event();
341 void CWindowGUI::draw_status(int flush)
343 if( (canvas->get_canvas() && canvas->get_canvas()->get_video_on()) ||
344 canvas->is_processing )
347 mwindow->theme->cstatus_x,
348 mwindow->theme->cstatus_y);
352 draw_pixmap(inactive,
353 mwindow->theme->cstatus_x,
354 mwindow->theme->cstatus_y);
358 // printf("CWindowGUI::draw_status %d %d %d\n", __LINE__, mwindow->theme->cstatus_x,
359 // mwindow->theme->cstatus_y);
360 flash(mwindow->theme->cstatus_x,
361 mwindow->theme->cstatus_y,
367 float CWindowGUI::get_auto_zoom()
369 float conformed_w, conformed_h;
370 mwindow->edl->calculate_conformed_dimensions(0, conformed_w, conformed_h);
371 float zoom_x = canvas->w / conformed_w;
372 float zoom_y = canvas->h / conformed_h;
373 return zoom_x < zoom_y ? zoom_x : zoom_y;
376 void CWindowGUI::zoom_canvas(double value, int update_menu)
379 float zoom = !value ? get_auto_zoom() : value;
380 mwindow->edl->session->cwindow_scrollbars = !value ? 0 : 1;
382 float cx = canvas->get_xscroll() + 0.5f*canvas->w_visible;
383 float cy = canvas->get_yscroll() + 0.5f*canvas->h_visible;
384 float output_x = cx, output_y = cy;
385 canvas->output_to_canvas(mwindow->edl, 0, cx, cy);
386 x = output_x - cx / zoom;
387 y = output_y - cy / zoom;
389 canvas->update_zoom((int)(x+0.5), (int)(y+0.5), zoom);
392 zoom_panel->update(value);
393 if( mwindow->edl->session->cwindow_operation == CWINDOW_ZOOM )
394 composite_panel->cpanel_zoom->update(zoom);
396 canvas->reposition_window(mwindow->edl,
397 mwindow->theme->ccanvas_x, mwindow->theme->ccanvas_y,
398 mwindow->theme->ccanvas_w, mwindow->theme->ccanvas_h);
399 canvas->draw_refresh();
404 void CWindowGUI::set_operation(int value)
406 mwindow->edl->session->cwindow_operation = value;
408 composite_panel->set_operation(value);
409 edit_panel->update();
411 tool_panel->start_tool(value);
412 canvas->draw_refresh();
415 void CWindowGUI::update_tool()
417 tool_panel->update_values();
420 int CWindowGUI::close_event()
422 cwindow->hide_window();
427 int CWindowGUI::keypress_event()
431 switch(get_keypress())
449 if(mwindow->session->cwindow_fullscreen)
450 canvas->stop_fullscreen();
452 canvas->start_fullscreen();
453 lock_window("CWindowGUI::keypress_event 1");
457 mwindow->gui->lock_window("CWindowGUI::keypress_event 2");
459 mwindow->gui->unlock_window();
460 lock_window("CWindowGUI::keypress_event 2");
464 mwindow->gui->lock_window("CWindowGUI::keypress_event 2");
465 mwindow->clear_entry();
466 mwindow->gui->unlock_window();
467 lock_window("CWindowGUI::keypress_event 3");
471 if(mwindow->session->cwindow_fullscreen)
472 canvas->stop_fullscreen();
473 lock_window("CWindowGUI::keypress_event 4");
480 int shift_down = this->shift_down();
482 mwindow->gui->mbuttons->transport->handle_transport(STOP, 1, 0, 0);
484 mwindow->gui->lock_window("CWindowGUI::keypress_event 2");
485 mwindow->prev_edit_handle(shift_down);
486 mwindow->gui->unlock_window();
488 lock_window("CWindowGUI::keypress_event 1");
494 mwindow->gui->lock_window("CWindowGUI::keypress_event 3");
495 mwindow->move_left();
496 mwindow->gui->unlock_window();
498 lock_window("CWindowGUI::keypress_event 2");
508 int shift_down = this->shift_down();
510 mwindow->gui->mbuttons->transport->handle_transport(STOP, 1, 0, 0);
512 mwindow->gui->lock_window("CWindowGUI::keypress_event 2");
513 mwindow->next_edit_handle(shift_down);
514 mwindow->gui->unlock_window();
516 lock_window("CWindowGUI::keypress_event 2");
522 mwindow->gui->lock_window("CWindowGUI::keypress_event 4");
523 mwindow->move_right();
524 mwindow->gui->unlock_window();
526 lock_window("CWindowGUI::keypress_event 3");
533 if(!result) result = transport->keypress_event();
539 void CWindowGUI::reset_affected()
546 void CWindowGUI::keyboard_zoomin()
548 // if(mwindow->edl->session->cwindow_scrollbars)
550 zoom_panel->zoom_tumbler->handle_up_event();
557 void CWindowGUI::keyboard_zoomout()
559 // if(mwindow->edl->session->cwindow_scrollbars)
561 zoom_panel->zoom_tumbler->handle_down_event();
569 void CWindowGUI::drag_motion()
571 if(get_hidden()) return;
573 if(mwindow->session->current_operation != DRAG_ASSET &&
574 mwindow->session->current_operation != DRAG_VTRANSITION &&
575 mwindow->session->current_operation != DRAG_VEFFECT) return;
576 int need_highlight = cursor_above() && get_cursor_over_window();
577 if( highlighted == need_highlight ) return;
578 highlighted = need_highlight;
579 canvas->draw_refresh();
582 int CWindowGUI::drag_stop()
585 if(get_hidden()) return 0;
586 if( !highlighted ) return 0;
587 if( mwindow->session->current_operation != DRAG_ASSET &&
588 mwindow->session->current_operation != DRAG_VTRANSITION &&
589 mwindow->session->current_operation != DRAG_VEFFECT) return 0;
591 canvas->draw_refresh();
594 if(mwindow->session->current_operation == DRAG_ASSET)
596 if(mwindow->session->drag_assets->total ||
597 mwindow->session->drag_clips->total)
599 mwindow->gui->lock_window("CWindowGUI::drag_stop 5");
600 mwindow->undo->update_undo_before(_("insert assets"), 0);
601 mwindow->gui->unlock_window();
604 if(mwindow->session->drag_assets->total)
606 mwindow->gui->lock_window("CWindowGUI::drag_stop 1");
608 mwindow->load_assets(mwindow->session->drag_assets,
609 mwindow->edl->local_session->get_selectionstart(),
611 mwindow->session->track_highlighted,
613 mwindow->edl->session->labels_follow_edits,
614 mwindow->edl->session->plugins_follow_edits,
615 mwindow->edl->session->autos_follow_edits,
619 if(mwindow->session->drag_clips->total)
621 mwindow->gui->lock_window("CWindowGUI::drag_stop 2");
623 mwindow->paste_edls(mwindow->session->drag_clips,
625 mwindow->session->track_highlighted,
626 mwindow->edl->local_session->get_selectionstart(),
627 mwindow->edl->session->labels_follow_edits,
628 mwindow->edl->session->plugins_follow_edits,
629 mwindow->edl->session->autos_follow_edits,
633 if(mwindow->session->drag_assets->total ||
634 mwindow->session->drag_clips->total)
636 mwindow->save_backup();
637 mwindow->restart_brender();
638 mwindow->gui->update(1, 1, 1, 1, 0, 1, 0);
639 mwindow->undo->update_undo_after(_("insert assets"), LOAD_ALL);
640 mwindow->gui->unlock_window();
641 mwindow->sync_parameters(LOAD_ALL);
645 if(mwindow->session->current_operation == DRAG_VEFFECT)
647 //printf("CWindowGUI::drag_stop 1\n");
648 Track *affected_track = cwindow->calculate_affected_track();
649 //printf("CWindowGUI::drag_stop 2\n");
651 mwindow->gui->lock_window("CWindowGUI::drag_stop 3");
652 mwindow->insert_effects_cwindow(affected_track);
653 mwindow->session->current_operation = NO_OPERATION;
654 mwindow->gui->unlock_window();
657 if(mwindow->session->current_operation == DRAG_VTRANSITION)
659 Track *affected_track = cwindow->calculate_affected_track();
660 mwindow->gui->lock_window("CWindowGUI::drag_stop 4");
661 mwindow->paste_transition_cwindow(affected_track);
662 mwindow->session->current_operation = NO_OPERATION;
663 mwindow->gui->unlock_window();
669 void CWindowGUI::update_meters()
671 if(mwindow->edl->session->cwindow_meter != meters->visible)
673 meters->set_meters(meters->meter_count, mwindow->edl->session->cwindow_meter);
674 mwindow->theme->get_cwindow_sizes(this, mwindow->session->cwindow_controls);
675 resize_event(get_w(), get_h());
680 CWindowEditing::CWindowEditing(MWindow *mwindow, CWindow *cwindow)
683 mwindow->theme->cedit_x,
684 mwindow->theme->cedit_y,
685 mwindow->edl->session->editing_mode,
704 this->mwindow = mwindow;
705 this->cwindow = cwindow;
708 #define CWrapper(fn) void CWindowEditing::fn() { \
709 mwindow->gui->lock_window("CWrapper::" #fn); \
711 mwindow->gui->unlock_window(); \
714 CWrapper(copy_selection)
715 CWrapper(splice_selection)
716 CWrapper(overwrite_selection)
717 CWrapper(set_inpoint)
718 CWrapper(set_outpoint)
719 CWrapper(clear_inpoint)
720 CWrapper(clear_outpoint)
721 CWrapper(toggle_label)
727 void CWindowEditing::to_clip()
729 mwindow->to_clip(mwindow->edl, _("composer window: "));
733 CWindowMeters::CWindowMeters(MWindow *mwindow,
738 : MeterPanel(mwindow,
744 mwindow->edl->session->audio_channels,
745 mwindow->edl->session->cwindow_meter,
749 this->mwindow = mwindow;
753 CWindowMeters::~CWindowMeters()
757 int CWindowMeters::change_status_event(int new_status)
759 mwindow->edl->session->cwindow_meter = new_status;
760 gui->update_meters();
767 CWindowZoom::CWindowZoom(MWindow *mwindow, CWindowGUI *gui, int x, int y, int w)
768 : ZoomPanel(mwindow, gui, (double)mwindow->edl->session->cwindow_zoom,
769 x, y, w, my_zoom_table, total_zooms, ZOOM_PERCENTAGE)
771 this->mwindow = mwindow;
775 CWindowZoom::~CWindowZoom()
779 void CWindowZoom::update(double value)
781 char string[BCSTRLEN];
782 const char *cp = string;
785 int frac = value >= 1.0f ? 1 :
787 value >= .01f ? 3 : 4;
788 sprintf(string, "x %.*f", frac, value);
792 ZoomPanel::update(cp);
795 int CWindowZoom::handle_event()
797 double value = !strcasecmp(gui->auto_zoom, get_text()) ? 0 : get_value();
798 gui->zoom_canvas(value, 0);
805 CWindowSlider::CWindowSlider(MWindow *mwindow, CWindow *cwindow, int x, int y, int pixels)
806 : BC_PercentageSlider(x,
815 this->mwindow = mwindow;
816 this->cwindow = cwindow;
817 set_precision(0.00001);
820 CWindowSlider::~CWindowSlider()
824 int CWindowSlider::handle_event()
826 cwindow->update_position((double)get_value());
830 void CWindowSlider::set_position()
832 double new_length = mwindow->edl->tracks->total_playable_length();
833 // if(mwindow->edl->local_session->preview_end <= 0 ||
834 // mwindow->edl->local_session->preview_end > new_length)
835 // mwindow->edl->local_session->preview_end = new_length;
836 // if(mwindow->edl->local_session->preview_start >
837 // mwindow->edl->local_session->preview_end)
838 // mwindow->edl->local_session->preview_start = 0;
841 update(mwindow->theme->cslider_w,
842 mwindow->edl->local_session->get_selectionstart(1),
845 // mwindow->edl->local_session->preview_start,
846 // mwindow->edl->local_session->preview_end);
850 int CWindowSlider::increase_value()
853 cwindow->gui->transport->handle_transport(SINGLE_FRAME_FWD);
854 lock_window("CWindowSlider::increase_value");
858 int CWindowSlider::decrease_value()
861 cwindow->gui->transport->handle_transport(SINGLE_FRAME_REWIND);
862 lock_window("CWindowSlider::decrease_value");
867 // CWindowDestination::CWindowDestination(MWindow *mwindow, CWindowGUI *cwindow, int x, int y)
868 // : BC_PopupTextBox(cwindow,
869 // &cwindow->destinations,
870 // cwindow->destinations.values[cwindow->cwindow->destination]->get_text(),
876 // this->mwindow = mwindow;
877 // this->cwindow = cwindow;
880 // CWindowDestination::~CWindowDestination()
884 // int CWindowDestination::handle_event()
895 CWindowTransport::CWindowTransport(MWindow *mwindow,
899 : PlayTransport(mwindow,
907 EDL* CWindowTransport::get_edl()
912 void CWindowTransport::goto_start()
914 gui->unlock_window();
915 handle_transport(REWIND, 1);
917 mwindow->gui->lock_window("CWindowTransport::goto_start 1");
918 mwindow->goto_start();
919 mwindow->gui->unlock_window();
921 gui->lock_window("CWindowTransport::goto_start 2");
924 void CWindowTransport::goto_end()
926 gui->unlock_window();
927 handle_transport(GOTO_END, 1);
929 mwindow->gui->lock_window("CWindowTransport::goto_end 1");
931 mwindow->gui->unlock_window();
933 gui->lock_window("CWindowTransport::goto_end 2");
938 CWindowCanvas::CWindowCanvas(MWindow *mwindow, CWindowGUI *gui)
941 mwindow->theme->ccanvas_x,
942 mwindow->theme->ccanvas_y,
943 mwindow->theme->ccanvas_w,
944 mwindow->theme->ccanvas_h,
947 mwindow->edl->session->cwindow_scrollbars)
949 this->mwindow = mwindow;
953 void CWindowCanvas::status_event()
958 int CWindowCanvas::get_fullscreen()
960 return mwindow->session->cwindow_fullscreen;
963 void CWindowCanvas::set_fullscreen(int value)
965 mwindow->session->cwindow_fullscreen = value;
969 void CWindowCanvas::update_zoom(int x, int y, float zoom)
971 use_scrollbars = mwindow->edl->session->cwindow_scrollbars;
973 mwindow->edl->session->cwindow_xscroll = x;
974 mwindow->edl->session->cwindow_yscroll = y;
975 mwindow->edl->session->cwindow_zoom = zoom;
978 void CWindowCanvas::zoom_auto()
980 gui->zoom_canvas(0, 1);
983 int CWindowCanvas::get_xscroll()
985 return mwindow->edl->session->cwindow_xscroll;
988 int CWindowCanvas::get_yscroll()
990 return mwindow->edl->session->cwindow_yscroll;
994 float CWindowCanvas::get_zoom()
996 return mwindow->edl->session->cwindow_zoom;
999 void CWindowCanvas::draw_refresh(int flush)
1001 if(get_canvas() && !get_canvas()->get_video_on())
1004 if(refresh_frame && refresh_frame->get_w()>0 && refresh_frame->get_h()>0)
1006 float in_x1, in_y1, in_x2, in_y2;
1007 float out_x1, out_y1, out_x2, out_y2;
1008 get_transfers(mwindow->edl,
1018 if(!EQUIV(out_x1, 0) ||
1019 !EQUIV(out_y1, 0) ||
1020 !EQUIV(out_x2, get_canvas()->get_w()) ||
1021 !EQUIV(out_y2, get_canvas()->get_h()))
1023 get_canvas()->clear_box(0,
1025 get_canvas()->get_w(),
1026 get_canvas()->get_h());
1029 //printf("CWindowCanvas::draw_refresh %.2f %.2f %.2f %.2f -> %.2f %.2f %.2f %.2f\n",
1030 //in_x1, in_y1, in_x2, in_y2, out_x1, out_y1, out_x2, out_y2);
1033 if(out_x2 > out_x1 &&
1038 // Can't use OpenGL here because it is called asynchronously of the
1039 // playback operation.
1040 get_canvas()->draw_vframe(refresh_frame,
1043 (int)(out_x2 - out_x1),
1044 (int)(out_y2 - out_y1),
1047 (int)(in_x2 - in_x1),
1048 (int)(in_y2 - in_y1),
1054 get_canvas()->clear_box(0,
1056 get_canvas()->get_w(),
1057 get_canvas()->get_h());
1061 get_canvas()->flash(flush);
1063 //printf("CWindowCanvas::draw_refresh 10\n");
1066 #define CROPHANDLE_W 10
1067 #define CROPHANDLE_H 10
1069 void CWindowCanvas::draw_crophandle(int x, int y)
1071 get_canvas()->draw_box(x, y, CROPHANDLE_W, CROPHANDLE_H);
1079 #define CONTROL_W 10
1080 #define CONTROL_H 10
1081 #define FIRST_CONTROL_W 20
1082 #define FIRST_CONTROL_H 20
1084 #define BC_INFINITY 65536
1086 #define RULERHANDLE_W 16
1087 #define RULERHANDLE_H 16
1091 int CWindowCanvas::do_ruler(int draw,
1097 float x1 = mwindow->edl->session->ruler_x1;
1098 float y1 = mwindow->edl->session->ruler_y1;
1099 float x2 = mwindow->edl->session->ruler_x2;
1100 float y2 = mwindow->edl->session->ruler_y2;
1101 float canvas_x1 = x1;
1102 float canvas_y1 = y1;
1103 float canvas_x2 = x2;
1104 float canvas_y2 = y2;
1105 float output_x = get_cursor_x();
1106 float output_y = get_cursor_y();
1107 float canvas_cursor_x = output_x;
1108 float canvas_cursor_y = output_y;
1110 canvas_to_output(mwindow->edl, 0, output_x, output_y);
1111 output_to_canvas(mwindow->edl, 0, canvas_x1, canvas_y1);
1112 output_to_canvas(mwindow->edl, 0, canvas_x2, canvas_y2);
1113 mwindow->session->cwindow_output_x = roundf(output_x);
1114 mwindow->session->cwindow_output_y = roundf(output_y);
1116 if(button_press && get_buttonpress() == 1)
1118 gui->ruler_handle = -1;
1119 gui->ruler_translate = 0;
1122 gui->ruler_translate = 1;
1123 gui->ruler_origin_x = x1;
1124 gui->ruler_origin_y = y1;
1127 if(canvas_cursor_x >= canvas_x1 - RULERHANDLE_W / 2 &&
1128 canvas_cursor_x < canvas_x1 + RULERHANDLE_W / 2 &&
1129 canvas_cursor_y >= canvas_y1 - RULERHANDLE_W &&
1130 canvas_cursor_y < canvas_y1 + RULERHANDLE_H / 2)
1132 gui->ruler_handle = 0;
1133 gui->ruler_origin_x = x1;
1134 gui->ruler_origin_y = y1;
1137 if(canvas_cursor_x >= canvas_x2 - RULERHANDLE_W / 2 &&
1138 canvas_cursor_x < canvas_x2 + RULERHANDLE_W / 2 &&
1139 canvas_cursor_y >= canvas_y2 - RULERHANDLE_W &&
1140 canvas_cursor_y < canvas_y2 + RULERHANDLE_H / 2)
1142 gui->ruler_handle = 1;
1143 gui->ruler_origin_x = x2;
1144 gui->ruler_origin_y = y2;
1148 // Start new selection
1149 if(!gui->ruler_translate &&
1150 (gui->ruler_handle < 0 ||
1155 do_ruler(1, 0, 0, 0);
1156 get_canvas()->flash();
1157 gui->ruler_handle = 1;
1158 mwindow->edl->session->ruler_x1 = output_x;
1159 mwindow->edl->session->ruler_y1 = output_y;
1160 mwindow->edl->session->ruler_x2 = output_x;
1161 mwindow->edl->session->ruler_y2 = output_y;
1162 gui->ruler_origin_x = mwindow->edl->session->ruler_x2;
1163 gui->ruler_origin_y = mwindow->edl->session->ruler_y2;
1166 gui->x_origin = output_x;
1167 gui->y_origin = output_y;
1168 gui->current_operation = CWINDOW_RULER;
1169 gui->tool_panel->raise_window();
1175 if(gui->current_operation == CWINDOW_RULER)
1177 if(gui->ruler_translate)
1180 do_ruler(1, 0, 0, 0);
1181 float x_difference = mwindow->edl->session->ruler_x1;
1182 float y_difference = mwindow->edl->session->ruler_y1;
1183 mwindow->edl->session->ruler_x1 = output_x - gui->x_origin + gui->ruler_origin_x;
1184 mwindow->edl->session->ruler_y1 = output_y - gui->y_origin + gui->ruler_origin_y;
1185 x_difference -= mwindow->edl->session->ruler_x1;
1186 y_difference -= mwindow->edl->session->ruler_y1;
1187 mwindow->edl->session->ruler_x2 -= x_difference;
1188 mwindow->edl->session->ruler_y2 -= y_difference;
1190 do_ruler(1, 0, 0, 0);
1191 get_canvas()->flash();
1195 switch(gui->ruler_handle)
1198 do_ruler(1, 0, 0, 0);
1199 mwindow->edl->session->ruler_x1 = output_x - gui->x_origin + gui->ruler_origin_x;
1200 mwindow->edl->session->ruler_y1 = output_y - gui->y_origin + gui->ruler_origin_y;
1201 if(gui->alt_down() || gui->ctrl_down())
1203 double angle_value = fabs(atan((mwindow->edl->session->ruler_y2 - mwindow->edl->session->ruler_y1) /
1204 (mwindow->edl->session->ruler_x2 - mwindow->edl->session->ruler_x1)) *
1208 double distance_value =
1209 sqrt(SQR(mwindow->edl->session->ruler_x2 - mwindow->edl->session->ruler_x1) +
1210 SQR(mwindow->edl->session->ruler_y2 - mwindow->edl->session->ruler_y1));
1211 if(angle_value < 22)
1212 mwindow->edl->session->ruler_y1 = mwindow->edl->session->ruler_y2;
1214 if(angle_value > 67)
1215 mwindow->edl->session->ruler_x1 = mwindow->edl->session->ruler_x2;
1217 if(mwindow->edl->session->ruler_x1 < mwindow->edl->session->ruler_x2 &&
1218 mwindow->edl->session->ruler_y1 < mwindow->edl->session->ruler_y2)
1220 mwindow->edl->session->ruler_x1 = mwindow->edl->session->ruler_x2 - distance_value / 1.414214;
1221 mwindow->edl->session->ruler_y1 = mwindow->edl->session->ruler_y2 - distance_value / 1.414214;
1224 if(mwindow->edl->session->ruler_x1 < mwindow->edl->session->ruler_x2 && mwindow->edl->session->ruler_y1 > mwindow->edl->session->ruler_y2)
1226 mwindow->edl->session->ruler_x1 = mwindow->edl->session->ruler_x2 - distance_value / 1.414214;
1227 mwindow->edl->session->ruler_y1 = mwindow->edl->session->ruler_y2 + distance_value / 1.414214;
1230 if(mwindow->edl->session->ruler_x1 > mwindow->edl->session->ruler_x2 &&
1231 mwindow->edl->session->ruler_y1 < mwindow->edl->session->ruler_y2)
1233 mwindow->edl->session->ruler_x1 = mwindow->edl->session->ruler_x2 + distance_value / 1.414214;
1234 mwindow->edl->session->ruler_y1 = mwindow->edl->session->ruler_y2 - distance_value / 1.414214;
1238 mwindow->edl->session->ruler_x1 = mwindow->edl->session->ruler_x2 + distance_value / 1.414214;
1239 mwindow->edl->session->ruler_y1 = mwindow->edl->session->ruler_y2 + distance_value / 1.414214;
1242 do_ruler(1, 0, 0, 0);
1243 get_canvas()->flash();
1248 do_ruler(1, 0, 0, 0);
1249 mwindow->edl->session->ruler_x2 = output_x - gui->x_origin + gui->ruler_origin_x;
1250 mwindow->edl->session->ruler_y2 = output_y - gui->y_origin + gui->ruler_origin_y;
1251 if(gui->alt_down() || gui->ctrl_down())
1253 double angle_value = fabs(atan((mwindow->edl->session->ruler_y2 - mwindow->edl->session->ruler_y1) /
1254 (mwindow->edl->session->ruler_x2 - mwindow->edl->session->ruler_x1)) *
1258 double distance_value =
1259 sqrt(SQR(mwindow->edl->session->ruler_x2 - mwindow->edl->session->ruler_x1) +
1260 SQR(mwindow->edl->session->ruler_y2 - mwindow->edl->session->ruler_y1));
1261 if(angle_value < 22)
1262 mwindow->edl->session->ruler_y2 = mwindow->edl->session->ruler_y1;
1264 if(angle_value > 67)
1265 mwindow->edl->session->ruler_x2 = mwindow->edl->session->ruler_x1;
1267 if(mwindow->edl->session->ruler_x2 < mwindow->edl->session->ruler_x1 &&
1268 mwindow->edl->session->ruler_y2 < mwindow->edl->session->ruler_y1)
1270 mwindow->edl->session->ruler_x2 = mwindow->edl->session->ruler_x1 - distance_value / 1.414214;
1271 mwindow->edl->session->ruler_y2 = mwindow->edl->session->ruler_y1 - distance_value / 1.414214;
1274 if(mwindow->edl->session->ruler_x2 < mwindow->edl->session->ruler_x1 &&
1275 mwindow->edl->session->ruler_y2 > mwindow->edl->session->ruler_y1)
1277 mwindow->edl->session->ruler_x2 = mwindow->edl->session->ruler_x1 - distance_value / 1.414214;
1278 mwindow->edl->session->ruler_y2 = mwindow->edl->session->ruler_y1 + distance_value / 1.414214;
1281 if(mwindow->edl->session->ruler_x2 > mwindow->edl->session->ruler_x1 && mwindow->edl->session->ruler_y2 < mwindow->edl->session->ruler_y1)
1283 mwindow->edl->session->ruler_x2 = mwindow->edl->session->ruler_x1 + distance_value / 1.414214;
1284 mwindow->edl->session->ruler_y2 = mwindow->edl->session->ruler_y1 - distance_value / 1.414214;
1288 mwindow->edl->session->ruler_x2 = mwindow->edl->session->ruler_x1 + distance_value / 1.414214;
1289 mwindow->edl->session->ruler_y2 = mwindow->edl->session->ruler_y1 + distance_value / 1.414214;
1292 do_ruler(1, 0, 0, 0);
1293 get_canvas()->flash();
1297 //printf("CWindowCanvas::do_ruler 2 %f %f %f %f\n", gui->ruler_x1, gui->ruler_y1, gui->ruler_x2, gui->ruler_y2);
1301 // printf("CWindowCanvas::do_ruler 2 %f %f %f %f\n",
1306 if(canvas_cursor_x >= canvas_x1 - RULERHANDLE_W / 2 &&
1307 canvas_cursor_x < canvas_x1 + RULERHANDLE_W / 2 &&
1308 canvas_cursor_y >= canvas_y1 - RULERHANDLE_W &&
1309 canvas_cursor_y < canvas_y1 + RULERHANDLE_H / 2)
1311 set_cursor(UPRIGHT_ARROW_CURSOR);
1314 if(canvas_cursor_x >= canvas_x2 - RULERHANDLE_W / 2 &&
1315 canvas_cursor_x < canvas_x2 + RULERHANDLE_W / 2 &&
1316 canvas_cursor_y >= canvas_y2 - RULERHANDLE_W &&
1317 canvas_cursor_y < canvas_y2 + RULERHANDLE_H / 2)
1319 set_cursor(UPRIGHT_ARROW_CURSOR);
1322 set_cursor(CROSS_CURSOR);
1324 // Update current position
1329 // Assume no ruler measurement if 0 length
1330 if(draw && (!EQUIV(x2, x1) || !EQUIV(y2, y1)))
1332 get_canvas()->set_inverse();
1333 get_canvas()->set_color(WHITE);
1334 get_canvas()->draw_line((int)canvas_x1,
1338 get_canvas()->draw_line(roundf(canvas_x1) - RULERHANDLE_W / 2,
1340 roundf(canvas_x1) + RULERHANDLE_W / 2,
1342 get_canvas()->draw_line(roundf(canvas_x1),
1343 roundf(canvas_y1) - RULERHANDLE_H / 2,
1345 roundf(canvas_y1) + RULERHANDLE_H / 2);
1346 get_canvas()->draw_line(roundf(canvas_x2) - RULERHANDLE_W / 2,
1348 roundf(canvas_x2) + RULERHANDLE_W / 2,
1350 get_canvas()->draw_line(roundf(canvas_x2),
1351 roundf(canvas_y2) - RULERHANDLE_H / 2,
1353 roundf(canvas_y2) + RULERHANDLE_H / 2);
1354 get_canvas()->set_opaque();
1361 static inline double line_dist(float cx,float cy, float tx,float ty)
1363 double dx = tx-cx, dy = ty-cy;
1364 return sqrt(dx*dx + dy*dy);
1367 static inline bool test_bbox(int cx, int cy, int tx, int ty)
1369 // printf("test_bbox %d,%d - %d,%d = %f\n",cx,cy,tx,ty,line_dist(cx,cy,tx,ty));
1370 return (llabs(cx-tx) < CONTROL_W/2 && llabs(cy-ty) < CONTROL_H/2);
1374 int CWindowCanvas::do_mask(int &redraw, int &rerender,
1375 int button_press, int cursor_motion, int draw)
1377 // Retrieve points from top recordable track
1378 //printf("CWindowCanvas::do_mask 1\n");
1379 Track *track = gui->cwindow->calculate_affected_track();
1380 //printf("CWindowCanvas::do_mask 2\n");
1382 if(!track) return 0;
1383 //printf("CWindowCanvas::do_mask 3\n");
1385 MaskAutos *mask_autos = (MaskAutos*)track->automation->autos[AUTOMATION_MASK];
1386 int64_t position = track->to_units(
1387 mwindow->edl->local_session->get_selectionstart(1),
1389 ArrayList<MaskPoint*> points;
1391 // Determine the points based on whether
1392 // new keyframes will be generated or drawing is performed.
1393 // If keyframe generation occurs, use the interpolated mask.
1394 // If no keyframe generation occurs, use the previous mask.
1395 int use_interpolated = 0;
1396 if(button_press || cursor_motion) {
1397 #ifdef USE_KEYFRAME_SPANNING
1398 double selection_start = mwindow->edl->local_session->get_selectionstart(0);
1399 double selection_end = mwindow->edl->local_session->get_selectionend(0);
1402 mask_autos->get_prev_auto(track->to_units(selection_start, 0),
1403 PLAY_FORWARD, first, 1);
1405 mask_autos->get_prev_auto(track->to_units(selection_end, 0),
1406 PLAY_FORWARD, last, 1);
1408 if(last == first && (!mwindow->edl->session->auto_keyframes))
1409 use_interpolated = 0;
1411 // If keyframe spanning occurs, use the interpolated points.
1412 // If new keyframe is generated, use the interpolated points.
1413 use_interpolated = 1;
1416 if(mwindow->edl->session->auto_keyframes)
1417 use_interpolated = 1;
1421 use_interpolated = 1;
1423 if(use_interpolated) {
1424 // Interpolate the points to get exactly what is being rendered at this position.
1425 mask_autos->get_points(&points,
1426 mwindow->edl->session->cwindow_mask,
1431 // Use the prev mask
1433 mask_autos->get_prev_auto(position,
1437 ((MaskAuto*)prev)->get_points(&points,
1438 mwindow->edl->session->cwindow_mask);
1441 // Projector zooms relative to the center of the track output.
1442 float half_track_w = (float)track->track_w / 2;
1443 float half_track_h = (float)track->track_h / 2;
1444 // Translate mask to projection
1445 float projector_x, projector_y, projector_z;
1446 track->automation->get_projector(
1447 &projector_x, &projector_y, &projector_z,
1448 position, PLAY_FORWARD);
1451 // Get position of cursor relative to mask
1452 float cursor_x = get_cursor_x(), cursor_y = get_cursor_y();
1453 float mask_cursor_x = cursor_x, mask_cursor_y = cursor_y;
1454 canvas_to_output(mwindow->edl, 0, mask_cursor_x, mask_cursor_y);
1456 projector_x += mwindow->edl->session->output_w / 2;
1457 projector_y += mwindow->edl->session->output_h / 2;
1458 mask_cursor_x = (mask_cursor_x - projector_x) / projector_z + half_track_w;
1459 mask_cursor_y = (mask_cursor_y - projector_y) / projector_z + half_track_h;
1461 // Fix cursor origin
1463 gui->x_origin = mask_cursor_x;
1464 gui->y_origin = mask_cursor_y;
1468 // Points of closest line
1469 int shortest_point1 = -1;
1470 int shortest_point2 = -1;
1472 int shortest_point = -1;
1473 // Distance to closest line
1474 float shortest_line_distance = BC_INFINITY;
1475 // Distance to closest point
1476 float shortest_point_distance = BC_INFINITY;
1477 int selected_point = -1;
1478 int selected_control_point = -1;
1479 float selected_control_point_distance = BC_INFINITY;
1480 ArrayList<int> x_points;
1481 ArrayList<int> y_points;
1483 if(!cursor_motion) {
1485 get_canvas()->set_color(WHITE);
1486 get_canvas()->set_inverse();
1488 //printf("CWindowCanvas::do_mask 1 %d\n", points.size());
1490 // Never draw closed polygon and a closed
1491 // polygon is harder to add points to.
1492 for(int i = 0; i < points.size() && !result; i++) {
1493 MaskPoint *point1 = points.get(i);
1494 MaskPoint *point2 = (i >= points.size() - 1) ?
1495 points.get(0) : points.get(i + 1);
1497 float point_distance1 = line_dist(point1->x,point1->y, mask_cursor_x,mask_cursor_y);
1498 if(point_distance1 < shortest_point_distance || shortest_point < 0) {
1499 shortest_point_distance = point_distance1;
1503 float point_distance2 = line_dist(point2->x,point2->y, mask_cursor_x,mask_cursor_y);
1504 if(point_distance2 < shortest_point_distance || shortest_point < 0) {
1505 shortest_point_distance = point_distance2;
1506 shortest_point = (i >= points.size() - 1) ? 0 : (i + 1);
1510 int segments = 1 + line_dist(point1->x,point1->y, point2->x,point2->y);
1512 //printf("CWindowCanvas::do_mask 1 %f, %f -> %f, %f projectorz=%f\n",
1513 //point1->x, point1->y, point2->x, point2->y, projector_z);
1514 for(int j = 0; j <= segments && !result; j++) {
1515 //printf("CWindowCanvas::do_mask 1 %f, %f -> %f, %f\n", x0, y0, x3, y3);
1516 float x0 = point1->x, y0 = point1->y;
1517 float x1 = point1->x + point1->control_x2;
1518 float y1 = point1->y + point1->control_y2;
1519 float x2 = point2->x + point2->control_x1;
1520 float y2 = point2->y + point2->control_y1;
1521 float x3 = point2->x, y3 = point2->y;
1522 float canvas_x0 = (x0 - half_track_w) * projector_z + projector_x;
1523 float canvas_y0 = (y0 - half_track_h) * projector_z + projector_y;
1524 float canvas_x1 = (x1 - half_track_w) * projector_z + projector_x;
1525 float canvas_y1 = (y1 - half_track_h) * projector_z + projector_y;
1526 float canvas_x2 = (x2 - half_track_w) * projector_z + projector_x;
1527 float canvas_y2 = (y2 - half_track_h) * projector_z + projector_y;
1528 float canvas_x3 = (x3 - half_track_w) * projector_z + projector_x;
1529 float canvas_y3 = (y3 - half_track_h) * projector_z + projector_y;
1531 float t = (float)j / segments;
1532 float tpow2 = t * t;
1533 float tpow3 = t * t * t;
1535 float invtpow2 = invt * invt;
1536 float invtpow3 = invt * invt * invt;
1538 float x = ( invtpow3 * x0
1539 + 3 * t * invtpow2 * x1
1540 + 3 * tpow2 * invt * x2
1542 float y = ( invtpow3 * y0
1543 + 3 * t * invtpow2 * y1
1544 + 3 * tpow2 * invt * y2
1546 float canvas_x = (x - half_track_w) * projector_z + projector_x;
1547 float canvas_y = (y - half_track_h) * projector_z + projector_y;
1548 // Test new point addition
1550 float line_distance = line_dist(x,y, mask_cursor_x,mask_cursor_y);
1552 //printf("CWindowCanvas::do_mask 1 x=%f cursor_x=%f y=%f cursor_y=%f %f %f %d, %d\n",
1553 // x, cursor_x, y, cursor_y, line_distance, shortest_line_distance, shortest_point1, shortest_point2);
1554 if(line_distance < shortest_line_distance ||
1555 shortest_point1 < 0) {
1556 shortest_line_distance = line_distance;
1557 shortest_point1 = i;
1558 shortest_point2 = (i >= points.size() - 1) ? 0 : (i + 1);
1559 //printf("CWindowCanvas::do_mask 2 %f %f %d, %d\n",
1560 // line_distance, shortest_line_distance, shortest_point1, shortest_point2);
1563 // Test existing point selection
1565 if(gui->ctrl_down()) {
1566 float distance = line_dist(x1,y1, mask_cursor_x,mask_cursor_y);
1568 if(distance < selected_control_point_distance) {
1570 selected_control_point = 1;
1571 selected_control_point_distance = distance;
1575 if(!gui->shift_down()) {
1576 output_to_canvas(mwindow->edl, 0, canvas_x0, canvas_y0);
1577 if(test_bbox(cursor_x, cursor_y, canvas_x0, canvas_y0)) {
1582 selected_point = shortest_point;
1585 // Test second point
1586 if(gui->ctrl_down()) {
1587 float distance = line_dist(x2,y2, mask_cursor_x,mask_cursor_y);
1589 //printf("CWindowCanvas::do_mask %d %f %f\n", i, distance, selected_control_point_distance);
1590 if(distance < selected_control_point_distance) {
1591 selected_point = (i < points.size() - 1 ? i + 1 : 0);
1592 selected_control_point = 0;
1593 selected_control_point_distance = distance;
1596 else if(i < points.size() - 1) {
1597 if(!gui->shift_down()) {
1598 output_to_canvas(mwindow->edl, 0, canvas_x3, canvas_y3);
1599 if(test_bbox(cursor_x, cursor_y, canvas_x3, canvas_y3)) {
1600 selected_point = (i < points.size() - 1 ? i + 1 : 0);
1604 selected_point = shortest_point;
1609 output_to_canvas(mwindow->edl, 0, canvas_x, canvas_y);
1613 if(draw) { // Draw joining line
1614 x_points.append((int)canvas_x);
1615 y_points.append((int)canvas_y);
1619 if(draw) { // Draw second anchor
1620 if(i < points.size() - 1) {
1621 if(i == gui->affected_point - 1)
1622 get_canvas()->draw_disc(
1623 (int)canvas_x - CONTROL_W / 2,
1624 (int)canvas_y - CONTROL_W / 2,
1625 CONTROL_W, CONTROL_H);
1627 get_canvas()->draw_circle(
1628 (int)canvas_x - CONTROL_W / 2,
1629 (int)canvas_y - CONTROL_W / 2,
1630 CONTROL_W, CONTROL_H);
1631 // char string[BCTEXTLEN];
1632 // sprintf(string, "%d", (i < points.size() - 1 ? i + 1 : 0));
1633 // canvas->draw_text((int)canvas_x + CONTROL_W, (int)canvas_y + CONTROL_W, string);
1635 // Draw second control point.
1636 output_to_canvas(mwindow->edl, 0, canvas_x2, canvas_y2);
1637 get_canvas()->draw_line(
1638 (int)canvas_x, (int)canvas_y,
1639 (int)canvas_x2, (int)canvas_y2);
1640 get_canvas()->draw_rectangle(
1641 (int)canvas_x2 - CONTROL_W / 2,
1642 (int)canvas_y2 - CONTROL_H / 2,
1643 CONTROL_W, CONTROL_H);
1648 // Draw first anchor
1649 if(i == 0 && draw) {
1650 char mask_label[BCSTRLEN];
1651 sprintf(mask_label, "%d",
1652 mwindow->edl->session->cwindow_mask);
1653 get_canvas()->draw_text(
1654 (int)canvas_x - FIRST_CONTROL_W,
1655 (int)canvas_y - FIRST_CONTROL_H,
1658 get_canvas()->draw_disc(
1659 (int)canvas_x - FIRST_CONTROL_W / 2,
1660 (int)canvas_y - FIRST_CONTROL_H / 2,
1661 FIRST_CONTROL_W, FIRST_CONTROL_H);
1664 // Draw first control point.
1666 output_to_canvas(mwindow->edl, 0, canvas_x1, canvas_y1);
1667 get_canvas()->draw_line(
1668 (int)canvas_x, (int)canvas_y,
1669 (int)canvas_x1, (int)canvas_y1);
1670 get_canvas()->draw_rectangle(
1671 (int)canvas_x1 - CONTROL_W / 2,
1672 (int)canvas_y1 - CONTROL_H / 2,
1673 CONTROL_W, CONTROL_H);
1675 x_points.append((int)canvas_x);
1676 y_points.append((int)canvas_y);
1679 //printf("CWindowCanvas::do_mask 1\n");
1683 //printf("CWindowCanvas::do_mask 1\n");
1686 get_canvas()->draw_polygon(&x_points, &y_points);
1687 get_canvas()->set_opaque();
1689 //printf("CWindowCanvas::do_mask 1\n");
1692 if(button_press && !result) {
1693 gui->affected_track = gui->cwindow->calculate_affected_track();
1695 // Get keyframe outside the EDL to edit. This must be rendered
1696 // instead of the EDL keyframes when it exists. Then it must be
1697 // applied to the EDL keyframes on buttonrelease.
1698 if(gui->affected_track) {
1699 #ifdef USE_KEYFRAME_SPANNING
1700 // Make copy of current parameters in local keyframe
1701 gui->mask_keyframe =
1702 (MaskAuto*)gui->cwindow->calculate_affected_auto(
1705 gui->orig_mask_keyframe->copy_data(gui->mask_keyframe);
1708 gui->mask_keyframe =
1709 (MaskAuto*)gui->cwindow->calculate_affected_auto(
1714 SubMask *mask = gui->mask_keyframe->get_submask(mwindow->edl->session->cwindow_mask);
1717 // Translate entire keyframe
1718 if(gui->alt_down() && mask->points.size()) {
1719 mwindow->undo->update_undo_before(_("mask translate"), 0);
1720 gui->current_operation = CWINDOW_MASK_TRANSLATE;
1721 gui->affected_point = 0;
1724 // Existing point or control point was selected
1725 if(selected_point >= 0) {
1726 mwindow->undo->update_undo_before(_("mask adjust"), 0);
1727 gui->affected_point = selected_point;
1729 if(selected_control_point == 0)
1730 gui->current_operation = CWINDOW_MASK_CONTROL_IN;
1732 if(selected_control_point == 1)
1733 gui->current_operation = CWINDOW_MASK_CONTROL_OUT;
1735 gui->current_operation = mwindow->edl->session->cwindow_operation;
1737 else // No existing point or control point was selected so create a new one
1738 if(!gui->ctrl_down() && !gui->alt_down()) {
1739 mwindow->undo->update_undo_before(_("mask point"), 0);
1740 // Create the template
1741 MaskPoint *point = new MaskPoint;
1742 point->x = mask_cursor_x;
1743 point->y = mask_cursor_y;
1744 point->control_x1 = 0;
1745 point->control_y1 = 0;
1746 point->control_x2 = 0;
1747 point->control_y2 = 0;
1750 if(shortest_point2 < shortest_point1) {
1751 shortest_point2 ^= shortest_point1;
1752 shortest_point1 ^= shortest_point2;
1753 shortest_point2 ^= shortest_point1;
1758 // printf("CWindowGUI::do_mask 40\n");
1759 // mwindow->edl->dump();
1760 // printf("CWindowGUI::do_mask 50\n");
1764 //printf("CWindowCanvas::do_mask 1 %f %f %d %d\n",
1765 // shortest_line_distance, shortest_point_distance, shortest_point1, shortest_point2);
1766 //printf("CWindowCanvas::do_mask %d %d\n", shortest_point1, shortest_point2);
1768 // Append to end of list
1769 if( shortest_point1 == shortest_point2 ||
1770 labs(shortest_point1 - shortest_point2) > 1) {
1771 #ifdef USE_KEYFRAME_SPANNING
1773 MaskPoint *new_point = new MaskPoint;
1774 points.append(new_point);
1775 *new_point = *point;
1776 gui->affected_point = points.size() - 1;
1780 // Need to apply the new point to every keyframe
1781 for(MaskAuto *current = (MaskAuto*)mask_autos->default_auto; current; ) {
1782 SubMask *submask = current->get_submask(mwindow->edl->session->cwindow_mask);
1783 MaskPoint *new_point = new MaskPoint;
1784 submask->points.append(new_point);
1785 *new_point = *point;
1786 if(current == (MaskAuto*)mask_autos->default_auto)
1787 current = (MaskAuto*)mask_autos->first;
1789 current = (MaskAuto*)NEXT;
1791 gui->affected_point = mask->points.size() - 1;
1797 // Insert between 2 points, shifting back point 2
1798 if(shortest_point1 >= 0 && shortest_point2 >= 0) {
1800 #ifdef USE_KEYFRAME_SPANNING
1801 // In case the keyframe point count isn't synchronized with the rest of the keyframes,
1803 if(points.size() >= shortest_point2) {
1804 MaskPoint *new_point = new MaskPoint;
1806 for(int i = points.size() - 1;
1807 i > shortest_point2;
1809 points.values[i] = points.values[i - 1];
1810 points.values[shortest_point2] = new_point;
1812 *new_point = *point;
1817 for(MaskAuto *current = (MaskAuto*)mask_autos->default_auto; current; ) {
1818 SubMask *submask = current->get_submask(mwindow->edl->session->cwindow_mask);
1819 // In case the keyframe point count isn't synchronized with the rest of the keyframes,
1821 if(submask->points.size() >= shortest_point2) {
1822 MaskPoint *new_point = new MaskPoint;
1823 submask->points.append(0);
1824 for(int i = submask->points.size() - 1;
1825 i > shortest_point2;
1827 submask->points.values[i] = submask->points.values[i - 1];
1828 submask->points.values[shortest_point2] = new_point;
1830 *new_point = *point;
1833 if(current == (MaskAuto*)mask_autos->default_auto)
1834 current = (MaskAuto*)mask_autos->first;
1836 current = (MaskAuto*)NEXT;
1840 gui->affected_point = shortest_point2;
1845 // printf("CWindowGUI::do_mask 20\n");
1846 // mwindow->edl->dump();
1847 // printf("CWindowGUI::do_mask 30\n");
1850 //printf("CWindowCanvas::do_mask 1\n");
1851 // Create the first point.
1852 #ifdef USE_KEYFRAME_SPANNING
1853 MaskPoint *new_point = new MaskPoint;
1854 points.append(new_point);
1855 *new_point = *point;
1856 gui->affected_point = points.size() - 1;
1858 for(MaskAuto *current = (MaskAuto*)mask_autos->default_auto; current; ) {
1859 SubMask *submask = current->get_submask(mwindow->edl->session->cwindow_mask);
1860 MaskPoint *new_point = new MaskPoint;
1861 submask->points.append(new_point);
1862 *new_point = *point;
1863 if(current == (MaskAuto*)mask_autos->default_auto)
1864 current = (MaskAuto*)mask_autos->first;
1866 current = (MaskAuto*)NEXT;
1868 gui->affected_point = points.size() - 1;
1871 //printf("CWindowCanvas::do_mask 3 %d\n", mask->points.size());
1874 gui->current_operation = mwindow->edl->session->cwindow_operation;
1875 // Delete the template
1884 if(button_press && result) {
1885 #ifdef USE_KEYFRAME_SPANNING
1886 MaskPoint *point = points.values[gui->affected_point];
1887 gui->center_x = point->x;
1888 gui->center_y = point->y;
1889 gui->control_in_x = point->control_x1;
1890 gui->control_in_y = point->control_y1;
1891 gui->control_out_x = point->control_x2;
1892 gui->control_out_y = point->control_y2;
1893 gui->tool_panel->raise_window();
1895 SubMask *mask = gui->mask_keyframe->get_submask(mwindow->edl->session->cwindow_mask);
1896 MaskPoint *point = mask->points.values[gui->affected_point];
1897 gui->center_x = point->x;
1898 gui->center_y = point->y;
1899 gui->control_in_x = point->control_x1;
1900 gui->control_in_y = point->control_y1;
1901 gui->control_out_x = point->control_x2;
1902 gui->control_out_y = point->control_y2;
1903 gui->tool_panel->raise_window();
1907 //printf("CWindowCanvas::do_mask 8\n");
1910 #ifdef USE_KEYFRAME_SPANNING
1911 // Must update the reference keyframes for every cursor motion
1912 gui->mask_keyframe =
1913 (MaskAuto*)gui->cwindow->calculate_affected_auto(
1916 gui->orig_mask_keyframe->copy_data(gui->mask_keyframe);
1919 //printf("CWindowCanvas::do_mask %d %d\n", __LINE__, gui->affected_point);
1921 SubMask *mask = gui->mask_keyframe->get_submask(mwindow->edl->session->cwindow_mask);
1922 if( gui->affected_point >= 0 && gui->affected_point < mask->points.size() &&
1923 gui->current_operation != CWINDOW_NONE) {
1924 // mwindow->undo->update_undo_before(_("mask point"), this);
1925 #ifdef USE_KEYFRAME_SPANNING
1926 MaskPoint *point = points.get(gui->affected_point);
1928 MaskPoint *point = mask->points.get(gui->affected_point);
1930 // canvas_to_output(mwindow->edl, 0, cursor_x, cursor_y);
1931 //printf("CWindowCanvas::do_mask 9 %d %d\n", mask->points.size(), gui->affected_point);
1933 float last_x = point->x;
1934 float last_y = point->y;
1935 float last_control_x1 = point->control_x1;
1936 float last_control_y1 = point->control_y1;
1937 float last_control_x2 = point->control_x2;
1938 float last_control_y2 = point->control_y2;
1940 switch(gui->current_operation) {
1942 //printf("CWindowCanvas::do_mask %d %d\n", __LINE__, gui->affected_point);
1943 point->x = mask_cursor_x - gui->x_origin + gui->center_x;
1944 point->y = mask_cursor_y - gui->y_origin + gui->center_y;
1947 case CWINDOW_MASK_CONTROL_IN:
1948 point->control_x1 = mask_cursor_x - gui->x_origin + gui->control_in_x;
1949 point->control_y1 = mask_cursor_y - gui->y_origin + gui->control_in_y;
1952 case CWINDOW_MASK_CONTROL_OUT:
1953 point->control_x2 = mask_cursor_x - gui->x_origin + gui->control_out_x;
1954 point->control_y2 = mask_cursor_y - gui->y_origin + gui->control_out_y;
1957 case CWINDOW_MASK_TRANSLATE:
1958 #ifdef USE_KEYFRAME_SPANNING
1959 for(int i = 0; i < points.size(); i++) {
1960 points.values[i]->x += mask_cursor_x - gui->x_origin;
1961 points.values[i]->y += mask_cursor_y - gui->y_origin;
1964 for(int i = 0; i < mask->points.size(); i++) {
1965 mask->points.values[i]->x += mask_cursor_x - gui->x_origin;
1966 mask->points.values[i]->y += mask_cursor_y - gui->y_origin;
1969 gui->x_origin = mask_cursor_x;
1970 gui->y_origin = mask_cursor_y;
1974 if( !EQUIV(last_x, point->x) ||
1975 !EQUIV(last_y, point->y) ||
1976 !EQUIV(last_control_x1, point->control_x1) ||
1977 !EQUIV(last_control_y1, point->control_y1) ||
1978 !EQUIV(last_control_x2, point->control_x2) ||
1979 !EQUIV(last_control_y2, point->control_y2)) {
1985 if(gui->current_operation == CWINDOW_NONE) {
1986 // printf("CWindowCanvas::do_mask %d\n", __LINE__);
1988 for(int i = 0; i < points.size() && !over_point; i++) {
1989 MaskPoint *point = points.get(i);
1990 float x0 = point->x;
1991 float y0 = point->y;
1992 float x1 = point->x + point->control_x1;
1993 float y1 = point->y + point->control_y1;
1994 float x2 = point->x + point->control_x2;
1995 float y2 = point->y + point->control_y2;
1996 float canvas_x0 = (x0 - half_track_w) * projector_z + projector_x;
1997 float canvas_y0 = (y0 - half_track_h) * projector_z + projector_y;
1999 output_to_canvas(mwindow->edl, 0, canvas_x0, canvas_y0);
2000 if(test_bbox(cursor_x, cursor_y, canvas_x0, canvas_y0)) {
2004 if(!over_point && gui->ctrl_down()) {
2005 float canvas_x1 = (x1 - half_track_w) * projector_z + projector_x;
2006 float canvas_y1 = (y1 - half_track_h) * projector_z + projector_y;
2007 output_to_canvas(mwindow->edl, 0, canvas_x1, canvas_y1);
2008 if(test_bbox(cursor_x, cursor_y, canvas_x1, canvas_y1)) {
2012 float canvas_x2 = (x2 - half_track_w) * projector_z + projector_x;
2013 float canvas_y2 = (y2 - half_track_h) * projector_z + projector_y;
2014 output_to_canvas(mwindow->edl, 0, canvas_x2, canvas_y2);
2015 if(test_bbox(cursor_x, cursor_y, canvas_x2, canvas_y2)) {
2022 set_cursor( over_point ? ARROW_CURSOR : CROSS_CURSOR );
2027 //printf("CWindowCanvas::do_mask 2 %d %d %d\n", result, rerender, redraw);
2030 #ifdef USE_KEYFRAME_SPANNING
2031 // Must commit change after operation.
2032 if(rerender && track) {
2033 // Swap EDL keyframe with original.
2034 // Apply new values to keyframe span
2035 MaskAuto temp_keyframe(mwindow->edl, mask_autos);
2036 temp_keyframe.copy_data(gui->mask_keyframe);
2037 // Apply interpolated points back to keyframe
2038 temp_keyframe.set_points(&points, mwindow->edl->session->cwindow_mask);
2039 gui->mask_keyframe->copy_data(gui->orig_mask_keyframe);
2040 mask_autos->update_parameter(&temp_keyframe);
2044 points.remove_all_objects();
2045 //printf("CWindowCanvas::do_mask 20\n");
2049 int CWindowCanvas::do_eyedrop(int &rerender, int button_press, int draw)
2052 int radius = mwindow->edl->session->eyedrop_radius;
2060 if(refresh_frame && refresh_frame->get_w()>0 && refresh_frame->get_h()>0)
2065 row1 = gui->eyedrop_y - radius;
2066 row2 = gui->eyedrop_y + radius;
2067 column1 = gui->eyedrop_x - radius;
2068 column2 = gui->eyedrop_x + radius;
2070 CLAMP(row1, 0, refresh_frame->get_h() - 1);
2071 CLAMP(row2, 0, refresh_frame->get_h() - 1);
2072 CLAMP(column1, 0, refresh_frame->get_w() - 1);
2073 CLAMP(column2, 0, refresh_frame->get_w() - 1);
2075 if(row2 <= row1) row2 = row1 + 1;
2076 if(column2 <= column1) column2 = column1 + 1;
2083 output_to_canvas(mwindow->edl, 0, x1, y1);
2084 output_to_canvas(mwindow->edl, 0, x2, y2);
2085 //printf("CWindowCanvas::do_eyedrop %d %f %f %f %f\n", __LINE__, x1, x2, y1, y2);
2087 if(x2 - x1 >= 1 && y2 - y1 >= 1)
2089 get_canvas()->set_inverse();
2090 get_canvas()->set_color(WHITE);
2092 get_canvas()->draw_rectangle((int)x1,
2097 get_canvas()->set_opaque();
2098 get_canvas()->flash();
2106 gui->current_operation = CWINDOW_EYEDROP;
2107 gui->tool_panel->raise_window();
2110 if(gui->current_operation == CWINDOW_EYEDROP)
2112 mwindow->undo->update_undo_before(_("Eyedrop"), this);
2114 // Get color out of frame.
2115 // Doesn't work during playback because that bypasses the refresh frame.
2116 if(refresh_frame && refresh_frame->get_w()>0 && refresh_frame->get_h()>0)
2118 float cursor_x = get_cursor_x();
2119 float cursor_y = get_cursor_y();
2120 canvas_to_output(mwindow->edl, 0, cursor_x, cursor_y);
2121 CLAMP(cursor_x, 0, refresh_frame->get_w() - 1);
2122 CLAMP(cursor_y, 0, refresh_frame->get_h() - 1);
2124 row1 = cursor_y - radius;
2125 row2 = cursor_y + radius;
2126 column1 = cursor_x - radius;
2127 column2 = cursor_x + radius;
2128 CLAMP(row1, 0, refresh_frame->get_h() - 1);
2129 CLAMP(row2, 0, refresh_frame->get_h() - 1);
2130 CLAMP(column1, 0, refresh_frame->get_w() - 1);
2131 CLAMP(column2, 0, refresh_frame->get_w() - 1);
2132 if(row2 <= row1) row2 = row1 + 1;
2133 if(column2 <= column1) column2 = column1 + 1;
2137 if(gui->eyedrop_visible)
2140 do_eyedrop(temp, 0, 1);
2141 gui->eyedrop_visible = 0;
2144 gui->eyedrop_x = cursor_x;
2145 gui->eyedrop_y = cursor_y;
2150 do_eyedrop(temp, 0, 1);
2151 gui->eyedrop_visible = 1;
2154 // Decompression coefficients straight out of jpeglib
2155 #define V_TO_R 1.40200
2156 #define V_TO_G -0.71414
2158 #define U_TO_G -0.34414
2159 #define U_TO_B 1.77200
2161 #define GET_COLOR(type, components, max, do_yuv) \
2163 type *row = (type*)(refresh_frame->get_rows()[i]) + \
2165 float red = (float)*row++ / max; \
2166 float green = (float)*row++ / max; \
2167 float blue = (float)*row++ / max; \
2170 mwindow->edl->local_session->red += red + V_TO_R * (blue - 0.5); \
2171 mwindow->edl->local_session->green += red + U_TO_G * (green - 0.5) + V_TO_G * (blue - 0.5); \
2172 mwindow->edl->local_session->blue += red + U_TO_B * (green - 0.5); \
2176 mwindow->edl->local_session->red += red; \
2177 mwindow->edl->local_session->green += green; \
2178 mwindow->edl->local_session->blue += blue; \
2184 mwindow->edl->local_session->red = 0;
2185 mwindow->edl->local_session->green = 0;
2186 mwindow->edl->local_session->blue = 0;
2187 for(int i = row1; i < row2; i++)
2189 for(int j = column1; j < column2; j++)
2191 switch(refresh_frame->get_color_model())
2194 GET_COLOR(unsigned char, 3, 0xff, 1);
2197 GET_COLOR(unsigned char, 4, 0xff, 1);
2200 GET_COLOR(uint16_t, 3, 0xffff, 1);
2202 case BC_YUVA16161616:
2203 GET_COLOR(uint16_t, 4, 0xffff, 1);
2206 GET_COLOR(unsigned char, 3, 0xff, 0);
2209 GET_COLOR(unsigned char, 4, 0xff, 0);
2212 GET_COLOR(float, 3, 1.0, 0);
2215 GET_COLOR(float, 4, 1.0, 0);
2221 mwindow->edl->local_session->red /= (row2 - row1) * (column2 - column1);
2222 mwindow->edl->local_session->green /= (row2 - row1) * (column2 - column1);
2223 mwindow->edl->local_session->blue /= (row2 - row1) * (column2 - column1);
2228 mwindow->edl->local_session->red = 0;
2229 mwindow->edl->local_session->green = 0;
2230 mwindow->edl->local_session->blue = 0;
2231 gui->eyedrop_visible = 0;
2240 // Can't rerender since the color value is from the output of any effect it
2243 mwindow->undo->update_undo_after(_("Eyedrop"), LOAD_SESSION);
2249 void CWindowCanvas::draw_overlays()
2251 if(mwindow->edl->session->safe_regions)
2253 draw_safe_regions();
2256 if(mwindow->edl->session->cwindow_scrollbars)
2258 // Always draw output rectangle
2259 float x1, y1, x2, y2;
2261 x2 = mwindow->edl->session->output_w;
2263 y2 = mwindow->edl->session->output_h;
2264 output_to_canvas(mwindow->edl, 0, x1, y1);
2265 output_to_canvas(mwindow->edl, 0, x2, y2);
2267 get_canvas()->set_inverse();
2268 get_canvas()->set_color(WHITE);
2270 get_canvas()->draw_rectangle((int)x1,
2275 get_canvas()->set_opaque();
2278 if(gui->highlighted)
2280 get_canvas()->set_color(WHITE);
2281 get_canvas()->set_inverse();
2282 get_canvas()->draw_rectangle(0, 0, get_canvas()->get_w(), get_canvas()->get_h());
2283 get_canvas()->draw_rectangle(1, 1, get_canvas()->get_w() - 2, get_canvas()->get_h() - 2);
2284 get_canvas()->set_opaque();
2287 int temp1 = 0, temp2 = 0;
2288 //printf("CWindowCanvas::draw_overlays 1 %d\n", mwindow->edl->session->cwindow_operation);
2289 switch(mwindow->edl->session->cwindow_operation)
2291 case CWINDOW_CAMERA:
2295 case CWINDOW_PROJECTOR:
2304 do_mask(temp1, temp2, 0, 0, 1);
2308 do_ruler(1, 0, 0, 0);
2311 case CWINDOW_EYEDROP:
2312 if(gui->eyedrop_visible)
2315 do_eyedrop(rerender, 0, 1);
2316 gui->eyedrop_visible = 1;
2322 void CWindowCanvas::draw_safe_regions()
2324 float action_x1, action_x2, action_y1, action_y2;
2325 float title_x1, title_x2, title_y1, title_y2;
2327 action_x1 = mwindow->edl->session->output_w / 2 - mwindow->edl->session->output_w / 2 * 0.9;
2328 action_x2 = mwindow->edl->session->output_w / 2 + mwindow->edl->session->output_w / 2 * 0.9;
2329 action_y1 = mwindow->edl->session->output_h / 2 - mwindow->edl->session->output_h / 2 * 0.9;
2330 action_y2 = mwindow->edl->session->output_h / 2 + mwindow->edl->session->output_h / 2 * 0.9;
2331 title_x1 = mwindow->edl->session->output_w / 2 - mwindow->edl->session->output_w / 2 * 0.8;
2332 title_x2 = mwindow->edl->session->output_w / 2 + mwindow->edl->session->output_w / 2 * 0.8;
2333 title_y1 = mwindow->edl->session->output_h / 2 - mwindow->edl->session->output_h / 2 * 0.8;
2334 title_y2 = mwindow->edl->session->output_h / 2 + mwindow->edl->session->output_h / 2 * 0.8;
2336 output_to_canvas(mwindow->edl, 0, action_x1, action_y1);
2337 output_to_canvas(mwindow->edl, 0, action_x2, action_y2);
2338 output_to_canvas(mwindow->edl, 0, title_x1, title_y1);
2339 output_to_canvas(mwindow->edl, 0, title_x2, title_y2);
2341 get_canvas()->set_inverse();
2342 get_canvas()->set_color(WHITE);
2344 get_canvas()->draw_rectangle((int)action_x1,
2346 (int)(action_x2 - action_x1),
2347 (int)(action_y2 - action_y1));
2348 get_canvas()->draw_rectangle((int)title_x1,
2350 (int)(title_x2 - title_x1),
2351 (int)(title_y2 - title_y1));
2353 get_canvas()->set_opaque();
2356 void CWindowCanvas::reset_keyframe(int do_camera)
2358 FloatAuto *x_keyframe = 0;
2359 FloatAuto *y_keyframe = 0;
2360 FloatAuto *z_keyframe = 0;
2361 Track *affected_track = 0;
2363 affected_track = gui->cwindow->calculate_affected_track();
2367 gui->cwindow->calculate_affected_autos(&x_keyframe,
2376 x_keyframe->set_value(0);
2377 y_keyframe->set_value(0);
2378 z_keyframe->set_value(1);
2380 mwindow->sync_parameters(CHANGE_PARAMS);
2385 void CWindowCanvas::reset_camera()
2390 void CWindowCanvas::reset_projector()
2395 int CWindowCanvas::test_crop(int button_press, int &redraw)
2398 int handle_selected = -1;
2399 float x1 = mwindow->edl->session->crop_x1;
2400 float y1 = mwindow->edl->session->crop_y1;
2401 float x2 = mwindow->edl->session->crop_x2;
2402 float y2 = mwindow->edl->session->crop_y2;
2403 float cursor_x = get_cursor_x();
2404 float cursor_y = get_cursor_y();
2405 float canvas_x1 = x1;
2406 float canvas_y1 = y1;
2407 float canvas_x2 = x2;
2408 float canvas_y2 = y2;
2409 float canvas_cursor_x = cursor_x;
2410 float canvas_cursor_y = cursor_y;
2412 canvas_to_output(mwindow->edl, 0, cursor_x, cursor_y);
2413 // Use screen normalized coordinates for hot spot tests.
2414 output_to_canvas(mwindow->edl, 0, canvas_x1, canvas_y1);
2415 output_to_canvas(mwindow->edl, 0, canvas_x2, canvas_y2);
2418 if(gui->current_operation == CWINDOW_CROP)
2420 handle_selected = gui->crop_handle;
2423 if(canvas_cursor_x >= canvas_x1 && canvas_cursor_x < canvas_x1 + CROPHANDLE_W &&
2424 canvas_cursor_y >= canvas_y1 && canvas_cursor_y < canvas_y1 + CROPHANDLE_H)
2426 handle_selected = 0;
2427 gui->crop_origin_x = x1;
2428 gui->crop_origin_y = y1;
2431 if(canvas_cursor_x >= canvas_x2 - CROPHANDLE_W && canvas_cursor_x < canvas_x2 &&
2432 canvas_cursor_y >= canvas_y1 && canvas_cursor_y < canvas_y1 + CROPHANDLE_H)
2434 handle_selected = 1;
2435 gui->crop_origin_x = x2;
2436 gui->crop_origin_y = y1;
2439 if(canvas_cursor_x >= canvas_x1 && canvas_cursor_x < canvas_x1 + CROPHANDLE_W &&
2440 canvas_cursor_y >= canvas_y2 - CROPHANDLE_H && canvas_cursor_y < canvas_y2)
2442 handle_selected = 2;
2443 gui->crop_origin_x = x1;
2444 gui->crop_origin_y = y2;
2447 if(canvas_cursor_x >= canvas_x2 - CROPHANDLE_W && canvas_cursor_x < canvas_x2 &&
2448 canvas_cursor_y >= canvas_y2 - CROPHANDLE_H && canvas_cursor_y < canvas_y2)
2450 handle_selected = 3;
2451 gui->crop_origin_x = x2;
2452 gui->crop_origin_y = y2;
2457 gui->crop_origin_x = cursor_x;
2458 gui->crop_origin_y = cursor_y;
2461 // printf("test crop %d %d\n",
2462 // gui->current_operation,
2463 // handle_selected);
2470 gui->crop_translate = 1;
2471 gui->crop_origin_x1 = x1;
2472 gui->crop_origin_y1 = y1;
2473 gui->crop_origin_x2 = x2;
2474 gui->crop_origin_y2 = y2;
2477 gui->crop_translate = 0;
2479 gui->current_operation = CWINDOW_CROP;
2480 gui->crop_handle = handle_selected;
2481 gui->x_origin = cursor_x;
2482 gui->y_origin = cursor_y;
2483 gui->tool_panel->raise_window();
2486 if(handle_selected < 0 && !gui->crop_translate)
2490 mwindow->edl->session->crop_x1 = (int)x1;
2491 mwindow->edl->session->crop_y1 = (int)y1;
2492 mwindow->edl->session->crop_x2 = (int)x2;
2493 mwindow->edl->session->crop_y2 = (int)y2;
2498 // Translate all 4 points
2499 if(gui->current_operation == CWINDOW_CROP && gui->crop_translate)
2501 x1 = cursor_x - gui->x_origin + gui->crop_origin_x1;
2502 y1 = cursor_y - gui->y_origin + gui->crop_origin_y1;
2503 x2 = cursor_x - gui->x_origin + gui->crop_origin_x2;
2504 y2 = cursor_y - gui->y_origin + gui->crop_origin_y2;
2506 mwindow->edl->session->crop_x1 = (int)x1;
2507 mwindow->edl->session->crop_y1 = (int)y1;
2508 mwindow->edl->session->crop_x2 = (int)x2;
2509 mwindow->edl->session->crop_y2 = (int)y2;
2515 if(gui->current_operation == CWINDOW_CROP)
2517 switch(gui->crop_handle)
2520 x1 = gui->crop_origin_x;
2521 y1 = gui->crop_origin_y;
2522 x2 = gui->crop_origin_x;
2523 y2 = gui->crop_origin_y;
2524 if(cursor_x < gui->x_origin)
2526 if(cursor_y < gui->y_origin)
2532 if(cursor_y >= gui->y_origin)
2539 if(cursor_x >= gui->x_origin)
2541 if(cursor_y < gui->y_origin)
2547 if(cursor_y >= gui->y_origin)
2554 // printf("test crop %d %d %d %d\n",
2555 // mwindow->edl->session->crop_x1,
2556 // mwindow->edl->session->crop_y1,
2557 // mwindow->edl->session->crop_x2,
2558 // mwindow->edl->session->crop_y2);
2561 x1 = cursor_x - gui->x_origin + gui->crop_origin_x;
2562 y1 = cursor_y - gui->y_origin + gui->crop_origin_y;
2565 x2 = cursor_x - gui->x_origin + gui->crop_origin_x;
2566 y1 = cursor_y - gui->y_origin + gui->crop_origin_y;
2569 x1 = cursor_x - gui->x_origin + gui->crop_origin_x;
2570 y2 = cursor_y - gui->y_origin + gui->crop_origin_y;
2573 x2 = cursor_x - gui->x_origin + gui->crop_origin_x;
2574 y2 = cursor_y - gui->y_origin + gui->crop_origin_y;
2578 if(!EQUIV(mwindow->edl->session->crop_x1, x1) ||
2579 !EQUIV(mwindow->edl->session->crop_x2, x2) ||
2580 !EQUIV(mwindow->edl->session->crop_y1, y1) ||
2581 !EQUIV(mwindow->edl->session->crop_y2, y2))
2588 switch (gui->crop_handle)
2590 case 0: gui->crop_handle = 1; break;
2591 case 1: gui->crop_handle = 0; break;
2592 case 2: gui->crop_handle = 3; break;
2593 case 3: gui->crop_handle = 2; break;
2603 switch (gui->crop_handle)
2605 case 0: gui->crop_handle = 2; break;
2606 case 1: gui->crop_handle = 3; break;
2607 case 2: gui->crop_handle = 0; break;
2608 case 3: gui->crop_handle = 1; break;
2613 mwindow->edl->session->crop_x1 = (int)x1;
2614 mwindow->edl->session->crop_y1 = (int)y1;
2615 mwindow->edl->session->crop_x2 = (int)x2;
2616 mwindow->edl->session->crop_y2 = (int)y2;
2622 // Update cursor font
2623 if(handle_selected >= 0)
2625 switch(handle_selected)
2628 set_cursor(UPLEFT_RESIZE);
2631 set_cursor(UPRIGHT_RESIZE);
2634 set_cursor(DOWNLEFT_RESIZE);
2637 set_cursor(DOWNRIGHT_RESIZE);
2644 set_cursor(ARROW_CURSOR);
2646 #define CLAMP(x, y, z) ((x) = ((x) < (y) ? (y) : ((x) > (z) ? (z) : (x))))
2650 CLAMP(mwindow->edl->session->crop_x1, 0, mwindow->edl->session->output_w);
2651 CLAMP(mwindow->edl->session->crop_x2, 0, mwindow->edl->session->output_w);
2652 CLAMP(mwindow->edl->session->crop_y1, 0, mwindow->edl->session->output_h);
2653 CLAMP(mwindow->edl->session->crop_y2, 0, mwindow->edl->session->output_h);
2654 // printf("CWindowCanvas::test_crop %d %d %d %d\n",
2655 // mwindow->edl->session->crop_x2,
2656 // mwindow->edl->session->crop_y2,
2657 // mwindow->edl->calculate_output_w(0),
2658 // mwindow->edl->calculate_output_h(0));
2664 void CWindowCanvas::draw_crop()
2666 get_canvas()->set_inverse();
2667 get_canvas()->set_color(WHITE);
2669 float x1 = mwindow->edl->session->crop_x1;
2670 float y1 = mwindow->edl->session->crop_y1;
2671 float x2 = mwindow->edl->session->crop_x2;
2672 float y2 = mwindow->edl->session->crop_y2;
2674 output_to_canvas(mwindow->edl, 0, x1, y1);
2675 output_to_canvas(mwindow->edl, 0, x2, y2);
2677 if(x2 - x1 && y2 - y1)
2678 get_canvas()->draw_rectangle((int)x1,
2683 draw_crophandle((int)x1, (int)y1);
2684 draw_crophandle((int)x2 - CROPHANDLE_W, (int)y1);
2685 draw_crophandle((int)x1, (int)y2 - CROPHANDLE_H);
2686 draw_crophandle((int)x2 - CROPHANDLE_W, (int)y2 - CROPHANDLE_H);
2687 get_canvas()->set_opaque();
2697 void CWindowCanvas::draw_bezier(int do_camera)
2699 Track *track = gui->cwindow->calculate_affected_track();
2706 int64_t position = track->to_units(
2707 mwindow->edl->local_session->get_selectionstart(1),
2710 track->automation->get_projector(¢er_x,
2716 // center_x += track->track_w / 2;
2717 // center_y += track->track_h / 2;
2718 center_x += mwindow->edl->session->output_w / 2;
2719 center_y += mwindow->edl->session->output_h / 2;
2720 float track_x1 = center_x - track->track_w / 2 * center_z;
2721 float track_y1 = center_y - track->track_h / 2 * center_z;
2722 float track_x2 = track_x1 + track->track_w * center_z;
2723 float track_y2 = track_y1 + track->track_h * center_z;
2725 output_to_canvas(mwindow->edl, 0, track_x1, track_y1);
2726 output_to_canvas(mwindow->edl, 0, track_x2, track_y2);
2728 #define DRAW_PROJECTION(offset) \
2729 get_canvas()->draw_rectangle((int)track_x1 + offset, \
2730 (int)track_y1 + offset, \
2731 (int)(track_x2 - track_x1), \
2732 (int)(track_y2 - track_y1)); \
2733 get_canvas()->draw_line((int)track_x1 + offset, \
2734 (int)track_y1 + offset, \
2735 (int)track_x2 + offset, \
2736 (int)track_y2 + offset); \
2737 get_canvas()->draw_line((int)track_x2 + offset, \
2738 (int)track_y1 + offset, \
2739 (int)track_x1 + offset, \
2740 (int)track_y2 + offset); \
2744 get_canvas()->set_color(BLACK);
2747 // canvas->set_inverse();
2749 get_canvas()->set_color(GREEN);
2751 get_canvas()->set_color(RED);
2754 // canvas->set_opaque();
2758 int CWindowCanvas::test_bezier(int button_press,
2766 // Processing drag operation.
2767 // Create keyframe during first cursor motion.
2771 float cursor_x = get_cursor_x();
2772 float cursor_y = get_cursor_y();
2773 canvas_to_output(mwindow->edl, 0, cursor_x, cursor_y);
2775 if(gui->current_operation == CWINDOW_CAMERA ||
2776 gui->current_operation == CWINDOW_PROJECTOR)
2778 if(!gui->ctrl_down() && gui->shift_down() && !gui->translating_zoom)
2780 gui->translating_zoom = 1;
2781 gui->reset_affected();
2784 if(!gui->ctrl_down() && !gui->shift_down() && gui->translating_zoom)
2786 gui->translating_zoom = 0;
2787 gui->reset_affected();
2790 // Get target keyframe
2791 float last_center_x;
2792 float last_center_y;
2793 float last_center_z;
2796 if(!gui->affected_x && !gui->affected_y && !gui->affected_z)
2798 FloatAutos *affected_x_autos;
2799 FloatAutos *affected_y_autos;
2800 FloatAutos *affected_z_autos;
2801 if(!gui->affected_track) return 0;
2802 double position = mwindow->edl->local_session->get_selectionstart(1);
2803 int64_t track_position = gui->affected_track->to_units(position, 0);
2805 if(mwindow->edl->session->cwindow_operation == CWINDOW_CAMERA)
2807 affected_x_autos = (FloatAutos*)gui->affected_track->automation->autos[AUTOMATION_CAMERA_X];
2808 affected_y_autos = (FloatAutos*)gui->affected_track->automation->autos[AUTOMATION_CAMERA_Y];
2809 affected_z_autos = (FloatAutos*)gui->affected_track->automation->autos[AUTOMATION_CAMERA_Z];
2813 affected_x_autos = (FloatAutos*)gui->affected_track->automation->autos[AUTOMATION_PROJECTOR_X];
2814 affected_y_autos = (FloatAutos*)gui->affected_track->automation->autos[AUTOMATION_PROJECTOR_Y];
2815 affected_z_autos = (FloatAutos*)gui->affected_track->automation->autos[AUTOMATION_PROJECTOR_Z];
2819 if(gui->translating_zoom)
2821 FloatAuto *previous = 0;
2822 FloatAuto *next = 0;
2823 float new_z = affected_z_autos->get_value(
2829 (FloatAuto*)gui->cwindow->calculate_affected_auto(
2830 affected_z_autos, 1, &created, 0);
2832 gui->affected_z->set_value(new_z);
2838 FloatAuto *previous = 0;
2839 FloatAuto *next = 0;
2840 float new_x = affected_x_autos->get_value(
2847 float new_y = affected_y_autos->get_value(
2853 (FloatAuto*)gui->cwindow->calculate_affected_auto(
2854 affected_x_autos, 1, &created, 0);
2856 gui->affected_x->set_value(new_x);
2860 (FloatAuto*)gui->cwindow->calculate_affected_auto(
2861 affected_y_autos, 1, &created, 0);
2863 gui->affected_y->set_value(new_y);
2870 if(gui->translating_zoom)
2872 gui->center_z = gui->affected_z->get_value();
2876 gui->center_x = gui->affected_x->get_value();
2877 gui->center_y = gui->affected_y->get_value();
2884 if(gui->translating_zoom)
2886 last_center_z = gui->affected_z->get_value();
2887 float z = gui->center_z + (cursor_y - gui->y_origin) / 128;
2889 if(!EQUIV(last_center_z, z))
2895 gui->affected_z->set_value(z);
2899 last_center_x = gui->affected_x->get_value();
2900 last_center_y = gui->affected_y->get_value();
2901 float x = gui->center_x + cursor_x - gui->x_origin;
2902 float y = gui->center_y + cursor_y - gui->y_origin;
2903 gui->affected_x->set_value(x);
2904 gui->affected_y->set_value(y);
2905 if( !EQUIV(last_center_x, x) || !EQUIV(last_center_y, y) )
2911 gui->affected_x->set_value(x);
2912 gui->affected_y->set_value(y);
2919 // Begin drag operation. Don't create keyframe here.
2921 // Get affected track off of the first recordable video track.
2922 // Calculating based on the alpha channel would require recording what layer
2923 // each output pixel belongs to as they're rendered and stacked. Forget it.
2924 gui->affected_track = gui->cwindow->calculate_affected_track();
2925 gui->reset_affected();
2927 if(gui->affected_track)
2929 if(gui->current_operation == CWINDOW_CAMERA)
2930 mwindow->undo->update_undo_before(_("camera"), this);
2932 mwindow->undo->update_undo_before(_("projector"), this);
2934 gui->current_operation =
2935 mwindow->edl->session->cwindow_operation;
2936 gui->tool_panel->raise_window();
2945 int CWindowCanvas::test_zoom(int &redraw)
2951 if( mwindow->edl->session->cwindow_scrollbars ) {
2952 if( *gui->zoom_panel->get_text() != 'x' ) {
2953 // Find current zoom in table
2954 int idx = total_zooms; float old_zoom = get_zoom();
2955 while( --idx >= 0 && !EQUIV(my_zoom_table[idx], old_zoom) );
2957 idx += get_buttonpress() == 5 ||
2958 gui->ctrl_down() || gui->shift_down() ? -1 : +1 ;
2959 CLAMP(idx, 0, total_zooms-1);
2960 zoom = my_zoom_table[idx];
2963 x = get_cursor_x(); y = get_cursor_y();
2965 mwindow->edl->session->cwindow_scrollbars = 0;
2966 gui->zoom_panel->update(0);
2967 zoom = gui->get_auto_zoom();
2970 gui->zoom_panel->ZoomPanel::update(zoom);
2971 float output_x = x, output_y = y;
2972 canvas_to_output(mwindow->edl, 0, output_x, output_y);
2973 x = output_x - x / zoom;
2974 y = output_y - y / zoom;
2978 mwindow->edl->session->cwindow_scrollbars = 1;
2979 x = (mwindow->edl->session->output_w - w) / 2;
2980 y = (mwindow->edl->session->output_h - h) / 2;
2983 update_zoom((int)x, (int)y, zoom);
2985 gui->composite_panel->cpanel_zoom->update(zoom);
2987 reposition_window(mwindow->edl,
2988 mwindow->theme->ccanvas_x, mwindow->theme->ccanvas_y,
2989 mwindow->theme->ccanvas_w, mwindow->theme->ccanvas_h);
2990 redraw = 1; result = 1;
2996 void CWindowCanvas::calculate_origin()
2998 gui->x_origin = get_cursor_x();
2999 gui->y_origin = get_cursor_y();
3000 //printf("CWindowCanvas::calculate_origin 1 %f %f\n", gui->x_origin, gui->y_origin);
3001 canvas_to_output(mwindow->edl, 0, gui->x_origin, gui->y_origin);
3002 //printf("CWindowCanvas::calculate_origin 2 %f %f\n", gui->x_origin, gui->y_origin);
3006 int CWindowCanvas::cursor_leave_event()
3008 set_cursor(ARROW_CURSOR);
3012 int CWindowCanvas::cursor_enter_event()
3015 switch(mwindow->edl->session->cwindow_operation)
3017 case CWINDOW_CAMERA:
3018 case CWINDOW_PROJECTOR:
3019 set_cursor(MOVE_CURSOR);
3022 set_cursor(MOVE_CURSOR);
3025 test_crop(0, redraw);
3027 case CWINDOW_PROTECT:
3028 set_cursor(ARROW_CURSOR);
3032 set_cursor(CROSS_CURSOR);
3034 case CWINDOW_EYEDROP:
3035 set_cursor(CROSS_CURSOR);
3041 int CWindowCanvas::cursor_motion_event()
3043 int redraw = 0, result = 0, rerender = 0, redraw_canvas = 0;
3046 //printf("CWindowCanvas::cursor_motion_event %d current_operation=%d\n", __LINE__, gui->current_operation);
3047 switch(gui->current_operation)
3049 case CWINDOW_SCROLL:
3051 float zoom = get_zoom();
3052 float cursor_x = get_cursor_x();
3053 float cursor_y = get_cursor_y();
3055 float zoom_x, zoom_y, conformed_w, conformed_h;
3056 get_zooms(mwindow->edl, 0, zoom_x, zoom_y, conformed_w, conformed_h);
3057 cursor_x = (float)cursor_x / zoom_x + gui->x_offset;
3058 cursor_y = (float)cursor_y / zoom_y + gui->y_offset;
3062 int x = (int)(gui->x_origin - cursor_x + gui->x_offset);
3063 int y = (int)(gui->y_origin - cursor_y + gui->y_offset);
3068 update_scrollbars(0);
3075 result = do_ruler(0, 1, 0, 0);
3078 case CWINDOW_CAMERA:
3079 result = test_bezier(0, redraw, redraw_canvas, rerender, 1);
3082 case CWINDOW_PROJECTOR:
3083 result = test_bezier(0, redraw, redraw_canvas, rerender, 0);
3088 result = test_crop(0, redraw);
3089 // printf("CWindowCanvas::cursor_motion_event %d result=%d redraw=%d\n",
3096 case CWINDOW_MASK_CONTROL_IN:
3097 case CWINDOW_MASK_CONTROL_OUT:
3098 case CWINDOW_MASK_TRANSLATE:
3100 result = do_mask(redraw,
3107 case CWINDOW_EYEDROP:
3108 result = do_eyedrop(rerender, 0, 0);
3117 // cursor font changes
3120 // printf("CWindowCanvas::cursor_motion_event %d cwindow_operation=%d\n",
3122 // mwindow->edl->session->cwindow_operation);
3123 switch(mwindow->edl->session->cwindow_operation)
3126 result = test_crop(0, redraw);
3129 result = do_ruler(0, 1, 0, 0);
3132 result = do_mask(redraw,
3142 // If the window is never unlocked before calling send_command the
3143 // display shouldn't get stuck on the old video frame although it will
3144 // flicker between the old video frame and the new video frame.
3154 gui->unlock_window();
3157 mwindow->gui->lock_window("CWindowCanvas::cursor_motion_event 1");
3158 mwindow->gui->draw_overlays(1);
3159 mwindow->gui->unlock_window();
3161 gui->lock_window("CWindowCanvas::cursor_motion_event 1");
3166 gui->unlock_window();
3167 mwindow->restart_brender();
3168 mwindow->sync_parameters(CHANGE_PARAMS);
3169 gui->cwindow->playback_engine->que->send_command(CURRENT_FRAME,
3173 if(!redraw) gui->update_tool();
3174 gui->lock_window("CWindowCanvas::cursor_motion_event 2");
3179 int CWindowCanvas::button_press_event()
3183 int redraw_canvas = 0;
3186 if(Canvas::button_press_event()) return 1;
3188 gui->translating_zoom = gui->shift_down();
3191 //printf("CWindowCanvas::button_press_event 2 %f %f\n", gui->x_origin, gui->y_origin, gui->x_origin, gui->y_origin);
3193 float zoom_x, zoom_y, conformed_w, conformed_h;
3194 get_zooms(mwindow->edl, 0, zoom_x, zoom_y, conformed_w, conformed_h);
3195 gui->x_offset = get_x_offset(mwindow->edl, 0, zoom_x, conformed_w, conformed_h);
3196 gui->y_offset = get_y_offset(mwindow->edl, 0, zoom_y, conformed_w, conformed_h);
3199 if(get_buttonpress() == 2)
3201 gui->current_operation = CWINDOW_SCROLL;
3207 switch(mwindow->edl->session->cwindow_operation)
3210 result = do_ruler(0, 0, 1, 0);
3213 case CWINDOW_CAMERA:
3214 result = test_bezier(1, redraw, redraw_canvas, rerender, 1);
3217 case CWINDOW_PROJECTOR:
3218 result = test_bezier(1, redraw, redraw_canvas, rerender, 0);
3222 result = test_zoom(redraw);
3226 result = test_crop(1, redraw);
3230 if(get_buttonpress() == 1)
3231 result = do_mask(redraw, rerender, 1, 0, 0);
3234 case CWINDOW_EYEDROP:
3235 result = do_eyedrop(rerender, 1, 0);
3243 gui->unlock_window();
3246 mwindow->gui->lock_window("CWindowCanvas::button_press_event 1");
3247 mwindow->gui->draw_overlays(1);
3248 mwindow->gui->unlock_window();
3251 gui->lock_window("CWindowCanvas::button_press_event 1");
3254 // rerendering can also be caused by press event
3257 gui->unlock_window();
3259 mwindow->restart_brender();
3260 mwindow->sync_parameters(CHANGE_PARAMS);
3261 gui->cwindow->playback_engine->que->send_command(CURRENT_FRAME,
3265 if(!redraw) gui->update_tool();
3266 gui->lock_window("CWindowCanvas::button_press_event 2");
3271 int CWindowCanvas::button_release_event()
3275 switch(gui->current_operation)
3277 case CWINDOW_SCROLL:
3282 do_ruler(0, 0, 0, 1);
3285 case CWINDOW_CAMERA:
3286 mwindow->undo->update_undo_after(_("camera"), LOAD_AUTOMATION);
3289 case CWINDOW_PROJECTOR:
3290 mwindow->undo->update_undo_after(_("projector"), LOAD_AUTOMATION);
3294 case CWINDOW_MASK_CONTROL_IN:
3295 case CWINDOW_MASK_CONTROL_OUT:
3296 case CWINDOW_MASK_TRANSLATE:
3297 // Finish mask operation
3298 gui->mask_keyframe = 0;
3299 mwindow->undo->update_undo_after(_("mask"), LOAD_AUTOMATION);
3302 result = Canvas::button_release_event();
3306 gui->current_operation = CWINDOW_NONE;
3310 void CWindowCanvas::zoom_resize_window(float percentage)
3312 int canvas_w, canvas_h;
3316 // Get required canvas size
3317 calculate_sizes(mwindow->edl->get_aspect_ratio(),
3318 mwindow->edl->session->output_w,
3319 mwindow->edl->session->output_h,
3324 // Estimate window size from current borders
3325 new_w = canvas_w + (gui->get_w() - mwindow->theme->ccanvas_w);
3326 new_h = canvas_h + (gui->get_h() - mwindow->theme->ccanvas_h);
3328 //printf("CWindowCanvas::zoom_resize_window %d %d %d\n", __LINE__, new_w, new_h);
3329 mwindow->session->cwindow_w = new_w;
3330 mwindow->session->cwindow_h = new_h;
3332 mwindow->theme->get_cwindow_sizes(gui,
3333 mwindow->session->cwindow_controls);
3335 // Estimate again from new borders
3336 new_w = canvas_w + (mwindow->session->cwindow_w - mwindow->theme->ccanvas_w);
3337 new_h = canvas_h + (mwindow->session->cwindow_h - mwindow->theme->ccanvas_h);
3338 //printf("CWindowCanvas::zoom_resize_window %d %d %d\n", __LINE__, new_w, new_h);
3340 gui->resize_window(new_w, new_h);
3341 gui->resize_event(new_w, new_h);
3344 void CWindowCanvas::toggle_controls()
3346 mwindow->session->cwindow_controls = !mwindow->session->cwindow_controls;
3347 gui->resize_event(gui->get_w(), gui->get_h());
3350 int CWindowCanvas::get_cwindow_controls()
3352 return mwindow->session->cwindow_controls;