build tweaks for fc30, glFinish fix
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / canvas.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008-2017 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include "bcsignals.h"
23 #include "canvas.h"
24 #include "clip.h"
25 #include "edl.h"
26 #include "edlsession.h"
27 #include "keys.h"
28 #include "language.h"
29 #include "mainsession.h"
30 #include "mwindowgui.h"
31 #include "mutex.h"
32 #include "mwindow.h"
33 #include "playback3d.h"
34 #include "videodevice.h"
35 #include "vframe.h"
36
37
38
39 Canvas::Canvas(MWindow *mwindow,
40         BC_WindowBase *subwindow,
41         int x,
42         int y,
43         int w,
44         int h,
45         int output_w,
46         int output_h,
47         int use_scrollbars)
48 {
49         reset();
50
51         if(w < 10) w = 10;
52         if(h < 10) h = 10;
53         this->mwindow = mwindow;
54         this->subwindow = subwindow;
55         this->x = x;
56         this->y = y;
57         this->w = w;
58         this->h = h;
59         this->output_w = output_w;
60         this->output_h = output_h;
61         this->use_scrollbars = use_scrollbars;
62         this->canvas_auxwindow = 0;
63         this->scr_w0 = subwindow->get_screen_w(0, 0);
64         this->root_w = subwindow->get_root_w(0);
65         this->root_h = subwindow->get_root_h(0);
66         canvas_lock = new Mutex("Canvas::canvas_lock", 1);
67 }
68
69 Canvas::~Canvas()
70 {
71         if(refresh_frame) delete refresh_frame;
72         delete canvas_menu;
73         if(yscroll) delete yscroll;
74         if(xscroll) delete xscroll;
75         delete canvas_subwindow;
76         delete canvas_fullscreen;
77         delete canvas_lock;
78 }
79
80 void Canvas::reset()
81 {
82         use_scrollbars = 0;
83         output_w = 0;
84         output_h = 0;
85         xscroll = 0;
86         yscroll = 0;
87         refresh_frame = 0;
88         canvas_subwindow = 0;
89         canvas_fullscreen = 0;
90         is_processing = 0;
91         is_fullscreen = 0;
92         cursor_inside = 0;
93 }
94
95 void Canvas::lock_canvas(const char *location)
96 {
97         canvas_lock->lock(location);
98 }
99
100 void Canvas::unlock_canvas()
101 {
102         canvas_lock->unlock();
103 }
104
105 int Canvas::is_locked()
106 {
107         return canvas_lock->is_locked();
108 }
109
110
111 BC_WindowBase* Canvas::get_canvas()
112 {
113         if(get_fullscreen() && canvas_fullscreen)
114                 return canvas_fullscreen;
115         return canvas_auxwindow ? canvas_auxwindow : canvas_subwindow;
116 }
117
118 void Canvas::use_auxwindow(BC_WindowBase *aux)
119 {
120         canvas_auxwindow = aux;
121 }
122
123 void Canvas::use_cwindow()
124 {
125         canvas_menu->use_cwindow();
126         fullscreen_menu->use_cwindow();
127 }
128
129 void Canvas::use_rwindow()
130 {
131         canvas_menu->use_rwindow();
132 }
133
134 void Canvas::use_vwindow()
135 {
136         canvas_menu->use_vwindow();
137 }
138
139 int Canvas::get_fullscreen()
140 {
141         return is_fullscreen;
142 }
143
144 void Canvas::set_fullscreen(int value)
145 {
146         is_fullscreen = value;
147 }
148
149 // Get dimensions given a zoom
150 void Canvas::calculate_sizes(float aspect_ratio,
151         int output_w,
152         int output_h,
153         float zoom,
154         int &w,
155         int &h)
156 {
157 // Horizontal stretch
158         if((float)output_w / output_h <= aspect_ratio)
159         {
160                 w = (int)((float)output_h * aspect_ratio * zoom);
161                 h = (int)((float)output_h * zoom);
162         }
163         else
164 // Vertical stretch
165         {
166                 h = (int)((float)output_w / aspect_ratio * zoom);
167                 w = (int)((float)output_w * zoom);
168         }
169 }
170
171 float Canvas::get_x_offset(EDL *edl,
172         int single_channel,
173         float zoom_x,
174         float conformed_w,
175         float conformed_h)
176 {
177         if(use_scrollbars)
178         {
179                 if(xscroll)
180                 {
181 // If the projection is smaller than the canvas, this forces it in the center.
182 //                      if(conformed_w < w_visible)
183 //                              return -(float)(w_visible - conformed_w) / 2;
184
185                         return (float)get_xscroll();
186                 }
187                 else
188                         return ((float)-get_canvas()->get_w() / zoom_x +
189                                 edl->session->output_w) / 2;
190         }
191         else
192         {
193                 int out_w, out_h;
194                 int canvas_w = get_canvas()->get_w();
195                 int canvas_h = get_canvas()->get_h();
196                 out_w = canvas_w;
197                 out_h = canvas_h;
198
199                 if((float)out_w / out_h > conformed_w / conformed_h)
200                 {
201                         out_w = (int)(out_h * conformed_w / conformed_h + 0.5);
202                 }
203
204                 if(out_w < canvas_w)
205                         return -(canvas_w - out_w) / 2 / zoom_x;
206         }
207
208         return 0;
209 }
210
211 float Canvas::get_y_offset(EDL *edl,
212         int single_channel,
213         float zoom_y,
214         float conformed_w,
215         float conformed_h)
216 {
217         if(use_scrollbars)
218         {
219                 if(yscroll)
220                 {
221 // If the projection is smaller than the canvas, this forces it in the center.
222 //                      if(conformed_h < h_visible)
223 //                              return -(float)(h_visible - conformed_h) / 2;
224
225                         return (float)get_yscroll();
226                 }
227                 else
228                         return ((float)-get_canvas()->get_h() / zoom_y +
229                                 edl->session->output_h) / 2;
230         }
231         else
232         {
233                 int out_w, out_h;
234                 int canvas_w = get_canvas()->get_w();
235                 int canvas_h = get_canvas()->get_h();
236                 out_w = canvas_w;
237                 out_h = canvas_h;
238
239                 if((float)out_w / out_h <= conformed_w / conformed_h)
240                 {
241                         out_h = (int)((float)out_w / (conformed_w / conformed_h) + 0.5);
242                 }
243
244 //printf("Canvas::get_y_offset 1 %d %d %f\n", out_h, canvas_h, -((float)canvas_h - out_h) / 2);
245                 if(out_h < canvas_h)
246                         return -((float)canvas_h - out_h) / 2 / zoom_y;
247         }
248
249         return 0;
250 }
251
252 // This may not be used anymore
253 void Canvas::check_boundaries(EDL *edl, int &x, int &y, float &zoom)
254 {
255         if(x + w_visible > w_needed) x = w_needed - w_visible;
256         if(y + h_visible > h_needed) y = h_needed - h_visible;
257
258         if(x < 0) x = 0;
259         if(y < 0) y = 0;
260 }
261
262 void Canvas::update_scrollbars(int flush)
263 {
264         if(use_scrollbars)
265         {
266                 if(xscroll) xscroll->update_length(w_needed, get_xscroll(), w_visible, flush);
267                 if(yscroll) yscroll->update_length(h_needed, get_yscroll(), h_visible, flush);
268         }
269 }
270
271 void Canvas::get_zooms(EDL *edl,
272         int single_channel,
273         float &zoom_x,
274         float &zoom_y,
275         float &conformed_w,
276         float &conformed_h)
277 {
278         edl->calculate_conformed_dimensions(single_channel,
279                 conformed_w,
280                 conformed_h);
281
282         if(use_scrollbars)
283         {
284                 zoom_x = get_zoom() *
285                         conformed_w /
286                         edl->session->output_w;
287                 zoom_y = get_zoom() *
288                         conformed_h /
289                         edl->session->output_h;
290         }
291         else
292         {
293                 int out_w, out_h;
294                 int canvas_w = get_canvas()->get_w();
295                 int canvas_h = get_canvas()->get_h();
296
297                 out_w = canvas_w;
298                 out_h = canvas_h;
299
300                 if((float)out_w / out_h > conformed_w / conformed_h)
301                 {
302                         out_w = (int)((float)out_h * conformed_w / conformed_h + 0.5);
303                 }
304                 else
305                 {
306                         out_h = (int)((float)out_w / (conformed_w / conformed_h) + 0.5);
307                 }
308
309                 zoom_x = (float)out_w / edl->session->output_w;
310                 zoom_y = (float)out_h / edl->session->output_h;
311 //printf("get zooms 2 %d %d %f %f\n", canvas_w, canvas_h, conformed_w, conformed_h);
312         }
313 }
314
315 // Convert a coordinate on the canvas to a coordinate on the output
316 void Canvas::canvas_to_output(EDL *edl, int single_channel, float &x, float &y)
317 {
318         float zoom_x, zoom_y, conformed_w, conformed_h;
319         get_zooms(edl, single_channel, zoom_x, zoom_y, conformed_w, conformed_h);
320
321 //printf("Canvas::canvas_to_output y=%f zoom_y=%f y_offset=%f\n",
322 //      y, zoom_y, get_y_offset(edl, single_channel, zoom_y, conformed_w, conformed_h));
323
324         x = (float)x / zoom_x + get_x_offset(edl, single_channel, zoom_x, conformed_w, conformed_h);
325         y = (float)y / zoom_y + get_y_offset(edl, single_channel, zoom_y, conformed_w, conformed_h);
326 }
327
328 void Canvas::output_to_canvas(EDL *edl, int single_channel, float &x, float &y)
329 {
330         float zoom_x, zoom_y, conformed_w, conformed_h;
331         get_zooms(edl, single_channel, zoom_x, zoom_y, conformed_w, conformed_h);
332
333 //printf("Canvas::output_to_canvas x=%f zoom_x=%f x_offset=%f\n", x, zoom_x, get_x_offset(edl, single_channel, zoom_x, conformed_w));
334
335         x = (float)zoom_x * (x - get_x_offset(edl, single_channel, zoom_x, conformed_w, conformed_h));
336         y = (float)zoom_y * (y - get_y_offset(edl, single_channel, zoom_y, conformed_w, conformed_h));
337 }
338
339
340
341 void Canvas::get_transfers(EDL *edl,
342         float &output_x1, float &output_y1, float &output_x2, float &output_y2,
343         float &canvas_x1, float &canvas_y1, float &canvas_x2, float &canvas_y2,
344         int canvas_w, int canvas_h)
345 {
346 //printf("Canvas::get_transfers %d canvas_w=%d canvas_h=%d\n", 
347 // __LINE__,  canvas_w, canvas_h);
348 // automatic canvas size detection
349         if(canvas_w < 0) canvas_w = get_canvas()->get_w();
350         if(canvas_h < 0) canvas_h = get_canvas()->get_h();
351
352 // Canvas is zoomed to a portion of the output frame
353         if(use_scrollbars)
354         {
355                 float in_x1, in_y1, in_x2, in_y2;
356                 float out_x1, out_y1, out_x2, out_y2;
357                 float zoom_x, zoom_y, conformed_w, conformed_h;
358
359                 get_zooms(edl, 0, zoom_x, zoom_y, conformed_w, conformed_h);
360                 out_x1 = 0;
361                 out_y1 = 0;
362                 out_x2 = canvas_w;
363                 out_y2 = canvas_h;
364                 in_x1 = 0;
365                 in_y1 = 0;
366                 in_x2 = canvas_w;
367                 in_y2 = canvas_h;
368
369                 canvas_to_output(edl, 0, in_x1, in_y1);
370                 canvas_to_output(edl, 0, in_x2, in_y2);
371
372 //printf("Canvas::get_transfers 1 %.0f %.0f %.0f %.0f -> %.0f %.0f %.0f %.0f\n",
373 //in_x1, in_y1, in_x2, in_y2, out_x1, out_y1, out_x2, out_y2);
374
375                 if(in_x1 < 0)
376                 {
377                         out_x1 += -in_x1 * zoom_x;
378                         in_x1 = 0;
379                 }
380
381                 if(in_y1 < 0)
382                 {
383                         out_y1 += -in_y1 * zoom_y;
384                         in_y1 = 0;
385                 }
386
387                 int output_w = get_output_w(edl);
388                 int output_h = get_output_h(edl);
389
390                 if(in_x2 > output_w)
391                 {
392                         out_x2 -= (in_x2 - output_w) * zoom_x;
393                         in_x2 = output_w;
394                 }
395
396                 if(in_y2 > output_h)
397                 {
398                         out_y2 -= (in_y2 - output_h) * zoom_y;
399                         in_y2 = output_h;
400                 }
401 // printf("Canvas::get_transfers 2 %.0f %.0f %.0f %.0f -> %.0f %.0f %.0f %.0f\n",
402 //                      in_x1, in_y1, in_x2, in_y2, out_x1, out_y1, out_x2, out_y2);
403
404                 output_x1 = in_x1;
405                 output_y1 = in_y1;
406                 output_x2 = in_x2;
407                 output_y2 = in_y2;
408                 canvas_x1 = out_x1;
409                 canvas_y1 = out_y1;
410                 canvas_x2 = out_x2;
411                 canvas_y2 = out_y2;
412
413 // Center on canvas
414 //              if(!scrollbars_exist())
415 //              {
416 //                      out_x = canvas_w / 2 - out_w / 2;
417 //                      out_y = canvas_h / 2 - out_h / 2;
418 //              }
419
420         }
421         else
422 // The output frame is normalized to the canvas
423         {
424 // Default canvas coords fill the entire canvas
425                 canvas_x1 = 0;
426                 canvas_y1 = 0;
427                 canvas_x2 = canvas_w;
428                 canvas_y2 = canvas_h;
429
430                 if(edl)
431                 {
432 // Use EDL aspect ratio to shrink one of the canvas dimensions
433                         float out_w = canvas_x2 - canvas_x1;
434                         float out_h = canvas_y2 - canvas_y1;
435                         if(out_w / out_h > edl->get_aspect_ratio())
436                         {
437                                 out_w = (int)(out_h * edl->get_aspect_ratio() + 0.5);
438                                 canvas_x1 = canvas_w / 2 - out_w / 2;
439                         }
440                         else
441                         {
442                                 out_h = (int)(out_w / edl->get_aspect_ratio() + 0.5);
443                                 canvas_y1 = canvas_h / 2 - out_h / 2;
444 // printf("Canvas::get_transfers %d canvas_h=%d out_h=%f canvas_y1=%f\n",
445 // __LINE__,
446 // canvas_h,
447 // out_h,
448 // canvas_y1);
449                         }
450                         canvas_x2 = canvas_x1 + out_w;
451                         canvas_y2 = canvas_y1 + out_h;
452
453 // Get output frame coords from EDL
454                         output_x1 = 0;
455                         output_y1 = 0;
456                         output_x2 = get_output_w(edl);
457                         output_y2 = get_output_h(edl);
458                 }
459                 else
460 // No EDL to get aspect ratio or output frame coords from
461                 {
462                         output_x1 = 0;
463                         output_y1 = 0;
464                         output_x2 = this->output_w;
465                         output_y2 = this->output_h;
466                 }
467         }
468
469 // Clamp to minimum value
470         output_x1 = MAX(0, output_x1);
471         output_y1 = MAX(0, output_y1);
472         output_x2 = MAX(output_x1, output_x2);
473         output_y2 = MAX(output_y1, output_y2);
474         canvas_x1 = MAX(0, canvas_x1);
475         canvas_y1 = MAX(0, canvas_y1);
476         canvas_x2 = MAX(canvas_x1, canvas_x2);
477         canvas_y2 = MAX(canvas_y1, canvas_y2);
478 // printf("Canvas::get_transfers %d %f,%f %f,%f -> %f,%f %f,%f\n",
479 // __LINE__,
480 // output_x1,
481 // output_y1,
482 // output_x2,
483 // output_y2,
484 // canvas_x1,
485 // canvas_y1,
486 // canvas_x2,
487 // canvas_y2);
488 }
489
490 int Canvas::scrollbars_exist()
491 {
492         return(use_scrollbars && (xscroll || yscroll));
493 }
494
495 int Canvas::get_output_w(EDL *edl)
496 {
497         return !edl ? 0 : edl->session->output_w;
498 }
499
500 int Canvas::get_output_h(EDL *edl)
501 {
502         return !edl ? 0 : edl->session->output_h;
503 }
504
505
506
507 void Canvas::get_scrollbars(EDL *edl,
508         int &canvas_x,
509         int &canvas_y,
510         int &canvas_w,
511         int &canvas_h)
512 {
513         int need_xscroll = 0;
514         int need_yscroll = 0;
515 //      int done = 0;
516         float zoom_x, zoom_y, conformed_w, conformed_h;
517
518         if(edl)
519         {
520                 w_needed = edl->session->output_w;
521                 h_needed = edl->session->output_h;
522                 w_visible = w_needed;
523                 h_visible = h_needed;
524         }
525 //printf("Canvas::get_scrollbars 1 %d %d\n", get_xscroll(), get_yscroll());
526
527         if( use_scrollbars ) {
528                 w_needed = edl->session->output_w;
529                 h_needed = edl->session->output_h;
530                 get_zooms(edl, 0, zoom_x, zoom_y, conformed_w, conformed_h);
531 //printf("Canvas::get_scrollbars 2 %d %d\n", get_xscroll(), get_yscroll());
532
533                 w_visible = (int)(canvas_w / zoom_x);
534                 h_visible = (int)(canvas_h / zoom_y);
535                 if( w_needed > w_visible ) {
536                         need_xscroll = 1;
537                         canvas_h -= BC_ScrollBar::get_span(SCROLL_HORIZ);
538                 }
539
540                 if( h_needed > h_visible ) {
541                         need_yscroll = 1;
542                         canvas_w -= BC_ScrollBar::get_span(SCROLL_VERT);
543                 }
544 //printf("Canvas::get_scrollbars %d %d %d %d %d %d\n", canvas_w, canvas_h, w_needed, h_needed, w_visible, h_visible);
545 //printf("Canvas::get_scrollbars 3 %d %d\n", get_xscroll(), get_yscroll());
546
547                 w_visible = (int)(canvas_w / zoom_x);
548                 h_visible = (int)(canvas_h / zoom_y);
549         }
550
551         if( need_xscroll ) {
552                 if( !xscroll ) {
553                         xscroll = new CanvasXScroll(edl, this, canvas_x, canvas_y + canvas_h,
554                                         w_needed, get_xscroll(), w_visible, canvas_w);
555                         subwindow->add_subwindow(xscroll);
556                         xscroll->show_window(0);
557                 }
558                 else
559                         xscroll->reposition_window(canvas_x, canvas_y + canvas_h, canvas_w);
560
561                 if( xscroll->get_length() != w_needed ||
562                     xscroll->get_handlelength() != w_visible )
563                         xscroll->update_length(w_needed, get_xscroll(), w_visible, 0);
564         }
565         else if( xscroll ) {
566                 delete xscroll;  xscroll = 0;
567         }
568 //printf("Canvas::get_scrollbars 4 %d %d\n", get_xscroll(), get_yscroll());
569
570         if( need_yscroll ) {
571                 if( !yscroll ) {
572                         yscroll = new CanvasYScroll(edl, this, canvas_x + canvas_w, canvas_y,
573                                         h_needed, get_yscroll(), h_visible, canvas_h);
574                         subwindow->add_subwindow(yscroll);
575                         yscroll->show_window(0);
576                 }
577                 else
578                         yscroll->reposition_window(canvas_x + canvas_w, canvas_y, canvas_h);
579
580                 if( yscroll->get_length() != edl->session->output_h ||
581                     yscroll->get_handlelength() != h_visible )
582                         yscroll->update_length(h_needed, get_yscroll(), h_visible, 0);
583         }
584         else if( yscroll ) {
585                 delete yscroll;  yscroll = 0;
586         }
587 //printf("Canvas::get_scrollbars 5 %d %d\n", get_xscroll(), get_yscroll());
588 }
589
590
591 void Canvas::update_geometry(EDL *edl, int x, int y, int w, int h)
592 {
593         int redraw = 0;
594         if( this->x != x || this->y != y ||
595             this->w != w || this->h != h ) redraw = 1;
596         if( !redraw ) {
597                 int vx = x, vy = y, vw = w, vh = h;
598                 get_scrollbars(edl, vx, vy, vw, vh);
599                 if( vx != view_x || vy != view_y ||
600                     vw != view_w || vh != view_h ) redraw = 1;
601         }
602         if( !redraw ) return;
603         reposition_window(edl, x, y, w, h);
604 }
605
606 void Canvas::reposition_window(EDL *edl, int x, int y, int w, int h)
607 {
608         this->x = view_x = x;  this->y = view_y = y;
609         this->w = view_w = w;  this->h = view_h = h;
610 //printf("Canvas::reposition_window 1\n");
611         get_scrollbars(edl, view_x, view_y, view_w, view_h);
612 //printf("Canvas::reposition_window %d %d %d %d\n", view_x, view_y, view_w, view_h);
613         if(canvas_subwindow)
614         {
615                 canvas_subwindow->reposition_window(view_x, view_y, view_w, view_h);
616
617 // Need to clear out the garbage in the back
618                 if(canvas_subwindow->get_video_on())
619                 {
620                         canvas_subwindow->set_color(BLACK);
621                         canvas_subwindow->draw_box(0, 0,
622                                 get_canvas()->get_w(), get_canvas()->get_h());
623                         canvas_subwindow->flash(0);
624                 }
625         }
626         draw_refresh(0);
627 }
628
629 void Canvas::set_cursor(int cursor)
630 {
631         get_canvas()->set_cursor(cursor, 0, 1);
632 }
633
634 int Canvas::get_cursor_x()
635 {
636         return get_canvas()->get_cursor_x();
637 }
638
639 int Canvas::get_cursor_y()
640 {
641         return get_canvas()->get_cursor_y();
642 }
643
644 int Canvas::get_buttonpress()
645 {
646         return get_canvas()->get_buttonpress();
647 }
648
649
650 void Canvas::create_objects(EDL *edl)
651 {
652         view_x = x;
653         view_y = y;
654         view_w = w;
655         view_h = h;
656         get_scrollbars(edl, view_x, view_y, view_w, view_h);
657
658         subwindow->unlock_window();
659         create_canvas();
660         subwindow->lock_window("Canvas::create_objects");
661
662         subwindow->add_subwindow(canvas_menu = new CanvasPopup(this));
663         canvas_menu->create_objects();
664
665         subwindow->add_subwindow(fullscreen_menu = new CanvasFullScreenPopup(this));
666         fullscreen_menu->create_objects();
667
668 }
669
670 int Canvas::button_press_event()
671 {
672         int result = 0;
673
674         if(get_canvas()->get_buttonpress() == 3)
675         {
676                 if(get_fullscreen())
677                         fullscreen_menu->activate_menu();
678                 else
679                         canvas_menu->activate_menu();
680                 result = 1;
681         }
682
683         return result;
684 }
685
686 void Canvas::start_single()
687 {
688         is_processing = 1;
689         status_event();
690 }
691
692 void Canvas::stop_single()
693 {
694         is_processing = 0;
695         status_event();
696 }
697
698 void Canvas::start_video()
699 {
700         if(get_canvas())
701         {
702                 get_canvas()->start_video();
703                 status_event();
704         }
705 }
706
707 void Canvas::stop_video()
708 {
709         if(get_canvas())
710         {
711                 get_canvas()->stop_video();
712                 status_event();
713         }
714 }
715
716
717 void Canvas::start_fullscreen()
718 {
719         set_fullscreen(1);
720         create_canvas();
721 }
722
723 void Canvas::stop_fullscreen()
724 {
725         set_fullscreen(0);
726         create_canvas();
727 }
728
729 void Canvas::create_canvas()
730 {
731         int video_on = 0;
732         lock_canvas("Canvas::create_canvas");
733
734         if(!get_fullscreen())
735 // Enter windowed
736         {
737                 if(canvas_fullscreen)
738                 {
739                         video_on = canvas_fullscreen->get_video_on();
740                         canvas_fullscreen->stop_video();
741                         canvas_fullscreen->lock_window("Canvas::create_canvas 2");
742                         canvas_fullscreen->hide_window();
743                         canvas_fullscreen->unlock_window();
744                 }
745
746                 if(!canvas_auxwindow && !canvas_subwindow)
747                 {
748                         subwindow->add_subwindow(canvas_subwindow = new CanvasOutput(this,
749                                 view_x,
750                                 view_y,
751                                 view_w,
752                                 view_h));
753                 }
754         }
755         else
756 // Enter fullscreen
757         {
758                 BC_WindowBase *wdw = canvas_auxwindow ?
759                         canvas_auxwindow : canvas_subwindow;
760                 if(wdw)
761                 {
762                         video_on = wdw->get_video_on();
763                         wdw->stop_video();
764                 }
765
766                 int x, y, w, h;
767                 wdw->get_fullscreen_geometry(x, y, w, h);
768
769                 if( canvas_fullscreen ) {
770                         if( x != canvas_fullscreen->get_x() ||
771                             y != canvas_fullscreen->get_y() ||
772                             w != canvas_fullscreen->get_w() ||
773                             h != canvas_fullscreen->get_h() ) {
774                                 delete canvas_fullscreen;
775                                 canvas_fullscreen = 0;
776                         }
777                 }
778                 if( !canvas_fullscreen )
779                         canvas_fullscreen = new CanvasFullScreen(this, w, h);
780                 canvas_fullscreen->show_window();
781                 canvas_fullscreen->sync_display();
782                 canvas_fullscreen->reposition_window(x, y);
783         }
784
785         if( !video_on ) {
786                 get_canvas()->lock_window("Canvas::create_canvas 1");
787                 draw_refresh();
788                 get_canvas()->unlock_window();
789         }
790
791         if( video_on )
792                 get_canvas()->start_video();
793
794         get_canvas()->lock_window("Canvas::create_canvas 2");
795         get_canvas()->focus();
796         get_canvas()->unlock_window();
797
798         unlock_canvas();
799 }
800
801
802
803 int Canvas::cursor_leave_event_base(BC_WindowBase *caller)
804 {
805         int result = 0;
806         if(cursor_inside) result = cursor_leave_event();
807         cursor_inside = 0;
808         return result;
809 }
810
811 int Canvas::cursor_enter_event_base(BC_WindowBase *caller)
812 {
813         int result = 0;
814         if(caller->is_event_win() && caller->cursor_inside())
815         {
816                 cursor_inside = 1;
817                 result = cursor_enter_event();
818         }
819         return result;
820 }
821
822 int Canvas::button_press_event_base(BC_WindowBase *caller)
823 {
824         if(caller->is_event_win() && caller->cursor_inside())
825         {
826                 return button_press_event();
827         }
828         return 0;
829 }
830
831 int Canvas::keypress_event(BC_WindowBase *caller)
832 {
833         int key = caller->get_keypress();
834         switch( key ) {
835         case 'f':
836                 caller->unlock_window();
837                 if(get_fullscreen())
838                         stop_fullscreen();
839                 else
840                         start_fullscreen();
841                 caller->lock_window("Canvas::keypress_event 1");
842                 break;
843         case ESC:
844                 caller->unlock_window();
845                 if(get_fullscreen())
846                         stop_fullscreen();
847                 caller->lock_window("Canvas::keypress_event 2");
848                 break;
849         default:
850                 return 0;
851         }
852         return 1;
853 }
854
855 void Canvas::update_refresh(VideoDevice *device, VFrame *output_frame)
856 {
857         int best_color_model = output_frame->get_color_model();
858         int use_opengl =
859                 device->out_config->driver == PLAYBACK_X11_GL &&
860                 output_frame->get_opengl_state() != VFrame::RAM;
861
862 // OpenGL does YUV->RGB in the compositing step
863         if( use_opengl )
864                 best_color_model = BC_RGB888;
865         else if( BC_CModels::has_alpha(best_color_model) ) {
866                 best_color_model =
867                         BC_CModels::is_float(best_color_model ) ?
868                                 BC_RGB_FLOAT :
869                         BC_CModels::is_yuv(best_color_model ) ?
870                                 ( BC_CModels::calculate_pixelsize(best_color_model) > 8 ?
871                                         BC_YUV161616 : BC_YUV888 ) :
872                                 ( BC_CModels::calculate_pixelsize(best_color_model) > 8 ?
873                                         BC_RGB161616 : BC_RGB888 ) ;
874         }
875         int out_w = output_frame->get_w();
876         int out_h = output_frame->get_h();
877         if( refresh_frame &&
878            (refresh_frame->get_w() != out_w ||
879             refresh_frame->get_h() != out_h ||
880             refresh_frame->get_color_model() != best_color_model ) ) {
881 // x11 direct render uses BC_BGR8888, use tranfer_from to remap
882                 delete refresh_frame;  refresh_frame = 0;
883         }
884
885         if( !refresh_frame ) {
886                 refresh_frame =
887                         new VFrame(out_w, out_h, best_color_model);
888         }
889
890         if( use_opengl ) {
891                 get_canvas()->unlock_window();
892                 unlock_canvas();
893                 mwindow->playback_3d->copy_from(this, refresh_frame, output_frame, 0);
894                 lock_canvas(" Canvas::output_refresh");
895                 get_canvas()->lock_window(" Canvas::output_refresh");
896         }
897         else
898                 refresh_frame->transfer_from(output_frame, -1);
899 }
900
901 void Canvas::clear(int flash)
902 {
903         BC_WindowBase *cwdw = get_canvas();
904         if( !cwdw )  return;
905         cwdw->set_bg_color(BLACK);
906         cwdw->clear_box(0,0, cwdw->get_w(), cwdw->get_h());
907         if( flash ) cwdw->flash();
908 }
909
910
911 CanvasOutput::CanvasOutput(Canvas *canvas,
912     int x,
913     int y,
914     int w,
915     int h)
916  : BC_SubWindow(x, y, w, h, BLACK)
917 {
918         this->canvas = canvas;
919 }
920
921 CanvasOutput::~CanvasOutput()
922 {
923 }
924
925 int CanvasOutput::cursor_leave_event()
926 {
927         return canvas->cursor_leave_event_base(canvas->get_canvas());
928 }
929
930 int CanvasOutput::cursor_enter_event()
931 {
932         return canvas->cursor_enter_event_base(canvas->get_canvas());
933 }
934
935 int CanvasOutput::button_press_event()
936 {
937         return canvas->button_press_event_base(canvas->get_canvas());
938 }
939
940 int CanvasOutput::button_release_event()
941 {
942         return canvas->button_release_event();
943 }
944
945 int CanvasOutput::cursor_motion_event()
946 {
947         return canvas->cursor_motion_event();
948 }
949
950 int CanvasOutput::keypress_event()
951 {
952         return canvas->keypress_event(canvas->get_canvas());
953 }
954
955
956
957 CanvasFullScreen::CanvasFullScreen(Canvas *canvas, int w, int h)
958  : BC_FullScreen(canvas->subwindow, w, h, BLACK, 0, 0, 0)
959 {
960         this->canvas = canvas;
961 }
962
963 CanvasFullScreen::~CanvasFullScreen()
964 {
965 }
966
967
968 CanvasXScroll::CanvasXScroll(EDL *edl, Canvas *canvas, int x, int y,
969         int length, int position, int handle_length, int pixels)
970  : BC_ScrollBar(x, y, SCROLL_HORIZ, pixels, length, position, handle_length)
971 {
972         this->canvas = canvas;
973 }
974
975 CanvasXScroll::~CanvasXScroll()
976 {
977 }
978
979 int CanvasXScroll::handle_event()
980 {
981 //printf("CanvasXScroll::handle_event %d %d %d\n", get_length(), get_value(), get_handlelength());
982         canvas->update_zoom(get_value(), canvas->get_yscroll(), canvas->get_zoom());
983         canvas->draw_refresh();
984         return 1;
985 }
986
987
988 CanvasYScroll::CanvasYScroll(EDL *edl, Canvas *canvas, int x, int y,
989         int length, int position, int handle_length, int pixels)
990  : BC_ScrollBar(x, y, SCROLL_VERT, pixels, length, position, handle_length)
991 {
992         this->canvas = canvas;
993 }
994
995 CanvasYScroll::~CanvasYScroll()
996 {
997 }
998
999 int CanvasYScroll::handle_event()
1000 {
1001 //printf("CanvasYScroll::handle_event %d %d\n", get_value(), get_length());
1002         canvas->update_zoom(canvas->get_xscroll(), get_value(), canvas->get_zoom());
1003         canvas->draw_refresh();
1004         return 1;
1005 }
1006
1007
1008 CanvasFullScreenPopup::CanvasFullScreenPopup(Canvas *canvas)
1009  : BC_PopupMenu(0, 0, 0, "", 0)
1010 {
1011         this->canvas = canvas;
1012 }
1013
1014
1015 void CanvasFullScreenPopup::create_objects()
1016 {
1017         add_item(new CanvasSubWindowItem(canvas));
1018 }
1019
1020 void CanvasFullScreenPopup::use_cwindow()
1021 {
1022         add_item(new CanvasPopupAuto(canvas));
1023 }
1024
1025 CanvasSubWindowItem::CanvasSubWindowItem(Canvas *canvas)
1026  : BC_MenuItem(_("Windowed"), "f", 'f')
1027 {
1028         this->canvas = canvas;
1029 }
1030
1031 int CanvasSubWindowItem::handle_event()
1032 {
1033 // It isn't a problem to delete the canvas from in here because the event
1034 // dispatcher is the canvas subwindow.
1035         canvas->subwindow->unlock_window();
1036         canvas->stop_fullscreen();
1037         canvas->subwindow->lock_window("CanvasSubWindowItem::handle_event");
1038         return 1;
1039 }
1040
1041
1042 CanvasPopup::CanvasPopup(Canvas *canvas)
1043  : BC_PopupMenu(0, 0, 0, "", 0)
1044 {
1045         this->canvas = canvas;
1046 }
1047
1048 CanvasPopup::~CanvasPopup()
1049 {
1050 }
1051
1052 CanvasZoomSize::CanvasZoomSize(Canvas *canvas)
1053  : BC_MenuItem(_("Zoom..."))
1054 {
1055         this->canvas = canvas;
1056 }
1057
1058 CanvasSizeSubMenu::CanvasSizeSubMenu(CanvasZoomSize *zoom_size)
1059 {
1060         this->zoom_size = zoom_size;
1061 }
1062
1063 void CanvasPopup::create_objects()
1064 {
1065         add_item(new BC_MenuItem("-"));
1066         add_item(new CanvasFullScreenItem(canvas));
1067
1068         CanvasZoomSize *zoom_size = new CanvasZoomSize(canvas);
1069         add_item(zoom_size);
1070         CanvasSizeSubMenu *submenu = new CanvasSizeSubMenu(zoom_size);
1071         zoom_size->add_submenu(submenu);
1072
1073         submenu->add_submenuitem(new CanvasPopupSize(canvas, _("Zoom 25%"), 0.25));
1074         submenu->add_submenuitem(new CanvasPopupSize(canvas, _("Zoom 33%"), 0.33));
1075         submenu->add_submenuitem(new CanvasPopupSize(canvas, _("Zoom 50%"), 0.5));
1076         submenu->add_submenuitem(new CanvasPopupSize(canvas, _("Zoom 75%"), 0.75));
1077         submenu->add_submenuitem(new CanvasPopupSize(canvas, _("Zoom 100%"), 1.0));
1078         submenu->add_submenuitem(new CanvasPopupSize(canvas, _("Zoom 150%"), 1.5));
1079         submenu->add_submenuitem(new CanvasPopupSize(canvas, _("Zoom 200%"), 2.0));
1080         submenu->add_submenuitem(new CanvasPopupSize(canvas, _("Zoom 300%"), 3.0));
1081         submenu->add_submenuitem(new CanvasPopupSize(canvas, _("Zoom 400%"), 4.0));
1082 }
1083
1084 void CanvasPopup::use_cwindow()
1085 {
1086         add_item(new CanvasPopupAuto(canvas));
1087         add_item(new CanvasPopupResetCamera(canvas));
1088         add_item(new CanvasPopupResetProjector(canvas));
1089         add_item(new CanvasPopupCameraKeyframe(canvas));
1090         add_item(new CanvasPopupProjectorKeyframe(canvas));
1091         add_item(toggle_controls = new CanvasToggleControls(canvas));
1092 }
1093
1094 void CanvasPopup::use_rwindow()
1095 {
1096         add_item(new CanvasPopupResetTranslation(canvas));
1097 }
1098
1099 void CanvasPopup::use_vwindow()
1100 {
1101         add_item(new CanvasPopupRemoveSource(canvas));
1102 }
1103
1104
1105 CanvasPopupAuto::CanvasPopupAuto(Canvas *canvas)
1106  : BC_MenuItem(_("Zoom Auto"))
1107 {
1108         this->canvas = canvas;
1109 }
1110
1111 int CanvasPopupAuto::handle_event()
1112 {
1113         canvas->zoom_auto();
1114         return 1;
1115 }
1116
1117
1118 CanvasPopupSize::CanvasPopupSize(Canvas *canvas, char *text, float percentage)
1119  : BC_MenuItem(text)
1120 {
1121         this->canvas = canvas;
1122         this->percentage = percentage;
1123 }
1124 CanvasPopupSize::~CanvasPopupSize()
1125 {
1126 }
1127 int CanvasPopupSize::handle_event()
1128 {
1129         canvas->zoom_resize_window(percentage);
1130         return 1;
1131 }
1132
1133
1134
1135 CanvasPopupResetCamera::CanvasPopupResetCamera(Canvas *canvas)
1136  : BC_MenuItem(_("Reset camera"), _("F11"), KEY_F11)
1137 {
1138         this->canvas = canvas;
1139 }
1140 int CanvasPopupResetCamera::handle_event()
1141 {
1142         canvas->reset_camera();
1143         return 1;
1144 }
1145
1146 CanvasPopupResetProjector::CanvasPopupResetProjector(Canvas *canvas)
1147  : BC_MenuItem(_("Reset projector"), _("F12"), KEY_F12)
1148 {
1149         this->canvas = canvas;
1150 }
1151 int CanvasPopupResetProjector::handle_event()
1152 {
1153         canvas->reset_projector();
1154         return 1;
1155 }
1156
1157
1158 CanvasPopupCameraKeyframe::CanvasPopupCameraKeyframe(Canvas *canvas)
1159  : BC_MenuItem(_("Camera keyframe"), _("Shift-F11"), KEY_F11)
1160 {
1161         this->canvas = canvas;
1162         set_shift(1);
1163 }
1164 int CanvasPopupCameraKeyframe::handle_event()
1165 {
1166         canvas->camera_keyframe();
1167         return 1;
1168 }
1169
1170 CanvasPopupProjectorKeyframe::CanvasPopupProjectorKeyframe(Canvas *canvas)
1171  : BC_MenuItem(_("Projector keyframe"), _("Shift-F12"), KEY_F12)
1172 {
1173         this->canvas = canvas;
1174         set_shift(1);
1175 }
1176 int CanvasPopupProjectorKeyframe::handle_event()
1177 {
1178         canvas->projector_keyframe();
1179         return 1;
1180 }
1181
1182
1183
1184 CanvasPopupResetTranslation::CanvasPopupResetTranslation(Canvas *canvas)
1185  : BC_MenuItem(_("Reset translation"))
1186 {
1187         this->canvas = canvas;
1188 }
1189 int CanvasPopupResetTranslation::handle_event()
1190 {
1191         canvas->reset_translation();
1192         return 1;
1193 }
1194
1195
1196
1197 CanvasToggleControls::CanvasToggleControls(Canvas *canvas)
1198  : BC_MenuItem(calculate_text(canvas->get_cwindow_controls()))
1199 {
1200         this->canvas = canvas;
1201 }
1202 int CanvasToggleControls::handle_event()
1203 {
1204         canvas->toggle_controls();
1205         set_text(calculate_text(canvas->get_cwindow_controls()));
1206         return 1;
1207 }
1208
1209 char* CanvasToggleControls::calculate_text(int cwindow_controls)
1210 {
1211         if(!cwindow_controls)
1212                 return _("Show controls");
1213         else
1214                 return _("Hide controls");
1215 }
1216
1217
1218
1219
1220
1221
1222
1223 CanvasFullScreenItem::CanvasFullScreenItem(Canvas *canvas)
1224  : BC_MenuItem(_("Fullscreen"), "f", 'f')
1225 {
1226         this->canvas = canvas;
1227 }
1228 int CanvasFullScreenItem::handle_event()
1229 {
1230         canvas->subwindow->unlock_window();
1231         canvas->start_fullscreen();
1232         canvas->subwindow->lock_window("CanvasFullScreenItem::handle_event");
1233         return 1;
1234 }
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244 CanvasPopupRemoveSource::CanvasPopupRemoveSource(Canvas *canvas)
1245  : BC_MenuItem(_("Close source"))
1246 {
1247         this->canvas = canvas;
1248 }
1249 int CanvasPopupRemoveSource::handle_event()
1250 {
1251         canvas->close_source();
1252         return 1;
1253 }
1254
1255