mask mousewheel segv bug, mask opengl sw fallback read to ram, fix tiff config withou...
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / cwindowtool.C
1 /*
2  * CINELERRA
3  * Copyright (C) 2008-2017 Adam Williams <broadcast at earthling dot net>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  */
20
21 #include <stdio.h>
22 #include <stdint.h>
23
24 #include "automation.h"
25 #include "bccolors.h"
26 #include "bctimer.h"
27 #include "clip.h"
28 #include "condition.h"
29 #include "cpanel.h"
30 #include "cplayback.h"
31 #include "cwindow.h"
32 #include "cwindowgui.h"
33 #include "cwindowtool.h"
34 #include "edl.h"
35 #include "edlsession.h"
36 #include "floatauto.h"
37 #include "floatautos.h"
38 #include "keys.h"
39 #include "language.h"
40 #include "localsession.h"
41 #include "mainsession.h"
42 #include "mainundo.h"
43 #include "maskauto.h"
44 #include "maskautos.h"
45 #include "mutex.h"
46 #include "mwindow.h"
47 #include "mwindowgui.h"
48 #include "theme.h"
49 #include "track.h"
50 #include "trackcanvas.h"
51 #include "transportque.h"
52
53
54 CWindowTool::CWindowTool(MWindow *mwindow, CWindowGUI *gui)
55  : Thread(1, 0, 0)
56 {
57         this->mwindow = mwindow;
58         this->gui = gui;
59         tool_gui = 0;
60         done = 0;
61         current_tool = CWINDOW_NONE;
62         set_synchronous(1);
63         input_lock = new Condition(0, "CWindowTool::input_lock");
64         output_lock = new Condition(1, "CWindowTool::output_lock");
65         tool_gui_lock = new Mutex("CWindowTool::tool_gui_lock");
66 }
67
68 CWindowTool::~CWindowTool()
69 {
70         done = 1;
71         stop_tool();
72         input_lock->unlock();
73         Thread::join();
74         delete input_lock;
75         delete output_lock;
76         delete tool_gui_lock;
77 }
78
79 void CWindowTool::start_tool(int operation)
80 {
81         CWindowToolGUI *new_gui = 0;
82         int result = 0;
83
84 //printf("CWindowTool::start_tool 1\n");
85         if(current_tool != operation)
86         {
87                 int previous_tool = current_tool;
88                 current_tool = operation;
89                 switch(operation)
90                 {
91                         case CWINDOW_EYEDROP:
92                                 new_gui = new CWindowEyedropGUI(mwindow, this);
93                                 break;
94                         case CWINDOW_CROP:
95                                 new_gui = new CWindowCropGUI(mwindow, this);
96                                 break;
97                         case CWINDOW_CAMERA:
98                                 new_gui = new CWindowCameraGUI(mwindow, this);
99                                 break;
100                         case CWINDOW_PROJECTOR:
101                                 new_gui = new CWindowProjectorGUI(mwindow, this);
102                                 break;
103                         case CWINDOW_MASK:
104                                 new_gui = new CWindowMaskGUI(mwindow, this);
105                                 break;
106                         case CWINDOW_RULER:
107                                 new_gui = new CWindowRulerGUI(mwindow, this);
108                                 break;
109                         case CWINDOW_PROTECT:
110                                 mwindow->edl->session->tool_window = 0;
111                                 gui->composite_panel->operation[CWINDOW_TOOL_WINDOW]->update(0);
112                                 // fall thru
113                         default:
114                                 result = 1;
115                                 stop_tool();
116                                 break;
117                 }
118
119 //printf("CWindowTool::start_tool 1\n");
120
121
122                 if(!result)
123                 {
124                         stop_tool();
125 // Wait for previous tool GUI to finish
126                         output_lock->lock("CWindowTool::start_tool");
127                         this->tool_gui = new_gui;
128                         tool_gui->create_objects();
129                         if( previous_tool == CWINDOW_PROTECT || previous_tool == CWINDOW_NONE ) {
130                                 mwindow->edl->session->tool_window = 1;
131                                 gui->composite_panel->operation[CWINDOW_TOOL_WINDOW]->update(1);
132                         }
133                         update_show_window();
134
135 // Signal thread to run next tool GUI
136                         input_lock->unlock();
137                 }
138 //printf("CWindowTool::start_tool 1\n");
139         }
140         else
141         if(tool_gui)
142         {
143                 tool_gui->lock_window("CWindowTool::start_tool");
144                 tool_gui->update();
145                 tool_gui->unlock_window();
146         }
147
148 //printf("CWindowTool::start_tool 2\n");
149
150 }
151
152
153 void CWindowTool::stop_tool()
154 {
155         if(tool_gui)
156         {
157                 tool_gui->lock_window("CWindowTool::stop_tool");
158                 tool_gui->set_done(0);
159                 tool_gui->unlock_window();
160         }
161 }
162
163 void CWindowTool::show_tool()
164 {
165         if(tool_gui && mwindow->edl->session->tool_window)
166         {
167                 tool_gui->lock_window("CWindowTool::show_tool");
168                 tool_gui->show_window();
169                 tool_gui->unlock_window();
170         }
171 }
172
173 void CWindowTool::hide_tool()
174 {
175         if(tool_gui && mwindow->edl->session->tool_window)
176         {
177                 tool_gui->lock_window("CWindowTool::show_tool");
178                 tool_gui->hide_window();
179                 tool_gui->unlock_window();
180         }
181 }
182
183
184 void CWindowTool::run()
185 {
186         while(!done)
187         {
188                 input_lock->lock("CWindowTool::run");
189                 if(!done)
190                 {
191                         tool_gui->run_window();
192                         tool_gui_lock->lock("CWindowTool::run");
193                         delete tool_gui;
194                         tool_gui = 0;
195                         tool_gui_lock->unlock();
196                 }
197                 output_lock->unlock();
198         }
199 }
200
201 void CWindowTool::update_show_window()
202 {
203         if(tool_gui)
204         {
205                 tool_gui->lock_window("CWindowTool::update_show_window");
206
207                 if(mwindow->edl->session->tool_window)
208                 {
209                         tool_gui->update();
210                         tool_gui->show_window();
211                 }
212                 else
213                         tool_gui->hide_window();
214                 tool_gui->flush();
215
216                 tool_gui->unlock_window();
217         }
218 }
219
220 void CWindowTool::raise_window()
221 {
222         if(tool_gui)
223         {
224                 gui->unlock_window();
225                 tool_gui->lock_window("CWindowTool::raise_window");
226                 tool_gui->raise_window();
227                 tool_gui->unlock_window();
228                 gui->lock_window("CWindowTool::raise_window");
229         }
230 }
231
232 void CWindowTool::update_values()
233 {
234         tool_gui_lock->lock("CWindowTool::update_values");
235         if(tool_gui)
236         {
237                 tool_gui->lock_window("CWindowTool::update_values");
238                 tool_gui->update();
239                 tool_gui->flush();
240                 tool_gui->unlock_window();
241         }
242         tool_gui_lock->unlock();
243 }
244
245
246
247
248
249
250
251 CWindowToolGUI::CWindowToolGUI(MWindow *mwindow,
252         CWindowTool *thread,
253         const char *title,
254         int w,
255         int h)
256  : BC_Window(title,
257         mwindow->session->ctool_x,
258         mwindow->session->ctool_y,
259         w,
260         h,
261         w,
262         h,
263         0,
264         0,
265         1)
266 {
267         this->mwindow = mwindow;
268         this->thread = thread;
269         current_operation = 0;
270 }
271
272 CWindowToolGUI::~CWindowToolGUI()
273 {
274 }
275
276 int CWindowToolGUI::close_event()
277 {
278         hide_window();
279         flush();
280         mwindow->edl->session->tool_window = 0;
281         unlock_window();
282
283
284
285         thread->gui->lock_window("CWindowToolGUI::close_event");
286         thread->gui->composite_panel->set_operation(mwindow->edl->session->cwindow_operation);
287         thread->gui->flush();
288         thread->gui->unlock_window();
289
290         lock_window("CWindowToolGUI::close_event");
291         return 1;
292 ;}
293
294 int CWindowToolGUI::keypress_event()
295 {
296         int result = 0;
297
298         switch( get_keypress() ) {
299         case 'w':
300         case 'W':
301                 return close_event();
302         case KEY_F1:
303         case KEY_F2:
304         case KEY_F3:
305         case KEY_F4:
306         case KEY_F5:
307         case KEY_F6:
308         case KEY_F7:
309         case KEY_F8:
310         case KEY_F9:
311         case KEY_F10:
312         case KEY_F11:
313         case KEY_F12:
314                 resend_event(thread->gui);
315                 result = 1;
316         }
317
318         return result;
319 }
320
321 int CWindowToolGUI::translation_event()
322 {
323         mwindow->session->ctool_x = get_x();
324         mwindow->session->ctool_y = get_y();
325         return 0;
326 }
327
328
329
330
331
332
333 CWindowCoord::CWindowCoord(CWindowToolGUI *gui, int x, int y, float value, int log_increment = 0)
334  : BC_TumbleTextBox(gui, (float)value, (float)-65536, (float)65536, x, y, 100, 3)
335 {
336         this->gui = gui;
337         set_log_floatincrement(log_increment);
338 }
339
340 CWindowCoord::CWindowCoord(CWindowToolGUI *gui, int x, int y, int value)
341  : BC_TumbleTextBox(gui, (int64_t)value, (int64_t)-65536, (int64_t)65536, x, y, 100, 3)
342 {
343         this->gui = gui;
344 }
345 int CWindowCoord::handle_event()
346 {
347         gui->event_caller = this;
348         gui->handle_event();
349         return 1;
350 }
351
352
353 CWindowCropOK::CWindowCropOK(MWindow *mwindow, CWindowToolGUI *gui, int x, int y)
354  : BC_GenericButton(x, y, _("Do it"))
355 {
356         this->mwindow = mwindow;
357         this->gui = gui;
358 }
359 int CWindowCropOK::handle_event()
360 {
361         mwindow->crop_video();
362         return 1;
363 }
364
365
366 int CWindowCropOK::keypress_event()
367 {
368         if(get_keypress() == 0xd)
369         {
370                 handle_event();
371                 return 1;
372         }
373         return 0;
374 }
375
376
377
378
379
380
381
382 CWindowCropGUI::CWindowCropGUI(MWindow *mwindow, CWindowTool *thread)
383  : CWindowToolGUI(mwindow,
384         thread,
385         _(PROGRAM_NAME ": Crop"),
386         330,
387         100)
388 {
389 }
390
391
392 CWindowCropGUI::~CWindowCropGUI()
393 {
394 }
395
396 void CWindowCropGUI::create_objects()
397 {
398         int x = 10, y = 10;
399         BC_Title *title;
400
401         lock_window("CWindowCropGUI::create_objects");
402         int column1 = 0;
403         int pad = MAX(BC_TextBox::calculate_h(this, MEDIUMFONT, 1, 1),
404                 BC_Title::calculate_h(this, "X")) + 5;
405         add_subwindow(title = new BC_Title(x, y, "X1:"));
406         column1 = MAX(column1, title->get_w());
407         y += pad;
408         add_subwindow(title = new BC_Title(x, y, _("W:")));
409         column1 = MAX(column1, title->get_w());
410         y += pad;
411         add_subwindow(new CWindowCropOK(mwindow, thread->tool_gui, x, y));
412
413         x += column1 + 5;
414         y = 10;
415         x1 = new CWindowCoord(thread->tool_gui, x, y,
416                 mwindow->edl->session->crop_x1);
417         x1->create_objects();
418         y += pad;
419         width = new CWindowCoord(thread->tool_gui, x, y,
420                 mwindow->edl->session->crop_x2 - mwindow->edl->session->crop_x1);
421         width->create_objects();
422
423
424         x += x1->get_w() + 10;
425         y = 10;
426         int column2 = 0;
427         add_subwindow(title = new BC_Title(x, y, "Y1:"));
428         column2 = MAX(column2, title->get_w());
429         y += pad;
430         add_subwindow(title = new BC_Title(x, y, _("H:")));
431         column2 = MAX(column2, title->get_w());
432         y += pad;
433
434         y = 10;
435         x += column2 + 5;
436         y1 = new CWindowCoord(thread->tool_gui, x, y,
437                 mwindow->edl->session->crop_y1);
438         y1->create_objects();
439         y += pad;
440         height = new CWindowCoord(thread->tool_gui, x, y,
441                 mwindow->edl->session->crop_y2 - mwindow->edl->session->crop_y1);
442         height->create_objects();
443         unlock_window();
444 }
445
446 void CWindowCropGUI::handle_event()
447 {
448         int new_x1, new_y1;
449         new_x1 = atol(x1->get_text());
450         new_y1 = atol(y1->get_text());
451         if(new_x1 != mwindow->edl->session->crop_x1)
452         {
453                 mwindow->edl->session->crop_x2 = new_x1 +
454                         mwindow->edl->session->crop_x2 -
455                         mwindow->edl->session->crop_x1;
456                 mwindow->edl->session->crop_x1 = new_x1;
457         }
458         if(new_y1 != mwindow->edl->session->crop_y1)
459         {
460                 mwindow->edl->session->crop_y2 = new_y1 +
461                         mwindow->edl->session->crop_y2 -
462                         mwindow->edl->session->crop_y1;
463                 mwindow->edl->session->crop_y1 = atol(y1->get_text());
464         }
465         mwindow->edl->session->crop_x2 = atol(width->get_text()) +
466                 mwindow->edl->session->crop_x1;
467         mwindow->edl->session->crop_y2 = atol(height->get_text()) +
468                 mwindow->edl->session->crop_y1;
469         update();
470         mwindow->cwindow->gui->canvas->redraw(1);
471 }
472
473 void CWindowCropGUI::update()
474 {
475         x1->update((int64_t)mwindow->edl->session->crop_x1);
476         y1->update((int64_t)mwindow->edl->session->crop_y1);
477         width->update((int64_t)mwindow->edl->session->crop_x2 -
478                 mwindow->edl->session->crop_x1);
479         height->update((int64_t)mwindow->edl->session->crop_y2 -
480                 mwindow->edl->session->crop_y1);
481 }
482
483
484 CWindowEyedropGUI::CWindowEyedropGUI(MWindow *mwindow, CWindowTool *thread)
485  : CWindowToolGUI(mwindow, thread, _(PROGRAM_NAME ": Color"), 220, 290)
486 {
487 }
488
489 CWindowEyedropGUI::~CWindowEyedropGUI()
490 {
491 }
492
493 void CWindowEyedropGUI::create_objects()
494 {
495         int margin = mwindow->theme->widget_border;
496         int x = 10 + margin;
497         int y = 10 + margin;
498         int x2 = 70, x3 = x2 + 60;
499         lock_window("CWindowEyedropGUI::create_objects");
500         BC_Title *title0, *title1, *title2, *title3, *title4, *title5, *title6, *title7;
501         add_subwindow(title0 = new BC_Title(x, y,_("X,Y:")));
502         y += title0->get_h() + margin;
503         add_subwindow(title7 = new BC_Title(x, y, _("Radius:")));
504         y += BC_TextBox::calculate_h(this, MEDIUMFONT, 1, 1) + margin;
505
506         add_subwindow(title1 = new BC_Title(x, y, _("Red:")));
507         y += title1->get_h() + margin;
508         add_subwindow(title2 = new BC_Title(x, y, _("Green:")));
509         y += title2->get_h() + margin;
510         add_subwindow(title3 = new BC_Title(x, y, _("Blue:")));
511         y += title3->get_h() + margin;
512
513         add_subwindow(title4 = new BC_Title(x, y, "Y:"));
514         y += title4->get_h() + margin;
515         add_subwindow(title5 = new BC_Title(x, y, "U:"));
516         y += title5->get_h() + margin;
517         add_subwindow(title6 = new BC_Title(x, y, "V:"));
518
519         add_subwindow(current = new BC_Title(x2, title0->get_y(), ""));
520
521         radius = new CWindowCoord(this, x2, title7->get_y(),
522                 mwindow->edl->session->eyedrop_radius);
523         radius->create_objects();
524         radius->set_boundaries((int64_t)0, (int64_t)255);
525
526         add_subwindow(red = new BC_Title(x2, title1->get_y(), "0"));
527         add_subwindow(green = new BC_Title(x2, title2->get_y(), "0"));
528         add_subwindow(blue = new BC_Title(x2, title3->get_y(), "0"));
529         add_subwindow(rgb_hex = new BC_Title(x3, red->get_y(), "#000000"));
530
531         add_subwindow(this->y = new BC_Title(x2, title4->get_y(), "0"));
532         add_subwindow(this->u = new BC_Title(x2, title5->get_y(), "0"));
533         add_subwindow(this->v = new BC_Title(x2, title6->get_y(), "0"));
534         add_subwindow(yuv_hex = new BC_Title(x3, this->y->get_y(), "#000000"));
535
536         y = title6->get_y() + this->v->get_h() + 2*margin;
537         add_subwindow(sample = new BC_SubWindow(x, y, 50, 50));
538         y += sample->get_h() + margin;
539         add_subwindow(use_max = new CWindowEyedropCheckBox(mwindow, this, x, y));
540         update();
541         unlock_window();
542 }
543
544 void CWindowEyedropGUI::update()
545 {
546         char string[BCTEXTLEN];
547         sprintf(string, "%d, %d",
548                 thread->gui->eyedrop_x,
549                 thread->gui->eyedrop_y);
550         current->update(string);
551
552         radius->update((int64_t)mwindow->edl->session->eyedrop_radius);
553
554         LocalSession *local_session = mwindow->edl->local_session;
555         int use_max = local_session->use_max;
556         float r = use_max ? local_session->red_max : local_session->red;
557         float g = use_max ? local_session->green_max : local_session->green;
558         float b = use_max ? local_session->blue_max : local_session->blue;
559         this->red->update(r);
560         this->green->update(g);
561         this->blue->update(b);
562
563         int rx = 255*r + 0.5;  bclamp(rx,0,255);
564         int gx = 255*g + 0.5;  bclamp(gx,0,255);
565         int bx = 255*b + 0.5;  bclamp(bx,0,255);
566         char rgb_text[BCSTRLEN];
567         sprintf(rgb_text, "#%02x%02x%02x", rx, gx, bx);
568         rgb_hex->update(rgb_text);
569         
570         float y, u, v;
571         YUV::yuv.rgb_to_yuv_f(r, g, b, y, u, v);
572         this->y->update(y);
573         this->u->update(u);  u += 0.5;
574         this->v->update(v);  v += 0.5;
575
576         int yx = 255*y + 0.5;  bclamp(yx,0,255);
577         int ux = 255*u + 0.5;  bclamp(ux,0,255);
578         int vx = 255*v + 0.5;  bclamp(vx,0,255);
579         char yuv_text[BCSTRLEN];
580         sprintf(yuv_text, "#%02x%02x%02x", yx, ux, vx);
581         yuv_hex->update(yuv_text);
582
583         int rgb = (rx << 16) | (gx << 8) | (bx << 0);
584         sample->set_color(rgb);
585         sample->draw_box(0, 0, sample->get_w(), sample->get_h());
586         sample->set_color(BLACK);
587         sample->draw_rectangle(0, 0, sample->get_w(), sample->get_h());
588         sample->flash();
589 }
590
591 void CWindowEyedropGUI::handle_event()
592 {
593         int new_radius = atoi(radius->get_text());
594         if(new_radius != mwindow->edl->session->eyedrop_radius)
595         {
596                 CWindowGUI *gui = mwindow->cwindow->gui;
597                 if(gui->eyedrop_visible)
598                 {
599                         gui->lock_window("CWindowEyedropGUI::handle_event");
600 // hide it
601                         int rerender;
602                         gui->canvas->do_eyedrop(rerender, 0, 1);
603                 }
604
605                 mwindow->edl->session->eyedrop_radius = new_radius;
606
607                 if(gui->eyedrop_visible)
608                 {
609 // draw it
610                         int rerender;
611                         gui->canvas->do_eyedrop(rerender, 0, 1);
612                         gui->unlock_window();
613                 }
614         }
615 }
616
617
618
619 /* Buttons to control Keyframe-Curve-Mode for Projector or Camera */
620
621 // Configuration for all possible Keyframe Curve Mode toggles
622 struct _CVD {
623         FloatAuto::t_mode mode;
624         bool use_camera;
625         const char* icon_id;
626         const char* tooltip;
627 };
628
629 const _CVD Camera_Crv_Smooth =
630         {       FloatAuto::SMOOTH,
631                 true,
632                 "tan_smooth",
633                 N_("\"smooth\" Curve on current Camera Keyframes")
634         };
635 const _CVD Camera_Crv_Linear =
636         {       FloatAuto::LINEAR,
637                 true,
638                 "tan_linear",
639                 N_("\"linear\" Curve on current Camera Keyframes")
640         };
641 const _CVD Projector_Crv_Smooth =
642         {       FloatAuto::SMOOTH,
643                 false,
644                 "tan_smooth",
645                 N_("\"smooth\" Curve on current Projector Keyframes")
646         };
647 const _CVD Projector_Crv_Linear =
648         {       FloatAuto::LINEAR,
649                 false,
650                 "tan_linear",
651                 N_("\"linear\" Curve on current Projector Keyframes")
652         };
653
654 // Implementation Class für Keyframe Curve Mode buttons
655 //
656 // This button reflects the state of the "current" keyframe
657 // (the nearest keyframe on the left) for all three automation
658 // lines together. Clicking on this button (re)sets the curve
659 // mode for the three "current" keyframes simultanously, but
660 // never creates a new keyframe.
661 //
662 class CWindowCurveToggle : public BC_Toggle
663 {
664 public:
665         CWindowCurveToggle(_CVD mode, MWindow *mwindow, CWindowToolGUI *gui, int x, int y);
666         void check_toggle_state(FloatAuto *x, FloatAuto *y, FloatAuto *z);
667         int handle_event();
668 private:
669         _CVD cfg;
670         MWindow *mwindow;
671         CWindowToolGUI *gui;
672 };
673
674
675 CWindowCurveToggle::CWindowCurveToggle(_CVD mode, MWindow *mwindow, CWindowToolGUI *gui, int x, int y)
676  : BC_Toggle(x, y, mwindow->theme->get_image_set(mode.icon_id), false),
677    cfg(mode)
678 {
679         this->gui = gui;
680         this->mwindow = mwindow;
681         set_tooltip(_(cfg.tooltip));
682 }
683
684 void CWindowCurveToggle::check_toggle_state(FloatAuto *x, FloatAuto *y, FloatAuto *z)
685 {
686 // the toggle state is only set to ON if all
687 // three automation lines have the same curve mode.
688 // For mixed states the toggle stays off.
689         set_value( x->curve_mode == this->cfg.mode &&
690                    y->curve_mode == this->cfg.mode &&
691                    z->curve_mode == this->cfg.mode
692                  ,true // redraw to show new state
693                  );
694 }
695
696 int CWindowCurveToggle::handle_event()
697 {
698         Track *track = mwindow->cwindow->calculate_affected_track();
699         if(track) {
700                 FloatAuto *x=0, *y=0, *z=0;
701                 mwindow->cwindow->calculate_affected_autos(track,
702                         &x, &y, &z, cfg.use_camera, 0,0,0); // don't create new keyframe
703                 if( x ) x->change_curve_mode(cfg.mode);
704                 if( y ) y->change_curve_mode(cfg.mode);
705                 if( z ) z->change_curve_mode(cfg.mode);
706
707                 gui->update();
708                 gui->update_preview();
709         }
710
711         return 1;
712 }
713
714
715 CWindowEyedropCheckBox::CWindowEyedropCheckBox(MWindow *mwindow, 
716         CWindowEyedropGUI *gui, int x, int y)
717  : BC_CheckBox(x, y, mwindow->edl->local_session->use_max, _("Use maximum"))
718 {
719         this->mwindow = mwindow;
720         this->gui = gui;
721 }
722
723 int CWindowEyedropCheckBox::handle_event()
724 {
725         mwindow->edl->local_session->use_max = get_value();
726         
727         gui->update();
728         return 1;
729 }
730
731
732 CWindowCameraGUI::CWindowCameraGUI(MWindow *mwindow, CWindowTool *thread)
733  : CWindowToolGUI(mwindow,
734         thread,
735         _(PROGRAM_NAME ": Camera"),
736         170,
737         170)
738 {
739 }
740 CWindowCameraGUI::~CWindowCameraGUI()
741 {
742 }
743
744 void CWindowCameraGUI::create_objects()
745 {
746         int x = 10, y = 10, x1;
747         Track *track = mwindow->cwindow->calculate_affected_track();
748         FloatAuto *x_auto = 0, *y_auto = 0, *z_auto = 0;
749         BC_Title *title;
750         BC_Button *button;
751
752         lock_window("CWindowCameraGUI::create_objects");
753         if( track ) {
754                 mwindow->cwindow->calculate_affected_autos(track,
755                         &x_auto, &y_auto, &z_auto, 1, 0, 0, 0);
756         }
757
758         add_subwindow(title = new BC_Title(x, y, "X:"));
759         x += title->get_w();
760         this->x = new CWindowCoord(this, x, y,
761                 x_auto ? x_auto->get_value() : (float)0);
762         this->x->create_objects();
763
764
765         y += 30;
766         x = 10;
767         add_subwindow(title = new BC_Title(x, y, "Y:"));
768         x += title->get_w();
769         this->y = new CWindowCoord(this, x, y,
770                 y_auto ? y_auto->get_value() : (float)0);
771         this->y->create_objects();
772         y += 30;
773         x = 10;
774         add_subwindow(title = new BC_Title(x, y, "Z:"));
775         x += title->get_w();
776         this->z = new CWindowCoord(this, x, y,
777                 z_auto ? z_auto->get_value() : (float)1);
778         this->z->create_objects();
779         this->z->set_increment(0.01);
780
781         y += 30;
782         x1 = 10;
783         add_subwindow(button = new CWindowCameraLeft(mwindow, this, x1, y));
784         x1 += button->get_w();
785         add_subwindow(button = new CWindowCameraCenter(mwindow, this, x1, y));
786         x1 += button->get_w();
787         add_subwindow(button = new CWindowCameraRight(mwindow, this, x1, y));
788
789         y += button->get_h();
790         x1 = 10;
791         add_subwindow(button = new CWindowCameraTop(mwindow, this, x1, y));
792         x1 += button->get_w();
793         add_subwindow(button = new CWindowCameraMiddle(mwindow, this, x1, y));
794         x1 += button->get_w();
795         add_subwindow(button = new CWindowCameraBottom(mwindow, this, x1, y));
796 // additional Buttons to control the curve mode of the "current" keyframe
797         x1 += button->get_w() + 15;
798         add_subwindow(this->t_smooth = new CWindowCurveToggle(Camera_Crv_Smooth, mwindow, this, x1, y));
799         x1 += button->get_w();
800         add_subwindow(this->t_linear = new CWindowCurveToggle(Camera_Crv_Linear, mwindow, this, x1, y));
801
802 // fill in current auto keyframe values, set toggle states.
803         this->update();
804         unlock_window();
805 }
806
807 void CWindowCameraGUI::update_preview()
808 {
809         CWindowGUI *cgui = mwindow->cwindow->gui;
810         cgui->lock_window("CWindowCameraGUI::update_preview");
811         cgui->sync_parameters(CHANGE_PARAMS, 0, 1);
812         cgui->unlock_window();
813 }
814
815
816 void CWindowCameraGUI::handle_event()
817 {
818         FloatAuto *x_auto = 0;
819         FloatAuto *y_auto = 0;
820         FloatAuto *z_auto = 0;
821         Track *track = mwindow->cwindow->calculate_affected_track();
822         if(track)
823         {
824                 mwindow->undo->update_undo_before(_("camera"), this);
825                 if(event_caller == x)
826                 {
827                         x_auto = (FloatAuto*)mwindow->cwindow->calculate_affected_auto(
828                                 track->automation->autos[AUTOMATION_CAMERA_X],
829                                 1);
830                         if(x_auto)
831                         {
832                                 x_auto->set_value(atof(x->get_text()));
833                                 update();
834                                 update_preview();
835                         }
836                 }
837                 else
838                 if(event_caller == y)
839                 {
840                         y_auto = (FloatAuto*)mwindow->cwindow->calculate_affected_auto(
841                                 track->automation->autos[AUTOMATION_CAMERA_Y],
842                                 1);
843                         if(y_auto)
844                         {
845                                 y_auto->set_value(atof(y->get_text()));
846                                 update();
847                                 update_preview();
848                         }
849                 }
850                 else
851                 if(event_caller == z)
852                 {
853                         z_auto = (FloatAuto*)mwindow->cwindow->calculate_affected_auto(
854                                 track->automation->autos[AUTOMATION_CAMERA_Z],
855                                 1);
856                         if(z_auto)
857                         {
858                                 float zoom = atof(z->get_text());
859                                 if(zoom > 100.) zoom = 100.;
860                                 else
861                                 if(zoom < 0.01) zoom = 0.01;
862         // Doesn't allow user to enter from scratch
863         //              if(zoom != atof(z->get_text()))
864         //                      z->update(zoom);
865
866                                 z_auto->set_value(zoom);
867                                 mwindow->gui->lock_window("CWindowCameraGUI::handle_event");
868                                 mwindow->gui->draw_overlays(1);
869                                 mwindow->gui->unlock_window();
870                                 update();
871                                 update_preview();
872                         }
873                 }
874
875                 mwindow->undo->update_undo_after(_("camera"), LOAD_ALL);
876         }
877 }
878
879 void CWindowCameraGUI::update()
880 {
881         FloatAuto *x_auto = 0;
882         FloatAuto *y_auto = 0;
883         FloatAuto *z_auto = 0;
884         Track *track = mwindow->cwindow->calculate_affected_track();
885         if( track ) {
886                 mwindow->cwindow->calculate_affected_autos(track,
887                         &x_auto, &y_auto, &z_auto, 1, 0, 0, 0);
888         }
889
890         if(x_auto)
891                 x->update(x_auto->get_value());
892         if(y_auto)
893                 y->update(y_auto->get_value());
894         if(z_auto) {
895                 float value = z_auto->get_value();
896                 z->update(value);
897                 thread->gui->lock_window("CWindowCameraGUI::update");
898                 thread->gui->composite_panel->cpanel_zoom->update(value);
899                 thread->gui->unlock_window();
900         }
901
902         if( x_auto && y_auto && z_auto )
903         {
904                 t_smooth->check_toggle_state(x_auto, y_auto, z_auto);
905                 t_linear->check_toggle_state(x_auto, y_auto, z_auto);
906         }
907 }
908
909
910
911
912 CWindowCameraLeft::CWindowCameraLeft(MWindow *mwindow, CWindowCameraGUI *gui, int x, int y)
913  : BC_Button(x, y, mwindow->theme->get_image_set("left_justify"))
914 {
915         this->gui = gui;
916         this->mwindow = mwindow;
917         set_tooltip(_("Left justify"));
918 }
919 int CWindowCameraLeft::handle_event()
920 {
921         FloatAuto *x_auto = 0;
922         FloatAuto *z_auto = 0;
923         Track *track = mwindow->cwindow->calculate_affected_track();
924         if( track ) {
925                 mwindow->cwindow->calculate_affected_autos(track,
926                         &x_auto, 0, &z_auto, 1, 1, 0, 0);
927         }
928
929         if(x_auto && z_auto)
930         {
931                 int w = 0, h = 0;
932                 track->get_source_dimensions(
933                         mwindow->edl->local_session->get_selectionstart(1),
934                         w,
935                         h);
936
937                 if(w && h)
938                 {
939                         mwindow->undo->update_undo_before(_("camera"), 0);
940                         x_auto->set_value(
941                                 (double)track->track_w / z_auto->get_value() / 2 -
942                                 (double)w / 2);
943                         mwindow->undo->update_undo_after(_("camera"), LOAD_ALL);
944                         gui->update();
945                         gui->update_preview();
946                 }
947         }
948
949         return 1;
950 }
951
952
953 CWindowCameraCenter::CWindowCameraCenter(MWindow *mwindow, CWindowCameraGUI *gui, int x, int y)
954  : BC_Button(x, y, mwindow->theme->get_image_set("center_justify"))
955 {
956         this->gui = gui;
957         this->mwindow = mwindow;
958         set_tooltip(_("Center horizontal"));
959 }
960 int CWindowCameraCenter::handle_event()
961 {
962         FloatAuto *x_auto = 0;
963         Track *track = mwindow->cwindow->calculate_affected_track();
964         if(track)
965                 x_auto = (FloatAuto*)mwindow->cwindow->calculate_affected_auto(
966                         track->automation->autos[AUTOMATION_CAMERA_X],
967                         1);
968
969         if(x_auto)
970         {
971                 mwindow->undo->update_undo_before(_("camera"), 0);
972                 x_auto->set_value(0);
973                 gui->update();
974                 gui->update_preview();
975                 mwindow->undo->update_undo_after(_("camera"), LOAD_ALL);
976         }
977
978         return 1;
979 }
980
981
982 CWindowCameraRight::CWindowCameraRight(MWindow *mwindow, CWindowCameraGUI *gui, int x, int y)
983  : BC_Button(x, y, mwindow->theme->get_image_set("right_justify"))
984 {
985         this->gui = gui;
986         this->mwindow = mwindow;
987         set_tooltip(_("Right justify"));
988 }
989 int CWindowCameraRight::handle_event()
990 {
991         FloatAuto *x_auto = 0;
992         FloatAuto *z_auto = 0;
993         Track *track = mwindow->cwindow->calculate_affected_track();
994         if( track ) {
995                 mwindow->cwindow->calculate_affected_autos(track,
996                         &x_auto, 0, &z_auto, 1, 1, 0, 0);
997         }
998
999         if(x_auto && z_auto)
1000         {
1001                 int w = 0, h = 0;
1002                 track->get_source_dimensions(
1003                         mwindow->edl->local_session->get_selectionstart(1),
1004                         w,
1005                         h);
1006
1007                 if(w && h)
1008                 {
1009                         mwindow->undo->update_undo_before(_("camera"), 0);
1010                         x_auto->set_value( -((double)track->track_w / z_auto->get_value() / 2 -
1011                                 (double)w / 2));
1012                         gui->update();
1013                         gui->update_preview();
1014                         mwindow->undo->update_undo_after(_("camera"), LOAD_ALL);
1015                 }
1016         }
1017
1018         return 1;
1019 }
1020
1021
1022 CWindowCameraTop::CWindowCameraTop(MWindow *mwindow, CWindowCameraGUI *gui, int x, int y)
1023  : BC_Button(x, y, mwindow->theme->get_image_set("top_justify"))
1024 {
1025         this->gui = gui;
1026         this->mwindow = mwindow;
1027         set_tooltip(_("Top justify"));
1028 }
1029 int CWindowCameraTop::handle_event()
1030 {
1031         FloatAuto *y_auto = 0;
1032         FloatAuto *z_auto = 0;
1033         Track *track = mwindow->cwindow->calculate_affected_track();
1034         if( track ) {
1035                 mwindow->cwindow->calculate_affected_autos(track,
1036                         0, &y_auto, &z_auto, 1, 0, 1, 0);
1037         }
1038
1039         if(y_auto && z_auto)
1040         {
1041                 int w = 0, h = 0;
1042                 track->get_source_dimensions(
1043                         mwindow->edl->local_session->get_selectionstart(1),
1044                         w,
1045                         h);
1046
1047                 if(w && h)
1048                 {
1049                         mwindow->undo->update_undo_before(_("camera"), 0);
1050                         y_auto->set_value((double)track->track_h / z_auto->get_value() / 2 -
1051                                 (double)h / 2);
1052                         gui->update();
1053                         gui->update_preview();
1054                         mwindow->undo->update_undo_after(_("camera"), LOAD_ALL);
1055                 }
1056         }
1057
1058         return 1;
1059 }
1060
1061
1062 CWindowCameraMiddle::CWindowCameraMiddle(MWindow *mwindow, CWindowCameraGUI *gui, int x, int y)
1063  : BC_Button(x, y, mwindow->theme->get_image_set("middle_justify"))
1064 {
1065         this->gui = gui;
1066         this->mwindow = mwindow;
1067         set_tooltip(_("Center vertical"));
1068 }
1069 int CWindowCameraMiddle::handle_event()
1070 {
1071         FloatAuto *y_auto = 0;
1072         Track *track = mwindow->cwindow->calculate_affected_track();
1073         if(track)
1074                 y_auto = (FloatAuto*)mwindow->cwindow->calculate_affected_auto(
1075                         track->automation->autos[AUTOMATION_CAMERA_Y], 1);
1076
1077         if(y_auto)
1078         {
1079                 mwindow->undo->update_undo_before(_("camera"), 0);
1080                 y_auto->set_value(0);
1081                 gui->update();
1082                 gui->update_preview();
1083                 mwindow->undo->update_undo_after(_("camera"), LOAD_ALL);
1084         }
1085
1086         return 1;
1087 }
1088
1089
1090 CWindowCameraBottom::CWindowCameraBottom(MWindow *mwindow, CWindowCameraGUI *gui, int x, int y)
1091  : BC_Button(x, y, mwindow->theme->get_image_set("bottom_justify"))
1092 {
1093         this->gui = gui;
1094         this->mwindow = mwindow;
1095         set_tooltip(_("Bottom justify"));
1096 }
1097 int CWindowCameraBottom::handle_event()
1098 {
1099         FloatAuto *y_auto = 0;
1100         FloatAuto *z_auto = 0;
1101         Track *track = mwindow->cwindow->calculate_affected_track();
1102         if( track ) {
1103                 mwindow->cwindow->calculate_affected_autos(track,
1104                         0, &y_auto, &z_auto, 1, 0, 1, 0);
1105         }
1106
1107         if(y_auto && z_auto)
1108         {
1109                 int w = 0, h = 0;
1110                 track->get_source_dimensions(
1111                         mwindow->edl->local_session->get_selectionstart(1),
1112                         w,
1113                         h);
1114
1115                 if(w && h)
1116                 {
1117                         mwindow->undo->update_undo_before(_("camera"), 0);
1118                         y_auto->set_value(-((double)track->track_h / z_auto->get_value() / 2 -
1119                                 (double)h / 2));
1120                         gui->update();
1121                         gui->update_preview();
1122                         mwindow->undo->update_undo_after(_("camera"), LOAD_ALL);
1123                 }
1124         }
1125
1126         return 1;
1127 }
1128
1129
1130 CWindowProjectorGUI::CWindowProjectorGUI(MWindow *mwindow, CWindowTool *thread)
1131  : CWindowToolGUI(mwindow,
1132         thread,
1133         _(PROGRAM_NAME ": Projector"),
1134         170,
1135         170)
1136 {
1137 }
1138 CWindowProjectorGUI::~CWindowProjectorGUI()
1139 {
1140 }
1141 void CWindowProjectorGUI::create_objects()
1142 {
1143         int x = 10, y = 10, x1;
1144         Track *track = mwindow->cwindow->calculate_affected_track();
1145         FloatAuto *x_auto = 0;
1146         FloatAuto *y_auto = 0;
1147         FloatAuto *z_auto = 0;
1148         BC_Title *title;
1149         BC_Button *button;
1150
1151         lock_window("CWindowProjectorGUI::create_objects");
1152         if( track ) {
1153                 mwindow->cwindow->calculate_affected_autos(track,
1154                         &x_auto, &y_auto, &z_auto, 0, 0, 0, 0);
1155         }
1156
1157         add_subwindow(title = new BC_Title(x, y, "X:"));
1158         x += title->get_w();
1159         this->x = new CWindowCoord(this, x, y,
1160                 x_auto ? x_auto->get_value() : (float)0);
1161         this->x->create_objects();
1162         y += 30;
1163         x = 10;
1164         add_subwindow(title = new BC_Title(x, y, "Y:"));
1165         x += title->get_w();
1166         this->y = new CWindowCoord(this, x, y,
1167                 y_auto ? y_auto->get_value() : (float)0);
1168         this->y->create_objects();
1169         y += 30;
1170         x = 10;
1171         add_subwindow(title = new BC_Title(x, y, "Z:"));
1172         x += title->get_w();
1173         this->z = new CWindowCoord(this, x, y,
1174                 z_auto ? z_auto->get_value() : (float)1);
1175         this->z->create_objects();
1176         this->z->set_increment(0.01);
1177
1178         y += 30;
1179         x1 = 10;
1180         add_subwindow(button = new CWindowProjectorLeft(mwindow, this, x1, y));
1181         x1 += button->get_w();
1182         add_subwindow(button = new CWindowProjectorCenter(mwindow, this, x1, y));
1183         x1 += button->get_w();
1184         add_subwindow(button = new CWindowProjectorRight(mwindow, this, x1, y));
1185
1186         y += button->get_h();
1187         x1 = 10;
1188         add_subwindow(button = new CWindowProjectorTop(mwindow, this, x1, y));
1189         x1 += button->get_w();
1190         add_subwindow(button = new CWindowProjectorMiddle(mwindow, this, x1, y));
1191         x1 += button->get_w();
1192         add_subwindow(button = new CWindowProjectorBottom(mwindow, this, x1, y));
1193
1194 // additional Buttons to control the curve mode of the "current" keyframe
1195         x1 += button->get_w() + 15;
1196         add_subwindow(this->t_smooth = new CWindowCurveToggle(Projector_Crv_Smooth, mwindow, this, x1, y));
1197         x1 += button->get_w();
1198         add_subwindow(this->t_linear = new CWindowCurveToggle(Projector_Crv_Linear, mwindow, this, x1, y));
1199
1200 // fill in current auto keyframe values, set toggle states.
1201         this->update();
1202         unlock_window();
1203 }
1204
1205 void CWindowProjectorGUI::update_preview()
1206 {
1207         CWindowGUI *cgui = mwindow->cwindow->gui;
1208         cgui->lock_window("CWindowProjectorGUI::update_preview");
1209         cgui->sync_parameters(CHANGE_PARAMS, 0, 1);
1210         cgui->unlock_window();
1211 }
1212
1213 void CWindowProjectorGUI::handle_event()
1214 {
1215         FloatAuto *x_auto = 0;
1216         FloatAuto *y_auto = 0;
1217         FloatAuto *z_auto = 0;
1218         Track *track = mwindow->cwindow->calculate_affected_track();
1219
1220         if(track)
1221         {
1222                 mwindow->undo->update_undo_before(_("projector"), this);
1223                 if(event_caller == x)
1224                 {
1225                         x_auto = (FloatAuto*)mwindow->cwindow->calculate_affected_auto(
1226                                 track->automation->autos[AUTOMATION_PROJECTOR_X],
1227                                 1);
1228                         if(x_auto)
1229                         {
1230                                 x_auto->set_value(atof(x->get_text()));
1231                                 update();
1232                                 update_preview();
1233                         }
1234                 }
1235                 else
1236                 if(event_caller == y)
1237                 {
1238                         y_auto = (FloatAuto*)mwindow->cwindow->calculate_affected_auto(
1239                                 track->automation->autos[AUTOMATION_PROJECTOR_Y],
1240                                 1);
1241                         if(y_auto)
1242                         {
1243                                 y_auto->set_value(atof(y->get_text()));
1244                                 update();
1245                                 update_preview();
1246                         }
1247                 }
1248                 else
1249                 if(event_caller == z)
1250                 {
1251                         z_auto = (FloatAuto*)mwindow->cwindow->calculate_affected_auto(
1252                                 track->automation->autos[AUTOMATION_PROJECTOR_Z],
1253                                 1);
1254                         if(z_auto)
1255                         {
1256                                 float zoom = atof(z->get_text());
1257                                 if(zoom > 100.) zoom = 100.;
1258                                 else if(zoom < 0.01) zoom = 0.01;
1259 //                      if (zoom != atof(z->get_text()))
1260 //                              z->update(zoom);
1261                                 z_auto->set_value(zoom);
1262
1263                                 mwindow->gui->lock_window("CWindowProjectorGUI::handle_event");
1264                                 mwindow->gui->draw_overlays(1);
1265                                 mwindow->gui->unlock_window();
1266
1267                                 update();
1268                                 update_preview();
1269                         }
1270                 }
1271                 mwindow->undo->update_undo_after(_("projector"), LOAD_ALL);
1272         }
1273 }
1274
1275 void CWindowProjectorGUI::update()
1276 {
1277         FloatAuto *x_auto = 0;
1278         FloatAuto *y_auto = 0;
1279         FloatAuto *z_auto = 0;
1280         Track *track = mwindow->cwindow->calculate_affected_track();
1281         if( track ) {
1282                 mwindow->cwindow->calculate_affected_autos(track,
1283                         &x_auto, &y_auto, &z_auto, 0, 0, 0, 0);
1284         }
1285
1286         if(x_auto)
1287                 x->update(x_auto->get_value());
1288         if(y_auto)
1289                 y->update(y_auto->get_value());
1290         if(z_auto) {
1291                 float value = z_auto->get_value();
1292                 z->update(value);
1293                 thread->gui->lock_window("CWindowProjectorGUI::update");
1294                 thread->gui->composite_panel->cpanel_zoom->update(value);
1295                 thread->gui->unlock_window();
1296         }
1297
1298         if( x_auto && y_auto && z_auto )
1299         {
1300                 t_smooth->check_toggle_state(x_auto, y_auto, z_auto);
1301                 t_linear->check_toggle_state(x_auto, y_auto, z_auto);
1302         }
1303 }
1304
1305 CWindowProjectorLeft::CWindowProjectorLeft(MWindow *mwindow, CWindowProjectorGUI *gui, int x, int y)
1306  : BC_Button(x, y, mwindow->theme->get_image_set("left_justify"))
1307 {
1308         this->gui = gui;
1309         this->mwindow = mwindow;
1310         set_tooltip(_("Left justify"));
1311 }
1312 int CWindowProjectorLeft::handle_event()
1313 {
1314         FloatAuto *x_auto = 0;
1315         FloatAuto *z_auto = 0;
1316         Track *track = mwindow->cwindow->calculate_affected_track();
1317         if( track ) {
1318                 mwindow->cwindow->calculate_affected_autos(track,
1319                         &x_auto, 0, &z_auto, 0, 1, 0, 0);
1320         }
1321         if(x_auto && z_auto)
1322         {
1323                 mwindow->undo->update_undo_before(_("projector"), 0);
1324                 x_auto->set_value( (double)track->track_w * z_auto->get_value() / 2 -
1325                         (double)mwindow->edl->session->output_w / 2 );
1326                 gui->update();
1327                 gui->update_preview();
1328                 mwindow->undo->update_undo_after(_("projector"), LOAD_ALL);
1329         }
1330
1331         return 1;
1332 }
1333
1334
1335 CWindowProjectorCenter::CWindowProjectorCenter(MWindow *mwindow, CWindowProjectorGUI *gui, int x, int y)
1336  : BC_Button(x, y, mwindow->theme->get_image_set("center_justify"))
1337 {
1338         this->gui = gui;
1339         this->mwindow = mwindow;
1340         set_tooltip(_("Center horizontal"));
1341 }
1342 int CWindowProjectorCenter::handle_event()
1343 {
1344         FloatAuto *x_auto = 0;
1345         Track *track = mwindow->cwindow->calculate_affected_track();
1346         if(track)
1347                 x_auto = (FloatAuto*)mwindow->cwindow->calculate_affected_auto(
1348                         track->automation->autos[AUTOMATION_PROJECTOR_X],
1349                         1);
1350
1351         if(x_auto)
1352         {
1353                 mwindow->undo->update_undo_before(_("projector"), 0);
1354                 x_auto->set_value(0);
1355                 gui->update();
1356                 gui->update_preview();
1357                 mwindow->undo->update_undo_after(_("projector"), LOAD_ALL);
1358         }
1359
1360         return 1;
1361 }
1362
1363
1364 CWindowProjectorRight::CWindowProjectorRight(MWindow *mwindow, CWindowProjectorGUI *gui, int x, int y)
1365  : BC_Button(x, y, mwindow->theme->get_image_set("right_justify"))
1366 {
1367         this->gui = gui;
1368         this->mwindow = mwindow;
1369         set_tooltip(_("Right justify"));
1370 }
1371 int CWindowProjectorRight::handle_event()
1372 {
1373         FloatAuto *x_auto = 0;
1374         FloatAuto *z_auto = 0;
1375         Track *track = mwindow->cwindow->calculate_affected_track();
1376         if( track ) {
1377                 mwindow->cwindow->calculate_affected_autos(track,
1378                         &x_auto, 0, &z_auto, 0, 1, 0, 0);
1379         }
1380
1381         if(x_auto && z_auto)
1382         {
1383                 mwindow->undo->update_undo_before(_("projector"), 0);
1384                 x_auto->set_value( -((double)track->track_w * z_auto->get_value() / 2 -
1385                         (double)mwindow->edl->session->output_w / 2));
1386                 gui->update();
1387                 gui->update_preview();
1388                 mwindow->undo->update_undo_after(_("projector"), LOAD_ALL);
1389         }
1390
1391         return 1;
1392 }
1393
1394
1395 CWindowProjectorTop::CWindowProjectorTop(MWindow *mwindow, CWindowProjectorGUI *gui, int x, int y)
1396  : BC_Button(x, y, mwindow->theme->get_image_set("top_justify"))
1397 {
1398         this->gui = gui;
1399         this->mwindow = mwindow;
1400         set_tooltip(_("Top justify"));
1401 }
1402 int CWindowProjectorTop::handle_event()
1403 {
1404         FloatAuto *y_auto = 0;
1405         FloatAuto *z_auto = 0;
1406         Track *track = mwindow->cwindow->calculate_affected_track();
1407         if( track ) {
1408                 mwindow->cwindow->calculate_affected_autos(track,
1409                         0, &y_auto, &z_auto, 0, 0, 1, 0);
1410         }
1411
1412         if(y_auto && z_auto)
1413         {
1414                 mwindow->undo->update_undo_before(_("projector"), 0);
1415                 y_auto->set_value( (double)track->track_h * z_auto->get_value() / 2 -
1416                         (double)mwindow->edl->session->output_h / 2 );
1417                 gui->update();
1418                 gui->update_preview();
1419                 mwindow->undo->update_undo_after(_("projector"), LOAD_ALL);
1420         }
1421
1422         return 1;
1423 }
1424
1425
1426 CWindowProjectorMiddle::CWindowProjectorMiddle(MWindow *mwindow, CWindowProjectorGUI *gui, int x, int y)
1427  : BC_Button(x, y, mwindow->theme->get_image_set("middle_justify"))
1428 {
1429         this->gui = gui;
1430         this->mwindow = mwindow;
1431         set_tooltip(_("Center vertical"));
1432 }
1433 int CWindowProjectorMiddle::handle_event()
1434 {
1435         FloatAuto *y_auto = 0;
1436         Track *track = mwindow->cwindow->calculate_affected_track();
1437         if(track)
1438                 y_auto = (FloatAuto*)mwindow->cwindow->calculate_affected_auto(
1439                         track->automation->autos[AUTOMATION_PROJECTOR_Y], 1);
1440
1441         if(y_auto)
1442         {
1443                 mwindow->undo->update_undo_before(_("projector"), 0);
1444                 y_auto->set_value(0);
1445                 gui->update();
1446                 gui->update_preview();
1447                 mwindow->undo->update_undo_after(_("projector"), LOAD_ALL);
1448         }
1449
1450         return 1;
1451 }
1452
1453
1454 CWindowProjectorBottom::CWindowProjectorBottom(MWindow *mwindow, CWindowProjectorGUI *gui, int x, int y)
1455  : BC_Button(x, y, mwindow->theme->get_image_set("bottom_justify"))
1456 {
1457         this->gui = gui;
1458         this->mwindow = mwindow;
1459         set_tooltip(_("Bottom justify"));
1460 }
1461 int CWindowProjectorBottom::handle_event()
1462 {
1463         FloatAuto *y_auto = 0;
1464         FloatAuto *z_auto = 0;
1465         Track *track = mwindow->cwindow->calculate_affected_track();
1466         if( track ) {
1467                 mwindow->cwindow->calculate_affected_autos(track,
1468                         0, &y_auto, &z_auto, 0, 0, 1, 0);
1469         }
1470
1471         if(y_auto && z_auto)
1472         {
1473                 mwindow->undo->update_undo_before(_("projector"), 0);
1474                 y_auto->set_value( -((double)track->track_h * z_auto->get_value() / 2 -
1475                         (double)mwindow->edl->session->output_h / 2));
1476                 gui->update();
1477                 gui->update_preview();
1478                 mwindow->undo->update_undo_after(_("projector"), LOAD_ALL);
1479         }
1480
1481         return 1;
1482 }
1483
1484
1485 CWindowMaskName::CWindowMaskName(MWindow *mwindow, CWindowMaskGUI *gui,
1486                 int x, int y, const char *text)
1487  : BC_PopupTextBox(gui, 0, text, x, y, 100, 160)
1488 {
1489         this->mwindow = mwindow;
1490         this->gui = gui;
1491 }
1492
1493 CWindowMaskName::~CWindowMaskName()
1494 {
1495 }
1496
1497 int CWindowMaskName::handle_event()
1498 {
1499         Track *track;
1500         MaskAutos *autos;
1501         MaskAuto *keyframe;
1502         SubMask *mask;
1503         MaskPoint *point;
1504 //printf("CWindowMaskGUI::update 1\n");
1505         gui->get_keyframe(track, autos, keyframe, mask, point, 0);
1506         if( track ) {
1507                 int k = get_number();
1508                 if( k < 0 ) k = mwindow->edl->session->cwindow_mask;
1509                 else mwindow->edl->session->cwindow_mask = k;
1510                 if( k >= 0 && k < mask_items.size() ) {
1511                         mask_items[k]->set_text(get_text());
1512                         update_list(&mask_items);
1513                 }
1514 #ifdef USE_KEYFRAME_SPANNING
1515                 MaskAuto temp_keyframe(mwindow->edl, autos);
1516                 temp_keyframe.copy_data(keyframe);
1517                 SubMask *submask = temp_keyframe.get_submask(mwindow->edl->session->cwindow_mask);
1518                 memset(submask->name, 0, sizeof(submask->name));
1519                 strncpy(submask->name, get_text(), sizeof(submask->name)-1);
1520                 ((MaskAutos*)track->automation->autos[AUTOMATION_MASK])->update_parameter(&temp_keyframe);
1521 #else
1522                 for(MaskAuto *current = (MaskAuto*)autos->default_auto; current; ) {
1523                         SubMask *submask = current->get_submask(mwindow->edl->session->cwindow_mask);
1524                         memset(submask->name, 0, sizeof(submask->name));
1525                         strncpy(submask->name, get_text(), sizeof(submask->name));
1526                         current = current == (MaskAuto*)autos->default_auto ?
1527                                 (MaskAuto*)autos->first : (MaskAuto*)NEXT;
1528                 }
1529 #endif
1530                 gui->update();
1531                 gui->update_preview();
1532         }
1533         return 1;
1534 }
1535
1536 void CWindowMaskName::update_items(MaskAuto *keyframe)
1537 {
1538         mask_items.remove_all_objects();
1539         int sz = !keyframe ? 0 : keyframe->masks.size();
1540         for( int i=0; i<SUBMASKS; ++i ) {
1541                 char text[BCSTRLEN];
1542                 if( i < sz ) {
1543                         SubMask *sub_mask = keyframe->masks.get(i);
1544                         strncpy(text, sub_mask->name, sizeof(text));
1545                 }
1546                 else
1547                         sprintf(text, "%d", i);
1548                 mask_items.append(new BC_ListBoxItem(text));
1549         }
1550         update_list(&mask_items);
1551 }
1552
1553
1554 CWindowMaskButton::CWindowMaskButton(MWindow *mwindow, CWindowMaskGUI *gui,
1555                  int x, int y, int no, int v)
1556  : BC_CheckBox(x, y, v)
1557 {
1558         this->mwindow = mwindow;
1559         this->gui = gui;
1560         this->no = no;
1561 }
1562
1563 CWindowMaskButton::~CWindowMaskButton()
1564 {
1565 }
1566
1567 int CWindowMaskButton::handle_event()
1568 {
1569         mwindow->edl->session->cwindow_mask = no;
1570         gui->name->update(gui->name->mask_items[no]->get_text());
1571         gui->update();
1572         gui->update_preview();
1573         return 1;
1574 }
1575
1576 CWindowMaskThumbler::CWindowMaskThumbler(MWindow *mwindow, CWindowMaskGUI *gui,
1577                 int x, int y)
1578  : BC_Tumbler(x, y)
1579 {
1580         this->mwindow = mwindow;
1581         this->gui = gui;
1582 }
1583
1584 CWindowMaskThumbler::~CWindowMaskThumbler()
1585 {
1586 }
1587
1588 int CWindowMaskThumbler::handle_up_event()
1589 {
1590         return do_event(1);
1591 }
1592
1593 int CWindowMaskThumbler::handle_down_event()
1594 {
1595         return do_event(-1);
1596 }
1597
1598 int CWindowMaskThumbler::do_event(int dir)
1599 {
1600         int k = mwindow->edl->session->cwindow_mask;
1601         if( (k+=dir) >= SUBMASKS ) k = 0;
1602         else if( k < 0 ) k = SUBMASKS-1;
1603         mwindow->edl->session->cwindow_mask = k;
1604         gui->name->update(gui->name->mask_items[k]->get_text());
1605         gui->update();
1606         gui->update_preview();
1607         return 1;
1608 }
1609
1610
1611 CWindowMaskDelMask::CWindowMaskDelMask(MWindow *mwindow,
1612         CWindowToolGUI *gui, int x, int y)
1613  : BC_GenericButton(x, y, _("Delete"))
1614 {
1615         this->mwindow = mwindow;
1616         this->gui = gui;
1617         set_tooltip(_("Delete mask"));
1618 }
1619
1620 int CWindowMaskDelMask::handle_event()
1621 {
1622         MaskAutos *autos;
1623         MaskAuto *keyframe;
1624         Track *track;
1625         MaskPoint *point;
1626         SubMask *mask;
1627         int total_points;
1628
1629 // Get existing keyframe
1630         ((CWindowMaskGUI*)gui)->get_keyframe(track, autos, keyframe, mask, point, 0);
1631
1632         if( track ) {
1633                 mwindow->undo->update_undo_before(_("mask delete"), 0);
1634
1635 #ifdef USE_KEYFRAME_SPANNING
1636 // Create temp keyframe
1637                 MaskAuto temp_keyframe(mwindow->edl, autos);
1638                 temp_keyframe.copy_data(keyframe);
1639                 SubMask *submask = temp_keyframe.get_submask(mwindow->edl->session->cwindow_mask);
1640                 submask->points.remove_all_objects();
1641                 total_points = 0;
1642 // Commit change to span of keyframes
1643                 ((MaskAutos*)track->automation->autos[AUTOMATION_MASK])->update_parameter(&temp_keyframe);
1644 #else
1645                 for(MaskAuto *current = (MaskAuto*)autos->default_auto; current; ) {
1646                         SubMask *submask = current->get_submask(mwindow->edl->session->cwindow_mask);
1647                         submask->points.clear();
1648                         current = current == (MaskAuto*)autos->default_auto ?
1649                                 (MaskAuto*)autos->first : (MaskAuto*)NEXT;
1650                 }
1651                 total_points = 0;
1652 #endif
1653                 if( mwindow->cwindow->gui->affected_point >= total_points )
1654                         mwindow->cwindow->gui->affected_point =
1655                                 total_points > 0 ? total_points-1 : 0;
1656
1657                 gui->update();
1658                 gui->update_preview();
1659                 mwindow->undo->update_undo_after(_("mask delete"), LOAD_AUTOMATION);
1660         }
1661
1662         return 1;
1663 }
1664
1665 CWindowMaskDelPoint::CWindowMaskDelPoint(MWindow *mwindow,
1666         CWindowToolGUI *gui, int x, int y)
1667  : BC_GenericButton(x, y, _("Delete"))
1668 {
1669         this->mwindow = mwindow;
1670         this->gui = gui;
1671         set_tooltip(_("Delete point"));
1672 }
1673
1674 int CWindowMaskDelPoint::handle_event()
1675 {
1676         MaskAutos *autos;
1677         MaskAuto *keyframe;
1678         Track *track;
1679         MaskPoint *point;
1680         SubMask *mask;
1681         int total_points;
1682
1683 // Get existing keyframe
1684         ((CWindowMaskGUI*)gui)->get_keyframe(track, autos, keyframe, mask, point, 0);
1685         if( track ) {
1686                 mwindow->undo->update_undo_before(_("point delete"), 0);
1687
1688 #ifdef USE_KEYFRAME_SPANNING
1689 // Create temp keyframe
1690                 MaskAuto temp_keyframe(mwindow->edl, autos);
1691                 temp_keyframe.copy_data(keyframe);
1692 // Update parameter
1693                 SubMask *submask = temp_keyframe.get_submask(mwindow->edl->session->cwindow_mask);
1694                 int i = mwindow->cwindow->gui->affected_point;
1695                 for( ; i<submask->points.total-1; ++i )
1696                         *submask->points.values[i] = *submask->points.values[i+1];
1697                 if( submask->points.total > 0 ) {
1698                         point = submask->points.values[submask->points.total-1];
1699                         submask->points.remove_object(point);
1700                 }
1701                 total_points = submask->points.total;
1702
1703 // Commit change to span of keyframes
1704                 ((MaskAutos*)track->automation->autos[AUTOMATION_MASK])->update_parameter(&temp_keyframe);
1705 #else
1706                 MaskAuto *current = (MaskAuto*)autos->default_auto;
1707                 while( current ) {
1708                         SubMask *submask = current->get_submask(mwindow->edl->session->cwindow_mask);
1709                         int i = mwindow->cwindow->gui->affected_point;
1710                         for( ; i<submask->points.total-1; ++i ) {
1711                                 *submask->points.values[i] = *submask->points.values[i+1];
1712                         if( submask->points.total > 0 ) {
1713                                 point = submask->points.values[submask->points.total-1];
1714                                 submask->points.remove_object(point);
1715                         }
1716                         total_points = submask->points.total;
1717                         current = current == (MaskAuto*)autos->default_auto ?
1718                                 (MaskAuto*)autos->first : (MaskAuto*)NEXT;
1719                 }
1720 #endif
1721                 if( mwindow->cwindow->gui->affected_point >= total_points )
1722                         mwindow->cwindow->gui->affected_point =
1723                                 total_points > 0 ? total_points-1 : 0;
1724
1725                 gui->update();
1726                 gui->update_preview();
1727                 mwindow->undo->update_undo_after(_("mask delete"), LOAD_AUTOMATION);
1728         }
1729
1730         return 1;
1731 }
1732
1733 int CWindowMaskDelPoint::keypress_event()
1734 {
1735         if( get_keypress() == BACKSPACE ||
1736             get_keypress() == DELETE )
1737                 return handle_event();
1738         return 0;
1739 }
1740
1741
1742
1743
1744 CWindowMaskAffectedPoint::CWindowMaskAffectedPoint(MWindow *mwindow,
1745         CWindowToolGUI *gui, int x, int y)
1746  : BC_TumbleTextBox(gui,
1747                 (int64_t)mwindow->cwindow->gui->affected_point,
1748                 (int64_t)0, INT64_MAX, x, y, 100)
1749 {
1750         this->mwindow = mwindow;
1751         this->gui = gui;
1752 }
1753
1754 CWindowMaskAffectedPoint::~CWindowMaskAffectedPoint()
1755 {
1756 }
1757
1758 int CWindowMaskAffectedPoint::handle_event()
1759 {
1760         int total_points = 0;
1761         int affected_point = atol(get_text());
1762         Track *track = mwindow->cwindow->calculate_affected_track();
1763         if(track) {
1764                 MaskAutos *autos = (MaskAutos*)track->automation->autos[AUTOMATION_MASK];
1765                 MaskAuto *keyframe = (MaskAuto*)mwindow->cwindow->calculate_affected_auto(autos, 0);
1766                 if( keyframe ) {
1767                         SubMask *mask = keyframe->get_submask(mwindow->edl->session->cwindow_mask);
1768                         total_points = mask->points.size();
1769                 }
1770         }
1771         int active_point = affected_point;
1772         if( affected_point >= total_points )
1773                 affected_point = total_points - 1;
1774         if( affected_point < 0 )
1775                 affected_point = 0;
1776         if( active_point != affected_point )
1777                 update((int64_t)affected_point);
1778         mwindow->cwindow->gui->affected_point = affected_point;
1779         gui->update();
1780         gui->update_preview();
1781         return 1;
1782 }
1783
1784
1785 CWindowMaskFocus::CWindowMaskFocus(MWindow *mwindow, CWindowToolGUI *gui, int x, int y)
1786  : BC_CheckBox(x, y, ((CWindowMaskGUI*)gui)->focused, _("Focus"))
1787 {
1788         this->mwindow = mwindow;
1789         this->gui = gui;
1790         set_tooltip("Center for rotate/scale");
1791 }
1792
1793 CWindowMaskFocus::~CWindowMaskFocus()
1794 {
1795 }
1796
1797 int CWindowMaskFocus::handle_event()
1798 {
1799         ((CWindowMaskGUI*)gui)->focused = get_value();
1800         gui->update();
1801         gui->update_preview();
1802         return 1;
1803 }
1804
1805 CWindowMaskDrawMarkers::CWindowMaskDrawMarkers(MWindow *mwindow, CWindowToolGUI *gui, int x, int y)
1806  : BC_CheckBox(x, y, ((CWindowMaskGUI*)gui)->markers, _("Markers"))
1807 {
1808         this->mwindow = mwindow;
1809         this->gui = gui;
1810         set_tooltip("Display points");
1811 }
1812
1813 CWindowMaskDrawMarkers::~CWindowMaskDrawMarkers()
1814 {
1815 }
1816
1817 int CWindowMaskDrawMarkers::handle_event()
1818 {
1819         ((CWindowMaskGUI*)gui)->markers = get_value();
1820         gui->update();
1821         gui->update_preview();
1822         return 1;
1823 }
1824
1825 CWindowMaskDrawBoundary::CWindowMaskDrawBoundary(MWindow *mwindow, CWindowToolGUI *gui, int x, int y)
1826  : BC_CheckBox(x, y, ((CWindowMaskGUI*)gui)->boundary, _("Boundary"))
1827 {
1828         this->mwindow = mwindow;
1829         this->gui = gui;
1830         set_tooltip("Display mask outline");
1831 }
1832
1833 CWindowMaskDrawBoundary::~CWindowMaskDrawBoundary()
1834 {
1835 }
1836
1837 int CWindowMaskDrawBoundary::handle_event()
1838 {
1839         ((CWindowMaskGUI*)gui)->boundary = get_value();
1840         gui->update();
1841         gui->update_preview();
1842         return 1;
1843 }
1844
1845
1846 CWindowMaskFeather::CWindowMaskFeather(MWindow *mwindow, CWindowToolGUI *gui, int x, int y)
1847  : BC_TumbleTextBox(gui, 0, -FEATHER_MAX, FEATHER_MAX, x, y, 64, 2)
1848 {
1849         this->mwindow = mwindow;
1850         this->gui = gui;
1851 }
1852 CWindowMaskFeather::~CWindowMaskFeather()
1853 {
1854 }
1855
1856 int CWindowMaskFeather::update(float v)
1857 {
1858         CWindowMaskGUI *mask_gui = (CWindowMaskGUI*)gui;
1859         mask_gui->feather_slider->update(v);
1860         return BC_TumbleTextBox::update(v);
1861 }
1862
1863 int CWindowMaskFeather::update_value(float v)
1864 {
1865         MaskAutos *autos;
1866         MaskAuto *keyframe;
1867         Track *track;
1868         MaskPoint *point;
1869         SubMask *mask;
1870 #ifdef USE_KEYFRAME_SPANNING
1871         int create_it = 0;
1872 #else
1873         int create_it = 1;
1874 #endif
1875
1876         mwindow->undo->update_undo_before(_("mask feather"), this);
1877
1878 // Get existing keyframe
1879         ((CWindowMaskGUI*)gui)->get_keyframe(track, autos, keyframe,
1880                         mask, point, create_it);
1881         if( track ) {
1882                 int gang = ((CWindowMaskGUI*)gui)->gang_feather->get_value();
1883 #ifdef USE_KEYFRAME_SPANNING
1884                 MaskAuto temp_keyframe(mwindow->edl, autos);
1885                 temp_keyframe.copy_data(keyframe);
1886                 keyframe = &temp_keyframe;
1887 #endif
1888                 float change = v - mask->feather;
1889                 int k = mwindow->edl->session->cwindow_mask;
1890                 int n = gang ? keyframe->masks.size() : k+1;
1891                 for( int i=gang? 0 : k; i<n; ++i ) {
1892                         SubMask *sub_mask = keyframe->get_submask(i);
1893                         float feather = sub_mask->feather + change;
1894                         bclamp(feather, -FEATHER_MAX, FEATHER_MAX);
1895                         sub_mask->feather = feather;
1896                 }
1897 #ifdef USE_KEYFRAME_SPANNING
1898                 autos->update_parameter(keyframe);
1899 #endif
1900                 gui->update_preview();
1901         }
1902
1903         mwindow->undo->update_undo_after(_("mask feather"), LOAD_AUTOMATION);
1904         return 1;
1905 }
1906
1907 int CWindowMaskFeather::handle_event()
1908 {
1909         float v = atof(get_text());
1910         CWindowMaskGUI * mask_gui = (CWindowMaskGUI*)gui;
1911         mask_gui->feather_slider->update(v);
1912         return mask_gui->feather->update_value(v);
1913 }
1914
1915 CWindowMaskFeatherSlider::CWindowMaskFeatherSlider(MWindow *mwindow,
1916                 CWindowToolGUI *gui, int x, int y, int w, float v)
1917  : BC_FSlider(x, y, 0, w, w, -FEATHER_MAX, FEATHER_MAX, v)
1918 {
1919         this->mwindow = mwindow;
1920         this->gui = gui;
1921         set_precision(0.01);
1922         timer = new Timer();
1923         stick = 0;
1924         last_v = 0;
1925 }
1926
1927 CWindowMaskFeatherSlider::~CWindowMaskFeatherSlider()
1928 {
1929         delete timer;
1930 }
1931
1932 int CWindowMaskFeatherSlider::handle_event()
1933 {
1934         float v = get_value();
1935         if( stick > 0 ) {
1936                 int64_t ms = timer->get_difference();
1937                 if( ms < 250 && --stick > 0 ) {
1938                         if( get_value() == 0 ) return 1;
1939                         update(v = 0);
1940                 }
1941                 else {
1942                         stick = 0;
1943                         last_v = v;
1944                 }
1945         }
1946         else if( (last_v>=0 && v<0) || (last_v<0 && v>=0) ) {
1947                 stick = 16;
1948                 v = 0;
1949         }
1950         else
1951                 last_v = v;
1952         timer->update();
1953         CWindowMaskGUI * mask_gui = (CWindowMaskGUI*)gui;
1954         mask_gui->feather->BC_TumbleTextBox::update(v);
1955         return mask_gui->feather->update_value(v);
1956 }
1957
1958 int CWindowMaskFeatherSlider::update(float v)
1959 {
1960         return BC_FSlider::update(v);
1961 }
1962
1963 CWindowMaskFade::CWindowMaskFade(MWindow *mwindow, CWindowToolGUI *gui, int x, int y)
1964  : BC_TumbleTextBox(gui, 0, -100.f, 100.f, x, y, 64, 2)
1965 {
1966         this->mwindow = mwindow;
1967         this->gui = gui;
1968 }
1969 CWindowMaskFade::~CWindowMaskFade()
1970 {
1971 }
1972
1973 int CWindowMaskFade::update(float v)
1974 {
1975         CWindowMaskGUI *mask_gui = (CWindowMaskGUI*)gui;
1976         mask_gui->fade_slider->update(v);
1977         return BC_TumbleTextBox::update(v);
1978 }
1979
1980 int CWindowMaskFade::update_value(float v)
1981 {
1982         MaskAutos *autos;
1983         MaskAuto *keyframe;
1984         Track *track;
1985         MaskPoint *point;
1986         SubMask *mask;
1987 #ifdef USE_KEYFRAME_SPANNING
1988         int create_it = 0;
1989 #else
1990         int create_it = 1;
1991 #endif
1992
1993         mwindow->undo->update_undo_before(_("mask fade"), this);
1994
1995 // Get existing keyframe
1996         ((CWindowMaskGUI*)gui)->get_keyframe(track, autos, keyframe,
1997                         mask, point, create_it);
1998         if( track ) {
1999                 int gang = ((CWindowMaskGUI*)gui)->gang_fader->get_value();
2000 #ifdef USE_KEYFRAME_SPANNING
2001                 MaskAuto temp_keyframe(mwindow->edl, autos);
2002                 temp_keyframe.copy_data(keyframe);
2003                 keyframe = &temp_keyframe;
2004 #endif
2005                 float change = v - mask->fader;
2006                 int k = mwindow->edl->session->cwindow_mask;
2007                 int n = gang ? keyframe->masks.size() : k+1;
2008                 for( int i=gang? 0 : k; i<n; ++i ) {
2009                         SubMask *sub_mask = keyframe->get_submask(i);
2010                         float fader = sub_mask->fader + change;
2011                         bclamp(fader, -100.f, 100.f);
2012                         sub_mask->fader = fader;
2013                 }
2014 #ifdef USE_KEYFRAME_SPANNING
2015                 autos->update_parameter(keyframe);
2016 #endif
2017                 gui->update_preview();
2018         }
2019
2020         mwindow->undo->update_undo_after(_("mask fade"), LOAD_AUTOMATION);
2021         return 1;
2022 }
2023
2024 int CWindowMaskFade::handle_event()
2025 {
2026         float v = atof(get_text());
2027         CWindowMaskGUI * mask_gui = (CWindowMaskGUI*)gui;
2028         mask_gui->fade_slider->update(v);
2029         return mask_gui->fade->update_value(v);
2030 }
2031
2032 CWindowMaskFadeSlider::CWindowMaskFadeSlider(MWindow *mwindow, CWindowToolGUI *gui,
2033                 int x, int y, int w)
2034  : BC_ISlider(x, y, 0, w, w, -200, 200, 0)
2035 {
2036         this->mwindow = mwindow;
2037         this->gui = gui;
2038         timer = new Timer();
2039         stick = 0;
2040         last_v = 0;
2041 }
2042
2043 CWindowMaskFadeSlider::~CWindowMaskFadeSlider()
2044 {
2045         delete timer;
2046 }
2047
2048 int CWindowMaskFadeSlider::handle_event()
2049 {
2050         float v = 100*get_value()/200;
2051         if( stick > 0 ) {
2052                 int64_t ms = timer->get_difference();
2053                 if( ms < 250 && --stick > 0 ) {
2054                         if( get_value() == 0 ) return 1;
2055                         update(v = 0);
2056                 }
2057                 else {
2058                         stick = 0;
2059                         last_v = v;
2060                 }
2061         }
2062         else if( (last_v>=0 && v<0) || (last_v<0 && v>=0) ) {
2063                 stick = 16;
2064                 v = 0;
2065         }
2066         else
2067                 last_v = v;
2068         timer->update();
2069         CWindowMaskGUI *mask_gui = (CWindowMaskGUI*)gui;
2070         mask_gui->fade->BC_TumbleTextBox::update(v);
2071         return mask_gui->fade->update_value(v);
2072 }
2073
2074 int CWindowMaskFadeSlider::update(int64_t v)
2075 {
2076         return BC_ISlider::update(200*v/100);
2077 }
2078
2079 CWindowMaskGangFader::CWindowMaskGangFader(MWindow *mwindow,
2080                 CWindowToolGUI *gui, int x, int y)
2081  : BC_Toggle(x, y, mwindow->theme->get_image_set("gangpatch_data"), 0)
2082 {
2083         this->mwindow = mwindow;
2084         this->gui = gui;
2085         set_tooltip(_("Gang fader"));
2086 }
2087
2088 CWindowMaskGangFader::~CWindowMaskGangFader()
2089 {
2090 }
2091
2092 int CWindowMaskGangFader::handle_event()
2093 {
2094         return 1;
2095 }
2096
2097 CWindowMaskBeforePlugins::CWindowMaskBeforePlugins(CWindowToolGUI *gui, int x, int y)
2098  : BC_CheckBox(x,
2099         y,
2100         1,
2101         _("Apply mask before plugins"))
2102 {
2103         this->gui = gui;
2104 }
2105
2106 int CWindowMaskBeforePlugins::handle_event()
2107 {
2108         Track *track;
2109         MaskAutos *autos;
2110         MaskAuto *keyframe;
2111         SubMask *mask;
2112         MaskPoint *point;
2113         ((CWindowMaskGUI*)gui)->get_keyframe(track, autos, keyframe, mask, point, 1);
2114
2115         if (keyframe) {
2116                 int v = get_value();
2117 #ifdef USE_KEYFRAME_SPANNING
2118                 MaskAuto temp_keyframe(gui->mwindow->edl, autos);
2119                 temp_keyframe.copy_data(keyframe);
2120                 temp_keyframe.apply_before_plugins = v;
2121                 autos->update_parameter(&temp_keyframe);
2122 #else
2123                 keyframe->apply_before_plugins = v;
2124 #endif
2125                 gui->update_preview();
2126         }
2127         return 1;
2128 }
2129
2130
2131 CWindowDisableOpenGLMasking::CWindowDisableOpenGLMasking(CWindowToolGUI *gui, int x, int y)
2132  : BC_CheckBox(x, y, 1, _("Disable OpenGL masking"))
2133 {
2134         this->gui = gui;
2135 }
2136
2137 int CWindowDisableOpenGLMasking::handle_event()
2138 {
2139         Track *track;
2140         MaskAutos *autos;
2141         MaskAuto *keyframe;
2142         SubMask *mask;
2143         MaskPoint *point;
2144         ((CWindowMaskGUI*)gui)->get_keyframe(track, autos, keyframe, mask, point, 1);
2145
2146         if( keyframe ) {
2147                 int v = get_value();
2148 #ifdef USE_KEYFRAME_SPANNING
2149                 MaskAuto temp_keyframe(gui->mwindow->edl, autos);
2150                 temp_keyframe.copy_data(keyframe);
2151                 temp_keyframe.disable_opengl_masking = v;
2152                 autos->update_parameter(&temp_keyframe);
2153 #else
2154                 keyframe->disable_opengl_masking = v;
2155 #endif
2156                 gui->update_preview();
2157         }
2158         return 1;
2159 }
2160
2161
2162 CWindowMaskClrMask::CWindowMaskClrMask(MWindow *mwindow,
2163                 CWindowMaskGUI *gui, int x, int y)
2164  : BC_Button(x, y, mwindow->theme->get_image_set("reset_button"))
2165 {
2166         this->mwindow = mwindow;
2167         this->gui = gui;
2168         set_tooltip(_("Delete all masks"));
2169 }
2170
2171 CWindowMaskClrMask::~CWindowMaskClrMask()
2172 {
2173 }
2174
2175 int CWindowMaskClrMask::calculate_w(MWindow *mwindow)
2176 {
2177         VFrame *vfrm = *mwindow->theme->get_image_set("reset_button");
2178         return vfrm->get_w();
2179 }
2180
2181 int CWindowMaskClrMask::handle_event()
2182 {
2183         MaskAutos *autos;
2184         MaskAuto *keyframe;
2185         Track *track;
2186         MaskPoint *point;
2187         SubMask *mask;
2188
2189 // Get existing keyframe
2190         ((CWindowMaskGUI*)gui)->get_keyframe(track, autos, keyframe, mask, point, 0);
2191
2192         if( track ) {
2193                 mwindow->undo->update_undo_before(_("del masks"), 0);
2194                 ((MaskAutos*)track->automation->autos[AUTOMATION_MASK])->clear_all();
2195                 gui->update();
2196                 gui->update_preview();
2197                 mwindow->undo->update_undo_after(_("del masks"), LOAD_AUTOMATION);
2198         }
2199
2200         return 1;
2201 }
2202
2203 CWindowMaskGangFeather::CWindowMaskGangFeather(MWindow *mwindow,
2204                 CWindowToolGUI *gui, int x, int y)
2205  : BC_Toggle(x, y, mwindow->theme->get_image_set("gangpatch_data"), 0)
2206 {
2207         this->mwindow = mwindow;
2208         this->gui = gui;
2209         set_tooltip(_("Gang feather"));
2210 }
2211
2212 CWindowMaskGangFeather::~CWindowMaskGangFeather()
2213 {
2214 }
2215
2216 int CWindowMaskGangFeather::handle_event()
2217 {
2218         return 1;
2219 }
2220
2221 CWindowMaskGUI::CWindowMaskGUI(MWindow *mwindow, CWindowTool *thread)
2222  : CWindowToolGUI(mwindow, thread,
2223         _(PROGRAM_NAME ": Mask"), 360, 500)
2224 {
2225         this->mwindow = mwindow;
2226         this->thread = thread;
2227         active_point = 0;
2228         fade = 0;
2229         feather = 0;
2230         focused = 0;
2231         markers = 1;
2232         boundary = 1;
2233 }
2234 CWindowMaskGUI::~CWindowMaskGUI()
2235 {
2236         lock_window("CWindowMaskGUI::~CWindowMaskGUI");
2237         delete active_point;
2238         delete fade;
2239         delete feather;
2240         unlock_window();
2241 }
2242
2243 void CWindowMaskGUI::create_objects()
2244 {
2245         int x = 10, y = 10, margin = mwindow->theme->widget_border;
2246         int clr_x = get_w()-x - CWindowMaskClrMask::calculate_w(mwindow);
2247         int del_x = clr_x-margin - CWindowMaskDelMask::calculate_w(this,_("Delete"));
2248         //MaskAuto *keyframe = 0;
2249         //Track *track = mwindow->cwindow->calculate_affected_track();
2250         //if(track)
2251         //      keyframe = (MaskAuto*)mwindow->cwindow->calculate_affected_auto(track->automation->autos[AUTOMATION_MASK], 0);
2252
2253         lock_window("CWindowMaskGUI::create_objects");
2254         BC_Title *title;
2255         add_subwindow(title = new BC_Title(x, y, _("Mask:")));
2256         int x1 = x + 70;
2257         name = new CWindowMaskName(mwindow, this, x1, y, "");
2258         name->create_objects();
2259         add_subwindow(clr_mask = new CWindowMaskClrMask(mwindow, this, clr_x, y));
2260         add_subwindow(del_mask = new CWindowMaskDelMask(mwindow, this, del_x, y));
2261         y += name->get_h() + margin;
2262
2263         int bw = 0, bh = 0;
2264         BC_CheckBox::calculate_extents(this, &bw, &bh);
2265         int bdx = bw + margin;
2266         int x2 = x;
2267         for( int i=0; i<SUBMASKS; x2+=bdx, ++i ) {
2268                 int v = i == mwindow->edl->session->cwindow_mask ? 1 : 0;
2269                 mask_buttons[i] = new CWindowMaskButton(mwindow, this, x2, y, i, v);
2270                 add_subwindow(mask_buttons[i]);
2271         }
2272         x2 += margin;
2273         add_subwindow(mask_thumbler = new CWindowMaskThumbler(mwindow, this, x2, y));
2274         y += bh + margin;
2275         x2 = x;
2276         for( int i=0; i<SUBMASKS; x2+=bdx, ++i ) {
2277                 char text[BCSTRLEN];  sprintf(text, "%d", i);
2278                 int tx = (bw - get_text_width(MEDIUMFONT, text)) / 2;
2279                 mask_blabels[i] = new BC_Title(x2+tx, y, text);
2280                 add_subwindow(mask_blabels[i]);
2281         }
2282         y += bh + 2*margin;
2283
2284         add_subwindow(title = new BC_Title(x, y, _("Fade:")));
2285         fade = new CWindowMaskFade(mwindow, this, x1, y);
2286         fade->create_objects();
2287         x2 = x1 + fade->get_w() + 2*margin;
2288         int w2 = clr_x-2*margin - x2;
2289         add_subwindow(fade_slider = new CWindowMaskFadeSlider(mwindow, this, x2, y, w2));
2290         add_subwindow(gang_fader = new CWindowMaskGangFader(mwindow, this, clr_x, y));
2291         y += fade->get_h() + margin;
2292         add_subwindow(title = new BC_Title(x, y, _("Feather:")));
2293         feather = new CWindowMaskFeather(mwindow, this, x1, y);
2294         feather->create_objects();
2295         w2 = clr_x - 2*margin - x2;
2296         feather_slider = new CWindowMaskFeatherSlider(mwindow, this, x2, y, w2, 0);
2297         add_subwindow(feather_slider);
2298         add_subwindow(gang_feather = new CWindowMaskGangFeather(mwindow, this, clr_x, y));
2299         y += feather->get_h() + 3*margin;
2300
2301         add_subwindow(title = new BC_Title(x, y, _("Point:")));
2302         active_point = new CWindowMaskAffectedPoint(mwindow, this, x1, y);
2303         active_point->create_objects();
2304         add_subwindow(del_point = new CWindowMaskDelPoint(mwindow, this, del_x, y));
2305         y += active_point->get_h() + margin;
2306         add_subwindow(title = new BC_Title(x, y, "X:"));
2307         this->x = new CWindowCoord(this, x1, y, (float)0.0);
2308         this->x->create_objects();
2309         add_subwindow(draw_markers = new CWindowMaskDrawMarkers(mwindow, this, del_x, y));
2310         y += this->x->get_h() + margin;
2311         add_subwindow(title = new BC_Title(x, y, "Y:"));
2312         this->y = new CWindowCoord(this, x1, y, (float)0.0);
2313         this->y->create_objects();
2314         add_subwindow(draw_boundary = new CWindowMaskDrawBoundary(mwindow, this, del_x, y));
2315         y += this->y->get_h() + margin;
2316         BC_Bar *bar;
2317         add_subwindow(bar = new BC_Bar(x, y, get_w()-2*x));
2318         y += bar->get_h() + margin;
2319
2320         add_subwindow(title = new BC_Title(x, y, "X:"));
2321         focus_x = new CWindowCoord(this, x1, y, (float)0.0);
2322         focus_x->create_objects();
2323         add_subwindow(focus = new CWindowMaskFocus(mwindow, this, del_x, y));
2324         y += focus_x->get_h() + margin;
2325         add_subwindow(title = new BC_Title(x, y, "Y:"));
2326         focus_y = new CWindowCoord(this, x1, y, (float)0.0);
2327         focus_y->create_objects();
2328         y += focus_x->get_h() + margin;
2329         add_subwindow(this->apply_before_plugins = new CWindowMaskBeforePlugins(this, 10, y));
2330         y += this->apply_before_plugins->get_h();
2331         add_subwindow(this->disable_opengl_masking = new CWindowDisableOpenGLMasking(this, 10, y));
2332         y += this->disable_opengl_masking->get_h() + margin;
2333         add_subwindow(bar = new BC_Bar(x, y, get_w()-2*x));
2334         y += bar->get_h() + margin;
2335
2336         y += margin;
2337         add_subwindow(title = new BC_Title(x, y, _(
2338                 "Shift+LMB: move an end point\n"
2339                 "Ctrl+LMB: move a control point\n"
2340                 "Alt+LMB: to drag translate the mask\n"
2341                 "Shift+Key Delete to delete the mask\n"
2342                 "Wheel Up/Dn: rotate around pointer\n"
2343                 "Shift+Wheel Up/Dn: scale around pointer\n"
2344                 "Shift+MMB: Toggle focus center at pointer")));
2345         update();
2346         unlock_window();
2347 }
2348
2349 void CWindowMaskGUI::get_keyframe(Track* &track,
2350         MaskAutos* &autos,
2351         MaskAuto* &keyframe,
2352         SubMask* &mask,
2353         MaskPoint* &point,
2354         int create_it)
2355 {
2356         autos = 0;
2357         keyframe = 0;
2358
2359         track = mwindow->cwindow->calculate_affected_track();
2360         if(track)
2361         {
2362                 autos = (MaskAutos*)track->automation->autos[AUTOMATION_MASK];
2363                 keyframe = (MaskAuto*)mwindow->cwindow->calculate_affected_auto(
2364                         autos,
2365                         create_it);
2366         }
2367
2368         if(keyframe)
2369                 mask = keyframe->get_submask(mwindow->edl->session->cwindow_mask);
2370         else
2371                 mask = 0;
2372
2373         point = 0;
2374         if(keyframe)
2375         {
2376                 if(mwindow->cwindow->gui->affected_point < mask->points.total &&
2377                         mwindow->cwindow->gui->affected_point >= 0)
2378                 {
2379                         point = mask->points.values[mwindow->cwindow->gui->affected_point];
2380                 }
2381         }
2382 }
2383
2384 void CWindowMaskGUI::update()
2385 {
2386         Track *track;
2387         MaskAutos *autos;
2388         MaskAuto *keyframe;
2389         SubMask *mask;
2390         MaskPoint *point;
2391 //printf("CWindowMaskGUI::update 1\n");
2392         get_keyframe(track, autos, keyframe, mask, point, 0);
2393
2394         name->update_items(keyframe);
2395         const char *text = "";
2396         int sz = !keyframe ? 0 : keyframe->masks.size();
2397         int k = mwindow->edl->session->cwindow_mask;
2398         if( k >= 0 && k < sz )
2399                 text = keyframe->masks[k]->name;
2400         name->update(text);
2401         update_buttons(keyframe, k);
2402         if( point ) {
2403                 x->update(point->x);
2404                 y->update(point->y);
2405         }
2406         if( track ) {
2407                 double position = mwindow->edl->local_session->get_selectionstart(1);
2408                 int64_t position_i = track->to_units(position, 0);
2409                 feather->update(autos->get_feather(position_i, k, PLAY_FORWARD));
2410                 fade->update(autos->get_fader(position_i, k, PLAY_FORWARD));
2411         }
2412         if( keyframe ) {
2413                 apply_before_plugins->update(keyframe->apply_before_plugins);
2414                 disable_opengl_masking->update(keyframe->disable_opengl_masking);
2415         }
2416         active_point->update((int64_t)mwindow->cwindow->gui->affected_point);
2417 }
2418
2419 void CWindowMaskGUI::handle_event()
2420 {
2421         Track *track;
2422         MaskAuto *keyframe;
2423         MaskAutos *autos;
2424         SubMask *mask;
2425         MaskPoint *point;
2426         get_keyframe(track, autos, keyframe, mask, point, 0);
2427
2428         mwindow->undo->update_undo_before(_("mask point"), this);
2429
2430         if(point)
2431         {
2432 #ifdef USE_KEYFRAME_SPANNING
2433 // Create temp keyframe
2434                 MaskAuto temp_keyframe(mwindow->edl, autos);
2435                 temp_keyframe.copy_data(keyframe);
2436 // Get affected point in temp keyframe
2437                 mask = temp_keyframe.get_submask(mwindow->edl->session->cwindow_mask);
2438                 if(mwindow->cwindow->gui->affected_point < mask->points.total &&
2439                         mwindow->cwindow->gui->affected_point >= 0)
2440                 {
2441                         point = mask->points.values[mwindow->cwindow->gui->affected_point];
2442                 }
2443
2444                 if(point)
2445                 {
2446                         point->x = atof(x->get_text());
2447                         point->y = atof(y->get_text());
2448 // Commit to spanned keyframes
2449                         autos->update_parameter(&temp_keyframe);
2450                 }
2451 #else
2452                 point->x = atof(x->get_text());
2453                 point->y = atof(y->get_text());
2454 #endif
2455         }
2456
2457         update_preview();
2458         mwindow->undo->update_undo_after(_("mask point"), LOAD_AUTOMATION);
2459 }
2460
2461 void CWindowMaskGUI::update_preview()
2462 {
2463         unlock_window();
2464         CWindowGUI *cgui = mwindow->cwindow->gui;
2465         cgui->lock_window("CWindowMaskGUI::update_preview");
2466         cgui->sync_parameters(CHANGE_PARAMS, 0, 1);
2467         cgui->unlock_window();
2468         lock_window("CWindowMaskGUI::update_preview");
2469 }
2470
2471 void CWindowMaskGUI::set_focused(int v, float cx, float cy)
2472 {
2473         focus_x->update(cx);
2474         focus_y->update(cy);
2475         focus->update(focused = v);
2476 }
2477
2478 void CWindowMaskGUI::update_buttons(MaskAuto *keyframe, int k)
2479 {
2480         int text_color = get_resources()->default_text_color;
2481         int high_color = get_resources()->button_highlighted;
2482         for( int i=0; i<SUBMASKS; ++i ) {
2483                 int color = text_color;
2484                 if( keyframe ) {
2485                         SubMask *submask = keyframe->get_submask(i);
2486                         if( submask && submask->points.size() )
2487                                 color = high_color;
2488                 }
2489                 mask_blabels[i]->set_color(color);
2490                 mask_buttons[i]->update(i==k ? 1 : 0);
2491         }
2492 }
2493
2494 CWindowRulerGUI::CWindowRulerGUI(MWindow *mwindow, CWindowTool *thread)
2495  : CWindowToolGUI(mwindow, thread, _(PROGRAM_NAME ": Ruler"), 320, 240)
2496 {
2497 }
2498
2499 CWindowRulerGUI::~CWindowRulerGUI()
2500 {
2501 }
2502
2503 void CWindowRulerGUI::create_objects()
2504 {
2505         int x = 10, y = 10, x1 = 100;
2506         BC_Title *title;
2507
2508         lock_window("CWindowRulerGUI::create_objects");
2509         add_subwindow(title = new BC_Title(x, y, _("Current:")));
2510         add_subwindow(current = new BC_TextBox(x1, y, 200, 1, ""));
2511         y += title->get_h() + 5;
2512         add_subwindow(title = new BC_Title(x, y, _("Point 1:")));
2513         add_subwindow(point1 = new BC_TextBox(x1, y, 200, 1, ""));
2514         y += title->get_h() + 5;
2515         add_subwindow(title = new BC_Title(x, y, _("Point 2:")));
2516         add_subwindow(point2 = new BC_TextBox(x1, y, 200, 1, ""));
2517         y += title->get_h() + 5;
2518         add_subwindow(title = new BC_Title(x, y, _("Deltas:")));
2519         add_subwindow(deltas = new BC_TextBox(x1, y, 200, 1, ""));
2520         y += title->get_h() + 5;
2521         add_subwindow(title = new BC_Title(x, y, _("Distance:")));
2522         add_subwindow(distance = new BC_TextBox(x1, y, 200, 1, ""));
2523         y += title->get_h() + 5;
2524         add_subwindow(title = new BC_Title(x, y, _("Angle:")));
2525         add_subwindow(angle = new BC_TextBox(x1, y, 200, 1, ""));
2526         y += title->get_h() + 10;
2527         char string[BCTEXTLEN];
2528         sprintf(string,
2529                  _("Press Ctrl to lock ruler to the\nnearest 45%c%c angle."),
2530                 0xc2, 0xb0); // degrees utf
2531         add_subwindow(title = new BC_Title(x,
2532                 y,
2533                 string));
2534         y += title->get_h() + 10;
2535         sprintf(string, _("Press Alt to translate the ruler."));
2536         add_subwindow(title = new BC_Title(x,
2537                 y,
2538                 string));
2539         update();
2540         unlock_window();
2541 }
2542
2543 void CWindowRulerGUI::update()
2544 {
2545         char string[BCTEXTLEN];
2546         int cx = mwindow->session->cwindow_output_x;
2547         int cy = mwindow->session->cwindow_output_y;
2548         sprintf(string, "%d, %d", cx, cy);
2549         current->update(string);
2550         double x1 = mwindow->edl->session->ruler_x1;
2551         double y1 = mwindow->edl->session->ruler_y1;
2552         sprintf(string, "%.0f, %.0f", x1, y1);
2553         point1->update(string);
2554         double x2 = mwindow->edl->session->ruler_x2;
2555         double y2 = mwindow->edl->session->ruler_y2;
2556         sprintf(string, "%.0f, %.0f", x2, y2);
2557         point2->update(string);
2558         double dx = x2 - x1, dy = y2 - y1;
2559         sprintf(string, "%s%.0f, %s%.0f", (dx>=0? "+":""), dx, (dy>=0? "+":""), dy);
2560         deltas->update(string);
2561         double d = sqrt(dx*dx + dy*dy);
2562         sprintf(string, _("%0.01f pixels"), d);
2563         distance->update(string);
2564         double a = d > 0 ? (atan2(-dy, dx) * 180/M_PI) : 0.;
2565         sprintf(string, "%0.02f %c%c", a, 0xc2, 0xb0);
2566         angle->update(string);
2567 }
2568
2569 void CWindowRulerGUI::handle_event()
2570 {
2571 }
2572
2573
2574
2575