ee3669beebbf22ee1366af72960b0943f73629e0
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / tracer / tracerwindow.C
1 /*
2  * CINELERRA
3  * Copyright (C) 2014 Adam Williams <broadcast at earthling dot net>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  */
20
21 #include "automation.h"
22 #include "bcdisplayinfo.h"
23 #include "clip.h"
24 #include "tracer.h"
25 #include "tracerwindow.h"
26 #include "cstrdup.h"
27 #include "cwindow.h"
28 #include "cwindowgui.h"
29 #include "edl.h"
30 #include "edlsession.h"
31 #include "language.h"
32 #include "mainerror.h"
33 #include "mwindow.h"
34 #include "plugin.h"
35 #include "pluginserver.h"
36 #include "theme.h"
37 #include "track.h"
38
39 #define COLOR_W 50
40 #define COLOR_H 30
41
42 TracerNum::TracerNum(TracerWindow *gui, int x, int y, float output)
43  : BC_TumbleTextBox(gui, output, -32767.0f, 32767.0f, x, y, 120)
44 {
45         this->gui = gui;
46         set_increment(1);
47         set_precision(1);
48 }
49
50 TracerNum::~TracerNum()
51 {
52 }
53
54 int TracerPointX::handle_event()
55 {
56         if( !TracerNum::handle_event() ) return 0;
57         TracerPointList *point_list = gui->point_list;
58         int hot_point = point_list->get_selection_number(0, 0);
59         TracerPoints &points = gui->plugin->config.points;
60         int sz = points.size();
61         if( hot_point >= 0 && hot_point < sz ) {
62                 float v = atof(get_text());
63                 points[hot_point]->x = v;
64                 point_list->set_point(hot_point, PT_X, v);
65         }
66         point_list->update_list(hot_point);
67         gui->send_configure_change();
68         return 1;
69 }
70 int TracerPointY::handle_event()
71 {
72         if( !TracerNum::handle_event() ) return 0;
73         TracerPointList *point_list = gui->point_list;
74         int hot_point = point_list->get_selection_number(0, 0);
75         TracerPoints &points = gui->plugin->config.points;
76         int sz = points.size();
77         if( hot_point >= 0 && hot_point < sz ) {
78                 float v = atof(get_text());
79                 points[hot_point]->y = v;
80                 point_list->set_point(hot_point, PT_Y, v);
81         }
82         point_list->update_list(hot_point);
83         gui->send_configure_change();
84         return 1;
85 }
86
87 TracerWindow::TracerWindow(Tracer *plugin)
88  : PluginClientWindow(plugin, 400, 420, 400, 420, 0)
89 {
90         this->plugin = plugin;
91         this->title_x = 0;    this->point_x = 0;
92         this->title_y = 0;    this->point_y = 0;
93         this->new_point = 0;  this->del_point = 0;
94         this->point_up = 0;   this->point_dn = 0;
95         this->drag = 0;       this->draw = 0;
96         this->button_no = 0;  this->invert = 0;
97         this->title_r = 0;    this->title_s = 0;
98         this->feather = 0;    this->radius = 0;
99         this->last_x = 0;     this->last_y = 0;
100         this->point_list = 0; this->pending_config = 0;
101 }
102
103 TracerWindow::~TracerWindow()
104 {
105         delete point_x;
106         delete point_y;
107 }
108
109 void TracerWindow::create_objects()
110 {
111         int x = 10, y = 10;
112         int margin = plugin->get_theme()->widget_border;
113         int hot_point = plugin->config.selected;
114         add_subwindow(title_x = new BC_Title(x, y, _("X:")));
115         int x1 = x + title_x->get_w() + margin;
116         TracerPoint *pt = hot_point >= 0 ? plugin->config.points[hot_point] : 0;
117         point_x = new TracerPointX(this, x1, y, !pt ? 0 : pt->x);
118         point_x->create_objects();
119         x1 += point_x->get_w() + margin;
120         add_subwindow(new_point = new TracerNewPoint(this, plugin, x1, y));
121         x1 += new_point->get_w() + margin;
122         add_subwindow(point_up = new TracerPointUp(this, x1, y));
123         y += point_x->get_h() + margin;
124         add_subwindow(title_y = new BC_Title(x, y, _("Y:")));
125         x1 = x + title_y->get_w() + margin;
126         point_y = new TracerPointY(this, x1, y, !pt ? 0 : pt->y);
127         point_y->create_objects();
128         x1 += point_y->get_w() + margin;
129         add_subwindow(del_point = new TracerDelPoint(this, plugin, x1, y));
130         x1 += del_point->get_w() + margin;
131         add_subwindow(point_dn = new TracerPointDn(this, x1, y));
132         y += point_y->get_h() + margin + 10;
133
134         add_subwindow(drag = new TracerDrag(this, x, y));
135         if( plugin->config.drag ) {
136                 if( !grab(plugin->server->mwindow->cwindow->gui) )
137                         eprintf("drag enabled, but compositor already grabbed\n");
138         }
139         x1 = x + drag->get_w() + margin + 20;
140         add_subwindow(draw = new TracerDraw(this, x1, y));
141         x1 += draw->get_w() + margin + 20;
142         add_subwindow(fill = new TracerFill(this, x1, y));
143         x1 += drag->get_w() + margin + 20;
144         int y1 = y + 3;
145         add_subwindow(reset = new TracerReset(this, plugin, x1, y1));
146         y1 += reset->get_h() + margin;
147         add_subwindow(invert = new TracerInvert(this, plugin, x1, y1));
148         y += drag->get_h() + margin + 15;
149
150         x1 = x + 80;
151         add_subwindow(title_r = new BC_Title(x, y, _("Feather:")));
152         add_subwindow(feather = new TracerFeather(this, x1, y, 150));
153         y += feather->get_h() + margin;
154         add_subwindow(title_s = new BC_Title(x, y, _("Radius:")));
155         add_subwindow(radius = new TracerRadius(this, x1, y, 150));
156         y += radius->get_h() + margin + 5;
157
158         add_subwindow(point_list = new TracerPointList(this, plugin, x, y));
159         point_list->update(plugin->config.selected);
160         y += point_list->get_h() + 10;
161
162         add_subwindow(new BC_Title(x, y, _(
163                 "Btn1: select/drag point\n"
164                 "Btn2: drag all points\n"
165                 "Btn3: add point on nearest line\n"
166                 "Btn3: shift: append point to end\n"
167                 "Wheel: rotate, centered on cursor\n"
168                 "Wheel: shift: scale, centered on cursor\n")));
169         show_window(1);
170 }
171
172 void TracerWindow::send_configure_change()
173 {
174         pending_config = 0;
175         plugin->send_configure_change();
176 }
177
178 int TracerWindow::grab_event(XEvent *event)
179 {
180         int ret = do_grab_event(event);
181         if( pending_config && !grab_event_count() )
182                 send_configure_change();
183         return ret;
184 }
185
186 int TracerWindow::do_grab_event(XEvent *event)
187 {
188         switch( event->type ) {
189         case ButtonPress: break;
190         case ButtonRelease: break;
191         case MotionNotify: break;
192         default:
193                 return 0;
194         }
195
196         MWindow *mwindow = plugin->server->mwindow;
197         CWindowGUI *cwindow_gui = mwindow->cwindow->gui;
198         CWindowCanvas *canvas = cwindow_gui->canvas;
199         int cx, cy;  cwindow_gui->get_relative_cursor(cx, cy);
200         cx -= canvas->view_x;
201         cy -= canvas->view_y;
202
203         if( !button_no ) {
204                 if( cx < 0 || cx >= canvas->view_w ||
205                     cy < 0 || cy >= canvas->view_h )
206                         return 0;
207         }
208
209         switch( event->type ) {
210         case ButtonPress:
211                 if( button_no ) return 0;
212                 button_no = event->xbutton.button;
213                 break;
214         case ButtonRelease:
215                 if( !button_no ) return 0;
216                 button_no = 0;
217                 return 1;
218         case MotionNotify:
219                 if( !button_no ) return 0;
220                 break;
221         default:
222                 return 0;
223         }
224
225         float cursor_x = cx, cursor_y = cy;
226         canvas->canvas_to_output(mwindow->edl, 0, cursor_x, cursor_y);
227         int64_t position = plugin->get_source_position();
228         float projector_x, projector_y, projector_z;
229         Track *track = plugin->server->plugin->track;
230         int track_w = track->track_w, track_h = track->track_h;
231         track->automation->get_projector(
232                 &projector_x, &projector_y, &projector_z,
233                 position, PLAY_FORWARD);
234         projector_x += mwindow->edl->session->output_w / 2;
235         projector_y += mwindow->edl->session->output_h / 2;
236         float output_x = (cursor_x - projector_x) / projector_z + track_w / 2;
237         float output_y = (cursor_y - projector_y) / projector_z + track_h / 2;
238         point_x->update((int64_t)(output_x));
239         point_y->update((int64_t)(output_y));
240         TracerPoints &points = plugin->config.points;
241
242         switch( event->type ) {
243         case ButtonPress: {
244                 float s = 1.02;
245                 float th = M_PI/360.f; // .5 deg per wheel_btn
246                 int shift_down = event->xbutton.state & ShiftMask;
247                 switch( button_no ) {
248                 case WHEEL_DOWN:
249                         s = 0.98;
250                         th = -th;  // fall thru
251                 case WHEEL_UP: {
252                         // shift_down scale, !shift_down rotate
253                         float st = sin(th), ct = cos(th);
254                         int sz = points.size();
255                         for( int i=0; i<sz; ++i ) {
256                                 TracerPoint *pt = points[i];
257                                 float px = pt->x - output_x, py = pt->y - output_y;
258                                 float nx = shift_down ? px*s : px*ct + py*st;
259                                 float ny = shift_down ? py*s : py*ct - px*st;
260                                 point_list->set_point(i, PT_X, pt->x = nx + output_x);
261                                 point_list->set_point(i, PT_Y, pt->y = ny + output_y);
262                         }
263                         point_list->update(-1);
264                         button_no = 0;
265                         break; }
266                 case RIGHT_BUTTON: {
267                         // shift_down adds to end
268                         int sz = !shift_down ? points.size() : 0;
269                         int k = !shift_down ? -1 : points.size()-1;
270                         float mx = FLT_MAX;
271                         for( int i=0; i<sz; ++i ) {
272                                 // pt on line pt[i+0]..pt[i+1] nearest cx,cy
273                                 TracerPoint *pt0 = points[i+0];
274                                 TracerPoint *pt1 = i+1<sz ? points[i+1] : points[0];
275                                 float x0 = pt0->x, y0 = pt0->y;
276                                 float x1 = pt1->x, y1 = pt1->y;
277                                 float dx = x1-x0, dy = y1-y0;
278                                 float rr = dx*dx + dy*dy;
279                                 if( !rr ) continue;
280                                 float u = ((x1-output_x)*dx + (y1-output_y)*dy) / rr;
281                                 if( u < 0 || u > 1 ) continue;  // past endpts
282                                 float x = x0*u + x1*(1-u);
283                                 float y = y0*u + y1*(1-u);
284                                 dx = output_x-x;  dy = output_y-y;
285                                 float dd = dx*dx + dy*dy;       // d**2 closest approach
286                                 if( mx > dd ) { mx = dd;  k = i; }
287                         }
288                         TracerPoint *pt = points[sz=plugin->new_point()];
289                         int hot_point = k+1;
290                         for( int i=sz; i>hot_point; --i ) points[i] = points[i-1];
291                         points[hot_point] = pt;
292                         pt->x = output_x;  pt->y = output_y;
293                         point_list->update(hot_point);
294                         break; }
295                 case LEFT_BUTTON: {
296                         int hot_point = -1, sz = points.size();
297                         if( sz > 0 ) {
298                                 TracerPoint *pt = points[hot_point=0];
299                                 double dist = DISTANCE(output_x,output_y, pt->x,pt->y);
300                                 for( int i=1; i<sz; ++i ) {
301                                         pt = points[i];
302                                         double d = DISTANCE(output_x,output_y, pt->x,pt->y);
303                                         if( d >= dist ) continue;
304                                         dist = d;  hot_point = i;
305                                 }
306                                 pt = points[hot_point];
307                                 float px = (pt->x - track_w / 2) * projector_z + projector_x;
308                                 float py = (pt->y - track_h / 2) * projector_z + projector_y;
309                                 dist = DISTANCE(px, py, cursor_x,cursor_y);
310                                 if( dist >= HANDLE_W ) hot_point = -1;
311                         }
312                         if( hot_point >= 0 && sz > 0 ) {
313                                 TracerPoint *pt = points[hot_point];
314                                 point_list->set_point(hot_point, PT_X, pt->x = output_x);
315                                 point_list->set_point(hot_point, PT_Y, pt->y = output_y);
316                                 point_list->update_list(hot_point);
317                         }
318                         break; }
319                 }
320                 break; }
321         case MotionNotify: {
322                 switch( button_no ) {
323                 case LEFT_BUTTON: {
324                         int hot_point = point_list->get_selection_number(0, 0);
325                         if( hot_point >= 0 && hot_point < points.size() ) {
326                                 TracerPoint *pt = points[hot_point];
327                                 if( pt->x == output_x && pt->y == output_y ) break;
328                                 point_list->set_point(hot_point, PT_X, pt->x = output_x);
329                                 point_list->set_point(hot_point, PT_Y, pt->y = output_y);
330                                 point_x->update(pt->x);
331                                 point_y->update(pt->y);
332                                 point_list->update_list(hot_point);
333                         }
334                         break; }
335                 case MIDDLE_BUTTON: {
336                         float dx = output_x - last_x, dy = output_y - last_y;
337                         int sz = points.size();
338                         for( int i=0; i<sz; ++i ) {
339                                 TracerPoint *pt = points[i];
340                                 point_list->set_point(i, PT_X, pt->x += dx);
341                                 point_list->set_point(i, PT_Y, pt->y += dy);
342                         }
343                         int hot_point = point_list->get_selection_number(0, 0);
344                         if( hot_point >= 0 && hot_point < sz ) {
345                                 TracerPoint *pt = points[hot_point];
346                                 point_x->update(pt->x);
347                                 point_y->update(pt->y);
348                                 point_list->update_list(hot_point);
349                         }
350                         break; }
351                 }
352                 break; }
353         }
354
355         last_x = output_x;  last_y = output_y;
356         pending_config = 1;
357         return 1;
358 }
359
360 void TracerWindow::done_event(int result)
361 {
362         ungrab(client->server->mwindow->cwindow->gui);
363 }
364
365 TracerPointList::TracerPointList(TracerWindow *gui, Tracer *plugin, int x, int y)
366  : BC_ListBox(x, y, 360, 130, LISTBOX_TEXT)
367 {
368         this->gui = gui;
369         this->plugin = plugin;
370         titles[PT_X] = _("X");    widths[PT_X] = 90;
371         titles[PT_Y] = _("Y");    widths[PT_Y] = 90;
372 }
373 TracerPointList::~TracerPointList()
374 {
375         clear();
376 }
377 void TracerPointList::clear()
378 {
379         for( int i=PT_SZ; --i>=0; )
380                 cols[i].remove_all_objects();
381 }
382
383 int TracerPointList::column_resize_event()
384 {
385         for( int i=PT_SZ; --i>=0; )
386                 widths[i] = get_column_width(i);
387         return 1;
388 }
389
390 int TracerPointList::handle_event()
391 {
392         int hot_point = get_selection_number(0, 0);
393         const char *x_text = "", *y_text = "";
394         TracerPoints &points = plugin->config.points;
395
396         int sz = points.size();
397         if( hot_point >= 0 && sz > 0 ) {
398                 x_text = gui->point_list->cols[PT_X].get(hot_point)->get_text();
399                 y_text = gui->point_list->cols[PT_Y].get(hot_point)->get_text();
400         }
401         gui->point_x->update(x_text);
402         gui->point_y->update(y_text);
403         update(hot_point);
404         gui->send_configure_change();
405         return 1;
406 }
407
408 int TracerPointList::selection_changed()
409 {
410         handle_event();
411         return 1;
412 }
413
414 void TracerPointList::new_point(const char *xp, const char *yp)
415 {
416         cols[PT_X].append(new BC_ListBoxItem(xp));
417         cols[PT_Y].append(new BC_ListBoxItem(yp));
418 }
419
420 void TracerPointList::del_point(int i)
421 {
422         for( int sz1=cols[0].size()-1, c=PT_SZ; --c>=0; )
423                 cols[c].remove_object_number(sz1-i);
424 }
425
426 void TracerPointList::set_point(int i, int c, float v)
427 {
428         char s[BCSTRLEN]; sprintf(s,"%0.4f",v);
429         set_point(i,c,s);
430 }
431 void TracerPointList::set_point(int i, int c, const char *cp)
432 {
433         cols[c].get(i)->set_text(cp);
434 }
435
436 int TracerPointList::set_selected(int k)
437 {
438         TracerPoints &points = plugin->config.points;
439         int sz = points.size();
440         if( !sz ) return -1;
441         bclamp(k, 0, sz-1);
442         update_selection(&cols[0], k);
443         return k;
444 }
445 void TracerPointList::update_list(int k)
446 {
447         int sz = plugin->config.points.size();
448         if( k < 0 || k >= sz ) k = -1;
449         plugin->config.selected = k;
450         update_selection(&cols[0], k);
451         int xpos = get_xposition(), ypos = get_yposition();
452         BC_ListBox::update(&cols[0], &titles[0],&widths[0],PT_SZ, xpos,ypos,k);
453         center_selection();
454 }
455 void TracerPointList::update(int k)
456 {
457         clear();
458         TracerPoints &points = plugin->config.points;
459         int sz = points.size();
460         for( int i=0; i<sz; ++i ) {
461                 TracerPoint *pt = points[i];
462                 char xtxt[BCSTRLEN];  sprintf(xtxt,"%0.4f", pt->x);
463                 char ytxt[BCSTRLEN];  sprintf(ytxt,"%0.4f", pt->y);
464                 new_point(xtxt, ytxt);
465         }
466         if( k >= 0 && k < sz ) {
467                 gui->point_x->update(gui->point_list->cols[PT_X].get(k)->get_text());
468                 gui->point_y->update(gui->point_list->cols[PT_Y].get(k)->get_text());
469         }
470         update_list(k);
471 }
472
473 void TracerWindow::update_gui()
474 {
475         TracerConfig &config = plugin->config;
476         drag->update(config.drag);
477         draw->update(config.draw);
478         fill->update(config.fill);
479         feather->update(config.feather);
480         radius->update(config.radius);
481         invert->update(config.invert);
482         point_list->update(-1);
483 }
484
485
486 TracerPointUp::TracerPointUp(TracerWindow *gui, int x, int y)
487  : BC_GenericButton(x, y, _("Up"))
488 {
489         this->gui = gui;
490 }
491 TracerPointUp::~TracerPointUp()
492 {
493 }
494
495 int TracerPointUp::handle_event()
496 {
497         TracerPoints &points = gui->plugin->config.points;
498         int sz = points.size();
499         int hot_point = gui->point_list->get_selection_number(0, 0);
500
501         if( sz > 1 && hot_point > 0 ) {
502                 TracerPoint *&pt0 = points[hot_point];
503                 TracerPoint *&pt1 = points[--hot_point];
504                 TracerPoint *t = pt0;  pt0 = pt1;  pt1 = t;
505                 gui->point_list->update(hot_point);
506         }
507         gui->send_configure_change();
508         return 1;
509 }
510
511 TracerPointDn::TracerPointDn(TracerWindow *gui, int x, int y)
512  : BC_GenericButton(x, y, _("Dn"))
513 {
514         this->gui = gui;
515 }
516 TracerPointDn::~TracerPointDn()
517 {
518 }
519
520 int TracerPointDn::handle_event()
521 {
522         TracerPoints &points = gui->plugin->config.points;
523         int sz = points.size();
524         int hot_point = gui->point_list->get_selection_number(0, 0);
525         if( sz > 1 && hot_point < sz-1 ) {
526                 TracerPoint *&pt0 = points[hot_point];
527                 TracerPoint *&pt1 = points[++hot_point];
528                 TracerPoint *t = pt0;  pt0 = pt1;  pt1 = t;
529                 gui->point_list->update(hot_point);
530         }
531         gui->send_configure_change();
532         return 1;
533 }
534
535 TracerDrag::TracerDrag(TracerWindow *gui, int x, int y)
536  : BC_CheckBox(x, y, gui->plugin->config.drag, _("Drag"))
537 {
538         this->gui = gui;
539 }
540 int TracerDrag::handle_event()
541 {
542         CWindowGUI *cwindow_gui = gui->plugin->server->mwindow->cwindow->gui;
543         int value = get_value();
544         if( value ) {
545                 if( !gui->grab(cwindow_gui) ) {
546                         update(value = 0);
547                         flicker(10,50);
548                 }
549         }
550         else
551                 gui->ungrab(cwindow_gui);
552         gui->plugin->config.drag = value;
553         gui->send_configure_change();
554         return 1;
555 }
556
557 TracerDraw::TracerDraw(TracerWindow *gui, int x, int y)
558  : BC_CheckBox(x, y, gui->plugin->config.draw, _("Draw"))
559 {
560         this->gui = gui;
561 }
562 int TracerDraw::handle_event()
563 {
564         gui->plugin->config.draw = get_value();
565         gui->send_configure_change();
566         return 1;
567 }
568
569 TracerFill::TracerFill(TracerWindow *gui, int x, int y)
570  : BC_CheckBox(x, y, gui->plugin->config.fill, _("Fill"))
571 {
572         this->gui = gui;
573 }
574 int TracerFill::handle_event()
575 {
576         gui->plugin->config.fill = get_value();
577         gui->send_configure_change();
578         return 1;
579 }
580
581 TracerFeather::TracerFeather(TracerWindow *gui, int x, int y, int w)
582  : BC_ISlider(x,y,0,w,w, -50,50, gui->plugin->config.feather)
583 {
584         this->gui = gui;
585 }
586 int TracerFeather::handle_event()
587 {
588         gui->plugin->config.feather = get_value();
589         gui->send_configure_change();
590         return 1;
591 }
592
593 TracerRadius::TracerRadius(TracerWindow *gui, int x, int y, int w)
594  : BC_FSlider(x,y, 0,w,w, -5.f,5.f, gui->plugin->config.radius)
595 {
596         this->gui = gui;
597 }
598 int TracerRadius::handle_event()
599 {
600         gui->plugin->config.radius = get_value();
601         gui->send_configure_change();
602         return 1;
603 }
604
605 TracerNewPoint::TracerNewPoint(TracerWindow *gui, Tracer *plugin, int x, int y)
606  : BC_GenericButton(x, y, 80, _("New"))
607 {
608         this->gui = gui;
609         this->plugin = plugin;
610 }
611 TracerNewPoint::~TracerNewPoint()
612 {
613 }
614 int TracerNewPoint::handle_event()
615 {
616         int k = plugin->new_point();
617         gui->point_list->update(k);
618         gui->send_configure_change();
619         return 1;
620 }
621
622 TracerDelPoint::TracerDelPoint(TracerWindow *gui, Tracer *plugin, int x, int y)
623  : BC_GenericButton(x, y, 80, C_("Del"))
624 {
625         this->gui = gui;
626         this->plugin = plugin;
627 }
628 TracerDelPoint::~TracerDelPoint()
629 {
630 }
631 int TracerDelPoint::handle_event()
632 {
633         int hot_point = gui->point_list->get_selection_number(0, 0);
634         TracerPoints &points = plugin->config.points;
635         if( hot_point >= 0 && hot_point < points.size() ) {
636                 plugin->config.del_point(hot_point);
637                 gui->point_list->update(--hot_point);
638                 gui->send_configure_change();
639         }
640         return 1;
641 }
642
643 TracerReset::TracerReset(TracerWindow *gui, Tracer *plugin, int x, int y)
644  : BC_GenericButton(x, y, _("Reset"))
645 {
646         this->gui = gui;
647         this->plugin = plugin;
648 }
649 TracerReset::~TracerReset()
650 {
651 }
652 int TracerReset::handle_event()
653 {
654         TracerConfig &config = plugin->config;
655         if( !config.drag ) {
656                 MWindow *mwindow = plugin->server->mwindow;
657                 CWindowGUI *cwindow_gui = mwindow->cwindow->gui;
658                 if( gui->grab(cwindow_gui) )
659                         config.drag = 1;
660                 else
661                         gui->drag->flicker(10,50);
662         }
663         config.draw = 1;
664         config.fill = 0;
665         config.invert = 0;
666         config.feather = 0;
667         config.radius = 1;
668         config.selected = -1;
669         TracerPoints &points = plugin->config.points;
670         points.remove_all_objects();
671         gui->point_list->update(-1);
672         gui->update_gui();
673         gui->send_configure_change();
674         return 1;
675 }
676
677 TracerInvert::TracerInvert(TracerWindow *gui, Tracer *plugin, int x, int y)
678  : BC_CheckBox(x, y, gui->plugin->config.invert, _("Invert"))
679 {
680         this->gui = gui;
681         this->plugin = plugin;
682 }
683 TracerInvert::~TracerInvert()
684 {
685 }
686 int TracerInvert::handle_event()
687 {
688         plugin->config.invert = get_value();
689         gui->send_configure_change();
690         return 1;
691 }
692