Credit Andrew - fix vorbis audio which was scratchy and ensure aging plugin does...
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / motion-cv / motionwindow-cv.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 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-cv.h"
29 #include "motionwindow-cv.h"
30 #include "mwindow.h"
31 #include "pluginserver.h"
32
33 MotionCVWindow::MotionCVWindow(MotionCVMain *plugin)
34  : PluginClientWindow(plugin, xS(815), yS(600), xS(815), yS(600), 0)
35 {
36         this->plugin = plugin;
37 }
38
39 MotionCVWindow::~MotionCVWindow()
40 {
41 }
42
43 void MotionCVWindow::create_objects()
44 {
45         int xs10 = xS(10), xs20 = xS(20), xs30 = xS(30), xs50 = xS(50), xs120 = xS(120), xs410 = xS(410);
46         int ys10 = yS(10), ys20 = yS(20), ys30 = yS(30), ys40 = yS(40), ys50 = yS(50);
47         int x1 = xs10, x = xs10, y = ys10;
48         int x2 = xs410;
49         BC_Title *title;
50
51         add_subwindow(global = new MotionCVGlobal(plugin, this, x1, y));
52         add_subwindow(rotate = new MotionCVRotate(plugin, this, x2, y));
53         y += ys50;
54
55         add_subwindow(title = new BC_Title(x1, y,
56                 _("Translation search radius:\n(W/H Percent of image)")));
57         add_subwindow(global_range_w = new GlobalRange(plugin,
58                         x1 + title->get_w() + xs10, y,
59                         &plugin->config.global_range_w));
60         add_subwindow(global_range_h = new GlobalRange(plugin,
61                         x1 + title->get_w() + xs30 + global_range_w->get_w(), y,
62                         &plugin->config.global_range_h));
63
64         add_subwindow(title = new BC_Title(x2, y,
65                 _("Rotation search radius:\n(Degrees)")));
66         add_subwindow(rotation_range =
67                       new RotationRange(plugin, x2 + title->get_w() + xs10, y));
68
69         y += ys50;
70         add_subwindow(title = new BC_Title(x1, y,
71                 _("Translation block size:\n(W/H Percent of image)")));
72         add_subwindow(global_block_w = new BlockSize(plugin,
73                         x1 + title->get_w() + xs10, y,
74                         &plugin->config.global_block_w));
75         add_subwindow(global_block_h = new BlockSize(plugin,
76                         x1 + title->get_w() + xs30 + global_block_w->get_w(), y,
77                         &plugin->config.global_block_h));
78
79         add_subwindow(title = new BC_Title(x2, y,
80                 _("Rotation block size:\n(W/H Percent of image)")));
81         add_subwindow(rotation_block_w = new BlockSize(plugin,
82                         x2 + title->get_w() + xs10, y,
83                         &plugin->config.rotation_block_w));
84         add_subwindow(rotation_block_h = new BlockSize(plugin,
85                         x2 + title->get_w() + xs30 + rotation_block_w->get_w(), y,
86                         &plugin->config.rotation_block_h));
87
88         y += ys50;
89         add_subwindow(title = new BC_Title(x1, y, _("Translation search steps:")));
90         add_subwindow(global_search_positions = new GlobalSearchPositions(plugin,
91                         x1 + title->get_w() + xs10, y, xs120));
92         global_search_positions->create_objects();
93
94         add_subwindow(title = new BC_Title(x2, y, _("Rotation search steps:")));
95         add_subwindow(rotation_search_positions = new RotationSearchPositions(plugin,
96                         x2 + title->get_w() + xs10, y, xs120));
97         rotation_search_positions->create_objects();
98
99         y += ys50;
100         add_subwindow(title = new BC_Title(x, y, _("Translation direction:")));
101         add_subwindow(mode3 = new Mode3(plugin,
102                         this, x + title->get_w() + xs10, y));
103         mode3->create_objects();
104
105         y += ys40;  int y1 = y;
106         add_subwindow(title = new BC_Title(x2, y, _("Tracking file:")));
107         add_subwindow(tracking_file = new MotionCVTrackingFile(plugin,
108                         plugin->config.  tracking_file, this,
109                         x2 + title->get_w() + xs20, y));
110         y1 += tracking_file->get_h() + ys10;
111
112         add_subwindow(title = new BC_Title(x, y + xs10, _("Block X:")));
113         add_subwindow(block_x = new MotionCVBlockX(plugin, this,
114                         x + title->get_w() + xs10, y));
115         add_subwindow(block_x_text = new MotionCVBlockXText(plugin,
116                         this, x + title->get_w() + xs10 + block_x->get_w() + xs10, y + ys10));
117
118         y += ys40;
119         add_subwindow(title = new BC_Title(x, y + ys10, _("Block Y:")));
120         add_subwindow(block_y = new MotionCVBlockY(plugin, this,
121                         x + title->get_w() + xs10, y));
122         add_subwindow(block_y_text = new MotionCVBlockYText(plugin, this,
123                         x + title->get_w() + xs10 + block_y->get_w() + xs10, y + ys10));
124
125         add_subwindow(title = new BC_Title(x2, y1 + ys10, _("Maximum absolute offset:")));
126         add_subwindow(magnitude = new MotionCVMagnitude(plugin,
127                         x2 + title->get_w() + xs10, y1));
128
129         y1 += ys40;
130         add_subwindow(title = new BC_Title(x2, y1 + ys10, _("Settling speed:")));
131         add_subwindow(return_speed = new MotionCVReturnSpeed(plugin,
132                         x2 + title->get_w() + xs10, y1));
133
134         y1 += ys40;
135         add_subwindow(vectors = new MotionCVDrawVectors(plugin, this, x2, y1));
136         y = y1 + vectors->get_h() + ys10;
137
138         x1 = x;  y1 = y;
139         add_subwindow(track_single =
140                 new TrackSingleFrame(plugin, this, x1, y1));
141         y += ys20;
142         add_subwindow(track_previous = new TrackPreviousFrame(plugin, this, x, y));
143         y += ys20;
144         add_subwindow(previous_same = new PreviousFrameSameBlock(plugin, this, x, y));
145
146         y += ys40;
147         add_subwindow(title = new BC_Title(x, y, _("Master layer:")));
148         add_subwindow(master_layer = new MasterLayer(plugin, this,
149                         x + title->get_w() + xs10, y));
150         master_layer->create_objects();
151         add_subwindow(title =
152                 new BC_Title(x1=x2, y1=y, _("Frame number:")));
153         add_subwindow(track_frame_number =
154                 new TrackFrameNumber(plugin, this, x1 += title->get_w(), y1));
155         if( plugin->config.mode3 != MotionCVConfig::TRACK_SINGLE )
156                 track_frame_number->disable();
157
158         add_subwindow(addtrackedframeoffset =
159                 new AddTrackedFrameOffset(plugin, this, x1=x2, y1+=track_frame_number->get_h()));
160         int pef = client->server->mwindow->edl->session->video_every_frame;
161         add_subwindow(pef_title = new BC_Title(x1=x2+xs50, y1+=addtrackedframeoffset->get_h() + yS(5),
162                 !pef ?  _("For best results\n"
163                                 " Set: Play every frame\n"
164                                 " Preferences-> Playback-> Video Out") :
165                         _("Currently using: Play every frame"), MEDIUMFONT,
166                 !pef ? RED : GREEN));
167
168         y += ys30;
169         add_subwindow(title = new BC_Title(x, y, _("Action:")));
170         add_subwindow(mode1 = new Mode1(plugin, this,
171                         x + title->get_w() + xs10, y));
172         mode1->create_objects();
173
174         y += ys30;
175         add_subwindow(title = new BC_Title(x, y, _("Calculation:")));
176         add_subwindow(mode2 = new Mode2(plugin, this,
177                         x + title->get_w() + xs10, y));
178         mode2->create_objects();
179
180         show_window(1);
181 }
182
183 void MotionCVWindow::update_mode()
184 {
185         global_range_w->update(plugin->config.global_range_w, MIN_RADIUS, MAX_RADIUS);
186         global_range_h->update(plugin->config.global_range_h, MIN_RADIUS, MAX_RADIUS);
187         rotation_range->update(plugin->config.rotation_range, MIN_ROTATION, MAX_ROTATION);
188         vectors->update(plugin->config.draw_vectors);
189         tracking_file->update(plugin->config.tracking_file);
190         global->update(plugin->config.global);
191         rotate->update(plugin->config.rotate);
192         addtrackedframeoffset->update(plugin->config.addtrackedframeoffset);
193 }
194
195 GlobalRange::GlobalRange(MotionCVMain *plugin, int x, int y, int *value)
196 :BC_IPot(x, y, (int64_t) * value, (int64_t) MIN_RADIUS, (int64_t) MAX_RADIUS)
197 {
198         this->plugin = plugin;
199         this->value = value;
200 }
201
202 int GlobalRange::handle_event()
203 {
204         *value = (int)get_value();
205         plugin->send_configure_change();
206         return 1;
207 }
208
209 RotationRange::RotationRange(MotionCVMain *plugin, int x, int y)
210  :
211 BC_IPot(x,
212     y, (int64_t) plugin->config.rotation_range,
213     (int64_t) MIN_ROTATION, (int64_t) MAX_ROTATION)
214 {
215         this->plugin = plugin;
216 }
217
218 int RotationRange::handle_event()
219 {
220         plugin->config.rotation_range = (int)get_value();
221         plugin->send_configure_change();
222         return 1;
223 }
224
225 BlockSize::BlockSize(MotionCVMain *plugin, int x, int y, int *value)
226  : BC_IPot(x, y, (int64_t) * value, (int64_t) MIN_BLOCK, (int64_t) MAX_BLOCK)
227 {
228         this->plugin = plugin;
229         this->value = value;
230 }
231
232 int BlockSize::handle_event()
233 {
234         *value = (int)get_value();
235         plugin->send_configure_change();
236         return 1;
237 }
238
239 GlobalSearchPositions::GlobalSearchPositions(MotionCVMain *plugin,
240                                              int x, int y, int w)
241  : BC_PopupMenu(x, y, w, "", 1)
242 {
243         this->plugin = plugin;
244 }
245
246 void GlobalSearchPositions::create_objects()
247 {
248         add_item(new BC_MenuItem("64"));
249         add_item(new BC_MenuItem("128"));
250         add_item(new BC_MenuItem("256"));
251         add_item(new BC_MenuItem("512"));
252         add_item(new BC_MenuItem("1024"));
253         add_item(new BC_MenuItem("2048"));
254         add_item(new BC_MenuItem("4096"));
255         add_item(new BC_MenuItem("8192"));
256         add_item(new BC_MenuItem("16384"));
257         add_item(new BC_MenuItem("32768"));
258         add_item(new BC_MenuItem("65536"));
259         add_item(new BC_MenuItem("131072"));
260         char string[BCTEXTLEN];
261         sprintf(string, "%d", plugin->config.global_positions);
262         set_text(string);
263 }
264
265 int GlobalSearchPositions::handle_event()
266 {
267         plugin->config.global_positions = atoi(get_text());
268         plugin->send_configure_change();
269         return 1;
270 }
271
272 RotationSearchPositions::RotationSearchPositions(MotionCVMain *plugin,
273                 int x, int y, int w)
274  : BC_PopupMenu(x, y, w, "", 1)
275 {
276         this->plugin = plugin;
277 }
278
279 void RotationSearchPositions::create_objects()
280 {
281         add_item(new BC_MenuItem("4"));
282         add_item(new BC_MenuItem("8"));
283         add_item(new BC_MenuItem("16"));
284         add_item(new BC_MenuItem("32"));
285         char string[BCTEXTLEN];
286         sprintf(string, "%d", plugin->config.rotate_positions);
287         set_text(string);
288 }
289
290 int RotationSearchPositions::handle_event()
291 {
292         plugin->config.rotate_positions = atoi(get_text());
293         plugin->send_configure_change();
294         return 1;
295 }
296
297 MotionCVMagnitude::MotionCVMagnitude(MotionCVMain *plugin, int x, int y)
298  : BC_IPot(x, y, (int64_t) plugin->config.magnitude, (int64_t) 0, (int64_t) 100)
299 {
300         this->plugin = plugin;
301 }
302
303 int MotionCVMagnitude::handle_event()
304 {
305         plugin->config.magnitude = (int)get_value();
306         plugin->send_configure_change();
307         return 1;
308 }
309
310 MotionCVReturnSpeed::MotionCVReturnSpeed(MotionCVMain *plugin, int x, int y)
311  : BC_IPot(x, y, (int64_t) plugin->config.return_speed, (int64_t) 0, (int64_t) 100)
312 {
313         this->plugin = plugin;
314 }
315
316 int MotionCVReturnSpeed::handle_event()
317 {
318         plugin->config.return_speed = (int)get_value();
319         plugin->send_configure_change();
320         return 1;
321 }
322
323 AddTrackedFrameOffset::AddTrackedFrameOffset(MotionCVMain *plugin,
324                 MotionCVWindow *gui, int x, int y)
325  : BC_CheckBox(x, y, plugin->config.addtrackedframeoffset,
326         _("Add (loaded) offset from tracked frame"))
327 {
328         this->plugin = plugin;
329         this->gui = gui;
330 }
331
332 int AddTrackedFrameOffset::handle_event()
333 {
334         plugin->config.addtrackedframeoffset = get_value();
335         plugin->send_configure_change();
336         return 1;
337 }
338
339 MotionCVTrackingFile::MotionCVTrackingFile(MotionCVMain *plugin,
340                 const char *filename, MotionCVWindow *gui, int x, int y)
341  : BC_TextBox(x, y, xS(250), 1, filename)
342 {
343         this->plugin = plugin;
344         this->gui = gui;
345 };
346
347 int MotionCVTrackingFile::handle_event()
348 {
349         strcpy(plugin->config.tracking_file, get_text());
350         plugin->send_configure_change();
351         return 1;
352 }
353
354 MotionCVGlobal::MotionCVGlobal(MotionCVMain *plugin,
355                 MotionCVWindow *gui, int x, int y)
356  :BC_CheckBox(x, y, plugin->config.global, _("Track translation"))
357 {
358         this->plugin = plugin;
359         this->gui = gui;
360 }
361
362 int MotionCVGlobal::handle_event()
363 {
364         plugin->config.global = get_value();
365         plugin->send_configure_change();
366         return 1;
367 }
368
369 MotionCVRotate::MotionCVRotate(MotionCVMain *plugin,
370                 MotionCVWindow *gui, int x, int y)
371  : BC_CheckBox(x, y, plugin->config.rotate, _("Track rotation"))
372 {
373         this->plugin = plugin;
374         this->gui = gui;
375 }
376
377 int MotionCVRotate::handle_event()
378 {
379         plugin->config.rotate = get_value();
380         plugin->send_configure_change();
381         return 1;
382 }
383
384 MotionCVBlockX::MotionCVBlockX(MotionCVMain *plugin,
385                 MotionCVWindow *gui, int x, int y)
386  : BC_FPot(x, y, plugin->config.block_x, (float)0, (float)100)
387 {
388         this->plugin = plugin;
389         this->gui = gui;
390 }
391
392 int MotionCVBlockX::handle_event()
393 {
394         plugin->config.block_x = get_value();
395         gui->block_x_text->update((float)plugin->config.block_x);
396         plugin->send_configure_change();
397         return 1;
398 }
399
400 MotionCVBlockY::MotionCVBlockY(MotionCVMain *plugin,
401                 MotionCVWindow *gui, int x, int y)
402  : BC_FPot(x, y, (float)plugin->config.block_y, (float)0, (float)100)
403 {
404         this->plugin = plugin;
405         this->gui = gui;
406 }
407
408 int MotionCVBlockY::handle_event()
409 {
410         plugin->config.block_y = get_value();
411         gui->block_y_text->update((float)plugin->config.block_y);
412         plugin->send_configure_change();
413         return 1;
414 }
415
416 MotionCVBlockXText::MotionCVBlockXText(MotionCVMain *plugin,
417                 MotionCVWindow *gui, int x, int y)
418  : BC_TextBox(x, y, xS(75), 1, (float)plugin->config.block_x)
419 {
420         this->plugin = plugin;
421         this->gui = gui;
422         set_precision(4);
423 }
424
425 int MotionCVBlockXText::handle_event()
426 {
427         plugin->config.block_x = atof(get_text());
428         gui->block_x->update(plugin->config.block_x);
429         plugin->send_configure_change();
430         return 1;
431 }
432
433 MotionCVBlockYText::MotionCVBlockYText(MotionCVMain *plugin,
434                 MotionCVWindow *gui, int x, int y)
435  : BC_TextBox(x, y, xS(75), 1, (float)plugin->config.block_y)
436 {
437         this->plugin = plugin;
438         this->gui = gui;
439         set_precision(4);
440 }
441
442 int MotionCVBlockYText::handle_event()
443 {
444         plugin->config.block_y = atof(get_text());
445         gui->block_y->update(plugin->config.block_y);
446         plugin->send_configure_change();
447         return 1;
448 }
449
450 MotionCVDrawVectors::MotionCVDrawVectors(MotionCVMain *plugin,
451                 MotionCVWindow *gui, int x, int y)
452  : BC_CheckBox(x, y, plugin->config.draw_vectors, _("Draw vectors"))
453 {
454         this->gui = gui;
455         this->plugin = plugin;
456 }
457
458 int MotionCVDrawVectors::handle_event()
459 {
460         plugin->config.draw_vectors = get_value();
461         plugin->send_configure_change();
462         return 1;
463 }
464
465 TrackSingleFrame::TrackSingleFrame(MotionCVMain *plugin,
466                 MotionCVWindow *gui, int x, int y)
467  :
468 BC_Radial(x,
469       y, plugin->config.mode3 == MotionCVConfig::TRACK_SINGLE,
470       _("Track single frame"))
471 {
472         this->plugin = plugin;
473         this->gui = gui;
474 }
475
476 int TrackSingleFrame::handle_event()
477 {
478         plugin->config.mode3 = MotionCVConfig::TRACK_SINGLE;
479         gui->track_previous->update(0);
480         gui->previous_same->update(0);
481         gui->track_frame_number->enable();
482         plugin->send_configure_change();
483         return 1;
484 }
485
486 TrackFrameNumber::TrackFrameNumber(MotionCVMain *plugin,
487                 MotionCVWindow *gui, int x, int y)
488  : BC_TextBox(x, y, xS(100), 1, plugin->config.track_frame)
489 {
490         this->plugin = plugin;
491         this->gui = gui;
492 }
493
494 int TrackFrameNumber::handle_event()
495 {
496         plugin->config.track_frame = atol(get_text());
497         plugin->send_configure_change();
498         return 1;
499 }
500
501 TrackPreviousFrame::TrackPreviousFrame(MotionCVMain *plugin,
502                 MotionCVWindow *gui, int x, int y)
503  :
504 BC_Radial(x,
505       y, plugin->config.mode3 == MotionCVConfig::TRACK_PREVIOUS,
506       _("Track previous frame"))
507 {
508         this->plugin = plugin;
509         this->gui = gui;
510 }
511
512 int TrackPreviousFrame::handle_event()
513 {
514         plugin->config.mode3 = MotionCVConfig::TRACK_PREVIOUS;
515         gui->track_single->update(0);
516         gui->previous_same->update(0);
517         gui->track_frame_number->disable();
518         plugin->send_configure_change();
519         return 1;
520 }
521
522 PreviousFrameSameBlock::PreviousFrameSameBlock(MotionCVMain *plugin,
523                 MotionCVWindow *gui, int x, int y)
524  :
525 BC_Radial(x,
526       y, plugin->config.mode3 == MotionCVConfig::PREVIOUS_SAME_BLOCK,
527       _("Previous frame same block"))
528 {
529         this->plugin = plugin;
530         this->gui = gui;
531 }
532
533 int PreviousFrameSameBlock::handle_event()
534 {
535         plugin->config.mode3 = MotionCVConfig::PREVIOUS_SAME_BLOCK;
536         gui->track_single->update(0);
537         gui->track_previous->update(0);
538         gui->track_frame_number->disable();
539         plugin->send_configure_change();
540         return 1;
541 }
542
543 MasterLayer::MasterLayer(MotionCVMain *plugin, MotionCVWindow *gui, int x,
544                          int y)
545  : BC_PopupMenu(x, y, calculate_w(gui),
546              to_text(plugin->config.bottom_is_master))
547 {
548         this->plugin = plugin;
549         this->gui = gui;
550 }
551
552 int MasterLayer::handle_event()
553 {
554         plugin->config.bottom_is_master = from_text(get_text());
555         plugin->send_configure_change();
556         return 1;
557 }
558
559 void MasterLayer::create_objects()
560 {
561         add_item(new BC_MenuItem(to_text(0)));
562         add_item(new BC_MenuItem(to_text(1)));
563 }
564
565 int MasterLayer::from_text(char *text)
566 {
567         if( !strcmp(text, _("Top")) ) return 0;
568         return 1;
569 }
570
571 const char *MasterLayer::to_text(int mode)
572 {
573         return mode ? _("Bottom") : _("Top");
574 }
575
576 int MasterLayer::calculate_w(MotionCVWindow *gui)
577 {
578         int result = 0;
579         result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(0)));
580         result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(1)));
581         return result + xS(80);
582 }
583
584 Mode1::Mode1(MotionCVMain *plugin, MotionCVWindow *gui, int x, int y)
585  : BC_PopupMenu(x, y, calculate_w(gui), to_text(plugin->config.mode1))
586 {
587         this->plugin = plugin;
588         this->gui = gui;
589 }
590
591 int Mode1::handle_event()
592 {
593         plugin->config.mode1 = from_text(get_text());
594         plugin->send_configure_change();
595         return 1;
596 }
597
598 void Mode1::create_objects()
599 {
600         add_item(new BC_MenuItem(to_text(MotionCVConfig::TRACK)));
601         add_item(new BC_MenuItem(to_text(MotionCVConfig::TRACK_PIXEL)));
602         add_item(new BC_MenuItem(to_text(MotionCVConfig::STABILIZE)));
603         add_item(new BC_MenuItem(to_text(MotionCVConfig::STABILIZE_PIXEL)));
604         add_item(new BC_MenuItem(to_text(MotionCVConfig::NOTHING)));
605 }
606
607 int Mode1::from_text(char *text)
608 {
609         if( !strcmp(text, _("Track Subpixel")) ) return MotionCVConfig::TRACK;
610         if( !strcmp(text, _("Track Pixel")) ) return MotionCVConfig::TRACK_PIXEL;
611         if( !strcmp(text, _("Stabilize Subpixel")) ) return MotionCVConfig::STABILIZE;
612         if( !strcmp(text, _("Stabilize Pixel")) ) return MotionCVConfig::STABILIZE_PIXEL;
613         //if( !strcmp(text, _("Do Nothing")) ) return MotionCVConfig::NOTHING;
614         return MotionCVConfig::NOTHING;
615 }
616
617 const char *Mode1::to_text(int mode)
618 {
619         switch( mode ) {
620         case MotionCVConfig::TRACK: return _("Track Subpixel");
621         case MotionCVConfig::TRACK_PIXEL: return _("Track Pixel");
622         case MotionCVConfig::STABILIZE: return _("Stabilize Subpixel");
623         case MotionCVConfig::STABILIZE_PIXEL: return _("Stabilize Pixel");
624         case MotionCVConfig::NOTHING: return _("Do Nothing");
625         }
626         return "";
627 }
628
629 int Mode1::calculate_w(MotionCVWindow *gui)
630 {
631         int result = 0;
632         result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionCVConfig::TRACK)));
633         result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionCVConfig::TRACK_PIXEL)));
634         result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionCVConfig::STABILIZE)));
635         result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionCVConfig::STABILIZE_PIXEL)));
636         result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionCVConfig::NOTHING)));
637         return result + xS(80);
638 }
639
640 Mode2::Mode2(MotionCVMain *plugin, MotionCVWindow *gui, int x, int y)
641  : BC_PopupMenu(x, y, calculate_w(gui), to_text(plugin->config.mode2))
642 {
643         this->plugin = plugin;
644         this->gui = gui;
645 }
646
647 int Mode2::handle_event()
648 {
649         plugin->config.mode2 = from_text(get_text());
650         plugin->send_configure_change();
651         return 1;
652 }
653
654 void Mode2::create_objects()
655 {
656         add_item(new BC_MenuItem(to_text(MotionCVConfig::SAVE)));
657         add_item(new BC_MenuItem(to_text(MotionCVConfig::LOAD)));
658         add_item(new BC_MenuItem(to_text(MotionCVConfig::RECALCULATE)));
659         add_item(new BC_MenuItem(to_text(MotionCVConfig::NO_CALCULATE)));
660 }
661
662 int Mode2::from_text(char *text)
663 {
664         if( !strcmp(text, _("Recalculate")) ) return MotionCVConfig::RECALCULATE;
665         if( !strcmp(text, _("Save coords to tracking file")) ) return MotionCVConfig::SAVE;
666         if( !strcmp(text, _("Load coords from tracking file")) ) return MotionCVConfig::LOAD;
667         //if( !strcmp(text, _("Don't Calculate")) ) return MotionCVConfig::NO_CALCULATE;
668         return MotionCVConfig::NO_CALCULATE;
669 }
670
671 const char *Mode2::to_text(int mode)
672 {
673         switch( mode ) {
674         case MotionCVConfig::NO_CALCULATE: return _("Don't Calculate");
675         case MotionCVConfig::RECALCULATE: return _("Recalculate");
676         case MotionCVConfig::SAVE: return _("Save coords to tracking file");
677         case MotionCVConfig::LOAD: return _("Load coords from tracking file");
678         }
679         return "";
680 }
681
682 int Mode2::calculate_w(MotionCVWindow *gui)
683 {
684         int result = 0;
685         result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionCVConfig::NO_CALCULATE)));
686         result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionCVConfig::RECALCULATE)));
687         result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionCVConfig::SAVE)));
688         result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionCVConfig::LOAD)));
689         return result + xS(80);
690 }
691
692 Mode3::Mode3(MotionCVMain *plugin, MotionCVWindow *gui, int x, int y)
693  :
694 BC_PopupMenu(x, y, calculate_w(gui),
695          to_text(plugin->config.horizontal_only, plugin->config.vertical_only))
696 {
697         this->plugin = plugin;
698         this->gui = gui;
699 }
700
701 int Mode3::handle_event()
702 {
703         from_text(&plugin->config.horizontal_only,
704                   &plugin->config.vertical_only, get_text());
705         plugin->send_configure_change();
706         return 1;
707 }
708
709 void Mode3::create_objects()
710 {
711         add_item(new BC_MenuItem(to_text(1, 0)));
712         add_item(new BC_MenuItem(to_text(0, 1)));
713         add_item(new BC_MenuItem(to_text(0, 0)));
714 }
715
716 void Mode3::from_text(int *horizontal_only, int *vertical_only, char *text)
717 {
718         *horizontal_only = 0;
719         *vertical_only = 0;
720         if( !strcmp(text, to_text(1, 0)) ) *horizontal_only = 1;
721         if( !strcmp(text, to_text(0, 1)) ) *vertical_only = 1;
722 }
723
724 const char *Mode3::to_text(int horizontal_only, int vertical_only)
725 {
726         if( horizontal_only ) return _("Horizontal only");
727         if( vertical_only ) return _("Vertical only");
728         return _("Both");
729 }
730
731 int Mode3::calculate_w(MotionCVWindow *gui)
732 {
733         int result = 0;
734         result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(1, 0)));
735         result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(0, 1)));
736         result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(0, 0)));
737         return result + xS(80);
738 }
739
740