2f984cddb372a9519a51a5427a0a56d12bcb7227
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / sketcher / sketcherwindow.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 "sketcher.h"
25 #include "sketcherwindow.h"
26 #include "cstrdup.h"
27 #include "cwindow.h"
28 #include "cwindowgui.h"
29 #include "edl.h"
30 #include "edlsession.h"
31 #include "keys.h"
32 #include "language.h"
33 #include "mainerror.h"
34 #include "mwindow.h"
35 #include "plugin.h"
36 #include "pluginserver.h"
37 #include "theme.h"
38 #include "track.h"
39
40 #define AltMask Mod1Mask
41
42 #define COLOR_W 32
43 #define COLOR_H 24
44
45 const char *SketcherPoint::types[] = {
46         N_("off"),
47         N_("line"),
48         N_("curve"),
49 };
50 const char *SketcherCurve::pens[] = {
51         N_("off"),
52         N_("box"),
53         N_("+"),
54         N_("/"),
55         N_("X"),
56 };
57
58
59 SketcherCurvePenItem::SketcherCurvePenItem(int pen)
60  : BC_MenuItem(_(SketcherCurve::pens[pen]))
61 {
62         this->pen = pen;
63 }
64 int SketcherCurvePenItem::handle_event()
65 {
66         SketcherCurvePen *popup = (SketcherCurvePen*)get_popup_menu();
67         popup->update(pen);
68         SketcherWindow *gui = popup->gui;
69         SketcherConfig &config = gui->plugin->config;
70         int ci = config.cv_selected;
71         if( ci >= 0 && ci < config.curves.size() ) {
72                 SketcherCurve *cv = config.curves[ci];
73                 cv->pen = pen;
74                 gui->curve_list->update(ci);
75                 gui->send_configure_change();
76         }
77         return 1;
78 }
79
80 SketcherCurvePen::SketcherCurvePen(SketcherWindow *gui, int x, int y, int pen)
81  : BC_PopupMenu(x,y,72,_(cv_pen[pen]))
82 {
83         this->gui = gui;
84 }
85 void SketcherCurvePen::create_objects()
86 {
87         int n = sizeof(cv_pen)/sizeof(cv_pen[0]);
88         for( int pen=0; pen<n; ++pen )
89                 add_item(new SketcherCurvePenItem(pen));
90 }
91 void SketcherCurvePen::update(int pen)
92 {
93         set_text(_(cv_pen[pen]));
94 }
95
96
97 SketcherCurveColor::SketcherCurveColor(SketcherWindow *gui, int x, int y, int w, int h)
98  : BC_Button(x, y, w, vframes)
99 {
100         this->gui = gui;
101         this->color = CV_COLOR;
102         for( int i=0; i<3; ++i ) {
103                 vframes[i] = new VFrame(w, h, BC_RGB888);
104                 vframes[i]->clear_frame();
105         }
106 }
107
108 SketcherCurveColor::~SketcherCurveColor()
109 {
110         for( int i=0; i<3; ++i )
111                 delete vframes[i];
112 }
113
114 void SketcherCurveColor::set_color(int color)
115 {
116         this->color = color;
117         int r = (color>>16) & 0xff;
118         int g = (color>>8) & 0xff;
119         int b = (color>>0) & 0xff;
120         for( int i=0; i<3; ++i ) {
121                 VFrame *vframe = vframes[i];
122                 int ww = vframe->get_w(), hh = vframe->get_h();
123                 uint8_t **rows = vframe->get_rows();
124                 int rr = r, gg = g, bb = b;
125                 switch( i ) {
126                 case BUTTON_UP:
127                         break;
128                 case BUTTON_UPHI:
129                         if( (rr+=48) > 0xff ) rr = 0xff;
130                         if( (gg+=48) > 0xff ) gg = 0xff;
131                         if( (bb+=48) > 0xff ) bb = 0xff;
132                         break;
133                 case BUTTON_DOWNHI:
134                         if( (rr-=48) < 0x00 ) rr = 0x00;
135                         if( (gg-=48) < 0x00 ) gg = 0x00;
136                         if( (bb-=48) < 0x00 ) bb = 0x00;
137                         break;
138                 }
139                 for( int y=0; y<hh; ++y ) {
140                         uint8_t *rp = rows[y];
141                         for( int x=0; x<ww; ++x ) {
142                                 *rp++ = rr;  *rp++ = gg;  *rp++ = bb;
143                         }
144                 }
145         }
146         set_images(vframes);
147 }
148
149 void SketcherCurveColor::update_gui(int color)
150 {
151         set_color(color);
152         draw_face();
153 }
154
155 int SketcherCurveColor::handle_event()
156 {
157         gui->start_color_thread(this);
158         return 1;
159 }
160
161 SketcherCurveColorPicker::SketcherCurveColorPicker(SketcherWindow *gui, SketcherCurveColor *color_button)
162  : ColorPicker(0, _("Color"))
163 {
164         this->gui = gui;
165         this->color_button = color_button;
166         this->color = 0;
167         color_update = new SketcherCurveColorThread(this);
168 }
169
170 SketcherCurveColorPicker::~SketcherCurveColorPicker()
171 {
172         delete color_update;
173 }
174
175 void SketcherCurveColorPicker::start(int color)
176 {
177         start_window(color, 0, 1);
178         color_update->start();
179 }
180
181 void SketcherCurveColorPicker::handle_done_event(int result)
182 {
183         color_update->stop();
184         gui->lock_window("SketcherCurveColorPicker::handle_done_event");
185         if( result ) color = orig_color;
186         color_button->update_gui(color);
187         gui->unlock_window();
188         SketcherConfig &config = gui->plugin->config;
189         int ci = config.cv_selected;
190         if( ci >= 0 && ci < config.curves.size() ) {
191                 SketcherCurve *cv = config.curves[ci];
192                 cv->color = color;
193                 gui->curve_list->update(ci);
194                 gui->send_configure_change();
195         }
196 }
197
198 int SketcherCurveColorPicker::handle_new_color(int color, int alpha)
199 {
200         this->color = color;
201         color_update->update_lock->unlock();
202         return 1;
203 }
204
205 void SketcherCurveColorPicker::update_gui()
206 {
207         gui->lock_window("SketcherCurveColorPicker::update_gui");
208         color_button->update_gui(color);
209         SketcherConfig &config = gui->plugin->config;
210         int ci = config.cv_selected;
211         if( ci >= 0 ) {
212                 SketcherCurve *cv = config.curves[ci];
213                 cv->color = color;
214                 gui->curve_list->update(ci);
215                 gui->send_configure_change();
216         }
217         gui->unlock_window();
218 }
219
220 SketcherCurveColorThread::SketcherCurveColorThread(SketcherCurveColorPicker *color_picker)
221  : Thread(1, 0, 0)
222 {
223         this->color_picker = color_picker;
224         this->update_lock = new Condition(0,"SketcherCurveColorThread::update_lock");
225         done = 1;
226 }
227
228 SketcherCurveColorThread::~SketcherCurveColorThread()
229 {
230         stop();
231         delete update_lock;
232 }
233
234 void SketcherCurveColorThread::start()
235 {
236         if( done ) {
237                 done = 0;
238                 Thread::start();
239         }
240 }
241
242 void SketcherCurveColorThread::stop()
243 {
244         if( !done ) {
245                 done = 1;
246                 update_lock->unlock();
247                 join();
248         }
249 }
250
251 void SketcherCurveColorThread::run()
252 {
253         while( !done ) {
254                 update_lock->lock("SketcherCurveColorThread::run");
255                 if( done ) break;
256                 color_picker->update_gui();
257         }
258 }
259
260
261 SketcherNum::SketcherNum(SketcherWindow *gui, int x, int y, int output,
262                 int mn, int mx)
263  : BC_TumbleTextBox(gui, output, mn, mx, x, y, 64)
264 {
265         this->gui = gui;
266         set_increment(1);
267 }
268
269 SketcherNum::~SketcherNum()
270 {
271 }
272
273 int SketcherPointX::handle_event()
274 {
275         if( !SketcherNum::handle_event() ) return 0;
276         SketcherConfig &config = gui->plugin->config;
277         int ci = config.cv_selected;
278         if( ci >= 0 && ci < config.curves.size() ) {
279                 SketcherCurve *cv = config.curves[ci];
280                 SketcherPointList *point_list = gui->point_list;
281                 int pi = config.pt_selected;
282                 SketcherPoints &points = cv->points;
283                 if( pi >= 0 && pi < points.size() ) {
284                         int v = atoi(get_text());
285                         points[pi]->x = v;
286                         point_list->set_point(pi, PT_X, v);
287                         point_list->update_list(pi);
288                         gui->send_configure_change();
289                 }
290         }
291         return 1;
292 }
293 int SketcherPointY::handle_event()
294 {
295         if( !SketcherNum::handle_event() ) return 0;
296         SketcherConfig &config = gui->plugin->config;
297         int ci = config.cv_selected;
298         if( ci >= 0 && ci < config.curves.size() ) {
299                 SketcherCurve *cv = config.curves[ci];
300                 SketcherPointList *point_list = gui->point_list;
301                 int pi = config.pt_selected;
302                 SketcherPoints &points = cv->points;
303                 if( pi >= 0 && pi < points.size() ) {
304                         int v = atoi(get_text());
305                         points[pi]->y = v;
306                         point_list->set_point(pi, PT_Y, v);
307                         point_list->update_list(pi);
308                         gui->send_configure_change();
309                 }
310         }
311         return 1;
312 }
313
314 int SketcherCurveRadius::handle_event()
315 {
316         if( !SketcherNum::handle_event() ) return 0;
317         SketcherConfig &config = gui->plugin->config;
318         int ci = config.cv_selected;
319         if( ci >= 0 && ci < config.curves.size() ) {
320                 SketcherCurve *cv = config.curves[ci];
321                 int v = atoi(get_text());
322                 cv->radius = v;
323                 gui->curve_list->update(ci);
324                 gui->send_configure_change();
325         }
326         return 1;
327 }
328
329
330 SketcherWindow::SketcherWindow(Sketcher *plugin)
331  : PluginClientWindow(plugin, 380, 580, 380, 580, 0)
332 {
333         this->plugin = plugin;
334         this->title_pen = 0;  this->curve_pen = 0;
335         this->title_color = 0; this->curve_color = 0;
336         this->color_picker = 0; this->new_points = 0;
337         this->new_curve = 0;  this->del_curve = 0;
338         this->curve_up = 0;   this->curve_dn = 0;
339         this->title_x = 0;    this->point_x = 0;
340         this->title_y = 0;    this->point_y = 0;
341         this->new_point = 0;  this->del_point = 0;
342         this->point_up = 0;   this->point_dn = 0;
343         this->drag = 0;       this->dragging = 0;
344         this->last_x = 0;     this->last_y = 0;
345         this->point_list = 0; this->pending_config = 0;
346 }
347
348 SketcherWindow::~SketcherWindow()
349 {
350         delete curve_radius;
351         delete point_x;
352         delete point_y;
353         delete color_picker;
354 }
355
356 void SketcherWindow::create_objects()
357 {
358         int x = 10, y = 10, dy = 0, x1, y1;
359         int margin = plugin->get_theme()->widget_border;
360         BC_Title *title;
361         int ci = plugin->config.cv_selected;
362         if( ci < 0 || ci >= plugin->config.curves.size() )
363                 ci = plugin->new_curve();
364         SketcherCurve *cv = plugin->config.curves[ci];
365
366         reset_curves = new SketcherResetCurves(this, plugin, x1=x, y+3);
367         add_subwindow(reset_curves);    dy = bmax(dy,reset_curves->get_h());
368         x1 += reset_curves->get_w() + 2*margin;
369         const char *curve_text = _("Curve");
370         title_radius = new BC_Title(x1, y, _("Width:"));
371         add_subwindow(title_radius);    dy = bmax(dy,title_radius->get_h());
372         x1 += title_radius->get_w() + margin;
373         curve_radius = new SketcherCurveRadius(this, x1, y, cv->radius);
374         curve_radius->create_objects();
375         y += dy + 2*margin;             dy = 0;
376
377         x1 = get_w()-x - BC_Title::calculate_w(this, curve_text, LARGEFONT);
378         y1 = y-margin - BC_Title::calculate_h(this, curve_text, LARGEFONT);
379         title = new BC_Title(x1, y1, curve_text, LARGEFONT,
380                 get_resources()->menu_highlighted_fontcolor);
381         add_subwindow(title);           dy = bmax(dy,title->get_h());
382         curve_list = new SketcherCurveList(this, plugin, x, y);
383         add_subwindow(curve_list);      dy = bmax(dy,curve_list->get_h());
384         y += dy + margin;               dy = 0;
385
386         new_curve = new SketcherNewCurve(this, plugin, x1=x, y);
387         add_subwindow(new_curve);       dy = bmax(dy,new_curve->get_h());
388         x1 += new_curve->get_w() + margin;
389         curve_up = new SketcherCurveUp(this, x1, y);
390         add_subwindow(curve_up);        dy = bmax(dy,curve_up->get_h());
391         x1 += curve_up->get_w() + 4*margin;
392         title_pen = new BC_Title(x1+30, y, _("Pen:"));
393         add_subwindow(title_pen);       dy = bmax(dy,title_pen->get_h());
394         int x2 = (get_w()+x1)/2;
395         title_color = new BC_Title(x2+10, y, _("Color:"));
396         add_subwindow(title_color);     dy = bmax(dy,title_color->get_h());
397         y += dy + margin;               dy = 0;
398
399         del_curve = new SketcherDelCurve(this, plugin, x1=x, y);
400         add_subwindow(del_curve);       dy = bmax(dy,del_curve->get_h());
401         x1 += del_curve->get_w() + margin;
402         curve_dn = new SketcherCurveDn(this, x1, y);
403         add_subwindow(curve_dn);        dy = bmax(dy,curve_dn->get_h());
404         x1 += curve_dn->get_w() + 4*margin;
405         curve_pen = new SketcherCurvePen(this, x1, y, cv->pen);
406         add_subwindow(curve_pen);       dy = bmax(dy,curve_pen->get_h());
407         curve_pen->create_objects();
408         curve_color = new SketcherCurveColor(this, x2+20, y, COLOR_W, COLOR_H);
409         add_subwindow(curve_color);     dy = bmax(dy,curve_color->get_h());
410         curve_color->set_color(cv->color);
411         curve_color->draw_face();
412         y += dy + margin;  dy = 0;
413         curve_list->update(ci);
414
415         BC_Bar *bar;
416         bar = new BC_Bar(x, y, get_w()-2*x);
417         add_subwindow(bar);             dy = bmax(dy,bar->get_h());
418         y += dy + 2*margin;
419
420         int pi = plugin->config.pt_selected;
421         SketcherPoint *pt = pi >= 0 && pi < cv->points.size() ? cv->points[pi] : 0;
422         reset_points = new SketcherResetPoints(this, plugin, x1=x, y+3);
423         add_subwindow(reset_points);    dy = bmax(dy,reset_points->get_h());
424         x1 += reset_points->get_w() + 2*margin; 
425         if( plugin->config.drag ) {
426                 if( !grab(plugin->server->mwindow->cwindow->gui) ) {
427                         eprintf("drag enabled, but compositor already grabbed\n");
428                         plugin->config.drag = 0;
429                 }
430         }
431         drag = new SketcherDrag(this, x1, y);
432         add_subwindow(drag);            dy = bmax(dy,drag->get_h());
433         x1 += drag->get_w() + 2*margin;
434         int pty = pt ? pt->pty : PTY_LINE;
435         point_type = new SketcherPointType(this, x1, y, pty);
436         add_subwindow(point_type);      dy = bmax(dy,point_type->get_h());
437         point_type->create_objects();
438         y += dy + margin;  dy = 0;
439
440         const char *point_text = _("Point");
441         x1 = get_w()-x - BC_Title::calculate_w(this, point_text, LARGEFONT);
442         y1 = y-margin - BC_Title::calculate_h(this, point_text, LARGEFONT);
443         add_subwindow(title = new BC_Title(x1, y1, point_text, LARGEFONT,
444                 get_resources()->menu_highlighted_fontcolor));
445         point_list = new SketcherPointList(this, plugin, x, y);
446         add_subwindow(point_list);      dy = bmax(dy,point_list->get_h());
447         y += dy + margin;               dy = 0;
448
449         new_point = new SketcherNewPoint(this, plugin, x1=x, y);
450         add_subwindow(new_point);       dy = bmax(dy,new_point->get_h());
451         x1 += new_point->get_w() + margin;
452         point_up = new SketcherPointUp(this, x1, y);
453         add_subwindow(point_up);        dy = bmax(dy,point_up->get_h());
454         x1 += point_up->get_w() + 2*margin;
455         title_x = new BC_Title(x1, y, _("X:"));
456         add_subwindow(title_x);         dy = bmax(dy,title_x->get_h());
457         x1 += title_x->get_w() + margin;
458         point_x = new SketcherPointX(this, x1, y, !pt ? 0.f : pt->x);
459         point_x->create_objects();      dy = bmax(dy, point_x->get_h());
460         y += dy + margin;  dy = 0;
461
462         del_point = new SketcherDelPoint(this, plugin, x1=x, y);
463         add_subwindow(del_point);       dy = bmax(dy,del_point->get_h());
464         x1 += del_point->get_w() + margin;
465         point_dn = new SketcherPointDn(this, x1, y);
466         add_subwindow(point_dn);        dy = bmax(dy,point_dn->get_h());
467         x1 += point_dn->get_w() + 2*margin;
468         title_y = new BC_Title(x1, y, _("Y:"));
469         add_subwindow(title_y);         dy = bmax(dy,title_y->get_h());
470         x1 += title_y->get_w() + margin;
471         point_y = new SketcherPointY(this, x1, y, !pt ? 0.f : pt->y);
472         point_y->create_objects();      dy = bmax(dy, point_y->get_h());
473         y += dy + margin + 5;
474         point_list->update(pi);
475
476         add_subwindow(notes0 = new BC_Title(x, y,
477                  _("\n"
478                    "Shift=\n"
479                    "None=\n"
480                    "Ctrl=\n"
481                    "Alt=\n"
482                    "DEL=\n")));
483         add_subwindow(notes1 = new BC_Title(x+80, y,
484                  _("     LMB\n"
485                    "new line point\n"
486                    "select point\n"
487                    "drag point\n"
488                    "new curve\n"
489                    "deletes point\n")));
490         add_subwindow(notes2 = new BC_Title(x+200, y,
491                  _("      RMB\n"
492                    "new arc point\n"
493                    "select curve\n"
494                    "drag curve\n"
495                    "drag all curves\n"
496                    "deletes curve\n")));
497         show_window(1);
498 }
499
500 void SketcherWindow::send_configure_change()
501 {
502         pending_config = 0;
503         plugin->send_configure_change();
504 }
505
506 int SketcherWindow::grab_event(XEvent *event)
507 {
508         int ret = do_grab_event(event);
509         if( pending_config && !grab_event_count() )
510                 send_configure_change();
511         return ret;
512 }
513
514 int SketcherWindow::do_grab_event(XEvent *event)
515 {
516         switch( event->type ) {
517         case ButtonPress: break;
518         case ButtonRelease: break;
519         case MotionNotify: break;
520         case KeyPress:
521                 if( keysym_lookup(event) > 0 ) {
522                         switch( get_keysym() ) {
523                         case XK_Delete:
524                                 pending_config = 1;
525                                 return (event->xkey.state & ShiftMask) ?
526                                         del_curve->handle_event() :
527                                         del_point->handle_event() ;
528                         }
529                 } // fall thru
530         default:
531                 return 0;
532         }
533
534         MWindow *mwindow = plugin->server->mwindow;
535         CWindowGUI *cwindow_gui = mwindow->cwindow->gui;
536         CWindowCanvas *canvas = cwindow_gui->canvas;
537         int cx, cy;  cwindow_gui->get_relative_cursor(cx, cy);
538         cx -= mwindow->theme->ccanvas_x;
539         cy -= mwindow->theme->ccanvas_y;
540
541         if( !dragging ) {
542                 if( cx < 0 || cx >= mwindow->theme->ccanvas_w ||
543                     cy < 0 || cy >= mwindow->theme->ccanvas_h )
544                         return 0;
545         }
546
547         switch( event->type ) {
548         case ButtonPress:
549                 if( dragging ) return 0;
550                 dragging = 1;
551                 break;
552         case ButtonRelease:
553         case MotionNotify:
554                 if( !dragging ) return 0;
555                 break;
556         default:
557                 return 0;
558         }
559
560         SketcherConfig &config = plugin->config;
561         int ci = config.cv_selected;
562         if( ci < 0 || ci >= plugin->config.curves.size() )
563                 return 1;
564         SketcherCurves &curves = config.curves;
565         SketcherCurve *cv = curves[ci];
566         int pi = config.pt_selected;
567
568         float cursor_x = cx, cursor_y = cy;
569         canvas->canvas_to_output(mwindow->edl, 0, cursor_x, cursor_y);
570         int64_t position = plugin->get_source_position();
571         float projector_x, projector_y, projector_z;
572         Track *track = plugin->server->plugin->track;
573         int track_w = track->track_w, track_h = track->track_h;
574         track->automation->get_projector(
575                 &projector_x, &projector_y, &projector_z,
576                 position, PLAY_FORWARD);
577         projector_x += mwindow->edl->session->output_w / 2;
578         projector_y += mwindow->edl->session->output_h / 2;
579         float output_x = (cursor_x - projector_x) / projector_z + track_w / 2;
580         float output_y = (cursor_y - projector_y) / projector_z + track_h / 2;
581         SketcherPoints &points = cv->points;
582         int state = event->xmotion.state;
583
584         switch( event->type ) {
585         case ButtonPress: {
586                 int button_no = event->xbutton.button;
587                 switch( button_no ) {
588                 case LEFT_BUTTON: {
589                         if( (state & ShiftMask) ) { // create new point/string
590                                 ++new_points;
591                                 pi = plugin->new_point(cv, PTY_LINE, output_x, output_y, pi+1);
592                                 point_list->update(pi);
593                                 break;
594                         }
595                         if( (state & AltMask) ) { // create new curve
596                                 ci = plugin->new_curve(cv->pen, cv->radius, cv->color);
597                                 curve_list->update(ci);
598                                 point_list->update(-1);
599                                 break;
600                         }
601                         SketcherPoint *pt = 0; // select point
602                         int last_point = pi;  pi = -1;
603                         int n = points.size();
604                         double dist = DBL_MAX;
605                         for( int i=0; i<n; ++i ) {
606                                 SketcherPoint *p = points[i];
607                                 double d = DISTANCE(output_x,output_y, p->x,p->y);
608                                 if( d < dist ) { dist = d;  pi = i;  pt = p; }
609                         }
610                         if( pt ) {
611                                 float px = (pt->x - track_w / 2) * projector_z + projector_x;
612                                 float py = (pt->y - track_h / 2) * projector_z + projector_y;
613                                 float pix = DISTANCE(px, py, cursor_x,cursor_y);
614                                 if( pix >= HANDLE_W ) { pi = -1;  pt = 0; }
615                         }
616                         if( pi != last_point )
617                                 point_list->set_selected(pi);
618                         break; }
619                 case RIGHT_BUTTON: {
620                         if( (state & ShiftMask) ) { // create new curve point
621                                 ++new_points;
622                                 pi = plugin->new_point(cv, PTY_CURVE,
623                                                 output_x, output_y, pi+1);
624                                 point_list->update(pi);
625                                 break;
626                         }
627                         SketcherPoint *pt = 0; // select point
628                         double dist = DBL_MAX;
629                         ci = -1;
630                         for( int i=0; i<curves.size(); ++i ) {
631                                 SketcherCurve *crv = curves[i];
632                                 int pts = crv->points.size();
633                                 for( int k=0; k<pts; ++k ) {
634                                         SketcherPoint *p = crv->points[k];
635                                         double d = DISTANCE(output_x,output_y, p->x,p->y);
636                                         if( d < dist ) {
637                                                 dist = d;
638                                                 pt = p;    pi = k;
639                                                 cv = crv;  ci = i;
640                                         }
641                                 }
642                         }
643                         if( pt ) {
644                                 float px = (pt->x - track_w / 2) * projector_z + projector_x;
645                                 float py = (pt->y - track_h / 2) * projector_z + projector_y;
646                                 float pix = DISTANCE(px, py, cursor_x,cursor_y);
647                                 if( pix >= HANDLE_W ) { pi = -1;  pt = 0; }
648                         }
649                         if( pi >= 0 ) {
650                                 curve_list->update(ci);
651                                 point_list->update(pi);
652                         }
653                         break; }
654                 }
655                 break; }
656         case MotionNotify: {
657                 if( (state & ShiftMask) ) {  // string of points
658                     if( (state & (Button1Mask|Button3Mask)) ) {
659                                 if( pi < 0 ) pi = points.size()-1;
660                                 if( pi >= 0 ) {
661                                         SketcherPoint *pt = pi >= 0 && pi < points.size() ?  points[pi] : 0;
662                                         float frac_w = DISTANCE(pt->x, pt->y, output_x, output_y) / get_w();
663                                         if( frac_w < 0.01 ) break; // 1 percent w
664                                 }
665                                 ++new_points;
666                                 int pty = (state & Button1Mask) ? PTY_LINE : PTY_CURVE;
667                                 pi = plugin->new_point(cv, pty, output_x, output_y, pi+1);
668                                 point_list->update(pi);
669                                 break;
670                         }
671                 }
672                 if( (state & Button1Mask) ) {
673                         if( (state & ControlMask) ) { // drag selected point
674                                 SketcherPoint *pt = pi >= 0 && pi < points.size() ?  points[pi] : 0;
675                                 if( pt ) {
676                                         point_list->set_point(pi, PT_X, pt->x = output_x);
677                                         point_list->set_point(pi, PT_Y, pt->y = output_y);
678                                         point_list->update_list(pi);
679                                         point_x->update(pt->x);
680                                         point_y->update(pt->y);
681                                 }
682                                 break;
683                         }
684                 }
685                 if( (state & Button3Mask) ) {
686                         if( (state & (ControlMask | AltMask)) ) { // drag selected curve(s)
687                                 SketcherCurves &curves = plugin->config.curves;
688                                 int dx = round(output_x - last_x);
689                                 int dy = round(output_y - last_y);
690                                 int mnc = (state & AltMask) || ci<0 ? 0 : ci;
691                                 int mxc = (state & AltMask) ? curves.size() : ci+1;
692                                 for( int i=mnc; i<mxc; ++i ) {
693                                         SketcherCurve *crv = plugin->config.curves[i];
694                                         int pts = crv->points.size();
695                                         for( int k=0; k<pts; ++k ) {
696                                                 SketcherPoint *pt = crv->points[k];
697                                                 pt->x += dx;  pt->y += dy;
698                                         }
699                                 }
700                                 SketcherPoint *pt = pi >= 0 && pi < points.size() ?
701                                         points[pi] : 0;
702                                 point_x->update(pt ? pt->x : 0.f);
703                                 point_y->update(pt ? pt->y : 0.f);
704                                 point_list->update(pi);
705                                 break;
706                         }
707                 }
708                 break; }
709         case ButtonRelease: {
710                 new_points = 0;
711                 dragging = 0;
712                 break; }
713         }
714
715         last_x = output_x;  last_y = output_y;
716         pending_config = 1;
717         return 1;
718 }
719
720 int SketcherWindow::keypress_event()
721 {
722         int key = get_keypress();
723         switch( key ) {
724         case DELETE: return shift_down() ?
725                         del_curve->handle_event() :
726                         del_point->handle_event() ;
727         }
728         return 0;
729 }
730
731 void SketcherWindow::done_event(int result)
732 {
733         ungrab(client->server->mwindow->cwindow->gui);
734 }
735
736 void SketcherWindow::start_color_thread(SketcherCurveColor *color_button)
737 {
738         unlock_window();
739         delete color_picker;
740         color_picker = new SketcherCurveColorPicker(this, color_button);
741         int color = CV_COLOR, ci = plugin->config.cv_selected;
742         if( ci >= 0 && ci < plugin->config.curves.size() ) {
743                 SketcherCurve *cv = plugin->config.curves[ci];
744                 color = cv->color;
745         }
746         color_picker->start(color);
747         lock_window("SketcherWindow::start_color_thread");
748 }
749
750
751 SketcherCurveList::SketcherCurveList(SketcherWindow *gui, Sketcher *plugin, int x, int y)
752  : BC_ListBox(x, y, 360, 130, LISTBOX_TEXT)
753 {
754         this->gui = gui;
755         this->plugin = plugin;
756         titles[CV_ID] = _("id");  widths[CV_ID] = 64;
757         titles[CV_RAD] = _("radius");  widths[CV_RAD] = 64;
758         titles[CV_PEN] = _("pen");  widths[CV_PEN] = 64;
759         titles[CV_CLR] = _("color");  widths[CV_CLR] = 64;
760 }
761 SketcherCurveList::~SketcherCurveList()
762 {
763         clear();
764 }
765 void SketcherCurveList::clear()
766 {
767         for( int i=CV_SZ; --i>=0; )
768                 cols[i].remove_all_objects();
769 }
770
771 int SketcherCurveList::column_resize_event()
772 {
773         for( int i=CV_SZ; --i>=0; )
774                 widths[i] = get_column_width(i);
775         return 1;
776 }
777
778 int SketcherCurveList::handle_event()
779 {
780         int ci = get_selection_number(0, 0);
781         set_selected(ci);
782         gui->point_list->update(0);
783         gui->send_configure_change();
784         return 1;
785 }
786
787 int SketcherCurveList::selection_changed()
788 {
789         handle_event();
790         return 1;
791 }
792
793 void SketcherCurveList::set_curve(int i, int c, const char *cp)
794 {
795         cols[c].get(i)->set_text(cp);
796 }
797
798 void SketcherCurveList::set_selected(int k)
799 {
800         int ci = -1;
801         if( k >= 0 && k < plugin->config.curves.size() ) {
802                 SketcherCurve *cv = plugin->config.curves[k];
803                 gui->curve_radius->update(cv->radius);
804                 gui->curve_pen->update(cv->pen);
805                 gui->curve_color->update_gui(cv->color);
806                 ci = k;
807         }
808         plugin->config.cv_selected = ci;
809         update_list(ci);
810 }
811
812 void SketcherCurveList::update_list(int k)
813 {
814         int xpos = get_xposition(), ypos = get_yposition();
815         if( k >= 0 ) update_selection(&cols[0], k);
816         BC_ListBox::update(&cols[0], &titles[0],&widths[0],CV_SZ, xpos,ypos,k);
817         center_selection();
818 }
819
820 void SketcherCurveList::update(int k)
821 {
822         clear();
823         SketcherCurves &curves = plugin->config.curves;
824         int sz = curves.size();
825         for( int i=0; i<sz; ++i ) {
826                 SketcherCurve *cv = curves[i];
827                 char itxt[BCSTRLEN];  sprintf(itxt,"%d", cv->id);
828                 char ptxt[BCSTRLEN];  sprintf(ptxt,"%s", cv_pen[cv->pen]);
829                 char rtxt[BCSTRLEN];  sprintf(rtxt,"%d", cv->radius);
830                 int color = cv->color;
831                 int r = (color>>16)&0xff, g = (color>>8)&0xff, b = (color>>0)&0xff;
832                 char ctxt[BCSTRLEN];  sprintf(ctxt,"#%02x%02x%02x", r, g, b);
833                 add_curve(itxt, ptxt, rtxt, ctxt);
834         }
835         set_selected(k);
836 }
837
838 void SketcherCurveList::add_curve(const char *id, const char *pen,
839                 const char *radius, const char *color)
840 {
841         cols[CV_ID].append(new BC_ListBoxItem(id));
842         cols[CV_RAD].append(new BC_ListBoxItem(radius));
843         cols[CV_PEN].append(new BC_ListBoxItem(pen));
844         cols[CV_CLR].append(new BC_ListBoxItem(color));
845 }
846
847 SketcherNewCurve::SketcherNewCurve(SketcherWindow *gui, Sketcher *plugin, int x, int y)
848  : BC_GenericButton(x, y, 64, _("New"))
849 {
850         this->gui = gui;
851         this->plugin = plugin;
852 }
853 SketcherNewCurve::~SketcherNewCurve()
854 {
855 }
856 int SketcherNewCurve::handle_event()
857 {
858         int pen = PTY_LINE, radius = 1, color = CV_COLOR;
859         int ci = plugin->config.cv_selected;
860         if( ci >= 0 && ci < plugin->config.curves.size() ) {
861                 SketcherCurve *cv = plugin->config.curves[ci];
862                 pen = cv->pen;  radius = cv->radius;  color = cv->color;
863         }
864         ci = plugin->new_curve(pen, radius, color);
865         gui->curve_list->update(ci);
866         gui->point_list->update(-1);
867         gui->send_configure_change();
868         return 1;
869 }
870
871 SketcherDelCurve::SketcherDelCurve(SketcherWindow *gui, Sketcher *plugin, int x, int y)
872  : BC_GenericButton(x, y, 64, C_("Del"))
873 {
874         this->gui = gui;
875         this->plugin = plugin;
876 }
877 SketcherDelCurve::~SketcherDelCurve()
878 {
879 }
880 int SketcherDelCurve::handle_event()
881 {
882         SketcherConfig &config = plugin->config;
883         int ci = config.cv_selected;
884         SketcherCurves &curves = config.curves;
885         if( ci >= 0 && ci < curves.size() ) {
886                 curves.remove_object_number(ci--);
887                 if( ci < 0 ) ci = 0;
888                 if( !curves.size() )
889                         ci = plugin->new_curve();
890                 gui->curve_list->update(ci);
891                 gui->point_list->update(-1);
892                 gui->send_configure_change();
893         }
894         return 1;
895 }
896
897 SketcherCurveUp::SketcherCurveUp(SketcherWindow *gui, int x, int y)
898  : BC_GenericButton(x, y, _("Up"))
899 {
900         this->gui = gui;
901 }
902 SketcherCurveUp::~SketcherCurveUp()
903 {
904 }
905
906 int SketcherCurveUp::handle_event()
907 {
908         SketcherConfig &config = gui->plugin->config;
909         int ci = config.cv_selected;
910         SketcherCurves &curves = config.curves;
911         if( ci > 0 && ci < curves.size() ) {
912                 SketcherCurve *&cv0 = curves[ci];
913                 SketcherCurve *&cv1 = curves[--ci];
914                 SketcherCurve *t = cv0;  cv0 = cv1;  cv1 = t;
915                 gui->curve_list->update(ci);
916         }
917         gui->send_configure_change();
918         return 1;
919 }
920
921 SketcherCurveDn::SketcherCurveDn(SketcherWindow *gui, int x, int y)
922  : BC_GenericButton(x, y, _("Dn"))
923 {
924         this->gui = gui;
925 }
926 SketcherCurveDn::~SketcherCurveDn()
927 {
928 }
929
930 int SketcherCurveDn::handle_event()
931 {
932         SketcherConfig &config = gui->plugin->config;
933         int ci = config.cv_selected;
934         SketcherCurves &curves = config.curves;
935         if( ci >= 0 && ci < curves.size()-1 ) {
936                 SketcherCurve *&cv0 = curves[ci];
937                 SketcherCurve *&cv1 = curves[++ci];
938                 SketcherCurve *t = cv0;  cv0 = cv1;  cv1 = t;
939                 gui->curve_list->update(ci);
940         }
941         gui->send_configure_change();
942         return 1;
943 }
944
945
946 SketcherPointTypeItem::SketcherPointTypeItem(int pty)
947  : BC_MenuItem(_(pt_type[pty]))
948 {
949         this->pty = pty;
950 }
951 int SketcherPointTypeItem::handle_event()
952 {
953         SketcherPointType *popup = (SketcherPointType*)get_popup_menu();
954         popup->update(pty);
955         SketcherWindow *gui = popup->gui;
956         SketcherConfig &config = gui->plugin->config;
957         SketcherCurves &curves = config.curves;
958         int ci = config.cv_selected;
959         if( ci < 0 || ci >= curves.size() )
960                 return 1;
961         SketcherCurve *cv = curves[ci];
962         SketcherPoints &points = cv->points;
963         int pi = config.pt_selected;
964
965         ArrayList<int> selected;
966         for( int v,i=0; (v=gui->point_list->get_selection_number(0, i))>=0; ++i )
967                 selected.append(v);
968
969         for( int i=selected.size(); --i>=0; ) {
970                 int k = selected[i];
971                 if( k < 0 || k >= points.size() ) continue;
972                 SketcherPoint *pt = cv->points[k];
973                 pt->pty = pty;
974                 gui->point_list->set_point(k, PT_TY, _(pt_type[pty]));
975         }
976
977         gui->point_list->update_list(pi);
978         gui->send_configure_change();
979         return 1;
980 }
981
982 SketcherPointType::SketcherPointType(SketcherWindow *gui, int x, int y, int pty)
983  : BC_PopupMenu(x,y,64,_(pt_type[pty]))
984 {
985         this->gui = gui;
986 }
987 void SketcherPointType::create_objects()
988 {
989         for( int pty=0; pty<PT_SZ; ++pty )
990                 add_item(new SketcherPointTypeItem(pty));
991 }
992 void SketcherPointType::update(int pty)
993 {
994         set_text(_(pt_type[pty]));
995 }
996
997
998 SketcherPointList::SketcherPointList(SketcherWindow *gui, Sketcher *plugin, int x, int y)
999  : BC_ListBox(x, y, 360, 130, LISTBOX_TEXT)
1000 {
1001         this->gui = gui;
1002         this->plugin = plugin;
1003         titles[PT_ID] = _("ID");    widths[PT_ID] = 50;
1004         titles[PT_TY] = _("Type");  widths[PT_TY] = 80;
1005         titles[PT_X] = _("X");      widths[PT_X] = 90;
1006         titles[PT_Y] = _("Y");      widths[PT_Y] = 90;
1007         set_selection_mode(LISTBOX_MULTIPLE);
1008 }
1009 SketcherPointList::~SketcherPointList()
1010 {
1011         clear();
1012 }
1013 void SketcherPointList::clear()
1014 {
1015         for( int i=PT_SZ; --i>=0; )
1016                 cols[i].remove_all_objects();
1017 }
1018
1019 int SketcherPointList::column_resize_event()
1020 {
1021         for( int i=PT_SZ; --i>=0; )
1022                 widths[i] = get_column_width(i);
1023         return 1;
1024 }
1025
1026 int SketcherPointList::handle_event()
1027 {
1028         int pi = get_selection_number(0, 0);
1029         if( get_selection_number(0, 1) >= 0 ) pi = -1;
1030         set_selected(pi);
1031         gui->send_configure_change();
1032         return 1;
1033 }
1034
1035 int SketcherPointList::selection_changed()
1036 {
1037         handle_event();
1038         return 1;
1039 }
1040
1041 void SketcherPointList::add_point(const char *id, const char *ty, const char *xp, const char *yp)
1042 {
1043         cols[PT_ID].append(new BC_ListBoxItem(id));
1044         cols[PT_TY].append(new BC_ListBoxItem(ty));
1045         cols[PT_X].append(new BC_ListBoxItem(xp));
1046         cols[PT_Y].append(new BC_ListBoxItem(yp));
1047 }
1048
1049 void SketcherPointList::set_point(int i, int c, int v)
1050 {
1051         char stxt[BCSTRLEN];
1052         sprintf(stxt,"%d",v);
1053         set_point(i,c,stxt);
1054 }
1055 void SketcherPointList::set_point(int i, int c, const char *cp)
1056 {
1057         cols[c].get(i)->set_text(cp);
1058 }
1059
1060 void SketcherPointList::set_selected(int k)
1061 {
1062         SketcherPoint *pt = 0;
1063         int ci = plugin->config.cv_selected, pi = -1;
1064         if( ci >= 0 && ci < plugin->config.curves.size() ) {
1065                 SketcherCurve *cv = plugin->config.curves[ci];
1066                 pt = k >= 0 && k < cv->points.size() ? cv->points[pi=k] : 0;
1067         }
1068         gui->point_type->update(pt ? pt->pty : PTY_OFF);
1069         gui->point_x->update(pt ? pt->x : 0.f);
1070         gui->point_y->update(pt ? pt->y : 0.f);
1071         plugin->config.pt_selected = pi;
1072         update_list(pi);
1073 }
1074 void SketcherPointList::update_list(int k)
1075 {
1076         int xpos = get_xposition(), ypos = get_yposition();
1077         if( k >= 0 ) update_selection(&cols[0], k);
1078         BC_ListBox::update(&cols[0], &titles[0],&widths[0],PT_SZ, xpos,ypos,k);
1079         center_selection();
1080 }
1081 void SketcherPointList::update(int k)
1082 {
1083         clear();
1084         int ci = plugin->config.cv_selected, sz = 0;
1085         if( ci >= 0 && ci < plugin->config.curves.size() ) {
1086                 SketcherCurve *cv = plugin->config.curves[ci];
1087                 SketcherPoints &points = cv->points;
1088                 sz = points.size();
1089                 for( int i=0; i<sz; ++i ) {
1090                         SketcherPoint *pt = points[i];
1091                         char itxt[BCSTRLEN];  sprintf(itxt,"%d", pt->id);
1092                         char ttxt[BCSTRLEN];  sprintf(ttxt,"%s", _(pt_type[pt->pty]));
1093                         char xtxt[BCSTRLEN];  sprintf(xtxt,"%d", pt->x);
1094                         char ytxt[BCSTRLEN];  sprintf(ytxt,"%d", pt->y);
1095                         add_point(itxt, ttxt, xtxt, ytxt);
1096                 }
1097         }
1098         set_selected(k);
1099 }
1100
1101 void SketcherWindow::update_gui()
1102 {
1103         SketcherConfig &config = plugin->config;
1104         int ci = config.cv_selected;
1105         int pi = config.pt_selected;
1106         curve_list->update(ci);
1107         point_list->update(pi);
1108         SketcherCurve *cv = ci >= 0 ? config.curves[ci] : 0;
1109         curve_radius->update(cv ? cv->radius : 1);
1110         curve_pen->update(cv ? cv->pen : PEN_SQUARE);
1111         curve_color->set_color(cv ? cv->color : CV_COLOR);
1112         SketcherPoint *pt = pi >= 0 ? cv->points[pi] : 0;
1113         point_x->update(pt ? pt->x : 0);
1114         point_y->update(pt ? pt->y : 0);
1115         drag->update(plugin->config.drag);
1116 }
1117
1118
1119 SketcherPointUp::SketcherPointUp(SketcherWindow *gui, int x, int y)
1120  : BC_GenericButton(x, y, _("Up"))
1121 {
1122         this->gui = gui;
1123 }
1124 SketcherPointUp::~SketcherPointUp()
1125 {
1126 }
1127
1128 int SketcherPointUp::handle_event()
1129 {
1130         SketcherConfig &config = gui->plugin->config;
1131         int ci = config.cv_selected;
1132         if( ci < 0 || ci >= config.curves.size() )
1133                 return 1;
1134         SketcherCurve *cv = config.curves[ci];
1135         SketcherPoints &points = cv->points;
1136         if( points.size() < 2 )
1137                 return 1;
1138         int pi = config.pt_selected;
1139
1140         ArrayList<int> selected;
1141         for( int v,i=0; (v=gui->point_list->get_selection_number(0, i))>=0; ++i )
1142                 selected.append(v);
1143
1144         for( int i=0; i<selected.size(); ++i ) {
1145                 int k = selected[i];
1146                 if( k <= 0 ) continue;
1147                 if( k == pi ) --pi;
1148                 SketcherPoint *&pt0 = points[k];
1149                 SketcherPoint *&pt1 = points[--k];
1150                 SketcherPoint *t = pt0;  pt0 = pt1;  pt1 = t;
1151         }
1152         gui->point_list->update(pi);
1153         gui->send_configure_change();
1154         return 1;
1155 }
1156
1157 SketcherPointDn::SketcherPointDn(SketcherWindow *gui, int x, int y)
1158  : BC_GenericButton(x, y, _("Dn"))
1159 {
1160         this->gui = gui;
1161 }
1162 SketcherPointDn::~SketcherPointDn()
1163 {
1164 }
1165
1166 int SketcherPointDn::handle_event()
1167 {
1168         SketcherConfig &config = gui->plugin->config;
1169         int ci = config.cv_selected;
1170         if( ci < 0 || ci >= config.curves.size() )
1171                 return 1;
1172         SketcherCurve *cv = config.curves[ci];
1173         SketcherPoints &points = cv->points;
1174         int sz1 = points.size()-1;
1175         if( sz1 < 1 )
1176                 return 1;
1177         int pi = config.pt_selected;
1178
1179         ArrayList<int> selected;
1180         for( int v,i=0; (v=gui->point_list->get_selection_number(0, i))>=0; ++i )
1181                 selected.append(v);
1182
1183         for( int i=selected.size(); --i>=0; ) {
1184                 int k = selected[i];
1185                 if( k >= sz1 ) continue;
1186                 if( k == pi ) ++pi;
1187                 SketcherPoint *&pt0 = points[k];
1188                 SketcherPoint *&pt1 = points[++k];
1189                 SketcherPoint *t = pt0;  pt0 = pt1;  pt1 = t;
1190         }
1191         gui->point_list->update(pi);
1192         gui->send_configure_change();
1193         return 1;
1194 }
1195
1196 SketcherDrag::SketcherDrag(SketcherWindow *gui, int x, int y)
1197  : BC_CheckBox(x, y, gui->plugin->config.drag, _("Drag"))
1198 {
1199         this->gui = gui;
1200 }
1201 int SketcherDrag::handle_event()
1202 {
1203         CWindowGUI *cwindow_gui = gui->plugin->server->mwindow->cwindow->gui;
1204         int value = get_value();
1205         if( value ) {
1206                 if( !gui->grab(cwindow_gui) ) {
1207                         update(value = 0);
1208                         flicker(10,50);
1209                 }
1210         }
1211         else
1212                 gui->ungrab(cwindow_gui);
1213         gui->plugin->config.drag = value;
1214         gui->send_configure_change();
1215         return 1;
1216 }
1217
1218 SketcherNewPoint::SketcherNewPoint(SketcherWindow *gui, Sketcher *plugin, int x, int y)
1219  : BC_GenericButton(x, y, 64, _("New"))
1220 {
1221         this->gui = gui;
1222         this->plugin = plugin;
1223 }
1224 SketcherNewPoint::~SketcherNewPoint()
1225 {
1226 }
1227 int SketcherNewPoint::handle_event()
1228 {
1229         int pi = plugin->config.pt_selected;
1230         int k = plugin->new_point(pi+1);
1231         gui->point_list->update(k);
1232         gui->send_configure_change();
1233         return 1;
1234 }
1235
1236 SketcherDelPoint::SketcherDelPoint(SketcherWindow *gui, Sketcher *plugin, int x, int y)
1237  : BC_GenericButton(x, y, 64, C_("Del"))
1238 {
1239         this->gui = gui;
1240         this->plugin = plugin;
1241 }
1242 SketcherDelPoint::~SketcherDelPoint()
1243 {
1244 }
1245 int SketcherDelPoint::handle_event()
1246 {
1247         SketcherConfig &config = gui->plugin->config;
1248         SketcherCurves &curves = config.curves;
1249         int ci = config.cv_selected;
1250         if( ci < 0 || ci >= curves.size() )
1251                 return 1;
1252         SketcherCurve *cv = curves[ci];
1253         SketcherPoints &points = cv->points;
1254         int pi = config.pt_selected;
1255
1256         ArrayList<int> selected;
1257         for( int v,i=0; (v=gui->point_list->get_selection_number(0, i))>=0; ++i )
1258                 selected.append(v);
1259
1260         for( int i=selected.size(); --i>=0; ) {
1261                 int k = selected[i];
1262                 if( k < 0 || k >= points.size() ) continue;
1263                 points.remove_object_number(k);
1264                 if( k == pi && --pi < 0 && points.size() > 0 ) pi = 0;
1265         }
1266         gui->point_list->update(pi);
1267         gui->send_configure_change();
1268         return 1;
1269 }
1270
1271 SketcherResetCurves::SketcherResetCurves(SketcherWindow *gui, Sketcher *plugin, int x, int y)
1272  : BC_GenericButton(x, y, _("Reset"))
1273 {
1274         this->gui = gui;
1275         this->plugin = plugin;
1276 }
1277 SketcherResetCurves::~SketcherResetCurves()
1278 {
1279 }
1280 int SketcherResetCurves::handle_event()
1281 {
1282         SketcherConfig &config = plugin->config;
1283         config.curves.remove_all_objects();
1284         int ci = plugin->new_curve();
1285         gui->curve_list->update(ci);
1286         gui->point_list->update(-1);
1287         gui->send_configure_change();
1288         return 1;
1289 }
1290
1291 SketcherResetPoints::SketcherResetPoints(SketcherWindow *gui, Sketcher *plugin, int x, int y)
1292  : BC_GenericButton(x, y, _("Reset"))
1293 {
1294         this->gui = gui;
1295         this->plugin = plugin;
1296 }
1297 SketcherResetPoints::~SketcherResetPoints()
1298 {
1299 }
1300 int SketcherResetPoints::handle_event()
1301 {
1302         SketcherConfig &config = gui->plugin->config;
1303         int ci = config.cv_selected;
1304         if( ci >= 0 && ci < config.curves.size() ) {
1305                 SketcherCurve *cv = config.curves[ci];
1306                 cv->points.remove_all_objects();
1307                 gui->point_list->update(-1);
1308                 gui->send_configure_change();
1309         }
1310         return 1;
1311 }
1312