yuv xfer error for ffmpeg, improve ffmpeg filters for opts, motion layout
[goodguy/history.git] / cinelerra-5.1 / plugins / motion / motionwindow.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2012 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include "bcdisplayinfo.h"
23 #include "clip.h"
24 #include "edl.h"
25 #include "fonts.h"
26 #include "edlsession.h"
27 #include "language.h"
28 #include "motion.h"
29 #include "motionscan.h"
30 #include "motionwindow.h"
31 #include "mwindow.h"
32 #include "pluginserver.h"
33
34 MotionWindow::MotionWindow(MotionMain *plugin)
35  : PluginClientWindow(plugin, 800, 660, 800, 660, 0)
36 {
37         this->plugin = plugin;
38 }
39
40 MotionWindow::~MotionWindow()
41 {
42 }
43
44 void MotionWindow::create_objects()
45 {
46         int x = 10, y = 10;
47         int x1 = x, x2 = get_w() / 2;
48         BC_Title *title;
49
50         add_subwindow(global = new MotionGlobal(plugin, this, x1, y));
51         add_subwindow(rotate = new MotionRotate(plugin, this, x2, y));
52         y += 50;
53
54         add_subwindow(title = new BC_Title(x1, y,
55                 _("Translation search radius:\n(W/H Percent of image)")));
56         add_subwindow(global_range_w = new GlobalRange(plugin,
57                 x1 + title->get_w() + 10, y,
58                 &plugin->config.global_range_w));
59         add_subwindow(global_range_h = new GlobalRange(plugin,
60                 x1 + title->get_w() + 10 + global_range_w->get_w(), y,
61                 &plugin->config.global_range_h));
62
63         add_subwindow(title = new BC_Title(x2, y,
64                 _("Rotation search radius:\n(Degrees)")));
65         add_subwindow(rotation_range = new RotationRange(plugin,
66                 x2 + title->get_w() + 10, y));
67
68         y += 50;
69         add_subwindow(title = new BC_Title(x1, y,
70                 _("Translation block size:\n(W/H Percent of image)")));
71         add_subwindow(global_block_w =
72                 new BlockSize(plugin, x1 + title->get_w() + 10, y,
73                 &plugin->config.global_block_w));
74         add_subwindow(global_block_h =
75                 new BlockSize(plugin, x1 + title->get_w() + 10 +
76                         global_block_w->get_w(), y,
77                         &plugin->config.global_block_h));
78
79 //      add_subwindow(title = new BC_Title(x2,
80 //              y,
81 //              _("Rotation block size:\n(W/H Percent of image)")));
82 //      add_subwindow(rotation_block_w = new BlockSize(plugin,
83 //              x2 + title->get_w() + 10,
84 //              y,
85 //              &plugin->config.rotation_block_w));
86 //      add_subwindow(rotation_block_h = new BlockSize(plugin,
87 //              x2 + title->get_w() + 10 + rotation_block_w->get_w(),
88 //              y,
89 //              &plugin->config.rotation_block_h));
90
91         y += 50;
92         add_subwindow(title = new BC_Title(x1, y, _("Translation search steps:")));
93         add_subwindow(global_search_positions =
94                 new GlobalSearchPositions(plugin, x1 + title->get_w() + 10, y, 80));
95         global_search_positions->create_objects();
96
97         add_subwindow(title = new BC_Title(x2, y, _("Rotation search steps:")));
98         add_subwindow(rotation_search_positions =
99                 new RotationSearchPositions(plugin, x2 + title->get_w() + 10, y, 80));
100         rotation_search_positions->create_objects();
101
102         y += 50;
103         add_subwindow(title = new BC_Title(x, y, _("Translation direction:")));
104         add_subwindow(track_direction = new TrackDirection(plugin,
105                 this,
106                 x + title->get_w() + 10,
107                 y));
108         track_direction->create_objects();
109
110         add_subwindow(title = new BC_Title(x2, y, _("Tracking file:")));
111         add_subwindow(tracking_file = new MotionTrackingFile(plugin,
112                 plugin->config.tracking_file, this, x2+title->get_w() + 20, y));
113
114         y += 40;
115         add_subwindow(title = new BC_Title(x, y + 10, _("Block X:")));
116         add_subwindow(block_x =
117                 new MotionBlockX(plugin, this, x + title->get_w() + 10, y));
118         add_subwindow(block_x_text =
119                 new MotionBlockXText(plugin, this,
120                         x + title->get_w() + 10 + block_x->get_w() + 10, y + 10));
121
122         add_subwindow(title = new BC_Title(x2, y, _("Rotation center:")));
123         add_subwindow(rotation_center =
124                 new RotationCenter(plugin, x2 + title->get_w() + 10, y));
125
126         int y1 = y;
127         y += 50;
128         add_subwindow(title = new BC_Title(x2, y + 10, _("Maximum angle offset:")));
129         add_subwindow(rotate_magnitude =
130                 new MotionRMagnitude(plugin, x2 + title->get_w() + 10, y));
131
132         y += 40;
133         add_subwindow(title = new BC_Title(x2, y + 10, _("Rotation settling speed:")));
134         add_subwindow(rotate_return_speed =
135                 new MotionRReturnSpeed(plugin, x2 + title->get_w() + 10, y));
136         y += 40;
137         add_subwindow(vectors = new MotionDrawVectors(plugin, this, x2, y));
138
139         y = y1 + 60;
140         add_subwindow(title = new BC_Title(x, y + 10, _("Block Y:")));
141         add_subwindow(block_y =
142                 new MotionBlockY(plugin, this, x + title->get_w() + 10, y));
143         add_subwindow(block_y_text =
144                 new MotionBlockYText(plugin, this,
145                         x + title->get_w() + 10 + block_y->get_w() + 10, y + 10));
146
147         y += 50;
148         add_subwindow(title = new BC_Title(x, y + 10, _("Maximum absolute offset:")));
149         add_subwindow(magnitude = new MotionMagnitude(plugin,
150                 x + title->get_w() + 10,
151                 y));
152
153         y += 40;
154         add_subwindow(title = new BC_Title(x, y + 10, _("Motion settling speed:")));
155         add_subwindow(return_speed =
156                 new MotionReturnSpeed(plugin, x + title->get_w() + 10, y));
157
158         y += 40;
159         add_subwindow(track_single =
160                 new TrackSingleFrame(plugin, this, x, y));
161         y += 20;
162         add_subwindow(track_previous =
163                 new TrackPreviousFrame(plugin, this, x, y));
164         y += 20;
165         add_subwindow(previous_same =
166                 new PreviousFrameSameBlock(plugin, this, x, y));
167
168         y += 40;
169         x1 = x;  y1 = y;
170         add_subwindow(title =
171                 new BC_Title(x1=x2, y1, _("Frame number:")));
172         add_subwindow(track_frame_number =
173                 new TrackFrameNumber(plugin, this, x1 += title->get_w(), y1));
174         add_subwindow(addtrackedframeoffset =
175                 new AddTrackedFrameOffset(plugin, this, x1=x2, y1+=track_frame_number->get_h()));
176         int pef = client->server->mwindow->edl->session->video_every_frame;
177         add_subwindow(pef_title = new BC_Title(x1=x2, y1+=addtrackedframeoffset->get_h() + 5,
178                 !pef ?  _("For best results\n"
179                                 " Set: Play every frame\n"
180                                 " Preferences-> Playback-> Video Out") :
181                         _("Currently using: Play every frame"), MEDIUMFONT,
182                 !pef ? RED : GREEN));
183
184         add_subwindow(title = new BC_Title(x, y, _("Master layer:")));
185         add_subwindow(master_layer = new MasterLayer(plugin,
186                 this, x + title->get_w() + 10, y));
187         master_layer->create_objects();
188         y += 30;
189
190         add_subwindow(title = new BC_Title(x, y, _("Action:")));
191         add_subwindow(action_type = new ActionType(plugin,
192                 this, x + title->get_w() + 10, y));
193         action_type->create_objects();
194         y += 30;
195
196         add_subwindow(title = new BC_Title(x, y, _("Calculation:")));
197         add_subwindow(tracking_type = new TrackingType(plugin,
198                 this, x + title->get_w() + 10, y));
199         tracking_type->create_objects();
200
201         show_window(1);
202 }
203
204 void MotionWindow::update_mode()
205 {
206         global_range_w->update(plugin->config.global_range_w,
207                 MIN_RADIUS, MAX_RADIUS);
208         global_range_h->update(plugin->config.global_range_h,
209                 MIN_RADIUS, MAX_RADIUS);
210         rotation_range->update(plugin->config.rotation_range,
211                 MIN_ROTATION, MAX_ROTATION);
212         vectors->update(plugin->config.draw_vectors);
213         tracking_file->update(plugin->config.tracking_file);
214         global->update(plugin->config.global);
215         rotate->update(plugin->config.rotate);
216         addtrackedframeoffset->update(plugin->config.addtrackedframeoffset);
217 }
218
219 MotionTrackingFile::MotionTrackingFile(MotionMain *plugin,
220         const char *filename, MotionWindow *gui, int x, int y)
221  : BC_TextBox(x, y, 150, 1, filename)
222 {
223         this->plugin = plugin;
224         this->gui = gui;
225 };
226
227 int MotionTrackingFile::handle_event()
228 {
229         strcpy(plugin->config.tracking_file, get_text());
230         plugin->send_configure_change();
231         return 1;
232 }
233
234
235 GlobalRange::GlobalRange(MotionMain *plugin,
236         int x, int y, int *value)
237  : BC_IPot(x, y, (int64_t)*value,
238         (int64_t)MIN_RADIUS, (int64_t)MAX_RADIUS)
239 {
240         this->plugin = plugin;
241         this->value = value;
242 }
243
244
245 int GlobalRange::handle_event()
246 {
247         *value = (int)get_value();
248         plugin->send_configure_change();
249         return 1;
250 }
251
252
253
254
255 RotationRange::RotationRange(MotionMain *plugin, int x, int y)
256  : BC_IPot(x, y, (int64_t)plugin->config.rotation_range,
257         (int64_t)MIN_ROTATION, (int64_t)MAX_ROTATION)
258 {
259         this->plugin = plugin;
260 }
261
262
263 int RotationRange::handle_event()
264 {
265         plugin->config.rotation_range = (int)get_value();
266         plugin->send_configure_change();
267         return 1;
268 }
269
270
271 RotationCenter::RotationCenter(MotionMain *plugin, int x, int y)
272  : BC_IPot(x, y, (int64_t)plugin->config.rotation_center,
273         (int64_t)-MAX_ROTATION, (int64_t)MAX_ROTATION)
274 {
275         this->plugin = plugin;
276 }
277
278
279 int RotationCenter::handle_event()
280 {
281         plugin->config.rotation_center = (int)get_value();
282         plugin->send_configure_change();
283         return 1;
284 }
285
286
287 BlockSize::BlockSize(MotionMain *plugin,
288         int x,
289         int y,
290         int *value)
291  : BC_IPot(x,
292                 y,
293                 (int64_t)*value,
294                 (int64_t)MIN_BLOCK,
295                 (int64_t)MAX_BLOCK)
296 {
297         this->plugin = plugin;
298         this->value = value;
299 }
300
301
302 int BlockSize::handle_event()
303 {
304         *value = (int)get_value();
305         plugin->send_configure_change();
306         return 1;
307 }
308
309
310 GlobalSearchPositions::GlobalSearchPositions(MotionMain *plugin,
311         int x, int y, int w)
312  : BC_PopupMenu(x, y, w, "", 1)
313 {
314         this->plugin = plugin;
315 }
316 void GlobalSearchPositions::create_objects()
317 {
318         add_item(new BC_MenuItem("16"));
319         add_item(new BC_MenuItem("32"));
320         add_item(new BC_MenuItem("64"));
321         add_item(new BC_MenuItem("128"));
322         add_item(new BC_MenuItem("256"));
323         add_item(new BC_MenuItem("512"));
324         add_item(new BC_MenuItem("1024"));
325         add_item(new BC_MenuItem("2048"));
326         add_item(new BC_MenuItem("4096"));
327         add_item(new BC_MenuItem("8192"));
328         add_item(new BC_MenuItem("16384"));
329         add_item(new BC_MenuItem("32768"));
330         add_item(new BC_MenuItem("65536"));
331         add_item(new BC_MenuItem("131072"));
332         char string[BCTEXTLEN];
333         sprintf(string, "%d", plugin->config.global_positions);
334         set_text(string);
335 }
336
337 int GlobalSearchPositions::handle_event()
338 {
339         plugin->config.global_positions = atoi(get_text());
340         plugin->send_configure_change();
341         return 1;
342 }
343
344
345 RotationSearchPositions::RotationSearchPositions(MotionMain *plugin,
346         int x, int y, int w)
347  : BC_PopupMenu(x, y, w, "", 1)
348 {
349         this->plugin = plugin;
350 }
351 void RotationSearchPositions::create_objects()
352 {
353         add_item(new BC_MenuItem("4"));
354         add_item(new BC_MenuItem("8"));
355         add_item(new BC_MenuItem("16"));
356         add_item(new BC_MenuItem("32"));
357         char string[BCTEXTLEN];
358         sprintf(string, "%d", plugin->config.rotate_positions);
359         set_text(string);
360 }
361
362 int RotationSearchPositions::handle_event()
363 {
364         plugin->config.rotate_positions = atoi(get_text());
365         plugin->send_configure_change();
366         return 1;
367 }
368
369
370 MotionMagnitude::MotionMagnitude(MotionMain *plugin, int x, int y)
371  : BC_IPot(x, y,
372         (int64_t)plugin->config.magnitude, (int64_t)0, (int64_t)100)
373 {
374         this->plugin = plugin;
375 }
376
377 int MotionMagnitude::handle_event()
378 {
379         plugin->config.magnitude = (int)get_value();
380         plugin->send_configure_change();
381         return 1;
382 }
383
384
385 MotionReturnSpeed::MotionReturnSpeed(MotionMain *plugin, int x, int y)
386  : BC_IPot(x, y,
387         (int64_t)plugin->config.return_speed, (int64_t)0, (int64_t)100)
388 {
389         this->plugin = plugin;
390 }
391
392 int MotionReturnSpeed::handle_event()
393 {
394         plugin->config.return_speed = (int)get_value();
395         plugin->send_configure_change();
396         return 1;
397 }
398
399
400
401 AddTrackedFrameOffset::AddTrackedFrameOffset(MotionMain *plugin,
402         MotionWindow *gui, int x, int y)
403  : BC_CheckBox(x, y, plugin->config.addtrackedframeoffset,
404         _("Add (loaded) offset from tracked frame"))
405 {
406         this->plugin = plugin;
407         this->gui = gui;
408 }
409
410 int AddTrackedFrameOffset::handle_event()
411 {
412         plugin->config.addtrackedframeoffset = get_value();
413         plugin->send_configure_change();
414         return 1;
415 }
416
417
418 MotionRMagnitude::MotionRMagnitude(MotionMain *plugin, int x, int y)
419  : BC_IPot(x, y,
420         (int64_t)plugin->config.rotate_magnitude, (int64_t)0, (int64_t)90)
421 {
422         this->plugin = plugin;
423 }
424
425 int MotionRMagnitude::handle_event()
426 {
427         plugin->config.rotate_magnitude = (int)get_value();
428         plugin->send_configure_change();
429         return 1;
430 }
431
432
433
434 MotionRReturnSpeed::MotionRReturnSpeed(MotionMain *plugin, int x, int y)
435  : BC_IPot(x, y,
436         (int64_t)plugin->config.rotate_return_speed, (int64_t)0, (int64_t)100)
437 {
438         this->plugin = plugin;
439 }
440
441 int MotionRReturnSpeed::handle_event()
442 {
443         plugin->config.rotate_return_speed = (int)get_value();
444         plugin->send_configure_change();
445         return 1;
446 }
447
448
449 MotionGlobal::MotionGlobal(MotionMain *plugin,
450         MotionWindow *gui, int x, int y)
451  : BC_CheckBox(x, y, plugin->config.global, _("Track translation"))
452 {
453         this->plugin = plugin;
454         this->gui = gui;
455 }
456
457 int MotionGlobal::handle_event()
458 {
459         plugin->config.global = get_value();
460         plugin->send_configure_change();
461         return 1;
462 }
463
464 MotionRotate::MotionRotate(MotionMain *plugin,
465         MotionWindow *gui, int x, int y)
466  : BC_CheckBox(x, y, plugin->config.rotate, _("Track rotation"))
467 {
468         this->plugin = plugin;
469         this->gui = gui;
470 }
471
472 int MotionRotate::handle_event()
473 {
474         plugin->config.rotate = get_value();
475         plugin->send_configure_change();
476         return 1;
477 }
478
479
480 MotionBlockX::MotionBlockX(MotionMain *plugin,
481         MotionWindow *gui, int x, int y)
482  : BC_FPot(x, y, plugin->config.block_x, (float)0, (float)100)
483 {
484         this->plugin = plugin;
485         this->gui = gui;
486 }
487
488 int MotionBlockX::handle_event()
489 {
490         plugin->config.block_x = get_value();
491         gui->block_x_text->update((float)plugin->config.block_x);
492         plugin->send_configure_change();
493         return 1;
494 }
495
496
497 MotionBlockY::MotionBlockY(MotionMain *plugin,
498         MotionWindow *gui,
499         int x,
500         int y)
501  : BC_FPot(x,
502         y,
503         (float)plugin->config.block_y,
504         (float)0,
505         (float)100)
506 {
507         this->plugin = plugin;
508         this->gui = gui;
509 }
510
511 int MotionBlockY::handle_event()
512 {
513         plugin->config.block_y = get_value();
514         gui->block_y_text->update((float)plugin->config.block_y);
515         plugin->send_configure_change();
516         return 1;
517 }
518
519 MotionBlockXText::MotionBlockXText(MotionMain *plugin,
520         MotionWindow *gui, int x, int y)
521  : BC_TextBox(x, y, 75, 1, (float)plugin->config.block_x)
522 {
523         this->plugin = plugin;
524         this->gui = gui;
525         set_precision(4);
526 }
527
528 int MotionBlockXText::handle_event()
529 {
530         plugin->config.block_x = atof(get_text());
531         gui->block_x->update(plugin->config.block_x);
532         plugin->send_configure_change();
533         return 1;
534 }
535
536
537
538
539 MotionBlockYText::MotionBlockYText(MotionMain *plugin,
540         MotionWindow *gui, int x, int y)
541  : BC_TextBox(x, y, 75, 1, (float)plugin->config.block_y)
542 {
543         this->plugin = plugin;
544         this->gui = gui;
545         set_precision(4);
546 }
547
548 int MotionBlockYText::handle_event()
549 {
550         plugin->config.block_y = atof(get_text());
551         gui->block_y->update(plugin->config.block_y);
552         plugin->send_configure_change();
553         return 1;
554 }
555
556
557 MotionDrawVectors::MotionDrawVectors(MotionMain *plugin,
558         MotionWindow *gui, int x, int y)
559  : BC_CheckBox(x,
560         y,
561         plugin->config.draw_vectors,
562         _("Draw vectors"))
563 {
564         this->gui = gui;
565         this->plugin = plugin;
566 }
567
568 int MotionDrawVectors::handle_event()
569 {
570         plugin->config.draw_vectors = get_value();
571         plugin->send_configure_change();
572         return 1;
573 }
574
575
576 TrackSingleFrame::TrackSingleFrame(MotionMain *plugin,
577         MotionWindow *gui,
578         int x,
579         int y)
580  : BC_Radial(x,
581         y,
582         plugin->config.tracking_object == MotionScan::TRACK_SINGLE,
583         _("Track single frame"))
584 {
585         this->plugin = plugin;
586         this->gui = gui;
587 }
588
589 int TrackSingleFrame::handle_event()
590 {
591         plugin->config.tracking_object = MotionScan::TRACK_SINGLE;
592         gui->track_previous->update(0);
593         gui->previous_same->update(0);
594         gui->track_frame_number->enable();
595         plugin->send_configure_change();
596         return 1;
597 }
598
599 TrackFrameNumber::TrackFrameNumber(MotionMain *plugin,
600         MotionWindow *gui,
601         int x,
602         int y)
603  : BC_TextBox(x, y, 100, 1, plugin->config.track_frame)
604 {
605         this->plugin = plugin;
606         this->gui = gui;
607         if(plugin->config.tracking_object != MotionScan::TRACK_SINGLE) disable();
608 }
609
610 int TrackFrameNumber::handle_event()
611 {
612         plugin->config.track_frame = atol(get_text());
613         plugin->send_configure_change();
614         return 1;
615 }
616
617
618 TrackPreviousFrame::TrackPreviousFrame(MotionMain *plugin,
619         MotionWindow *gui,
620         int x,
621         int y)
622  : BC_Radial(x,
623         y,
624         plugin->config.tracking_object == MotionScan::TRACK_PREVIOUS,
625         _("Track previous frame"))
626 {
627         this->plugin = plugin;
628         this->gui = gui;
629 }
630 int TrackPreviousFrame::handle_event()
631 {
632         plugin->config.tracking_object = MotionScan::TRACK_PREVIOUS;
633         gui->track_single->update(0);
634         gui->previous_same->update(0);
635         gui->track_frame_number->disable();
636         plugin->send_configure_change();
637         return 1;
638 }
639
640
641 PreviousFrameSameBlock::PreviousFrameSameBlock(MotionMain *plugin,
642         MotionWindow *gui,
643         int x,
644         int y)
645  : BC_Radial(x,
646         y,
647         plugin->config.tracking_object == MotionScan::PREVIOUS_SAME_BLOCK,
648         _("Previous frame same block"))
649 {
650         this->plugin = plugin;
651         this->gui = gui;
652 }
653 int PreviousFrameSameBlock::handle_event()
654 {
655         plugin->config.tracking_object = MotionScan::PREVIOUS_SAME_BLOCK;
656         gui->track_single->update(0);
657         gui->track_previous->update(0);
658         gui->track_frame_number->disable();
659         plugin->send_configure_change();
660         return 1;
661 }
662
663
664 MasterLayer::MasterLayer(MotionMain *plugin, MotionWindow *gui, int x, int y)
665  : BC_PopupMenu(x,
666         y,
667         calculate_w(gui),
668         to_text(plugin->config.bottom_is_master))
669 {
670         this->plugin = plugin;
671         this->gui = gui;
672 }
673
674 int MasterLayer::handle_event()
675 {
676         plugin->config.bottom_is_master = from_text(get_text());
677         plugin->send_configure_change();
678         return 1;
679 }
680
681 void MasterLayer::create_objects()
682 {
683         add_item(new BC_MenuItem(to_text(0)));
684         add_item(new BC_MenuItem(to_text(1)));
685 }
686
687 int MasterLayer::from_text(char *text)
688 {
689         if(!strcmp(text, _("Top"))) return 0;
690         return 1;
691 }
692
693 char* MasterLayer::to_text(int mode)
694 {
695         return mode ? _("Bottom") : _("Top");
696 }
697
698 int MasterLayer::calculate_w(MotionWindow *gui)
699 {
700         int result = 0;
701         result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(0)));
702         result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(1)));
703         return result + 50;
704 }
705
706
707 ActionType::ActionType(MotionMain *plugin, MotionWindow *gui, int x, int y)
708  : BC_PopupMenu(x,
709         y,
710         calculate_w(gui),
711         to_text(plugin->config.action_type))
712 {
713         this->plugin = plugin;
714         this->gui = gui;
715 }
716
717 int ActionType::handle_event()
718 {
719         plugin->config.action_type = from_text(get_text());
720         plugin->send_configure_change();
721         return 1;
722 }
723
724 void ActionType::create_objects()
725 {
726         add_item(new BC_MenuItem(to_text(MotionScan::TRACK)));
727         add_item(new BC_MenuItem(to_text(MotionScan::TRACK_PIXEL)));
728         add_item(new BC_MenuItem(to_text(MotionScan::STABILIZE)));
729         add_item(new BC_MenuItem(to_text(MotionScan::STABILIZE_PIXEL)));
730         add_item(new BC_MenuItem(to_text(MotionScan::NOTHING)));
731 }
732
733 int ActionType::from_text(char *text)
734 {
735         if(!strcmp(text, _("Track Subpixel"))) return MotionScan::TRACK;
736         if(!strcmp(text, _("Track Pixel"))) return MotionScan::TRACK_PIXEL;
737         if(!strcmp(text, _("Stabilize Subpixel"))) return MotionScan::STABILIZE;
738         if(!strcmp(text, _("Stabilize Pixel"))) return MotionScan::STABILIZE_PIXEL;
739         //if(!strcmp(text, _("Do Nothing"))) return MotionScan::NOTHING;
740         return MotionScan::NOTHING;
741 }
742
743 char* ActionType::to_text(int mode)
744 {
745         switch(mode)
746         {
747                 case MotionScan::TRACK:
748                         return _("Track Subpixel");
749                 case MotionScan::TRACK_PIXEL:
750                         return _("Track Pixel");
751                 case MotionScan::STABILIZE:
752                         return _("Stabilize Subpixel");
753                 case MotionScan::STABILIZE_PIXEL:
754                         return _("Stabilize Pixel");
755                 default:
756                 case MotionScan::NOTHING:
757                         return _("Do Nothing");
758         }
759 }
760
761 int ActionType::calculate_w(MotionWindow *gui)
762 {
763         int result = 0;
764         result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionScan::TRACK)));
765         result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionScan::TRACK_PIXEL)));
766         result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionScan::STABILIZE)));
767         result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionScan::STABILIZE_PIXEL)));
768         result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionScan::NOTHING)));
769         return result + 50;
770 }
771
772
773 TrackingType::TrackingType(MotionMain *plugin, MotionWindow *gui, int x, int y)
774  : BC_PopupMenu(x,
775         y,
776         calculate_w(gui),
777         to_text(plugin->config.tracking_type))
778 {
779         this->plugin = plugin;
780         this->gui = gui;
781 }
782
783 int TrackingType::handle_event()
784 {
785         plugin->config.tracking_type = from_text(get_text());
786         plugin->send_configure_change();
787         return 1;
788 }
789
790 void TrackingType::create_objects()
791 {
792         add_item(new BC_MenuItem(to_text(MotionScan::SAVE)));
793         add_item(new BC_MenuItem(to_text(MotionScan::LOAD)));
794         add_item(new BC_MenuItem(to_text(MotionScan::CALCULATE)));
795         add_item(new BC_MenuItem(to_text(MotionScan::NO_CALCULATE)));
796 }
797
798 int TrackingType::from_text(char *text)
799 {
800         if(!strcmp(text, _("Save coords to tracking file"))) return MotionScan::SAVE;
801         if(!strcmp(text, _("Load coords from tracking file"))) return MotionScan::LOAD;
802         if(!strcmp(text, _("Recalculate"))) return MotionScan::CALCULATE;
803         //if(!strcmp(text, _("Don't Calculate"))) return MotionScan::NO_CALCULATE;
804         return MotionScan::NO_CALCULATE;
805 }
806
807 char* TrackingType::to_text(int mode)
808 {
809         switch(mode)
810         {
811                 case MotionScan::SAVE:          return _("Save coords to tracking file");
812                 case MotionScan::LOAD:          return _("Load coords from tracking file");
813                 case MotionScan::CALCULATE:     return _("Recalculate");
814                 default:
815                 case MotionScan::NO_CALCULATE:  return _("Don't Calculate");
816         }
817 }
818
819 int TrackingType::calculate_w(MotionWindow *gui)
820 {
821         int result = 0;
822         result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionScan::NO_CALCULATE)));
823         result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionScan::CALCULATE)));
824         result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionScan::SAVE)));
825         result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionScan::LOAD)));
826         return result + 50;
827 }
828
829
830 TrackDirection::TrackDirection(MotionMain *plugin, MotionWindow *gui, int x, int y)
831  : BC_PopupMenu(x,
832         y,
833         calculate_w(gui),
834         to_text(plugin->config.horizontal_only, plugin->config.vertical_only))
835 {
836         this->plugin = plugin;
837         this->gui = gui;
838 }
839
840 int TrackDirection::handle_event()
841 {
842         from_text(&plugin->config.horizontal_only, &plugin->config.vertical_only, get_text());
843         plugin->send_configure_change();
844         return 1;
845 }
846
847 void TrackDirection::create_objects()
848 {
849         add_item(new BC_MenuItem(to_text(1, 0)));
850         add_item(new BC_MenuItem(to_text(0, 1)));
851         add_item(new BC_MenuItem(to_text(0, 0)));
852 }
853
854 void TrackDirection::from_text(int *horizontal_only, int *vertical_only, char *text)
855 {
856         *horizontal_only = 0;
857         *vertical_only = 0;
858         if(!strcmp(text, to_text(1, 0))) *horizontal_only = 1;
859         if(!strcmp(text, to_text(0, 1))) *vertical_only = 1;
860 }
861
862 char* TrackDirection::to_text(int horizontal_only, int vertical_only)
863 {
864         if(horizontal_only) return _("Horizontal only");
865         if(vertical_only) return _("Vertical only");
866         return _("Both");
867 }
868
869 int TrackDirection::calculate_w(MotionWindow *gui)
870 {
871         int result = 0;
872         result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(1, 0)));
873         result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(0, 1)));
874         result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(0, 0)));
875         return result + 50;
876 }
877