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