new colorspace plugin
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / motion2point / motionwindow.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 "bcsignals.h"
24 #include "clip.h"
25 #include "language.h"
26 #include "motion.h"
27 #include "motionscan-hv.h"
28 #include "motionwindow.h"
29
30
31
32
33
34
35
36
37
38
39 MotionWindow::MotionWindow(MotionMain2 *plugin)
40  : PluginClientWindow(plugin, xS(680), yS(660), xS(680), yS(660), 0)
41 {
42         this->plugin = plugin;
43 }
44
45 MotionWindow::~MotionWindow()
46 {
47 }
48
49 void MotionWindow::create_objects()
50 {
51         int xs10 = xS(10), xs20 = xS(20), xs120 = xS(120);
52         int ys10 = yS(10), ys20 = yS(20), ys30 = yS(30), ys40  = yS(40), ys50 = yS(50);
53         int x1[] = { 10, get_w()/2 };
54         int x = xs10, y = ys10, y1 = ys10;
55         BC_Title *title;
56
57
58         for(int i = 0; i < TOTAL_POINTS; i++)
59         {
60                 y = y1;
61                 char *global_title[] =
62                 {
63                         _("Track Point 1"),
64                         _("Track Point 2"),
65                 };
66                 add_subwindow(global[i] = new MotionGlobal(plugin,
67                         this,
68                         x1[i],
69                         y,
70                         &plugin->config.global[i],
71                         global_title[i]));
72                 y += yS(50);
73
74                 add_subwindow(title = new BC_Title(x1[i],
75                         y,
76                         _("Translation search radius:\n(W/H Percent of image)")));
77                 add_subwindow(global_range_w[i] = new MotionPot(plugin,
78                         x1[i] + title->get_w() + xs10,
79                         y,
80                         &plugin->config.global_range_w[i],
81                         MIN_RADIUS,
82                         MAX_RADIUS));
83                 add_subwindow(global_range_h[i] = new MotionPot(plugin,
84                         x1[i] + title->get_w() + xs10 + global_range_w[i]->get_w(),
85                         y,
86                         &plugin->config.global_range_h[i],
87                         MIN_RADIUS,
88                         MAX_RADIUS));
89
90                 y += ys50;
91
92                 add_subwindow(title = new BC_Title(x1[i],
93                         y,
94                         _("Translation search offset:\n(X/Y Percent of image)")));
95                 add_subwindow(global_origin_x[i] = new MotionPot(plugin,
96                         x1[i] + title->get_w() + xs10,
97                         y,
98                         &plugin->config.global_origin_x[i],
99                         MIN_ORIGIN,
100                         MAX_ORIGIN));
101                 add_subwindow(global_origin_y[i] = new MotionPot(plugin,
102                         x1[i] + title->get_w() + xs10 + global_origin_x[i]->get_w(),
103                         y,
104                         &plugin->config.global_origin_y[i],
105                         MIN_ORIGIN,
106                         MAX_ORIGIN));
107
108                 y += ys50;
109                 add_subwindow(title = new BC_Title(x1[i],
110                         y,
111                         _("Translation block size:\n(W/H Percent of image)")));
112                 add_subwindow(global_block_w[i] = new MotionPot(plugin,
113                         x1[i] + title->get_w() + xs10,
114                         y,
115                         &plugin->config.global_block_w[i],
116                         MIN_BLOCK,
117                         MAX_BLOCK));
118                 add_subwindow(global_block_h[i] = new MotionPot(plugin,
119                         x1[i] + title->get_w() + xs10 + global_block_w[i]->get_w(),
120                         y,
121                         &plugin->config.global_block_h[i],
122                         MIN_BLOCK,
123                         MAX_BLOCK));
124
125
126                 y += ys40;
127                 add_subwindow(title = new BC_Title(x1[i], y + ys10, _("Block X:")));
128                 add_subwindow(block_x[i] = new MotionBlockX(plugin,
129                         this,
130                         x1[i] + title->get_w() + xs10,
131                         y,
132                         i));
133                 add_subwindow(block_x_text[i] = new MotionBlockXText(plugin,
134                         this,
135                         x1[i] + title->get_w() + xs10 + block_x[i]->get_w() + xs10,
136                         y + ys10,
137                         i));
138
139                 y += ys40;
140                 add_subwindow(title = new BC_Title(x1[i], y + ys10, _("Block Y:")));
141                 add_subwindow(block_y[i] = new MotionBlockY(plugin,
142                         this,
143                         x1[i] + title->get_w() + xs10,
144                         y,
145                         i));
146                 add_subwindow(block_y_text[i] = new MotionBlockYText(plugin,
147                         this,
148                         x1[i] + title->get_w() + xs10 + block_y[i]->get_w() + xs10,
149                         y + ys10,
150                         i));
151
152
153                 y += ys40;
154                 add_subwindow(vectors[i] = new MotionDrawVectors(plugin,
155                         this,
156                         x1[i],
157                         y,
158                         i));
159         }
160
161
162         y += ys30;
163         add_subwindow(new BC_Bar(x, y, get_w() - x * 2));
164         y += ys10;
165         add_subwindow(title = new BC_Title(x, y, _("Search steps:")));
166         add_subwindow(global_search_positions = new GlobalSearchPositions(plugin,
167                 x + title->get_w() + xs10, y, xs120));
168         global_search_positions->create_objects();
169
170         y += ys30;
171         add_subwindow(title = new BC_Title(x, y, _("Search directions:")));
172         add_subwindow(tracking_direction = new TrackingDirection(plugin,
173                 this,
174                 x + title->get_w() + xs10,
175                 y));
176         tracking_direction->create_objects();
177
178         y += ys30;
179         add_subwindow(title = new BC_Title(x, y + ys10, _("Maximum absolute offset:")));
180         add_subwindow(magnitude = new MotionMagnitude(plugin,
181                 x + title->get_w() + xs10,
182                 y));
183
184         y += ys40;
185         add_subwindow(title = new BC_Title(x, y + ys10, _("Settling speed:")));
186         add_subwindow(return_speed = new MotionReturnSpeed(plugin,
187                 x + title->get_w() + xs10,
188                 y));
189
190
191         y += ys40;
192         add_subwindow(track_single = new TrackSingleFrame(plugin,
193                 this,
194                 x,
195                 y));
196         add_subwindow(title = new BC_Title(x + track_single->get_w() + xs20,
197                 y,
198                 _("Frame number:")));
199         add_subwindow(track_frame_number = new TrackFrameNumber(plugin,
200                 this,
201                 x + track_single->get_w() + title->get_w() + xs20,
202                 y));
203         if(plugin->config.tracking_object != MotionScan::TRACK_SINGLE)
204                 track_frame_number->disable();
205
206         y += ys20;
207         add_subwindow(track_previous = new TrackPreviousFrame(plugin,
208                 this,
209                 x,
210                 y));
211
212         y += ys20;
213         add_subwindow(previous_same = new PreviousFrameSameBlock(plugin,
214                 this,
215                 x,
216                 y));
217
218         y += ys40;
219         y1 = y;
220         add_subwindow(title = new BC_Title(x, y, _("Master layer:")));
221         add_subwindow(master_layer = new MasterLayer(plugin,
222                 this,
223                 x + title->get_w() + xs10,
224                 y));
225         master_layer->create_objects();
226         y += ys30;
227
228
229         add_subwindow(title = new BC_Title(x, y, _("Action:")));
230         add_subwindow(action = new Action(plugin,
231                 this,
232                 x + title->get_w() + xs10,
233                 y));
234         action->create_objects();
235         y += ys30;
236
237
238
239
240         add_subwindow(title = new BC_Title(x, y, _("Calculation:")));
241         add_subwindow(calculation = new Calculation(plugin,
242                 this,
243                 x + title->get_w() + xs10,
244                 y));
245         calculation->create_objects();
246
247
248
249         show_window();
250         flush();
251 }
252
253 void MotionWindow::update_mode()
254 {
255         for(int i = 0; i < TOTAL_POINTS; i++)
256         {
257                 global_range_w[i]->update(plugin->config.global_range_w[i],
258                         MIN_RADIUS,
259                         MAX_RADIUS);
260                 global_range_h[i]->update(plugin->config.global_range_h[i],
261                         MIN_RADIUS,
262                         MAX_RADIUS);
263                 vectors[i]->update(plugin->config.draw_vectors[i]);
264                         global[i]->update(plugin->config.global[i]);
265         }
266 }
267
268
269
270
271
272
273
274
275
276
277
278
279
280 MotionGlobal::MotionGlobal(MotionMain2 *plugin,
281         MotionWindow *gui,
282         int x,
283         int y,
284         int *value,
285         char *text)
286  : BC_CheckBox(x,
287         y,
288         *value,
289         text)
290 {
291         this->plugin = plugin;
292         this->gui = gui;
293         this->value = value;
294 }
295
296 int MotionGlobal::handle_event()
297 {
298         *value = get_value();
299         plugin->send_configure_change();
300         return 1;
301 }
302
303
304 MotionPot::MotionPot(MotionMain2 *plugin,
305         int x,
306         int y,
307         int *value,
308         int min,
309         int max)
310  : BC_IPot(x,
311                 y,
312                 (int64_t)*value,
313                 (int64_t)min,
314                 (int64_t)max)
315 {
316         this->plugin = plugin;
317         this->value = value;
318 }
319
320
321 int MotionPot::handle_event()
322 {
323         *value = (int)get_value();
324         plugin->send_configure_change();
325         return 1;
326 }
327
328
329
330
331
332
333
334
335
336
337
338
339 GlobalSearchPositions::GlobalSearchPositions(MotionMain2 *plugin,
340         int x,
341         int y,
342         int w)
343  : BC_PopupMenu(x,
344         y,
345         w,
346         "",
347         1)
348 {
349         this->plugin = plugin;
350 }
351 void GlobalSearchPositions::create_objects()
352 {
353         add_item(new BC_MenuItem("16"));
354         add_item(new BC_MenuItem("32"));
355         add_item(new BC_MenuItem("64"));
356         add_item(new BC_MenuItem("128"));
357         add_item(new BC_MenuItem("256"));
358         add_item(new BC_MenuItem("512"));
359         add_item(new BC_MenuItem("1024"));
360         add_item(new BC_MenuItem("2048"));
361         add_item(new BC_MenuItem("4096"));
362         add_item(new BC_MenuItem("8192"));
363         add_item(new BC_MenuItem("16384"));
364         add_item(new BC_MenuItem("32768"));
365         add_item(new BC_MenuItem("65536"));
366         add_item(new BC_MenuItem("131072"));
367         char string[BCTEXTLEN];
368         sprintf(string, "%d", plugin->config.global_positions);
369         set_text(string);
370 }
371
372 int GlobalSearchPositions::handle_event()
373 {
374         plugin->config.global_positions = atoi(get_text());
375         plugin->send_configure_change();
376         return 1;
377 }
378
379
380
381
382
383
384
385
386
387
388
389
390 MotionMagnitude::MotionMagnitude(MotionMain2 *plugin,
391         int x,
392         int y)
393  : BC_IPot(x,
394                 y,
395                 (int64_t)plugin->config.magnitude,
396                 (int64_t)0,
397                 (int64_t)100)
398 {
399         this->plugin = plugin;
400 }
401
402 int MotionMagnitude::handle_event()
403 {
404         plugin->config.magnitude = (int)get_value();
405         plugin->send_configure_change();
406         return 1;
407 }
408
409
410 MotionReturnSpeed::MotionReturnSpeed(MotionMain2 *plugin,
411         int x,
412         int y)
413  : BC_IPot(x,
414                 y,
415                 (int64_t)plugin->config.return_speed,
416                 (int64_t)0,
417                 (int64_t)100)
418 {
419         this->plugin = plugin;
420 }
421
422 int MotionReturnSpeed::handle_event()
423 {
424         plugin->config.return_speed = (int)get_value();
425         plugin->send_configure_change();
426         return 1;
427 }
428
429
430
431
432
433 MotionBlockX::MotionBlockX(MotionMain2 *plugin,
434         MotionWindow *gui,
435         int x,
436         int y,
437         int number)
438  : BC_FPot(x,
439         y,
440         (float)plugin->config.block_x[number],
441         (float)0,
442         (float)100)
443 {
444         this->plugin = plugin;
445         this->gui = gui;
446         this->number = number;
447 }
448
449 int MotionBlockX::handle_event()
450 {
451         plugin->config.block_x[number] = get_value();
452         gui->block_x_text[number]->update((float)plugin->config.block_x[number]);
453         plugin->send_configure_change();
454         return 1;
455 }
456
457
458
459
460 MotionBlockY::MotionBlockY(MotionMain2 *plugin,
461         MotionWindow *gui,
462         int x,
463         int y,
464         int number)
465  : BC_FPot(x,
466         y,
467         (float)plugin->config.block_y[number],
468         (float)0,
469         (float)100)
470 {
471         this->plugin = plugin;
472         this->gui = gui;
473         this->number = number;
474 }
475
476 int MotionBlockY::handle_event()
477 {
478         plugin->config.block_y[number] = get_value();
479         gui->block_y_text[number]->update((float)plugin->config.block_y[number]);
480         plugin->send_configure_change();
481         return 1;
482 }
483
484 MotionBlockXText::MotionBlockXText(MotionMain2 *plugin,
485         MotionWindow *gui,
486         int x,
487         int y,
488         int number)
489  : BC_TextBox(x, y, xS(75), 1,
490         (float)plugin->config.block_x[number])
491 {
492         this->plugin = plugin;
493         this->gui = gui;
494         this->number = number;
495         set_precision(4);
496 }
497
498 int MotionBlockXText::handle_event()
499 {
500         plugin->config.block_x[number] = atof(get_text());
501         gui->block_x[number]->update(plugin->config.block_x[number]);
502         plugin->send_configure_change();
503         return 1;
504 }
505
506
507
508
509 MotionBlockYText::MotionBlockYText(MotionMain2 *plugin,
510         MotionWindow *gui,
511         int x,
512         int y,
513         int number)
514  : BC_TextBox(x, y, xS(75), 1,
515         (float)plugin->config.block_y[number])
516 {
517         this->plugin = plugin;
518         this->gui = gui;
519         this->number = number;
520         set_precision(4);
521 }
522
523 int MotionBlockYText::handle_event()
524 {
525         plugin->config.block_y[number] = atof(get_text());
526         gui->block_y[number]->update(plugin->config.block_y[number]);
527         plugin->send_configure_change();
528         return 1;
529 }
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546 MotionDrawVectors::MotionDrawVectors(MotionMain2 *plugin,
547         MotionWindow *gui,
548         int x,
549         int y,
550         int number)
551  : BC_CheckBox(x,
552         y,
553         plugin->config.draw_vectors[number],
554         _("Draw vectors"))
555 {
556         this->gui = gui;
557         this->plugin = plugin;
558         this->number = number;
559 }
560
561 int MotionDrawVectors::handle_event()
562 {
563         plugin->config.draw_vectors[number] = get_value();
564         plugin->send_configure_change();
565         return 1;
566 }
567
568
569
570
571
572
573
574
575 TrackSingleFrame::TrackSingleFrame(MotionMain2 *plugin,
576         MotionWindow *gui,
577         int x,
578         int y)
579  : BC_Radial(x,
580         y,
581         plugin->config.tracking_object == MotionScan::TRACK_SINGLE,
582         _("Track single frame"))
583 {
584         this->plugin = plugin;
585         this->gui = gui;
586 }
587
588 int TrackSingleFrame::handle_event()
589 {
590         plugin->config.tracking_object = MotionScan::TRACK_SINGLE;
591         gui->track_previous->update(0);
592         gui->previous_same->update(0);
593         gui->track_frame_number->enable();
594         plugin->send_configure_change();
595         return 1;
596 }
597
598
599
600
601
602
603
604
605 TrackFrameNumber::TrackFrameNumber(MotionMain2 *plugin,
606         MotionWindow *gui,
607         int x,
608         int y)
609  : BC_TextBox(x, y, xS(100), 1, plugin->config.track_frame)
610 {
611         this->plugin = plugin;
612         this->gui = gui;
613 }
614
615 int TrackFrameNumber::handle_event()
616 {
617         plugin->config.track_frame = atol(get_text());
618         plugin->send_configure_change();
619         return 1;
620 }
621
622
623
624
625
626
627
628 TrackPreviousFrame::TrackPreviousFrame(MotionMain2 *plugin,
629         MotionWindow *gui,
630         int x,
631         int y)
632  : BC_Radial(x,
633         y,
634         plugin->config.tracking_object == MotionScan::TRACK_PREVIOUS,
635         _("Track previous frame"))
636 {
637         this->plugin = plugin;
638         this->gui = gui;
639 }
640 int TrackPreviousFrame::handle_event()
641 {
642         plugin->config.tracking_object = MotionScan::TRACK_PREVIOUS;
643         gui->track_single->update(0);
644         gui->previous_same->update(0);
645         gui->track_frame_number->disable();
646         plugin->send_configure_change();
647         return 1;
648 }
649
650
651
652
653
654
655
656
657 PreviousFrameSameBlock::PreviousFrameSameBlock(MotionMain2 *plugin,
658         MotionWindow *gui,
659         int x,
660         int y)
661  : BC_Radial(x,
662         y,
663         plugin->config.tracking_object == MotionScan::PREVIOUS_SAME_BLOCK,
664         _("Previous frame same block"))
665 {
666         this->plugin = plugin;
667         this->gui = gui;
668 }
669 int PreviousFrameSameBlock::handle_event()
670 {
671         plugin->config.tracking_object = MotionScan::PREVIOUS_SAME_BLOCK;
672         gui->track_single->update(0);
673         gui->track_previous->update(0);
674         gui->track_frame_number->disable();
675         plugin->send_configure_change();
676         return 1;
677 }
678
679
680
681
682
683
684
685
686 MasterLayer::MasterLayer(MotionMain2 *plugin, MotionWindow *gui, int x, int y)
687  : BC_PopupMenu(x,
688         y,
689         calculate_w(gui),
690         to_text(plugin->config.bottom_is_master))
691 {
692         this->plugin = plugin;
693         this->gui = gui;
694 }
695
696 int MasterLayer::handle_event()
697 {
698         plugin->config.bottom_is_master = from_text(get_text());
699         plugin->send_configure_change();
700         return 1;
701 }
702
703 void MasterLayer::create_objects()
704 {
705         add_item(new BC_MenuItem(to_text(0)));
706         add_item(new BC_MenuItem(to_text(1)));
707 }
708
709 int MasterLayer::from_text(char *text)
710 {
711         if(!strcmp(text, _("Top"))) return 0;
712         return 1;
713 }
714
715 char* MasterLayer::to_text(int mode)
716 {
717         return mode ? _("Bottom") : _("Top");
718 }
719
720 int MasterLayer::calculate_w(MotionWindow *gui)
721 {
722         int result = 0;
723         result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(0)));
724         result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(1)));
725         return result + xS(80);
726 }
727
728
729
730
731
732
733
734
735 Action::Action(MotionMain2 *plugin, MotionWindow *gui, int x, int y)
736  : BC_PopupMenu(x,
737         y,
738         calculate_w(gui),
739         to_text(plugin->config.action))
740 {
741         this->plugin = plugin;
742         this->gui = gui;
743 }
744
745 int Action::handle_event()
746 {
747         plugin->config.action = from_text(get_text());
748         plugin->send_configure_change();
749         return 1;
750 }
751
752 void Action::create_objects()
753 {
754         add_item(new BC_MenuItem(to_text(MotionScan::TRACK)));
755         add_item(new BC_MenuItem(to_text(MotionScan::TRACK_PIXEL)));
756         add_item(new BC_MenuItem(to_text(MotionScan::STABILIZE)));
757         add_item(new BC_MenuItem(to_text(MotionScan::STABILIZE_PIXEL)));
758         add_item(new BC_MenuItem(to_text(MotionScan::NOTHING)));
759 }
760
761 int Action::from_text(char *text)
762 {
763         if(!strcmp(text, _("Track"))) return MotionScan::TRACK;
764         if(!strcmp(text, _("Track Pixel"))) return MotionScan::TRACK_PIXEL;
765         if(!strcmp(text, _("Stabilize"))) return MotionScan::STABILIZE;
766         if(!strcmp(text, _("Stabilize Pixel"))) return MotionScan::STABILIZE_PIXEL;
767         if(!strcmp(text, _("Do Nothing"))) return MotionScan::NOTHING;
768         return 0;
769 }
770
771 char* Action::to_text(int mode)
772 {
773         switch(mode)
774         {
775                 case MotionScan::TRACK:
776                         return _("Track");
777                         break;
778                 case MotionScan::TRACK_PIXEL:
779                         return _("Track Pixel");
780                         break;
781                 case MotionScan::STABILIZE:
782                         return _("Stabilize");
783                         break;
784                 case MotionScan::STABILIZE_PIXEL:
785                         return _("Stabilize Pixel");
786                         break;
787                 case MotionScan::NOTHING:
788                         return _("Do Nothing");
789                         break;
790                 default:
791                         return _("Unknown");
792                         break;
793         }
794 }
795
796 int Action::calculate_w(MotionWindow *gui)
797 {
798         int result = 0;
799         result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionScan::TRACK)));
800         result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionScan::TRACK_PIXEL)));
801         result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionScan::STABILIZE)));
802         result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionScan::STABILIZE_PIXEL)));
803         result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionScan::NOTHING)));
804         return result + xS(80);
805 }
806
807
808
809
810
811 Calculation::Calculation(MotionMain2 *plugin, MotionWindow *gui, int x, int y)
812  : BC_PopupMenu(x,
813         y,
814         calculate_w(gui),
815         to_text(plugin->config.calculation))
816 {
817         this->plugin = plugin;
818         this->gui = gui;
819 }
820
821 int Calculation::handle_event()
822 {
823         plugin->config.calculation = from_text(get_text());
824         plugin->send_configure_change();
825         return 1;
826 }
827
828 void Calculation::create_objects()
829 {
830         add_item(new BC_MenuItem(to_text(MotionScan::NO_CALCULATE)));
831         add_item(new BC_MenuItem(to_text(MotionScan::CALCULATE)));
832         add_item(new BC_MenuItem(to_text(MotionScan::SAVE)));
833         add_item(new BC_MenuItem(to_text(MotionScan::LOAD)));
834 }
835
836 int Calculation::from_text(char *text)
837 {
838         if(!strcmp(text, _("Don't Calculate"))) return MotionScan::NO_CALCULATE;
839         if(!strcmp(text, _("Recalculate"))) return MotionScan::CALCULATE;
840         if(!strcmp(text, _("Save coords to /tmp"))) return MotionScan::SAVE;
841         if(!strcmp(text, _("Load coords from /tmp"))) return MotionScan::LOAD;
842         return 0;
843 }
844
845 char* Calculation::to_text(int mode)
846 {
847         switch(mode)
848         {
849                 case MotionScan::NO_CALCULATE:
850                         return _("Don't Calculate");
851                         break;
852                 case MotionScan::CALCULATE:
853                         return _("Recalculate");
854                         break;
855                 case MotionScan::SAVE:
856                         return _("Save coords to /tmp");
857                         break;
858                 case MotionScan::LOAD:
859                         return _("Load coords from /tmp");
860                         break;
861                 default:
862                         return _("Unknown");
863                         break;
864         }
865 }
866
867 int Calculation::calculate_w(MotionWindow *gui)
868 {
869         int result = 0;
870         result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionScan::NO_CALCULATE)));
871         result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionScan::CALCULATE)));
872         result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionScan::SAVE)));
873         result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(MotionScan::LOAD)));
874         return result + xS(80);
875 }
876
877
878
879
880
881
882
883
884
885
886 TrackingDirection::TrackingDirection(MotionMain2 *plugin, MotionWindow *gui, int x, int y)
887  : BC_PopupMenu(x,
888         y,
889         calculate_w(gui),
890         to_text(plugin->config.horizontal_only, plugin->config.vertical_only))
891 {
892         this->plugin = plugin;
893         this->gui = gui;
894 }
895
896 int TrackingDirection::handle_event()
897 {
898         from_text(&plugin->config.horizontal_only, &plugin->config.vertical_only, get_text());
899         plugin->send_configure_change();
900         return 1;
901 }
902
903 void TrackingDirection::create_objects()
904 {
905         add_item(new BC_MenuItem(to_text(1, 0)));
906         add_item(new BC_MenuItem(to_text(0, 1)));
907         add_item(new BC_MenuItem(to_text(0, 0)));
908 }
909
910 void TrackingDirection::from_text(int *horizontal_only, int *vertical_only, char *text)
911 {
912         *horizontal_only = 0;
913         *vertical_only = 0;
914         if(!strcmp(text, to_text(1, 0))) *horizontal_only = 1;
915         if(!strcmp(text, to_text(0, 1))) *vertical_only = 1;
916 }
917
918 char* TrackingDirection::to_text(int horizontal_only, int vertical_only)
919 {
920         if(horizontal_only) return _("Horizontal only");
921         if(vertical_only) return _("Vertical only");
922         return _("Both");
923 }
924
925 int TrackingDirection::calculate_w(MotionWindow *gui)
926 {
927         int result = 0;
928         result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(1, 0)));
929         result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(0, 1)));
930         result = MAX(result, gui->get_text_width(MEDIUMFONT, to_text(0, 0)));
931         return result + xS(80);
932 }
933