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