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