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