detect missing transitions, dont draw transitions if show off, obey audio transition...
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / boxblur / boxblur.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 1997-2020 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 "guicast.h"
23 #include "boxblur.h"
24 #include "dragcheckbox.h"
25 #include "edl.h"
26 #include "filexml.h"
27 #include "language.h"
28 #include "mainerror.h"
29 #include "plugin.h"
30 #include "pluginserver.h"
31 #include "pluginvclient.h"
32 #include "track.h"
33 #include "tracks.h"
34 #include "theme.h"
35
36 #include <stdint.h>
37 #include <string.h>
38
39 class BoxBlurConfig;
40 class BoxBlurNumISlider;
41 class BoxBlurNumIText;
42 class BoxBlurNumClear;
43 class BoxBlurNum;
44 class BoxBlurRadius;
45 class BoxBlurPower;
46 class BoxBlurDrag;
47 class BoxBlurReset;
48 class BoxBlurX;
49 class BoxBlurY;
50 class BoxBlurW;
51 class BoxBlurH;
52 class BoxBlurWindow;
53 class BoxBlurEffect;
54
55
56 class BoxBlurConfig
57 {
58 public:
59         BoxBlurConfig();
60         void copy_from(BoxBlurConfig &that);
61         int equivalent(BoxBlurConfig &that);
62         void interpolate(BoxBlurConfig &prev, BoxBlurConfig &next,
63                 int64_t prev_frame, int64_t next_frame, int64_t current_frame);
64         void reset();
65         void preset();
66
67         int horz_radius, vert_radius, power;
68         float box_x, box_y;
69         int box_w, box_h;
70         int drag;
71 };
72
73
74 class BoxBlurNumISlider : public BC_ISlider
75 {
76 public:
77         BoxBlurNumISlider(BoxBlurNum *num, int x, int y);
78         int handle_event();
79         BoxBlurNum *num;
80 };
81
82 class BoxBlurNumIText : public BC_TumbleTextBox
83 {
84 public:
85         BoxBlurNumIText(BoxBlurNum *num, int x, int y);
86         int handle_event();
87         BoxBlurNum *num;
88 };
89
90 class BoxBlurNumClear : public BC_Button
91 {
92 public:
93         BoxBlurNumClear(BoxBlurNum *num, int x, int y);
94         static int calculate_w(BoxBlurNum *num);
95         int handle_event();
96
97         BoxBlurNum *num;
98 };
99
100 class BoxBlurNum
101 {
102 public:
103         BoxBlurNum(BoxBlurWindow *gui, int x, int y, int w,
104                 const char *name, int *iv, int imn, int imx);
105         ~BoxBlurNum();
106         void create_objects();
107         void update(int value);
108         int get_w();
109         int get_h();
110
111         BoxBlurWindow *gui;
112         int x, y, w, h;
113         const char *name;
114         int imn, imx, *ivalue;
115         int title_w, text_w, slider_w;
116         BC_Title *title;
117         BoxBlurNumIText *text;
118         BoxBlurNumISlider *slider;
119         BoxBlurNumClear *clear;
120 };
121
122
123 class BoxBlurRadius : public BoxBlurNum
124 {
125 public:
126         BoxBlurRadius(BoxBlurWindow *gui, int x, int y, int w,
127                         const char *name, int *radius);
128 };
129
130 class BoxBlurPower : public BoxBlurNum
131 {
132 public:
133         BoxBlurPower(BoxBlurWindow *gui, int x, int y, int w,
134                         const char *name, int *power);
135 };
136
137 class BoxBlurX : public BC_TumbleTextBox
138 {
139 public:
140         BoxBlurX(BoxBlurWindow *gui, int x, int y);
141         int handle_event();
142         BoxBlurWindow *gui;
143 };
144 class BoxBlurY : public BC_TumbleTextBox
145 {
146 public:
147         BoxBlurY(BoxBlurWindow *gui, int x, int y);
148         int handle_event();
149         BoxBlurWindow *gui;
150 };
151 class BoxBlurW : public BC_TumbleTextBox
152 {
153 public:
154         BoxBlurW(BoxBlurWindow *gui, int x, int y);
155         int handle_event();
156         BoxBlurWindow *gui;
157 };
158 class BoxBlurH : public BC_TumbleTextBox
159 {
160 public:
161         BoxBlurH(BoxBlurWindow *gui, int x, int y);
162         int handle_event();
163         BoxBlurWindow *gui;
164 };
165
166 class BoxBlurDrag : public DragCheckBox
167 {
168 public:
169         BoxBlurDrag(BoxBlurWindow *gui, BoxBlurEffect *plugin, int x, int y);
170         int handle_event();
171         void update_gui();
172         Track *get_drag_track();
173         int64_t get_drag_position();
174         static int calculate_w(BoxBlurWindow *gui);
175
176         BoxBlurWindow *gui;
177         BoxBlurEffect *plugin;
178 };
179
180 class BoxBlurReset : public BC_GenericButton
181 {
182 public:
183         BoxBlurReset(BoxBlurWindow *gui, int x, int y);
184         int handle_event();
185         static int calculate_w(BoxBlurWindow *gui);
186
187         BoxBlurWindow *gui;
188 };
189
190 class BoxBlurPreset : public BC_GenericButton
191 {
192 public:
193         BoxBlurPreset(BoxBlurWindow *gui, int x, int y);
194         int handle_event();
195         static int calculate_w(BoxBlurWindow *gui);
196
197         BoxBlurWindow *gui;
198 };
199
200 class BoxBlurWindow : public PluginClientWindow
201 {
202 public:
203         BoxBlurWindow(BoxBlurEffect *plugin);
204         ~BoxBlurWindow();
205         void create_objects();
206         void update_gui();
207         void update_drag();
208
209         BoxBlurEffect *plugin;
210         BoxBlurReset *reset;
211         BoxBlurPreset *preset;
212         BoxBlurRadius *blur_horz;
213         BoxBlurRadius *blur_vert;
214         BoxBlurPower *blur_power;
215         BoxBlurDrag *drag;
216         BoxBlurX *box_x;
217         BoxBlurY *box_y;
218         BoxBlurW *box_w;
219         BoxBlurH *box_h;
220 };
221
222
223 class BoxBlurEffect : public PluginVClient
224 {
225 public:
226         BoxBlurEffect(PluginServer *server);
227         ~BoxBlurEffect();
228
229         PLUGIN_CLASS_MEMBERS(BoxBlurConfig)
230         void render_gui(void *data);
231         int is_dragging();
232         int process_realtime(VFrame *input, VFrame *output);
233         void update_gui();
234         int is_realtime();
235         void save_data(KeyFrame *keyframe);
236         void read_data(KeyFrame *keyframe);
237         void draw_boundry();
238
239         VFrame *input, *output;
240         BoxBlur *box_blur;
241         int drag;
242 };
243
244
245 void BoxBlurConfig::reset()
246 {
247         horz_radius = 0;
248         vert_radius = 0;
249         power = 1;
250         box_x = box_y = 0.0;
251         box_w = box_h = 0;
252 }
253
254 void BoxBlurConfig::preset()
255 {
256         horz_radius = 2;
257         vert_radius = 2;
258         power = 2;
259         box_x = box_y = 0.0;
260         box_w = box_h = 0;
261 }
262
263
264 BoxBlurConfig::BoxBlurConfig()
265 {
266         preset();
267 }
268
269 void BoxBlurConfig::copy_from(BoxBlurConfig &that)
270 {
271         horz_radius = that.horz_radius;
272         vert_radius = that.vert_radius;
273         power = that.power;
274         box_x = that.box_x;  box_y = that.box_y;
275         box_w = that.box_w;  box_h = that.box_h;
276 }
277
278 int BoxBlurConfig::equivalent(BoxBlurConfig &that)
279 {
280         return horz_radius == that.horz_radius &&
281                 vert_radius == that.vert_radius &&
282                 power == that.power &&
283                 EQUIV(box_x, that.box_x) && EQUIV(box_y, that.box_y) &&
284                 box_w == that.box_w && box_h == that.box_h;
285 }
286
287 void BoxBlurConfig::interpolate(BoxBlurConfig &prev, BoxBlurConfig &next,
288         int64_t prev_frame, int64_t next_frame, int64_t current_frame)
289 {
290         double u = (double)(next_frame - current_frame) / (next_frame - prev_frame);
291         double v = 1. - u;
292         this->horz_radius = u*prev.horz_radius + v*next.horz_radius;
293         this->vert_radius = u*prev.vert_radius + v*next.vert_radius;
294         this->power = u*prev.power + v*next.power + 1e-6; // avoid truncation jitter
295         this->box_x = u*prev.box_x + v*next.box_x;
296         this->box_y = u*prev.box_y + v*next.box_y;
297         this->box_w = u*prev.box_w + v*next.box_w + 1e-6;
298         this->box_h = u*prev.box_h + v*next.box_h + 1e-6;
299 }
300
301
302 int BoxBlurNum::get_w() { return w; }
303 int BoxBlurNum::get_h() { return h; }
304
305 BoxBlurNumISlider::BoxBlurNumISlider(BoxBlurNum *num, int x, int y)
306  : BC_ISlider(x, y, 0, num->slider_w, num->slider_w,
307                 num->imn, num->imx, *num->ivalue)
308 {
309         this->num = num;
310 }
311
312 int BoxBlurNumISlider::handle_event()
313 {
314         int iv = get_value();
315         num->update(iv);
316         num->gui->update_drag();
317         return 1;
318 }
319
320 BoxBlurNumIText::BoxBlurNumIText(BoxBlurNum *num, int x, int y)
321  : BC_TumbleTextBox(num->gui, *num->ivalue, num->imn, num->imx,
322                         x, y, num->text_w)
323 {
324         this->num = num;
325 }
326
327 int BoxBlurNumIText::handle_event()
328 {
329         int iv = atoi(get_text());
330         num->update(iv);
331         num->gui->update_drag();
332         return 1;
333 }
334
335 BoxBlurNumClear::BoxBlurNumClear(BoxBlurNum *num, int x, int y)
336  : BC_Button(x, y, num->gui->plugin->get_theme()->get_image_set("reset_button"))
337 {
338         this->num = num;
339 }
340
341 int BoxBlurNumClear::calculate_w(BoxBlurNum *num)
342 {
343         VFrame **imgs = num->gui->plugin->get_theme()->get_image_set("reset_button");
344         return imgs[0]->get_w();
345 }
346
347 int BoxBlurNumClear::handle_event()
348 {
349         int v = num->imn;
350         num->update(v);
351         num->gui->update_drag();
352         return 1;
353 }
354
355 BoxBlurNum::BoxBlurNum(BoxBlurWindow *gui, int x, int y, int w,
356                  const char *name, int *iv, int imn, int imx)
357 {
358         this->gui = gui;
359         this->x = x;
360         this->y = y;
361         this->w = w;
362         this->h = 0;
363         this->name = name;
364         this->ivalue = iv;
365         this->imn = imn;
366         this->imx = imx;
367         int margin = gui->plugin->get_theme()->widget_border;
368         int clear_w = BoxBlurNumClear::calculate_w(this);
369         int tumble_w = BC_Tumbler::calculate_w();
370         int len = w - 2*margin - clear_w - tumble_w;
371         this->title_w = xS(60);
372         this->text_w = xS(60) - tumble_w;
373         this->slider_w = len - title_w - text_w - 2*margin;
374
375         title = 0;
376         text = 0;
377         slider = 0;
378         clear = 0;
379 }
380
381 BoxBlurNum::~BoxBlurNum()
382 {
383         delete text;
384 }
385
386 void BoxBlurNum::create_objects()
387 {
388         int x1 = this->x;
389         gui->add_subwindow(title = new BC_Title(x1, y, name));
390         int margin = gui->plugin->get_theme()->widget_border;
391         x1 += title_w + margin;
392         text = new BoxBlurNumIText(this, x1, y);
393         text->create_objects();
394         x1 += text_w + BC_Tumbler::calculate_w() + margin;
395         gui->add_subwindow(slider = new BoxBlurNumISlider(this, x1, y));
396         x1 += slider_w + 2*margin;
397         gui->add_subwindow(clear = new BoxBlurNumClear(this, x1, y));
398         h = bmax(title->get_h(), bmax(text->get_h(),
399                 bmax(slider->get_h(), clear->get_h())));
400 }
401
402 void BoxBlurNum::update(int value)
403 {
404         text->update((int64_t)value);
405         slider->update(value);
406         *ivalue = value;
407 }
408
409
410 BoxBlurRadius::BoxBlurRadius(BoxBlurWindow *gui, int x, int y, int w,
411                 const char *name, int *radius)
412  : BoxBlurNum(gui, x, y, w, name, radius, 0, 100)
413 {
414 }
415
416 BoxBlurPower::BoxBlurPower(BoxBlurWindow *gui, int x, int y, int w,
417                 const char *name, int *power)
418  : BoxBlurNum(gui, x, y, w, name, power, 1, 10)
419 {
420 }
421
422 BoxBlurWindow::BoxBlurWindow(BoxBlurEffect *plugin)
423  : PluginClientWindow(plugin, xS(360), yS(260), xS(360), yS(260), 0)
424 {
425         this->plugin = plugin;
426         blur_horz = 0;
427         blur_vert = 0;
428         blur_power = 0;
429         box_x = 0;  box_y = 0;
430         box_w = 0;  box_h = 0;
431 }
432
433 BoxBlurWindow::~BoxBlurWindow()
434 {
435         delete blur_horz;
436         delete blur_vert;
437         delete blur_power;
438         delete box_x;
439         delete box_y;
440         delete box_w;
441         delete box_h;
442 }
443
444 void BoxBlurWindow::create_objects()
445 {
446         int x = xS(10), y = yS(10);
447         int ys10 = yS(10), ys20 = yS(20), ys30 = yS(30), ys40 = yS(40);
448         int t1 = x, t2 = t1+xS(24), t3 = t2+xS(100), t4 = t3+xS(24);
449         int ww = get_w() - 2*x, bar_o = xS(30), bar_m = xS(15);
450         int margin = plugin->get_theme()->widget_border;
451
452         BC_TitleBar *tbar;
453         add_subwindow(tbar = new BC_TitleBar(x, y, ww, bar_o, bar_m, _("Position & Size")));
454         y += ys20;
455         int x1 = ww - BoxBlurDrag::calculate_w(this) - margin;
456         if( plugin->drag && drag->drag_activate() ) {
457                 eprintf("drag enabled, but compositor already grabbed\n");
458                 plugin->drag = 0;
459         }
460         add_subwindow(drag = new BoxBlurDrag(this, plugin, x1, y));
461         drag->create_objects();
462
463         BC_Title *title;
464         add_subwindow(title = new BC_Title(t1, y, _("X:")));
465         box_x = new BoxBlurX(this, t2, y);
466         box_x->create_objects();
467         add_subwindow(title = new BC_Title(t3, y, _("W:")));
468         box_w = new BoxBlurW(this, t4, y);
469         box_w->create_objects();
470         y += ys30;
471         add_subwindow(title = new BC_Title(t1, y, _("Y:")));
472         box_y = new BoxBlurY(this, t2, y);
473         box_y->create_objects();
474         add_subwindow(title = new BC_Title(t3, y, _("H:")));
475         box_h = new BoxBlurH(this, t4, y);
476         box_h->create_objects();
477         y += ys40;
478
479         add_subwindow(tbar = new BC_TitleBar(x, y, ww, bar_o, bar_m, _("Blur")));
480         y += ys20;
481         blur_horz = new BoxBlurRadius(this, x, y, ww, _("Horz:"),
482                         &plugin->config.horz_radius);
483         blur_horz->create_objects();
484         y += ys30;
485         blur_vert = new BoxBlurRadius(this, x, y, ww, _("Vert:"),
486                         &plugin->config.vert_radius);
487         blur_vert->create_objects();
488         y += ys30;
489         blur_power = new BoxBlurPower(this, x, y, ww, _("Power:"),
490                         &plugin->config.power);
491         blur_power->create_objects();
492         y += ys40;
493         BC_Bar *bar;
494         add_subwindow(bar = new BC_Bar(x, y, ww));
495         y += ys10;
496
497         add_subwindow(reset = new BoxBlurReset(this, x, y));
498         x1 = x + ww - BoxBlurPreset::calculate_w(this);
499         add_subwindow(preset = new BoxBlurPreset(this, x1, y));
500         y += bmax(title->get_h(), reset->get_h()) + 2*margin;
501         show_window(1);
502 }
503
504 void BoxBlurWindow::update_gui()
505 {
506         BoxBlurConfig &config = plugin->config;
507         blur_horz->update(config.horz_radius);
508         blur_vert->update(config.vert_radius);
509         blur_power->update(config.power);
510         box_x->update(config.box_x);
511         box_y->update(config.box_y);
512         box_w->update((int64_t)config.box_w);
513         box_h->update((int64_t)config.box_h);
514         drag->drag_x = config.box_x;
515         drag->drag_y = config.box_y;
516         drag->drag_w = config.box_w;
517         drag->drag_h = config.box_h;
518 }
519
520
521 REGISTER_PLUGIN(BoxBlurEffect)
522 NEW_WINDOW_MACRO(BoxBlurEffect, BoxBlurWindow)
523 LOAD_CONFIGURATION_MACRO(BoxBlurEffect, BoxBlurConfig)
524
525 void BoxBlurEffect::render_gui(void *data)
526 {
527         BoxBlurEffect *box_blur = (BoxBlurEffect *)data;
528         box_blur->drag = drag;
529 }
530
531 int BoxBlurEffect::is_dragging()
532 {
533         drag = 0;
534         send_render_gui(this);
535         return drag;
536 }
537
538
539 BoxBlurEffect::BoxBlurEffect(PluginServer *server)
540  : PluginVClient(server)
541 {
542         box_blur = 0;
543         drag = 0;
544 }
545
546 BoxBlurEffect::~BoxBlurEffect()
547 {
548         delete box_blur;
549 }
550
551 const char* BoxBlurEffect::plugin_title() { return N_("BoxBlur"); }
552 int BoxBlurEffect::is_realtime() { return 1; }
553
554
555 void BoxBlurEffect::save_data(KeyFrame *keyframe)
556 {
557         FileXML output;
558         output.set_shared_output(keyframe->xbuf);
559         output.tag.set_title("BOXBLUR");
560         output.tag.set_property("HORZ_RADIUS", config.horz_radius);
561         output.tag.set_property("VERT_RADIUS", config.vert_radius);
562         output.tag.set_property("POWER", config.power);
563         output.tag.set_property("BOX_X", config.box_x);
564         output.tag.set_property("BOX_Y", config.box_y);
565         output.tag.set_property("BOX_W", config.box_w);
566         output.tag.set_property("BOX_H", config.box_h);
567         output.append_tag();
568         output.tag.set_title("/BOXBLUR");
569         output.append_tag();
570         output.append_newline();
571         output.terminate_string();
572 }
573
574 void BoxBlurEffect::read_data(KeyFrame *keyframe)
575 {
576         FileXML input;
577         input.set_shared_input(keyframe->xbuf);
578         int result = 0;
579
580         while( !(result = input.read_tag()) ) {
581                 if( input.tag.title_is("BOXBLUR") ) {
582                         config.horz_radius = input.tag.get_property("HORZ_RADIUS", config.horz_radius);
583                         config.vert_radius = input.tag.get_property("VERT_RADIUS", config.vert_radius);
584                         config.power = input.tag.get_property("POWER", config.power);
585                         config.box_x = input.tag.get_property("BOX_X", config.box_x);
586                         config.box_y = input.tag.get_property("BOX_Y", config.box_y);
587                         config.box_w = input.tag.get_property("BOX_W", config.box_w);
588                         config.box_h = input.tag.get_property("BOX_H", config.box_h);
589                 }
590         }
591 }
592
593 void BoxBlurEffect::draw_boundry()
594 {
595         if( !gui_open() ) return;
596         int box_x = config.box_x, box_y = config.box_y;
597         int box_w = config.box_w ? config.box_w : input->get_w();
598         int box_h = config.box_h ? config.box_h : input->get_h();
599         DragCheckBox::draw_boundary(output, box_x, box_y, box_w, box_h);
600 }
601
602 int BoxBlurEffect::process_realtime(VFrame *input, VFrame *output)
603 {
604         this->input = input;
605         this->output = output;
606         load_configuration();
607         int out_w = output->get_w(), out_h = output->get_h();
608
609         if( !box_blur ) {
610                 int cpus = (out_w * out_h)/0x80000 + 1;
611                 box_blur = new BoxBlur(cpus);
612         }
613         int x = config.box_x, y = config.box_y;
614         int ow = config.box_w ? config.box_w : out_w;
615         int oh = config.box_h ? config.box_h : out_h;
616         if( config.horz_radius ) {
617                 box_blur->hblur(output, input, config.horz_radius, config.power,
618                         -1, x,y, ow, oh);
619                 input = output;
620         }
621         if( config.vert_radius ) {
622                 box_blur->vblur(output, input, config.vert_radius, config.power,
623                         -1, x,y, ow, oh);
624         }
625
626         if( is_dragging() )
627                 draw_boundry();
628
629         return 1;
630 }
631
632 void BoxBlurEffect::update_gui()
633 {
634         if( !thread ) return;
635         load_configuration();
636         thread->window->lock_window("BoxBlurEffect::update_gui");
637         BoxBlurWindow *gui = (BoxBlurWindow *)thread->window;
638         gui->update_gui();
639         thread->window->unlock_window();
640 }
641
642
643 BoxBlurX::BoxBlurX(BoxBlurWindow *gui, int x, int y)
644  : BC_TumbleTextBox(gui, gui->plugin->config.box_x,
645                 -32767.f, 32767.f, x, y, xS(64))
646 {
647         this->gui = gui;
648         set_precision(1);
649 }
650 int BoxBlurX::handle_event()
651 {
652         gui->plugin->config.box_x = atof(get_text());
653         gui->update_drag();
654         return 1;
655 }
656
657 BoxBlurY::BoxBlurY(BoxBlurWindow *gui, int x, int y)
658  : BC_TumbleTextBox(gui, gui->plugin->config.box_y,
659                 -32767.f, 32767.f, x, y, xS(64))
660 {
661         this->gui = gui;
662         set_precision(1);
663 }
664 int BoxBlurY::handle_event()
665 {
666         gui->plugin->config.box_y = atof(get_text());
667         gui->update_drag();
668         return 1;
669 }
670
671 BoxBlurW::BoxBlurW(BoxBlurWindow *gui, int x, int y)
672  : BC_TumbleTextBox(gui, gui->plugin->config.box_w,
673                 0, 32767, x, y, xS(64))
674 {
675         this->gui = gui;
676 }
677 int BoxBlurW::handle_event()
678 {
679         gui->plugin->config.box_w = atol(get_text());
680         gui->update_drag();
681         return 1;
682 }
683
684 BoxBlurH::BoxBlurH(BoxBlurWindow *gui, int x, int y)
685  : BC_TumbleTextBox(gui, gui->plugin->config.box_h,
686                 0, 32767, x, y, xS(64))
687 {
688         this->gui = gui;
689 }
690 int BoxBlurH::handle_event()
691 {
692         gui->plugin->config.box_h = atol(get_text());
693         gui->update_drag();
694         return 1;
695 }
696
697 BoxBlurDrag::BoxBlurDrag(BoxBlurWindow *gui, BoxBlurEffect *plugin, int x, int y)
698  : DragCheckBox(plugin->server->mwindow, x, y, _("Drag"), &plugin->drag,
699                 plugin->config.box_x, plugin->config.box_y,
700                 plugin->config.box_w, plugin->config.box_h)
701 {
702         this->plugin = plugin;
703         this->gui = gui;
704 }
705
706 int BoxBlurDrag::calculate_w(BoxBlurWindow *gui)
707 {
708         int w, h;
709         calculate_extents(gui, &w, &h, _("Drag"));
710         return w;
711 }
712
713 Track *BoxBlurDrag::get_drag_track()
714 {
715         PluginServer *server = plugin->server;
716         int plugin_id = server->plugin_id;
717         Plugin *plugin = server->edl->tracks->plugin_exists(plugin_id);
718         return !plugin ? 0 : plugin->track;
719 }
720 int64_t BoxBlurDrag::get_drag_position()
721 {
722         return plugin->get_source_position();
723 }
724
725 void BoxBlurDrag::update_gui()
726 {
727         plugin->drag = get_value();
728         plugin->config.box_x = drag_x;
729         plugin->config.box_y = drag_y;
730         plugin->config.box_w = drag_w+0.5;
731         plugin->config.box_h = drag_h+0.5;
732         gui->box_x->update((float)plugin->config.box_x);
733         gui->box_y->update((float)plugin->config.box_y);
734         gui->box_w->update((int64_t)plugin->config.box_w);
735         gui->box_h->update((int64_t)plugin->config.box_h);
736         plugin->send_configure_change();
737 }
738
739 int BoxBlurDrag::handle_event()
740 {
741         int ret = DragCheckBox::handle_event();
742         plugin->drag = get_value();
743         plugin->send_configure_change();
744         return ret;
745 }
746
747 void BoxBlurWindow::update_drag()
748 {
749         drag->drag_x = plugin->config.box_x;
750         drag->drag_y = plugin->config.box_y;
751         drag->drag_w = plugin->config.box_w;
752         drag->drag_h = plugin->config.box_h;
753         plugin->send_configure_change();
754 }
755
756 BoxBlurReset::BoxBlurReset(BoxBlurWindow *gui, int x, int y)
757  : BC_GenericButton(x, y, _("Reset"))
758 {
759         this->gui = gui;
760 }
761
762 int BoxBlurReset::calculate_w(BoxBlurWindow *gui)
763 {
764         return BC_GenericButton::calculate_w(gui,_("Reset"));
765 }
766
767 int BoxBlurReset::handle_event()
768 {
769         BoxBlurEffect *plugin = gui->plugin;
770         plugin->config.reset();
771         gui->drag->update(0);
772         gui->drag->drag_deactivate();
773         gui->update_gui();
774         gui->update_drag();
775         return 1;
776 }
777
778 BoxBlurPreset::BoxBlurPreset(BoxBlurWindow *gui, int x, int y)
779  : BC_GenericButton(x, y, _("Default"))
780 {
781         this->gui = gui;
782 }
783
784 int BoxBlurPreset::calculate_w(BoxBlurWindow *gui)
785 {
786         return BC_GenericButton::calculate_w(gui,_("Default"));
787 }
788
789 int BoxBlurPreset::handle_event()
790 {
791         BoxBlurEffect *plugin = gui->plugin;
792         plugin->config.preset();
793         gui->drag->update(0);
794         gui->drag->drag_deactivate();
795         gui->update_gui();
796         gui->update_drag();
797         return 1;
798 }
799