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