sketcher rework, plugindialog selection fixes, new ffmpeg plugin.opts/plugin info...
authorGood Guy <[email protected]>
Sun, 18 Nov 2018 03:01:09 +0000 (20:01 -0700)
committerGood Guy <[email protected]>
Sun, 18 Nov 2018 03:01:09 +0000 (20:01 -0700)
cinelerra-5.1/cinelerra/plugindialog.C
cinelerra-5.1/cinelerra/track.C
cinelerra-5.1/cinelerra/vrender.C
cinelerra-5.1/expanders.txt
cinelerra-5.1/ffmpeg/plugin.opts
cinelerra-5.1/guicast/bclistbox.C
cinelerra-5.1/info/plugins.txt
cinelerra-5.1/plugins/sketcher/sketcher.C
cinelerra-5.1/plugins/sketcher/sketcher.h
cinelerra-5.1/plugins/sketcher/sketcherwindow.C
cinelerra-5.1/plugins/sketcher/sketcherwindow.h

index 439a6efb5d5feffb6d83f6b48bae9b94fd412dc7..ad964d52bbdef8801e530f21cf45d9d17b8599b9 100644 (file)
@@ -258,18 +258,19 @@ void PluginDialog::create_objects()
                thread->data_type);
 
 // Construct listbox items
-       for(int i = 0; i < plugin_locations.total; i++)
+       for(int i = 0; i < plugin_locations.total; )
        {
                Track *track = mwindow->edl->tracks->number(plugin_locations.values[i]->module);
                char *track_title = track->title;
                int number = plugin_locations.values[i]->plugin;
                double start = mwindow->edl->local_session->get_selectionstart(1);
                Plugin *plugin = track->get_current_plugin(start, number, PLAY_FORWARD, 1, 0);
-               if( !plugin ) continue;
+               if( !plugin ) { plugin_locations.remove_object_number(i);  continue; }
                char string[BCTEXTLEN];
                const char *plugin_title = _(plugin->title);
                snprintf(string, sizeof(string), "%s: %s", track_title, plugin_title);
                shared_data.append(new BC_ListBoxItem(string));
+               ++i;
        }
        for(int i = 0; i < module_locations.total; i++)
        {
index bac9abd68050bed5c1f8908fa9e92e239f8e4b7d..4afeeab86d9a369a09549ab546aa66b201b88165 100644 (file)
@@ -517,7 +517,7 @@ Plugin* Track::insert_effect(const char *title,
                if(source_track)
                {
                        Plugin *source_plugin = source_track->get_current_plugin(
-                               edl->local_session->get_selectionstart(),
+                               edl->local_session->get_selectionstart(1),
                                shared_location->plugin,
                                PLAY_FORWARD,
                                1,
index 42f83ef87e7d86e57a2c84a8bf7b4781fad41984..770dfb8877e168e7f92be2e7123ce4f653801e06 100644 (file)
@@ -61,7 +61,7 @@ VRender::VRender(RenderEngine *renderengine)
 {
        data_type = TRACK_VIDEO;
        transition_temp = 0;
-       overlayer = new OverlayFrame(renderengine->preferences->processors);
+       overlayer = new OverlayFrame(renderengine->preferences->project_smp);
        input_temp = 0;
        vmodule_render_fragment = 0;
        playback_buffer = 0;
index b4a2d6e90680c4b629cbda6cd4b7826ed74bb478..507b611cdd0b4719294855e55530d1d8e60110be 100644 (file)
@@ -42,6 +42,7 @@ Video Effects
                F_tlut2
                F_vectorscope
                F_vignette
+               F_vibrance
        - Motion
                Motion
                Motion 2 Point
@@ -75,6 +76,7 @@ Video Effects
                F_atadenoise
                F_bitplanenoise
                F_dctdnoiz
+               F_fftdnoiz
                F_hqdn3d
                F_nlmeans
                F_noise
index 27fcfaed52d37d73f12771ee853a73df3636fe2d..e59ea6a3c81fa62829ea3e161343ae2e3b1c30b6 100644 (file)
@@ -13,7 +13,7 @@ aeval exprs=(sin(2*PI*t*440)+sin(2*PI*t*350))/2*mod(floor(2*t),2):channel_layout
 #aevalsrc 0
 afade
 #afftfilt 1-clip((b/nb)*b,0,1)
-#afifo
+#afifo  ###will not work within cin
 aformat sample_fmts=u8|s16:channel_layouts=stereo
 agate
 #ahistogram dmode=single:r=25:s=hd720:scale=log:ascale=log:slide=replace
@@ -26,7 +26,7 @@ aloop
 #alphaextract
 #alphamerge
 #amerge
-#ametadata mode=print:file=ametadata.txt
+ametadata mode=print:file=/tmp/ametadata.txt
 #amix
 #amovie
 #anequalizer c0 f=200 w=100 g=-10 t=1|c1 f=200 w=100 g=-10 t=1
@@ -34,7 +34,7 @@ anoisesrc d=60:c=pink:r=48000:a=0.5
 #anull
 #anullsink
 #anullsrc
-#apad pad_len=1024
+#apad   ###not part of frame data
 aperms
 #aphasemeter r=25:s=800x400:rc=2:gc=7:bc=1
 aphaser
@@ -45,10 +45,10 @@ aresample sample_rate=48000
 #aselect
 #asendcmd
 #asetnsamples
-#asetpts PTS-STARTPTS
+#asetpts   ###not part of frame data
 asetrate r=48000
 #asettb
-#ashowinfo
+#ashowinfo ###not part of frame data
 #asidedata
 #asplit
 astats
@@ -125,7 +125,7 @@ field
 #fieldhint
 #fieldmatch
 fieldorder
-#fifo
+#fifo   ###will not work within cin
 fillborders
 #find_rect
 #firequalizer delay=0.1:fixed=on:zero_phase=on
@@ -139,8 +139,8 @@ fspp
 gblur
 #geq
 gradfun
-#haldclut
-#haldclutsrc
+#haldclut ###not working due to need for multiple video streams
+haldclutsrc
 #hdcd
 hflip
 highpass
@@ -177,7 +177,7 @@ mandelbrot
 mcdeint
 #mergeplanes 0x03010200:yuva444p
 mestimate
-#metadata mode=print:file=metadata.txt
+metadata mode=print:file=/tmp/metadata.txt
 #midequalizer
 #minterpolate
 #movie
@@ -186,7 +186,7 @@ mptestsrc t=dc_luma
 negate
 nlmeans r=15:p=7:s=2
 #nnedi
-#noformat pix_fmts=yuv420p
+#noformat ###not part of frame data
 noise
 #null
 #nullsink
@@ -196,7 +196,7 @@ owdenoise
 pad
 #palettegen
 #paletteuse
-#pan 1c|c0=0.9*c0+0.1*c1
+pan 1c|c0=0.9*c0+0.1*c1
 perms
 perspective
 phase
@@ -207,7 +207,7 @@ pp7
 prewitt
 #psnr PSNR=10*log10(MAX^2/MSE)
 #pullup
-#qp 2+2*sin(PI*qp)
+#qp     ###not part of frame data
 #random seed=-1
 readeia608
 readvitc
@@ -227,14 +227,14 @@ scale 200:100
 #selectivecolor greens=.5 0 -.33 0:blues=0 .27
 #sendcmd
 separatefields
-#setdar dar=16/9
-#setfield mode=auto
-#setpts PTS-STARTPTS
-#setsar sar=10/11
+#setdar   ###will not work because Format already set
+#setfield ###not part of frame data
+#setpts   ###not part of frame data
+#setsar   ###will not work because Format already set
 #settb
 #showcqt
 #showfreqs
-showinfo
+#showinfo ###not part of frame data
 showpalette s=30
 #showspectrum s=1280x480:scale=log
 #showspectrumpic
@@ -245,15 +245,15 @@ shuffleframes
 shuffleplanes
 #sidechaincompress
 #sidechaingate
-#sidedata mode=delete
+#sidedata mode=add
 signalstats
 #signature
-#silencedetect n=0.001
+#silencedetect n=0.001  ###does not appear to work
 silenceremove
 sine
 smartblur
-#smptebars
-#smptehdbars
+smptebars
+smptehdbars
 sobel
 #spectrumsynth
 #split
@@ -318,7 +318,7 @@ tlut2
 #tonemap
 #vmafmotion
 ; new in 4.0
-#acontrast Contrast=33
+acontrast
 #afir
 #convolve
 #deconvolve
@@ -338,14 +338,14 @@ acue
 #adeclick
 #adeclip
 aderivative
-afftdn
+#afftdn
 aintegral
 amplify
 chromahold
-cue
+#cue    ###freeze
 deblock
 fttdnoiz
-#graphmonitor
+graphmonitor
 greyedge
 #highshelf
 #lowshelf
@@ -353,14 +353,14 @@ lut1d
 pal75bars
 pal100bars
 setparams
-#sinc
+#sinc   ###freeze
 tmix
 vibrance
 ; broken in 4.1
 #acrossover
 #aiir
 #amultiply
-#bm3d
+#bm3d sigma=3:block=4:bstep=2:group=1:estim=basic
 #sr
 #xstack
 #agraphmonitor
index 2dd4283c990fc325d4caf6edc68068c882a4b035..4a55593fae1e2d23479905b3c8c3dd3c6e620919 100644 (file)
@@ -1643,6 +1643,7 @@ int BC_ListBox::center_selection(int selection,
                                        yposition = item->text_y - top_item->text_y - view_h / 2;
                                }
                        }
+                       if( yposition < 0 ) yposition = 0;
                        return 1;
                }
 
@@ -2645,11 +2646,9 @@ int BC_ListBox::button_press_event()
                        }
 // Select single item
                        else {
-                               if( !current_item->selected ) {
+                               if( !current_item->selected || !new_value ) {
                                        set_all_selected(data, 0);
-                                       set_selected(data,
-                                               selection_number,
-                                               1);
+                                       set_selected(data, selection_number, 1);
                                }
                                new_value = 1;
                        }
@@ -3033,9 +3032,6 @@ int BC_ListBox::cursor_motion_event()
                        if( (display_format == LISTBOX_TEXT ||
                             display_format == LISTBOX_ICON_LIST) &&
                                shift_down() ) {
-// Deselect everything.
-                               set_all_selected(data, 0);
-
 // Select just the items
                                redraw = expand_selection(0, selection_number);
                        }
index 86e83395b0d0a83e55561dbe46af179cee3d7574..fc19135492f8118b2fbbf41aa2e2a22c76f20a64 100644 (file)
@@ -214,6 +214,7 @@ Zoom Blur:  Blur the video and use a zoom effect.
 #
 #  Description of FFmpeg Video Plugins
 #
+F_amplify:     Amplify changes between successive video frames.
 F_atadenoise:  Apply an Adaptive Temporal Averaging Denoiser.
 F_avgblur:     Apply average blur filter.
 F_bbox:                Compute bounding box for each frame.
@@ -226,6 +227,7 @@ F_boxblur:  Blurs the input video.
                able to change the power and the
                radius of the boxblur applied to luma, chroma and alpha.
 F_bwdif:       Deinterlaces the input image.
+F_chromahold:  Turns a certain color range into gray.
 F_chromakey:   Turns a certain color into
                transparency.  Operates on YUV colors.
 F_ciescope:    Video CIE scope.
@@ -243,6 +245,7 @@ F_curves:   Adjust components curves.
 F_datascope:   Video data analysis.
 F_dctdnoiz:    Denoise frames using 2D DCT.
 F_deband:      Debands video.
+F_deblock:     Deblock video.
 F_deflate:     Applies deflate effect.
 F_deflicker:   Remove temporal frame luminance variations.
 F_dejudder:    Removes judder produced by pullup.
@@ -276,6 +279,7 @@ F_eq:               Adjusts brightness, contrast, gamma and saturation.
 F_entropy:     Measure video frames entropy.
 F_erosion:     Applies erosion effect.
 F_fade:                Fade in/out input video.
+F_fftdnoiz:    Denoise rames using 3D FFT.
 F_fftfilt:     Apply arbitrary expressions to pixels in frequency domain.
 F_field:       Extract a field from the input video.
 F_fieldorder:  Set the field order.
@@ -284,9 +288,13 @@ F_floodfill:       Fill area of the same color with another color.
 F_format:      Convert the input video to one of the specified pixel formats.
 F_framerate:   Upsamples or downsamples progressive
                source between specified frame rates.
+F_framestep:   Select one frame every N frames.
 F_fspp:                Applies Fast Simple Post-processing filter.
 F_gblur:       Apply Gaussian Blur filter.
 F_gradfun:     Debands video quickly using gradients.
+F_graphmonitor:        Show various filtergraph stats.
+F_greyedge:    Estimates scene illumination by grey edge assumption.
+F_haldclutsrc: Provide an identity Hald CLUT.
 F_hflip:       Horizontally flips the input video.
 F_histeq:      Applies global color histogram equalization.
 F_histogram:   Computes and draws a histogram.
@@ -300,18 +308,20 @@ F_inflate:        Applies inflate effect.
 F_interlace:   Convert progressive video into interlaced.
 F_kerndeint:   Applies kernel deinterlacing to the input.
 F_lenscorrection: Rectifies the image by correcting for lens distortion.
-F_Life:                Generate a life pattern.
+F_life:                Generate a life pattern.
 F_limiter:     Limit pixels components to the specified range.
 F_loop:                Loops video frames.
 F_lumakey:     Turns a certain luma into transparency.
 F_lut:         Compute and apply a lookup
                table to the RGB/YUV input video.
+F_lut1d:       Adjust colors using a 1D LUT.
 F_lut3d:       Apply a 3D LUT (look up table) to an input video.
 F_lutrgb:      Compute and apply a lookup table to the RGB input video.
 F_lutyuv:      Combine and apply a lookup table to the YUV input video.
 F_mandelbrot:  Render a Mandelbrot fractal.
 F_mcdeint:     Applies motion compensating deinterlacing.
 F_mestimate:   Generate motion vectors.
+F_metadata:    Manipulate video frame metadata.
 F_mpdecimate:  Remove near-duplicate frames.
 F_mptestsrc:   Generate various test pattern.
 F_negate:      Negates input video.
@@ -326,8 +336,10 @@ F_owdenoise:       Denoises using wavelets.
 F_oscilloscope:        2D video oscilloscope.  Useful to measure spatial impulse,
                step responses, and chroma delays.
 F_owndenoise:  Denoises using wavelets.
-F_Pad:         Add paddings to the input image, and place the original
+F_pad:         Add paddings to the input image, and place the original
                input at the provided x, y coordinates.
+F_pal100bars:  Generate PAL 100% color bars.
+F_pal75bars:   Generate PAL 75% color bars.
 F_perms:       Set permissions for the output video frame.
 F_perspective: Corrects the perspective of video.
 F_phase:       Phases shift fields.
@@ -353,6 +365,7 @@ F_rotate:   Rotates the input image.
 F_sab:         Applies shape adaptive blur.
 F_scale:       Scale the input video size and/or convert the image format.
 F_separatefields: Split input video frames into fields.
+F_setparams:   Force field, or color property for the output video frame.
 F_setrange:    Force color range for the output video frame.
 F_showinfo:    Show textual information for each video frame.
 F_showpalette: Display frame palette.
@@ -363,6 +376,8 @@ F_smartblur:        Blurs the input video without impacting
                the outlines. Through the settings you can
                select the radius,
                the strength and the threshold of luma and chroma.
+F_smptebars:   Generate SMPTE color bars.
+F_smptehdbars: Generate SMPTE HD color bars.
 F_sobel:       Applies sobel operator.
 F_spp:         Applies a simple post processing filter.
 F_stereo3d:    Converts video stereoscopic 3D view.
@@ -376,6 +391,7 @@ F_testsrc2: Generate another test pattern.
 F_tile:                Tile several successive frames together.
 F_tinterlace:  Performs temporal field interlacing.
 F_tlut2:       Compute and apply a lookup table from 2 successive frames.
+F_tmix:                Mix successive video frames.
 F_transpose:   Transposes input video.
 F_unsharp:     Sharpen or blur the input video.
 F_uspp:                Applies Ultra Simple/Slow Post-processing filter.
@@ -383,6 +399,7 @@ F_vaguedenoiser: Applies a Wavelet based Denoiser.
 F_vectorscope: Video vectorscope.
 F_vflip:       Flips the input video vertically.
 F_vfrdet:      Variable frame rate detect filter.
+F_vibrance:    Boost or alter saturation.
 F_vignette:    Makes or reverses a vignette effect.
                Through the settings you can set the circle center
                position on a X-Y axis,choose the angle,
@@ -401,7 +418,9 @@ F_abench:   Benchmark part of a filtergraph.
 F_acompressor: Audio compressor.
 F_acontrast:   Simple audio dynamic range compression/expansion filter.
 F_acrusher:    Reduces audio bit resolution.
+F_acue:                Delay filtering to match a cue.
 F_adelay:      Delays one or more audio channels.
+F_aderivative: Compute derivative of input audio.
 F_aecho:       Adds echoing to the audio.
 F_aemphasis:   Audio emphasis.
 F_aeval:       Filters audio signal according to a specific expression.
@@ -410,8 +429,10 @@ F_aformat: Convert the input audio to one of the specified formats.
 F_agate:       Audio gate.
 F_aiir:                Apply infinite Impulse Response filter with supplied
                coefficients.
+F_aintegral:   Compute integral of input audio.
 F_allpass:     Applies a two-pole all-pass filter.
 F_aloop:       Loops audio samples.
+F_ametadata:   Manipulate audio frame metadata.
 F_anoisesrc:   Generates a noise audio signal.
 F_aperms:      Set permissions for the output audio frame.
 F_aphaser:     Adds a phasing effect to the audio.
@@ -466,6 +487,7 @@ F_lowpass:  Applies a low-pass filter with 3dB point frequency.
 F_mcompand:    Multiband compress or expand audiodynamic range. The input audio
                is divided into bands which is like the crossover of a loudspeaker,
                resulting in flat frequency response when absent compander action.
+F_pan:         Remix channels with coefficients (panning).
 F_silenceremove: Removes silence.
 F_sine:                Generate sine wave audio signal.
 F_stereotools: Applies various stereo tools.  When using this plugin,
index a4ce51f9e55f215e0f682768e5eec4417c2a3a15..e3b61b192e15f85f030c4b69d80660c95a011ba0 100644 (file)
 #include "language.h"
 #include "vframe.h"
 
-void SketcherPoint::init(int id, int x, int y)
+void SketcherPoint::init(int id, int pty, int x, int y)
 {
-       this->id = id;
+       this->id = id;  this->pty = pty;
        this->x = x;    this->y = y;
 }
 SketcherPoint::SketcherPoint(int id)
 {
-       init(id, 0, 0);
+       init(id, PTY_LINE, 0, 0);
 }
-SketcherPoint::SketcherPoint(int id, int x, int y)
+SketcherPoint::SketcherPoint(int id, int pty, int x, int y)
 {
-       init(id, x, y);
+       init(id, pty, x, y);
 }
 SketcherPoint::~SketcherPoint()
 {
@@ -57,12 +57,13 @@ SketcherPoint::SketcherPoint(SketcherPoint &pt)
 int SketcherPoint::equivalent(SketcherPoint &that)
 {
        return this->id == that.id &&
+               this->pty == that.pty &&
                this->x == that.x &&
                this->y == that.y ? 1 : 0;
 }
 void SketcherPoint::copy_from(SketcherPoint &that)
 {
-       this->id = that.id;
+       this->id = that.id;  this->pty = that.pty;
        this->x = that.x;    this->y = that.y;
 }
 void SketcherPoint::save_data(FileXML &output)
@@ -70,6 +71,7 @@ void SketcherPoint::save_data(FileXML &output)
        char point[BCSTRLEN];
        sprintf(point,"/POINT_%d",id);
        output.tag.set_title(point+1);
+       output.tag.set_property("TYPE", pty);
        output.tag.set_property("X", x);
        output.tag.set_property("Y", y);
        output.append_tag();
@@ -80,25 +82,26 @@ void SketcherPoint::save_data(FileXML &output)
 void SketcherPoint::read_data(FileXML &input)
 {
        id = atoi(input.tag.get_title() + 6);
+       pty = input.tag.get_property("TYPE", PTY_OFF);
        x = input.tag.get_property("X", 0.f);
        y = input.tag.get_property("Y", 0.f);
+       bclamp(pty, 0, PTY_SZ-1);
 }
 
-void SketcherCurve::init(int id, int ty, int radius, int pen, int color)
+void SketcherCurve::init(int id, int pen, int radius, int color)
 {
        this->id = id;
-       this->ty = ty;
        this->radius = radius;
        this->pen = pen;
        this->color = color;
 }
 SketcherCurve::SketcherCurve(int id)
 {
-       init(id, 0, 1, 0, BLACK);
+       init(id, 1, PTY_LINE, CV_COLOR);
 }
-SketcherCurve::SketcherCurve(int id, int ty,  int radius,int pen, int color)
+SketcherCurve::SketcherCurve(int id, int pen, int radius, int color)
 {
-       init(id, ty, radius, pen, color);
+       init(id, pen, radius, color);
 }
 SketcherCurve::~SketcherCurve()
 {
@@ -110,9 +113,8 @@ SketcherCurve::SketcherCurve(SketcherCurve &cv)
 int SketcherCurve::equivalent(SketcherCurve &that)
 {
        if( this->id != that.id ) return 0;
-       if( this->ty != that.ty ) return 0;
-       if( this->radius != that.radius ) return 0;
        if( this->pen != that.pen ) return 0;
+       if( this->radius != that.radius ) return 0;
        if( this->color != that.color ) return 0;
        int n = this->points.size();
        if( n != that.points.size() ) return 0;
@@ -124,9 +126,8 @@ int SketcherCurve::equivalent(SketcherCurve &that)
 void SketcherCurve::copy_from(SketcherCurve &that)
 {
        this->id = that.id;
-       this->ty = that.ty;
-       this->radius = that.radius;
        this->pen = that.pen;
+       this->radius = that.radius;
        this->color = that.color;
        int m = points.size(), n = that.points.size();
        while( m > n ) points.remove_object_number(--m);
@@ -135,14 +136,12 @@ void SketcherCurve::copy_from(SketcherCurve &that)
 }
 void SketcherCurve::save_data(FileXML &output)
 {
-       this->ty = ty;
        this->pen = pen;  this->color = color;
        char curve[BCSTRLEN];
        sprintf(curve,"/CURVE_%d",id);
        output.tag.set_title(curve+1);
-       output.tag.set_property("TYPE", ty);
-       output.tag.set_property("RADIUS", radius);
        output.tag.set_property("PEN", pen);
+       output.tag.set_property("RADIUS", radius);
        output.tag.set_property("COLOR", color);
        output.append_tag();
        output.append_newline();
@@ -155,13 +154,13 @@ void SketcherCurve::save_data(FileXML &output)
 void SketcherCurve::read_data(FileXML &input)
 {
        id = atoi(input.tag.get_title() + 6);
-       ty = input.tag.get_property("TYPE", 0);
+       pen = input.tag.get_property("PEN", PTY_OFF);
        radius = input.tag.get_property("RADIUS", 1.);
-       pen = input.tag.get_property("PEN", 0);
-       color = input.tag.get_property("COLOR", BLACK);
+       color = input.tag.get_property("COLOR", CV_COLOR);
+       bclamp(pen, 0, PEN_SZ-1);
 }
 
-int Sketcher::new_curve(int ty, int radius, int pen, int color)
+int Sketcher::new_curve(int pen, int radius, int color)
 {
        SketcherCurves &curves = config.curves;
        int k = curves.size(), id = 1;
@@ -169,7 +168,7 @@ int Sketcher::new_curve(int ty, int radius, int pen, int color)
                int n = config.curves[i]->id;
                if( n >= id ) id = n + 1;
        }
-       SketcherCurve *cv = new SketcherCurve(id, ty, radius, pen, color);
+       SketcherCurve *cv = new SketcherCurve(id, pen, radius, color);
        curves.append(cv);
        config.cv_selected = k;
        return k;
@@ -177,22 +176,24 @@ int Sketcher::new_curve(int ty, int radius, int pen, int color)
 
 int Sketcher::new_curve()
 {
-       return new_curve(0, 1, 0, BLACK);
+       return new_curve(PEN_XLANT, 1, CV_COLOR);
 }
 
-int Sketcher::new_point(SketcherCurve *cv, int x, int y)
+int Sketcher::new_point(SketcherCurve *cv, int pty, int x, int y, int idx)
 {
-       int k = cv->points.size(), id = 1;
-       for( int i=k; --i>=0; ) {
+       int id = 1;
+       for( int i=cv->points.size(); --i>=0; ) {
                int n = cv->points[i]->id;
                if( n >= id ) id = n + 1;
        }
-       SketcherPoint *pt = new SketcherPoint(id, x, y);
-       cv->points.append(pt);
-       return k;
+       SketcherPoint *pt = new SketcherPoint(id, pty, x, y);
+       int n = cv->points.size();
+       if( idx < 0 || idx > n ) idx = n;
+       cv->points.insert(pt, idx);
+       return idx;
 }
 
-int Sketcher::new_point()
+int Sketcher::new_point(int idx)
 {
        int ci = config.cv_selected;
        if( ci < 0 || ci >= config.curves.size() )
@@ -201,7 +202,7 @@ int Sketcher::new_point()
        EDLSession *session = get_edlsession();
        int x = !session ? 0.f : session->output_w / 2.f;
        int y = !session ? 0.f : session->output_h / 2.f;
-       return new_point(cv, x, y);
+       return new_point(cv, PTY_LINE, x, y, idx);
 }
 
 REGISTER_PLUGIN(Sketcher)
@@ -259,9 +260,8 @@ void SketcherConfig::interpolate(SketcherConfig &prev, SketcherConfig &next,
                while( --k >= 0 && pcv->id != (ncv=next.curves[k])->id );
                if( k >= 0 ) {
                        cv->id = pcv->id;
-                       cv->ty = pcv->ty;
-                       cv->radius = pcv->radius;
                        cv->pen = pcv->pen;
+                       cv->radius = pcv->radius;
                        cv->color = pcv->color;
                        int prev_pt_sz = pcv->points.size(), next_pt_sz = ncv->points.size();
                        for( int j=0; j<prev_pt_sz; ++j ) {
@@ -273,7 +273,7 @@ void SketcherConfig::interpolate(SketcherConfig &prev, SketcherConfig &next,
                                        x = x * prev_scale + nt->x * next_scale;
                                        y = y * prev_scale + nt->y * next_scale;
                                }
-                               cv->points.append(new SketcherPoint(pt.id, x, y));
+                               cv->points.append(new SketcherPoint(pt.id, pt.pty, x, y));
                        }
                }
                else
@@ -309,8 +309,8 @@ void Sketcher::save_data(KeyFrame *keyframe)
 
        output.tag.set_title("SKETCHER");
        output.tag.set_property("DRAG", config.drag);
-       output.tag.set_property("CURVE_SELECTED", config.cv_selected);
-       output.tag.set_property("POINT_SELECTED", config.pt_selected);
+       output.tag.set_property("CV_SELECTED", config.cv_selected);
+       output.tag.set_property("PT_SELECTED", config.pt_selected);
        output.append_tag();
        output.append_newline();
        for( int i=0,n=config.curves.size(); i<n; ++i ) {
@@ -354,9 +354,8 @@ void Sketcher::read_data(KeyFrame *keyframe)
                }
        }
 
-       if( !config.curves.size() ) {
-               new_curve(0, 1, 0, BLACK);
-       }
+       if( !config.curves.size() )
+               new_curve();
        config.limits();
 }
 
@@ -375,11 +374,11 @@ void Sketcher::update_gui()
 void Sketcher::draw_point(VFrame *vfrm, SketcherPoint *pt, int color, int d)
 {
        int r = d/2+1, x = pt->x, y = pt->y;
+       vfrm->set_pixel_color(color);
        vfrm->draw_smooth(x-r,y+0, x-r, y-r, x+0,y-r);
        vfrm->draw_smooth(x+0,y-r, x+r, y-r, x+r,y+0);
        vfrm->draw_smooth(x+r,y+0, x+r, y+r, x+0,y+r);
        vfrm->draw_smooth(x+0,y+r, x-r, y+r, x-r,y+0);
-       vfrm->set_pixel_color(color);
        vfrm->draw_x(pt->x, pt->y, d);
 }
 void Sketcher::draw_point(VFrame *vfrm, SketcherPoint *pt, int color)
@@ -435,156 +434,100 @@ VFrame *SketcherCurve::new_vpen(VFrame *out)
        return 0;
 }
 
-void SketcherCurve::draw_line(VFrame *out)
+static int intersects_at(float &x, float &y,
+               float ax,float ay, float bx, float by, float cx,float cy,  // line slope ab thru c
+               float dx,float dy, float ex, float ey, float fx,float fy, // line slope de thru f
+               float mx=0)
 {
-       SketcherPoint *pt0 = points[0];
-       VFrame *vpen = new_vpen(out);
-       out->set_pixel_color(color);
-       int n = points.size();
-       if( n >= 2 ) {
-               for( int pi=1; pi<n; ++pi ) {
-                       SketcherPoint *pt1 = points[pi];
-                       vpen->draw_line(pt0->x, pt0->y, pt1->x, pt1->y);
-                       pt0 = pt1;
-               }
-       }
-       else
-               vpen->draw_pixel(pt0->x, pt0->y);
-       delete vpen;
+       float badx = bx - ax, bady = by - ay;
+       float eddx = ex - dx, eddy = ey - dy;
+       float d = badx*eddy - bady*eddx;
+       int ret = 0;
+       if( fabsf(d) < 1 ) { ret = 1;  d = signbit(d) ? -1 : 1; }
+       x = (badx*cy*eddx - badx*eddx*fy + badx*eddy*fx - bady*cx*eddx) / d;
+       y = (badx*cy*eddy - bady*cx*eddy - bady*eddx*fy + bady*eddy*fx) / d;
+       if( mx > 0 ) { bclamp(x, -mx,mx);  bclamp(y, -mx,mx); }
+       return ret;
 }
 
-/*
-# python
-from sympy import *
-var("x,y, ax,ay, bx,by, cx,cy, dx,dy")
-
-var("abdx,abdy, acdx,acdy, bddx,bddy, cddx,cddy");
-abdx = bx-ax;  abdy = by-ay;
-acdx = cx-ax;  acdy = cy-ay;
-bddx = dx-bx;  bddy = dy-by;
-cddx = dx-cx;  cddy = dy-cy;
-
-var("xc,yc, xd,yd, sx,sy");
-xc = (bx+dx)/2;  yc = (by+dy)/2;
-xd = cx-xc;      yd = cy-yc;
-ax = xc-xd;      ay = yc-yd;
-# line thru b with slope (c-a) intersects line thru c with slope (d-b)
-sx = solve(((x - bx) * acdy/acdx + by) - ((x - cx) * bddy/bddx + cy),x)
-sy = solve(((y - by) * acdx/acdy + bx) - ((y - cy) * bddx/bddy + cx),y)
-
-var("zx,zy, zdx,zdy, sx,sy, px,py, qx,qy");
-# point z = (b+c)/2
-zx = (bx+cx)/2;  zy = (by+cy)/2;
-zdx = (abdx+cddx)/2;  zdy = (abdy+cddy)/2;
-# line thru z with slope (d-a) intersects line thru b with slope (c-a)
-px = solve(((x-zx)*zdy/zdx + zy) - ((x-bx) * acdy/acdx + by),x);
-py = solve(((y-zy)*zdx/zdy + zx) - ((y-by) * acdx/acdy + bx),y);
-# line thru z with slope (c-a + d-b)/2 intersects line thru c with slope (d-b)
-qx = solve(((x-zx)*zdy/zdx + zy) - ((x-cx) * bddy/bddx + cy),x);
-qy = solve(((y-zy)*zdx/zdy + zx) - ((y-cy) * bddx/bddy + cx),y);
-*/
-
-static void smooth_sxy(
-       float ax, float ay, float bx, float by,
-       float cx, float cy, float dx, float dy,
-       float &sx, float &sy)
+static void smooth_axy(float &ax, float &ay,
+       float bx, float by, float cx, float cy, float dx, float dy)
 {
-       float acdx = cx-ax, acdy = cy-ay;
-       float bddx = dx-bx, bddy = dy-by;
-       float d = acdx*bddy - acdy*bddx;
-       if( fabsf(d) < 1 ) d = 1;
-       sx = (acdx*bddx*by - acdx*bddx*cy + acdx*bddy*cx - acdy*bddx*bx) / d;
-       sy = (acdx*bddy*by - acdy*bddx*cy - acdy*bddy*bx + acdy*bddy*cx) / d;
-       bclamp(sx, -4095.f, 4095.f);
-       bclamp(sy, -4095.f, 4095.f);
-}
-
-static void smooth_pxy(
-       float ax, float ay, float bx, float by,
-       float cx, float cy, float dx, float dy,
-       float &px, float &py)
-{
-       float abdx = bx - ax, abdy = by - ay;
-       float acdx = cx - ax, acdy = cy - ay;
-       float cddx = dx - cx, cddy = dy - cy;
-       float d = (2*(abdx*acdy - abdy*acdx - acdx*cddy + acdy*cddx));
-       if( fabsf(d) < 1 ) d = 1;
-       px = (-abdx*acdx*by + abdx*acdx*cy + 2*abdx*acdy*bx - abdy*acdx*bx - abdy*acdx*cx -
-               acdx*bx*cddy - acdx*by*cddx + acdx*cddx*cy - acdx*cddy*cx + 2*acdy*bx*cddx) / d;
-       py = (abdx*acdy*by + abdx*acdy*cy - 2*abdy*acdx*by + abdy*acdy*bx - abdy*acdy*cx -
-                2*acdx*by*cddy + acdy*bx*cddy + acdy*by*cddx + acdy*cddx*cy - acdy*cddy*cx) / d;
-       bclamp(px, -4095.f, 4095.f);
-       bclamp(py, -4095.f, 4095.f);
-}
-static void smooth_qxy(
-       float ax, float ay, float bx, float by,
-       float cx, float cy, float dx, float dy,
-       float &qx, float &qy)
-{
-       float abdx = bx - ax, abdy = by - ay;
-       float bddx = dx - bx, bddy = dy - by;
-       float cddx = dx - cx, cddy = dy - cy;
-       float d = (2*(abdx*bddy - abdy*bddx - bddx*cddy + bddy*cddx));
-       if( fabsf(d) < 1 ) d = 1;
-       qx = (abdx*bddx*by - abdx*bddx*cy + 2*abdx*bddy*cx - abdy*bddx*bx - abdy*bddx*cx -
-               bddx*bx*cddy + bddx*by*cddx - bddx*cddx*cy - bddx*cddy*cx + 2*bddy*cddx*cx) / d;
-       qy = (abdx*bddy*by + abdx*bddy*cy - 2*abdy*bddx*cy - abdy*bddy*bx + abdy*bddy*cx -
-               2*bddx*cddy*cy - bddy*bx*cddy + bddy*by*cddx + bddy*cddx*cy + bddy*cddy*cx) / d;
-       bclamp(qx, -4095.f, 4095.f);
-       bclamp(qy, -4095.f, 4095.f);
+//middle of bd reflected around ctr
+// point ctr = b+d/2, dv=c-ctr, a=ctr-dv;
+       float xc = (bx+dx)*.5f, yc = (by+dy)*.5f;
+       float xd = cx - xc, yd = cy - yc;
+       ax = xc - xd;  ay = yc - yd;
+}
+static void smooth_dxy(float &dx, float &dy,
+       float ax, float ay, float bx, float by, float cx, float cy)
+{
+//middle of ac reflected around ctr
+// point ctr = a+c/2, dv=c-ctr, d=ctr-dv;
+       float xc = (ax+cx)*.5f, yc = (ay+cy)*.5f;
+       float xd = bx - xc, yd = by - yc;
+       dx = xc - xd;  dy = yc - yd;
 }
 
-
+#if 0
 static int convex(float ax,float ay, float bx,float by,
                  float cx,float cy, float dx,float dy)
 {
-       float abdx = bx - ax, abdy = by - ay;
-       float acdx = cx - ax, acdy = cy - ay;
-       float bcdx = cx - bx, bcdy = cy - by;
-       float bddx = dx - bx, bddy = dy - by;
+       float abdx = bx-ax, abdy = by-ay;
+       float acdx = cx-ax, acdy = cy-ay;
+       float bcdx = cx-bx, bcdy = cy-by;
+       float bddx = dx-bx, bddy = dy-by;
        float abc = abdx*acdy - abdy*acdx;
        float bcd = bcdx*bddy - bcdy*bddx;
        float v = abc * bcd;
        return !v ? 0 : v>0 ? 1 : -1;
 }
+#endif
 
-void SketcherCurve::draw_smooth(VFrame *out)
+void SketcherCurve::draw(VFrame *out)
 {
+       const float fmx = 16383;
        VFrame *vpen = new_vpen(out);
        out->set_pixel_color(color);
        int n = points.size();
        if( !n ) return;
        if( n > 2 ) {
-               SketcherPoint *pt0 = points[0], *pt1 = points[1], *pt2 = points[2];
-               float bx = pt0->x, by = pt0->y;
-               float cx = pt1->x, cy = pt1->y;
-               float dx = pt2->x, dy = pt2->y;
-               float xc = (bx+dx)/2.f, yc = (by+dy)/2.f;
-               float xd = cx - xc, yd = cy - yc;
-               float ax = xc - xd, ay = yc - yd;
-               float sx, sy;
-               for( int pi=0,n2=n-2; pi<n2; ++pi ) {
-                       float dx = points[pi+2]->x, dy = points[pi+2]->y;
-                       if( convex(ax,ay, bx,by, cx,cy, dx,dy) >= 0 ) {
-                               smooth_sxy(ax,ay, bx,by, cx,cy, dx,dy, sx, sy);
+               int n2 = n - 2;
+               SketcherPoint *pt0 = points[0];
+               SketcherPoint *pt1 = points[1];
+               SketcherPoint *pt2 = points[2];
+               float ax,ay, bx,by, cx,cy, dx,dy, sx,sy;
+               bx = pt0->x;  by = pt0->y;
+               cx = pt1->x;  cy = pt1->y;
+               dx = pt2->x;  dy = pt2->y;
+               smooth_axy(ax,ay, bx,by, cx,cy, dx,dy);
+               for( int pi=0; pi<n2; ++pi ) {
+                       int pty = points[pi]->pty;
+                       dx = points[pi+2]->x;  dy = points[pi+2]->y;
+                       switch( pty ) {
+                       case PTY_LINE:
+                               vpen->draw_line(bx, by, cx, cy);
+                               break;
+                       case PTY_CURVE: {
+                               // s = ac thru b x bd thru c
+                               intersects_at(sx,sy, ax,ay,cx,cy,bx,by, bx,by,dx,dy,cx,cy,fmx);
                                vpen->draw_smooth(bx,by, sx,sy, cx,cy);
-                       }
-                       else {
-                               float zx = (bx+cx)/2.f, zy = (by+cy)/2.f;
-                               smooth_pxy(ax,ay, bx,by, cx,cy, dx,dy, sx,sy);
-                               vpen->draw_smooth(bx,by, sx,sy, zx,zy);
-                               smooth_qxy(ax,ay, bx,by, cx,cy, dx,dy, sx,sy);
-                               vpen->draw_smooth(zx,zy, sx,sy, cx,cy);
+                               break; }
                        }
                        ax = bx;  ay = by;
                        bx = cx;  by = cy;
                        cx = dx;  cy = dy;
                }
-               xc = (ax+cx)/2.f; yc = (ay+cy)/2.f;
-               xd = bx - xc, yd = by - yc;
-               dx = xc - xd, dy = yc - yd;
-               smooth_sxy(ax, ay, bx, by, cx, cy, dx, dy, sx, sy);
-               vpen->draw_smooth(bx, by, sx, sy, cx, cy);
+               switch( points[n2]->pty ) {
+               case PTY_LINE:
+                       vpen->draw_line(bx, by, cx, cy);
+                       break;
+               case PTY_CURVE: {
+                       smooth_dxy(dx,dy, ax,ay, bx,by, cx,cy);
+                       intersects_at(sx,sy, ax,ay,cx,cy,bx,by, bx,by,dx,dy,cx,cy,fmx);
+                       vpen->draw_smooth(bx,by, sx,sy, cx,cy);
+                       break; }
+               }
        }
        else if( n == 2 ) {
                SketcherPoint *pt0 = points[0], *pt1 = points[1];
@@ -608,24 +551,18 @@ int Sketcher::process_realtime(VFrame *input, VFrame *output)
        for( int ci=0, n=config.curves.size(); ci<n; ++ci ) {
                SketcherCurve *cv = config.curves[ci];
                int m = cv->points.size();
-               if( !m ) continue;
-               switch( cv->ty ) {
-               case TYP_OFF:
-                       break;
-               case TYP_SKETCHER:
-                       cv->draw_line(output);
-                       break;
-               case TYP_SMOOTH:
-                       cv->draw_smooth(output);
-                       break;
-               }
+               if( !m || cv->pen == PTY_OFF ) continue;
+               cv->draw(output);
        }
 
        if( config.drag ) {
                for( int ci=0, n=config.curves.size(); ci<n; ++ci ) {
                        SketcherCurve *cv = config.curves[ci];
-                       for( int pi=0,m=cv->points.size(); pi<m; ++pi )
-                               draw_point(output, cv->points[pi], cv->color);
+                       for( int pi=0,m=cv->points.size(); pi<m; ++pi ) {
+                               int color = ci==config.cv_selected && pi==config.pt_selected ?
+                                       RED : cv->color ; 
+                               draw_point(output, cv->points[pi], color);
+                       }
                }
        }
 
@@ -636,8 +573,8 @@ void SketcherCurves::dump()
 {
        for( int i=0; i<size(); ++i ) {
                SketcherCurve *cv = get(i);
-               printf("Curve %d, id=%d, ty=%s, r=%d, pen=%s, color=%02x%02x%02x\n",
-                       i, cv->id, cv_type[cv->ty], cv->radius, cv_pen[cv->pen],
+               printf("Curve %d, id=%d, pen=%s, r=%d, color=%02x%02x%02x\n",
+                       i, cv->id, cv_pen[cv->pen], cv->radius,
                        (cv->color>>16)&0xff, (cv->color>>8)&0xff, (cv->color>>0)&0xff);
                cv->points.dump();
        }
@@ -646,7 +583,8 @@ void SketcherPoints::dump()
 {
        for( int i=0; i<size(); ++i ) {
                SketcherPoint *pt = get(i);
-               printf("  Pt %d, id=%d, x=%d, y=%d\n", i, pt->id, pt->x, pt->y);
+               printf("  Pt %d, id=%d, pty=%s, x=%d, y=%d\n",
+                       i, pt->id, pt_type[pt->pty], pt->x, pt->y);
        }
 }
 
index d0429cb1ffcd0eb7c97f03ff0e6253e7ef3ca636..be0f46b9f1e478289f3d001f183d96a48a59852f 100644 (file)
 
 class Sketcher;
 
-enum { PT_ID, PT_X, PT_Y, PT_SZ };
-enum { CV_ID, CV_TY, CV_RAD, CV_PEN, CV_CLR, CV_SZ };
-enum { TYP_OFF, TYP_SKETCHER, TYP_SMOOTH, TYP_SZ };
-enum { PEN_SQUARE, PEN_PLUS, PEN_SLANT, PEN_XLANT, PEN_SZ };
+#define pt_type SketcherPoint::types
+#define cv_pen SketcherCurve::pens
+#define CV_COLOR WHITE
+
+enum { PT_ID, PT_TY, PT_X, PT_Y, PT_SZ };
+enum { CV_ID, CV_RAD, CV_PEN, CV_CLR, CV_SZ };
+enum { PTY_OFF, PTY_LINE, PTY_CURVE, PTY_SZ };
+enum { PEN_OFF, PEN_SQUARE, PEN_PLUS, PEN_SLANT, PEN_XLANT, PEN_SZ };
 
 class SketcherVPen : public VFrame
 {
@@ -76,11 +80,11 @@ public:
 class SketcherPoint
 {
 public:
-       int id;
+       int id, pty;
        int x, y;
 
-       void init(int id, int x, int y);
-       SketcherPoint(int id, int x, int y);
+       void init(int id, int pty, int x, int y);
+       SketcherPoint(int id, int pty, int x, int y);
        SketcherPoint(int id=-1);
        SketcherPoint(SketcherPoint &pt);
        ~SketcherPoint();
@@ -88,6 +92,7 @@ public:
        void copy_from(SketcherPoint &that);
        void save_data(FileXML &output);
        void read_data(FileXML &input);
+       static const char *types[PTY_SZ];
 };
 class SketcherPoints : public ArrayList<SketcherPoint *>
 {
@@ -97,20 +102,17 @@ public:
        void dump();
 };
 
-#define cv_type SketcherCurve::types
-#define cv_pen SketcherCurve::pens
 
 class SketcherCurve
 {
 public:
-       int id, ty, radius, pen, color;
-       static const char *types[TYP_SZ];
+       int id, pen, radius, color;
        static const char *pens[PEN_SZ];
 
        SketcherPoints points;
 
-       void init(int id, int ty, int radius, int pen, int color);
-       SketcherCurve(int id, int ty, int radius, int pen, int color);
+       void init(int id, int pen, int radius, int color);
+       SketcherCurve(int id, int pen, int radius, int color);
        SketcherCurve(int id=-1);
        ~SketcherCurve();
        SketcherCurve(SketcherCurve &cv);
@@ -119,8 +121,7 @@ public:
        void save_data(FileXML &output);
        void read_data(FileXML &input);
        VFrame *new_vpen(VFrame *out);
-       void draw_line(VFrame *out);
-       void draw_smooth(VFrame *out);
+       void draw(VFrame *out);
 };
 class SketcherCurves : public ArrayList<SketcherCurve *>
 {
@@ -152,16 +153,15 @@ class Sketcher : public PluginVClient
 public:
        Sketcher(PluginServer *server);
        ~Sketcher();
-// required for all realtime plugins
        PLUGIN_CLASS_MEMBERS2(SketcherConfig)
        int is_realtime();
        void update_gui();
        void save_data(KeyFrame *keyframe);
        void read_data(KeyFrame *keyframe);
-       int new_curve(int ty, int radius, int pen, int color);
+       int new_curve(int pen, int radius, int color);
        int new_curve();
-       int new_point(SketcherCurve *cv, int x, int y);
-       int new_point();
+       int new_point(SketcherCurve *cv, int pty, int x, int y, int idx=-1);
+       int new_point(int idx=-1);
        int process_realtime(VFrame *input, VFrame *output);
        static void draw_point(VFrame *vfrm, SketcherPoint *pt, int color, int d);
        void draw_point(VFrame *vfrm, SketcherPoint *pt, int color);
index 5e55f29e583b473277c3ba4a248ad2cf500c3419..2f984cddb372a9519a51a5427a0a56d12bcb7227 100644 (file)
 #include "theme.h"
 #include "track.h"
 
-#define COLOR_W 30
-#define COLOR_H 30
+#define AltMask Mod1Mask
 
-const char *SketcherCurve::types[] = {
+#define COLOR_W 32
+#define COLOR_H 24
+
+const char *SketcherPoint::types[] = {
        N_("off"),
        N_("line"),
-       N_("smooth"),
+       N_("curve"),
 };
 const char *SketcherCurve::pens[] = {
+       N_("off"),
        N_("box"),
        N_("+"),
        N_("/"),
        N_("X"),
 };
 
-SketcherCurveTypeItem::SketcherCurveTypeItem(int ty)
- : BC_MenuItem(_(cv_type[ty]))
-{
-       this->ty = ty;
-}
-int SketcherCurveTypeItem::handle_event()
-{
-       SketcherCurveType *popup = (SketcherCurveType*)get_popup_menu();
-       popup->update(ty);
-       SketcherWindow *gui = popup->gui;
-       SketcherConfig &config = gui->plugin->config;
-       int ci = config.cv_selected;
-       if( ci >= 0 && ci < config.curves.size() ) {
-               SketcherCurve *cv = config.curves[ci];
-               cv->ty = ty;
-               gui->curve_list->update(ci);
-               gui->send_configure_change();
-       }
-       return 1;
-}
-
-SketcherCurveType::SketcherCurveType(SketcherWindow *gui, int x, int y, int ty)
- : BC_PopupMenu(x,y,64,_(cv_type[ty]))
-{
-       this->gui = gui;
-}
-void SketcherCurveType::create_objects()
-{
-       int n = sizeof(cv_type)/sizeof(cv_type[0]);
-       for( int ty=0; ty<n; ++ty )
-               add_item(new SketcherCurveTypeItem(ty));
-}
-void SketcherCurveType::update(int ty)
-{
-       set_text(_(cv_type[ty]));
-}
-
 
 SketcherCurvePenItem::SketcherCurvePenItem(int pen)
- : BC_MenuItem(_(cv_pen[pen]))
+ : BC_MenuItem(_(SketcherCurve::pens[pen]))
 {
        this->pen = pen;
 }
@@ -128,13 +94,13 @@ void SketcherCurvePen::update(int pen)
 }
 
 
-SketcherCurveColor::SketcherCurveColor(SketcherWindow *gui, int x, int y, int w)
+SketcherCurveColor::SketcherCurveColor(SketcherWindow *gui, int x, int y, int w, int h)
  : BC_Button(x, y, w, vframes)
 {
        this->gui = gui;
-       this->color = BLACK;
+       this->color = CV_COLOR;
        for( int i=0; i<3; ++i ) {
-               vframes[i] = new VFrame(w, w, BC_RGBA8888);
+               vframes[i] = new VFrame(w, h, BC_RGB888);
                vframes[i]->clear_frame();
        }
 }
@@ -154,12 +120,8 @@ void SketcherCurveColor::set_color(int color)
        for( int i=0; i<3; ++i ) {
                VFrame *vframe = vframes[i];
                int ww = vframe->get_w(), hh = vframe->get_h();
-               int cx = (ww+1)/2, cy = hh/2;
-               double cc = (cx*cx + cy*cy) / 4.;
-               uint8_t *bp = vframe->get_data(), *dp = bp;
-               uint8_t *ep = dp + vframe->get_data_size();
+               uint8_t **rows = vframe->get_rows();
                int rr = r, gg = g, bb = b;
-               int bpl = vframe->get_bytes_per_line();
                switch( i ) {
                case BUTTON_UP:
                        break;
@@ -174,13 +136,11 @@ void SketcherCurveColor::set_color(int color)
                        if( (bb-=48) < 0x00 ) bb = 0x00;
                        break;
                }
-               while( dp < ep ) {
-                       int yy = (dp-bp) / bpl, xx = ((dp-bp) % bpl) >> 2;
-                       int dy = cy - yy, dx = cx - xx;
-                       double s = dx*dx + dy*dy - cc;
-                       double ss = s < 0 ? 1 : s >= cc ? 0 : 1 - s/cc;
-                       int aa = ss * 0xff;
-                       *dp++ = rr; *dp++ = gg; *dp++ = bb; *dp++ = aa;
+               for( int y=0; y<hh; ++y ) {
+                       uint8_t *rp = rows[y];
+                       for( int x=0; x<ww; ++x ) {
+                               *rp++ = rr;  *rp++ = gg;  *rp++ = bb;
+                       }
                }
        }
        set_images(vframes);
@@ -318,13 +278,13 @@ int SketcherPointX::handle_event()
        if( ci >= 0 && ci < config.curves.size() ) {
                SketcherCurve *cv = config.curves[ci];
                SketcherPointList *point_list = gui->point_list;
-               int hot_point = point_list->get_selection_number(0, 0);
+               int pi = config.pt_selected;
                SketcherPoints &points = cv->points;
-               if( hot_point >= 0 && hot_point < points.size() ) {
+               if( pi >= 0 && pi < points.size() ) {
                        int v = atoi(get_text());
-                       points[hot_point]->x = v;
-                       point_list->set_point(hot_point, PT_X, v);
-                       point_list->update_list(hot_point);
+                       points[pi]->x = v;
+                       point_list->set_point(pi, PT_X, v);
+                       point_list->update_list(pi);
                        gui->send_configure_change();
                }
        }
@@ -338,13 +298,13 @@ int SketcherPointY::handle_event()
        if( ci >= 0 && ci < config.curves.size() ) {
                SketcherCurve *cv = config.curves[ci];
                SketcherPointList *point_list = gui->point_list;
-               int hot_point = point_list->get_selection_number(0, 0);
+               int pi = config.pt_selected;
                SketcherPoints &points = cv->points;
-               if( hot_point >= 0 && hot_point < points.size() ) {
+               if( pi >= 0 && pi < points.size() ) {
                        int v = atoi(get_text());
-                       points[hot_point]->y = v;
-                       point_list->set_point(hot_point, PT_Y, v);
-                       point_list->update_list(hot_point);
+                       points[pi]->y = v;
+                       point_list->set_point(pi, PT_Y, v);
+                       point_list->update_list(pi);
                        gui->send_configure_change();
                }
        }
@@ -371,7 +331,6 @@ SketcherWindow::SketcherWindow(Sketcher *plugin)
  : PluginClientWindow(plugin, 380, 580, 380, 580, 0)
 {
        this->plugin = plugin;
-       this->title_type = 0; this->curve_type = 0;
        this->title_pen = 0;  this->curve_pen = 0;
        this->title_color = 0; this->curve_color = 0;
        this->color_picker = 0; this->new_points = 0;
@@ -396,115 +355,145 @@ SketcherWindow::~SketcherWindow()
 
 void SketcherWindow::create_objects()
 {
-       int x = 10, y = 10, x1, y1;
+       int x = 10, y = 10, dy = 0, x1, y1;
        int margin = plugin->get_theme()->widget_border;
        BC_Title *title;
        int ci = plugin->config.cv_selected;
        if( ci < 0 || ci >= plugin->config.curves.size() )
-               ci = plugin->new_curve(0, 1, 0, BLACK);
+               ci = plugin->new_curve();
        SketcherCurve *cv = plugin->config.curves[ci];
-       add_subwindow(reset_curves = new SketcherResetCurves(this, plugin, x1=x, y+3));
+
+       reset_curves = new SketcherResetCurves(this, plugin, x1=x, y+3);
+       add_subwindow(reset_curves);    dy = bmax(dy,reset_curves->get_h());
        x1 += reset_curves->get_w() + 2*margin;
        const char *curve_text = _("Curve");
-       add_subwindow(title_radius = new BC_Title(x1, y, _("Width:")));
+       title_radius = new BC_Title(x1, y, _("Width:"));
+       add_subwindow(title_radius);    dy = bmax(dy,title_radius->get_h());
        x1 += title_radius->get_w() + margin;
        curve_radius = new SketcherCurveRadius(this, x1, y, cv->radius);
        curve_radius->create_objects();
-       y += reset_curves->get_h() + 2*margin;
+       y += dy + 2*margin;             dy = 0;
+
        x1 = get_w()-x - BC_Title::calculate_w(this, curve_text, LARGEFONT);
        y1 = y-margin - BC_Title::calculate_h(this, curve_text, LARGEFONT);
-       add_subwindow(title = new BC_Title(x1, y1, curve_text, LARGEFONT,
-               get_resources()->menu_highlighted_fontcolor));
-       add_subwindow(curve_list = new SketcherCurveList(this, plugin, x, y));
-       y += curve_list->get_h() + margin;
-       add_subwindow(title_type = new BC_Title(x, y, _("Type:")));
-       x1 = x + title_type->get_w() + margin;
-       add_subwindow(curve_type = new SketcherCurveType(this, x1, y, cv->ty));
-       curve_type->create_objects();
-       x1 += curve_type->get_w() + margin;
-       add_subwindow(new_curve = new SketcherNewCurve(this, plugin, x1, y));
+       title = new BC_Title(x1, y1, curve_text, LARGEFONT,
+               get_resources()->menu_highlighted_fontcolor);
+       add_subwindow(title);           dy = bmax(dy,title->get_h());
+       curve_list = new SketcherCurveList(this, plugin, x, y);
+       add_subwindow(curve_list);      dy = bmax(dy,curve_list->get_h());
+       y += dy + margin;               dy = 0;
+
+       new_curve = new SketcherNewCurve(this, plugin, x1=x, y);
+       add_subwindow(new_curve);       dy = bmax(dy,new_curve->get_h());
        x1 += new_curve->get_w() + margin;
-       add_subwindow(curve_up = new SketcherCurveUp(this, x1, y));
-       x1 += curve_up->get_w() + 2*margin;
-       add_subwindow(title_color = new BC_Title(x1, y, _("Color:")));
-       y += curve_type->get_h() + margin;
-
-       add_subwindow(title_pen = new BC_Title(x, y, _("Pen:")));
-       x1 = x + title_pen->get_w() + margin;
-       add_subwindow(curve_pen = new SketcherCurvePen(this, x1, y, cv->pen));
-       curve_pen->create_objects();
-       x1 += curve_pen->get_w() + margin;
-       add_subwindow(del_curve = new SketcherDelCurve(this, plugin, x1, y));
+       curve_up = new SketcherCurveUp(this, x1, y);
+       add_subwindow(curve_up);        dy = bmax(dy,curve_up->get_h());
+       x1 += curve_up->get_w() + 4*margin;
+       title_pen = new BC_Title(x1+30, y, _("Pen:"));
+       add_subwindow(title_pen);       dy = bmax(dy,title_pen->get_h());
+       int x2 = (get_w()+x1)/2;
+       title_color = new BC_Title(x2+10, y, _("Color:"));
+       add_subwindow(title_color);     dy = bmax(dy,title_color->get_h());
+       y += dy + margin;               dy = 0;
+
+       del_curve = new SketcherDelCurve(this, plugin, x1=x, y);
+       add_subwindow(del_curve);       dy = bmax(dy,del_curve->get_h());
        x1 += del_curve->get_w() + margin;
-       add_subwindow(curve_dn = new SketcherCurveDn(this, x1, y));
-       x1 += curve_dn->get_w() + 2*margin;
-       add_subwindow(curve_color = new SketcherCurveColor(this, x1, y, COLOR_W));
-       curve_color->create_objects();
+       curve_dn = new SketcherCurveDn(this, x1, y);
+       add_subwindow(curve_dn);        dy = bmax(dy,curve_dn->get_h());
+       x1 += curve_dn->get_w() + 4*margin;
+       curve_pen = new SketcherCurvePen(this, x1, y, cv->pen);
+       add_subwindow(curve_pen);       dy = bmax(dy,curve_pen->get_h());
+       curve_pen->create_objects();
+       curve_color = new SketcherCurveColor(this, x2+20, y, COLOR_W, COLOR_H);
+       add_subwindow(curve_color);     dy = bmax(dy,curve_color->get_h());
        curve_color->set_color(cv->color);
        curve_color->draw_face();
-       y += COLOR_H + margin;
+       y += dy + margin;  dy = 0;
        curve_list->update(ci);
 
        BC_Bar *bar;
-       add_subwindow(bar = new BC_Bar(x, y, get_w()-2*x));
-       y += bar->get_h() + 2*margin;
+       bar = new BC_Bar(x, y, get_w()-2*x);
+       add_subwindow(bar);             dy = bmax(dy,bar->get_h());
+       y += dy + 2*margin;
 
        int pi = plugin->config.pt_selected;
        SketcherPoint *pt = pi >= 0 && pi < cv->points.size() ? cv->points[pi] : 0;
-       add_subwindow(reset_points = new SketcherResetPoints(this, plugin, x1=x, y+3));
-       x1 += reset_points->get_w() + 2*margin;
-       add_subwindow(drag = new SketcherDrag(this, x1, y));
-       y += drag->get_h() + margin;
+       reset_points = new SketcherResetPoints(this, plugin, x1=x, y+3);
+       add_subwindow(reset_points);    dy = bmax(dy,reset_points->get_h());
+       x1 += reset_points->get_w() + 2*margin; 
        if( plugin->config.drag ) {
-               if( !grab(plugin->server->mwindow->cwindow->gui) )
+               if( !grab(plugin->server->mwindow->cwindow->gui) ) {
                        eprintf("drag enabled, but compositor already grabbed\n");
+                       plugin->config.drag = 0;
+               }
        }
+       drag = new SketcherDrag(this, x1, y);
+       add_subwindow(drag);            dy = bmax(dy,drag->get_h());
+       x1 += drag->get_w() + 2*margin;
+       int pty = pt ? pt->pty : PTY_LINE;
+       point_type = new SketcherPointType(this, x1, y, pty);
+       add_subwindow(point_type);      dy = bmax(dy,point_type->get_h());
+       point_type->create_objects();
+       y += dy + margin;  dy = 0;
+
        const char *point_text = _("Point");
        x1 = get_w()-x - BC_Title::calculate_w(this, point_text, LARGEFONT);
        y1 = y-margin - BC_Title::calculate_h(this, point_text, LARGEFONT);
        add_subwindow(title = new BC_Title(x1, y1, point_text, LARGEFONT,
                get_resources()->menu_highlighted_fontcolor));
-       add_subwindow(point_list = new SketcherPointList(this, plugin, x, y));
+       point_list = new SketcherPointList(this, plugin, x, y);
+       add_subwindow(point_list);      dy = bmax(dy,point_list->get_h());
+       y += dy + margin;               dy = 0;
 
-       y += point_list->get_h() + margin;
-       add_subwindow(title_x = new BC_Title(x, y, _("X:")));
-       x1 = x + title_x->get_w() + margin;
-       point_x = new SketcherPointX(this, x1, y, !pt ? 0.f : pt->x);
-       point_x->create_objects();
-       x1 += point_x->get_w() + 2*margin;
-       add_subwindow(new_point = new SketcherNewPoint(this, plugin, x1, y));
+       new_point = new SketcherNewPoint(this, plugin, x1=x, y);
+       add_subwindow(new_point);       dy = bmax(dy,new_point->get_h());
        x1 += new_point->get_w() + margin;
-       add_subwindow(point_up = new SketcherPointUp(this, x1, y));
-       y += point_x->get_h() + margin;
-       add_subwindow(title_y = new BC_Title(x, y, _("Y:")));
-       x1 = x + title_y->get_w() + margin;
-       point_y = new SketcherPointY(this, x1, y, !pt ? 0.f : pt->y);
-       point_y->create_objects();
-       x1 += point_y->get_w() + 2*margin;
-       add_subwindow(del_point = new SketcherDelPoint(this, plugin, x1, y));
+       point_up = new SketcherPointUp(this, x1, y);
+       add_subwindow(point_up);        dy = bmax(dy,point_up->get_h());
+       x1 += point_up->get_w() + 2*margin;
+       title_x = new BC_Title(x1, y, _("X:"));
+       add_subwindow(title_x);         dy = bmax(dy,title_x->get_h());
+       x1 += title_x->get_w() + margin;
+       point_x = new SketcherPointX(this, x1, y, !pt ? 0.f : pt->x);
+       point_x->create_objects();      dy = bmax(dy, point_x->get_h());
+       y += dy + margin;  dy = 0;
+
+       del_point = new SketcherDelPoint(this, plugin, x1=x, y);
+       add_subwindow(del_point);       dy = bmax(dy,del_point->get_h());
        x1 += del_point->get_w() + margin;
-       add_subwindow(point_dn = new SketcherPointDn(this, x1, y));
-       y += point_y->get_h() + margin + 10;
+       point_dn = new SketcherPointDn(this, x1, y);
+       add_subwindow(point_dn);        dy = bmax(dy,point_dn->get_h());
+       x1 += point_dn->get_w() + 2*margin;
+       title_y = new BC_Title(x1, y, _("Y:"));
+       add_subwindow(title_y);         dy = bmax(dy,title_y->get_h());
+       x1 += title_y->get_w() + margin;
+       point_y = new SketcherPointY(this, x1, y, !pt ? 0.f : pt->y);
+       point_y->create_objects();      dy = bmax(dy, point_y->get_h());
+       y += dy + margin + 5;
        point_list->update(pi);
 
        add_subwindow(notes0 = new BC_Title(x, y,
                 _("\n"
-                  "LMB=\n"
-                  "Alt+LMB=\n"
-                  "MMB=\n"
+                  "Shift=\n"
+                  "None=\n"
+                  "Ctrl=\n"
+                  "Alt=\n"
                   "DEL=\n")));
        add_subwindow(notes1 = new BC_Title(x+80, y,
-                _("     No Shift\n"
+                _("     LMB\n"
+                  "new line point\n"
                   "select point\n"
-                  "drag curve\n"
-                  "next curve type\n"
+                  "drag point\n"
+                  "new curve\n"
                   "deletes point\n")));
        add_subwindow(notes2 = new BC_Title(x+200, y,
-                _("             Shift\n"
-                  "append new points\n"
-                  "drag image\n"
-                  "append new curve\n"
-                  "delete curve\n")));
+                _("      RMB\n"
+                  "new arc point\n"
+                  "select curve\n"
+                  "drag curve\n"
+                  "drag all curves\n"
+                  "deletes curve\n")));
        show_window(1);
 }
 
@@ -532,6 +521,7 @@ int SketcherWindow::do_grab_event(XEvent *event)
                if( keysym_lookup(event) > 0 ) {
                        switch( get_keysym() ) {
                        case XK_Delete:
+                               pending_config = 1;
                                return (event->xkey.state & ShiftMask) ?
                                        del_curve->handle_event() :
                                        del_point->handle_event() ;
@@ -557,7 +547,7 @@ int SketcherWindow::do_grab_event(XEvent *event)
        switch( event->type ) {
        case ButtonPress:
                if( dragging ) return 0;
-               dragging = event->xbutton.state & Mod1Mask ? -1 : 1; // alt_down
+               dragging = 1;
                break;
        case ButtonRelease:
        case MotionNotify:
@@ -567,10 +557,13 @@ int SketcherWindow::do_grab_event(XEvent *event)
                return 0;
        }
 
-
-       int ci = plugin->config.cv_selected;
+       SketcherConfig &config = plugin->config;
+       int ci = config.cv_selected;
        if( ci < 0 || ci >= plugin->config.curves.size() )
                return 1;
+       SketcherCurves &curves = config.curves;
+       SketcherCurve *cv = curves[ci];
+       int pi = config.pt_selected;
 
        float cursor_x = cx, cursor_y = cy;
        canvas->canvas_to_output(mwindow->edl, 0, cursor_x, cursor_y);
@@ -585,113 +578,131 @@ int SketcherWindow::do_grab_event(XEvent *event)
        projector_y += mwindow->edl->session->output_h / 2;
        float output_x = (cursor_x - projector_x) / projector_z + track_w / 2;
        float output_y = (cursor_y - projector_y) / projector_z + track_h / 2;
-       SketcherCurve *cv = plugin->config.curves[ci];
        SketcherPoints &points = cv->points;
        int state = event->xmotion.state;
 
        switch( event->type ) {
        case ButtonPress: {
-               if( dragging < 0 ) break;
-               int hot_point = -1;
                int button_no = event->xbutton.button;
-               if( button_no == LEFT_BUTTON ) {
-// create new point string
-                       if( (state & ShiftMask) ) {
+               switch( button_no ) {
+               case LEFT_BUTTON: {
+                       if( (state & ShiftMask) ) { // create new point/string
                                ++new_points;
-                               hot_point = plugin->new_point(cv, output_x, output_y);
-                               point_list->update(hot_point);
+                               pi = plugin->new_point(cv, PTY_LINE, output_x, output_y, pi+1);
+                               point_list->update(pi);
+                               break;
                        }
-                       else {
-// select point
-                               int sz = points.size();
-                               int last_point = hot_point;
-                               if( sz > 0 ) {
-                                       SketcherPoint *pt = points[hot_point=0];
-                                       double dist = DISTANCE(output_x,output_y, pt->x,pt->y);
-                                       for( int i=1; i<sz; ++i ) {
-                                               pt = points[i];
-                                               double d = DISTANCE(output_x,output_y, pt->x,pt->y);
-                                               if( d >= dist ) continue;
-                                               dist = d;  hot_point = i;
-                                       }
-                                       pt = points[hot_point];
-                                       float px = (pt->x - track_w / 2) * projector_z + projector_x;
-                                       float py = (pt->y - track_h / 2) * projector_z + projector_y;
-                                       dist = DISTANCE(px, py, cursor_x,cursor_y);
-                                       if( dist >= HANDLE_W ) hot_point = -1;
-                               }
-                               if( hot_point != last_point ) {
-                                       SketcherPoint *pt = 0;
-                                       if( hot_point >= 0 && hot_point < sz ) {
-                                               pt = points[hot_point];
-                                               point_list->set_point(hot_point, PT_X, pt->x = output_x);
-                                               point_list->set_point(hot_point, PT_Y, pt->y = output_y);
+                       if( (state & AltMask) ) { // create new curve
+                               ci = plugin->new_curve(cv->pen, cv->radius, cv->color);
+                               curve_list->update(ci);
+                               point_list->update(-1);
+                               break;
+                       }
+                       SketcherPoint *pt = 0; // select point
+                       int last_point = pi;  pi = -1;
+                       int n = points.size();
+                       double dist = DBL_MAX;
+                       for( int i=0; i<n; ++i ) {
+                               SketcherPoint *p = points[i];
+                               double d = DISTANCE(output_x,output_y, p->x,p->y);
+                               if( d < dist ) { dist = d;  pi = i;  pt = p; }
+                       }
+                       if( pt ) {
+                               float px = (pt->x - track_w / 2) * projector_z + projector_x;
+                               float py = (pt->y - track_h / 2) * projector_z + projector_y;
+                               float pix = DISTANCE(px, py, cursor_x,cursor_y);
+                               if( pix >= HANDLE_W ) { pi = -1;  pt = 0; }
+                       }
+                       if( pi != last_point )
+                               point_list->set_selected(pi);
+                       break; }
+               case RIGHT_BUTTON: {
+                       if( (state & ShiftMask) ) { // create new curve point
+                               ++new_points;
+                               pi = plugin->new_point(cv, PTY_CURVE,
+                                               output_x, output_y, pi+1);
+                               point_list->update(pi);
+                               break;
+                       }
+                       SketcherPoint *pt = 0; // select point
+                       double dist = DBL_MAX;
+                       ci = -1;
+                       for( int i=0; i<curves.size(); ++i ) {
+                               SketcherCurve *crv = curves[i];
+                               int pts = crv->points.size();
+                               for( int k=0; k<pts; ++k ) {
+                                       SketcherPoint *p = crv->points[k];
+                                       double d = DISTANCE(output_x,output_y, p->x,p->y);
+                                       if( d < dist ) {
+                                               dist = d;
+                                               pt = p;    pi = k;
+                                               cv = crv;  ci = i;
                                        }
-                                       point_list->update_list(hot_point);
-                                       point_x->update(pt ? pt->x : 0.f);
-                                       point_y->update(pt ? pt->y : 0.f);
                                }
                        }
-               }
-               else if( button_no == MIDDLE_BUTTON ) {
-                       if( (state & ShiftMask) ) {
-                               int ci = plugin->new_curve(cv->ty, cv->radius, cv->pen, cv->color);
-                               curve_list->update(ci);
-                               point_list->update(-1);
+                       if( pt ) {
+                               float px = (pt->x - track_w / 2) * projector_z + projector_x;
+                               float py = (pt->y - track_h / 2) * projector_z + projector_y;
+                               float pix = DISTANCE(px, py, cursor_x,cursor_y);
+                               if( pix >= HANDLE_W ) { pi = -1;  pt = 0; }
                        }
-                       else {
-                               int ty = cv->ty + 1;
-                               if( ty >= TYP_SZ ) ty = 0;
-                               cv->ty = ty;
-                               curve_type->update(ty);
+                       if( pi >= 0 ) {
                                curve_list->update(ci);
+                               point_list->update(pi);
                        }
+                       break; }
                }
                break; }
        case MotionNotify: {
-               int hot_point = point_list->get_selection_number(0, 0);
-               if( dragging < 0 ) {
-                       SketcherCurves &curves = plugin->config.curves;
-                       int dx = round(output_x - last_x);
-                       int dy = round(output_y - last_y);
-                       int mnc = (state & ShiftMask) || ci<0 ? 0 : ci;
-                       int mxc = (state & ShiftMask) ? curves.size() : ci+1;
-                       for( int i=mnc; i<mxc; ++i ) {
-                               SketcherCurve *crv = plugin->config.curves[i];
-                               int pts = crv->points.size();
-                               for( int k=0; k<pts; ++k ) {
-                                       SketcherPoint *pt = crv->points[k];
-                                       pt->x += dx;  pt->y += dy;
+               if( (state & ShiftMask) ) {  // string of points
+                   if( (state & (Button1Mask|Button3Mask)) ) {
+                               if( pi < 0 ) pi = points.size()-1;
+                               if( pi >= 0 ) {
+                                       SketcherPoint *pt = pi >= 0 && pi < points.size() ?  points[pi] : 0;
+                                       float frac_w = DISTANCE(pt->x, pt->y, output_x, output_y) / get_w();
+                                       if( frac_w < 0.01 ) break; // 1 percent w
                                }
+                               ++new_points;
+                               int pty = (state & Button1Mask) ? PTY_LINE : PTY_CURVE;
+                               pi = plugin->new_point(cv, pty, output_x, output_y, pi+1);
+                               point_list->update(pi);
+                               break;
                        }
-                       SketcherPoint *pt = hot_point >= 0 && hot_point < points.size() ?
-                               points[hot_point] : 0;
-                       point_x->update(pt ? pt->x : 0.f);
-                       point_y->update(pt ? pt->y : 0.f);
-                       point_list->update(hot_point);
-                       break;
                }
                if( (state & Button1Mask) ) {
-                       SketcherPoint *pt = hot_point >= 0 && hot_point < points.size() ?
-                               points[hot_point] : 0;
-                       if( pt && pt->x == output_x && pt->y == output_y ) break;
-                       if( new_points ) {
+                       if( (state & ControlMask) ) { // drag selected point
+                               SketcherPoint *pt = pi >= 0 && pi < points.size() ?  points[pi] : 0;
                                if( pt ) {
-                                       float frac_w = DISTANCE(pt->x, pt->y, output_x, output_y) / get_w();
-                                       if( frac_w < 0.01 ) break; // 1 percent w
-                               }
-                               if( (state & ShiftMask) ) {
-                                       ++new_points;
-                                       hot_point = plugin->new_point(cv, output_x, output_y);
-                                       point_list->update(hot_point);
+                                       point_list->set_point(pi, PT_X, pt->x = output_x);
+                                       point_list->set_point(pi, PT_Y, pt->y = output_y);
+                                       point_list->update_list(pi);
+                                       point_x->update(pt->x);
+                                       point_y->update(pt->y);
                                }
+                               break;
                        }
-                       else if( pt ) {
-                               point_list->set_point(hot_point, PT_X, pt->x = output_x);
-                               point_list->set_point(hot_point, PT_Y, pt->y = output_y);
-                               point_list->update_list(hot_point);
-                               point_x->update(pt->x);
-                               point_y->update(pt->y);
+               }
+               if( (state & Button3Mask) ) {
+                       if( (state & (ControlMask | AltMask)) ) { // drag selected curve(s)
+                               SketcherCurves &curves = plugin->config.curves;
+                               int dx = round(output_x - last_x);
+                               int dy = round(output_y - last_y);
+                               int mnc = (state & AltMask) || ci<0 ? 0 : ci;
+                               int mxc = (state & AltMask) ? curves.size() : ci+1;
+                               for( int i=mnc; i<mxc; ++i ) {
+                                       SketcherCurve *crv = plugin->config.curves[i];
+                                       int pts = crv->points.size();
+                                       for( int k=0; k<pts; ++k ) {
+                                               SketcherPoint *pt = crv->points[k];
+                                               pt->x += dx;  pt->y += dy;
+                                       }
+                               }
+                               SketcherPoint *pt = pi >= 0 && pi < points.size() ?
+                                       points[pi] : 0;
+                               point_x->update(pt ? pt->x : 0.f);
+                               point_y->update(pt ? pt->y : 0.f);
+                               point_list->update(pi);
+                               break;
                        }
                }
                break; }
@@ -727,7 +738,7 @@ void SketcherWindow::start_color_thread(SketcherCurveColor *color_button)
        unlock_window();
        delete color_picker;
        color_picker = new SketcherCurveColorPicker(this, color_button);
-       int color = BLACK, ci = plugin->config.cv_selected;
+       int color = CV_COLOR, ci = plugin->config.cv_selected;
        if( ci >= 0 && ci < plugin->config.curves.size() ) {
                SketcherCurve *cv = plugin->config.curves[ci];
                color = cv->color;
@@ -743,7 +754,6 @@ SketcherCurveList::SketcherCurveList(SketcherWindow *gui, Sketcher *plugin, int
        this->gui = gui;
        this->plugin = plugin;
        titles[CV_ID] = _("id");  widths[CV_ID] = 64;
-       titles[CV_TY] = _("type");  widths[CV_TY] = 64;
        titles[CV_RAD] = _("radius");  widths[CV_RAD] = 64;
        titles[CV_PEN] = _("pen");  widths[CV_PEN] = 64;
        titles[CV_CLR] = _("color");  widths[CV_CLR] = 64;
@@ -780,27 +790,29 @@ int SketcherCurveList::selection_changed()
        return 1;
 }
 
+void SketcherCurveList::set_curve(int i, int c, const char *cp)
+{
+       cols[c].get(i)->set_text(cp);
+}
+
 void SketcherCurveList::set_selected(int k)
 {
        int ci = -1;
        if( k >= 0 && k < plugin->config.curves.size() ) {
                SketcherCurve *cv = plugin->config.curves[k];
-               gui->curve_type->update(cv->ty);
                gui->curve_radius->update(cv->radius);
                gui->curve_pen->update(cv->pen);
                gui->curve_color->update_gui(cv->color);
                ci = k;
        }
        plugin->config.cv_selected = ci;
-       update_selection(&cols[0], ci);
-       update_list(-1);
+       update_list(ci);
 }
 
 void SketcherCurveList::update_list(int k)
 {
        int xpos = get_xposition(), ypos = get_yposition();
-       if( k < 0 ) k = get_selection_number(0, 0);
-       update_selection(&cols[0], k);
+       if( k >= 0 ) update_selection(&cols[0], k);
        BC_ListBox::update(&cols[0], &titles[0],&widths[0],CV_SZ, xpos,ypos,k);
        center_selection();
 }
@@ -813,22 +825,20 @@ void SketcherCurveList::update(int k)
        for( int i=0; i<sz; ++i ) {
                SketcherCurve *cv = curves[i];
                char itxt[BCSTRLEN];  sprintf(itxt,"%d", cv->id);
-               char ttxt[BCSTRLEN];  sprintf(ttxt,"%s", cv_type[cv->ty]);
-               char rtxt[BCSTRLEN];  sprintf(rtxt,"%d", cv->radius);
                char ptxt[BCSTRLEN];  sprintf(ptxt,"%s", cv_pen[cv->pen]);
+               char rtxt[BCSTRLEN];  sprintf(rtxt,"%d", cv->radius);
                int color = cv->color;
                int r = (color>>16)&0xff, g = (color>>8)&0xff, b = (color>>0)&0xff;
                char ctxt[BCSTRLEN];  sprintf(ctxt,"#%02x%02x%02x", r, g, b);
-               add_curve(itxt, ttxt, rtxt, ptxt, ctxt);
+               add_curve(itxt, ptxt, rtxt, ctxt);
        }
        set_selected(k);
 }
 
-void SketcherCurveList::add_curve(const char *id, const char *type,
-               const char *radius, const char *pen, const char *color)
+void SketcherCurveList::add_curve(const char *id, const char *pen,
+               const char *radius, const char *color)
 {
        cols[CV_ID].append(new BC_ListBoxItem(id));
-       cols[CV_TY].append(new BC_ListBoxItem(type));
        cols[CV_RAD].append(new BC_ListBoxItem(radius));
        cols[CV_PEN].append(new BC_ListBoxItem(pen));
        cols[CV_CLR].append(new BC_ListBoxItem(color));
@@ -845,15 +855,14 @@ SketcherNewCurve::~SketcherNewCurve()
 }
 int SketcherNewCurve::handle_event()
 {
-       int ty = 1, pen = 0, color = 0, radius = 1;
+       int pen = PTY_LINE, radius = 1, color = CV_COLOR;
        int ci = plugin->config.cv_selected;
        if( ci >= 0 && ci < plugin->config.curves.size() ) {
                SketcherCurve *cv = plugin->config.curves[ci];
-               ty = cv->ty;  pen = cv->pen;
-               color = cv->color;  radius = cv->radius;
+               pen = cv->pen;  radius = cv->radius;  color = cv->color;
        }
-       int k = plugin->new_curve(ty, radius, pen, color);
-       gui->curve_list->update(k);
+       ci = plugin->new_curve(pen, radius, color);
+       gui->curve_list->update(ci);
        gui->point_list->update(-1);
        gui->send_configure_change();
        return 1;
@@ -870,13 +879,15 @@ SketcherDelCurve::~SketcherDelCurve()
 }
 int SketcherDelCurve::handle_event()
 {
-       int hot_curve = gui->curve_list->get_selection_number(0, 0);
-       SketcherCurves &curves = plugin->config.curves;
-       if( hot_curve >= 0 && hot_curve < curves.size() ) {
-               curves.remove_object_number(hot_curve);
-               if( --hot_curve < 0 )
-                       hot_curve = plugin->new_curve(0, 1, 0, BLACK);
-               gui->curve_list->update(hot_curve);
+       SketcherConfig &config = plugin->config;
+       int ci = config.cv_selected;
+       SketcherCurves &curves = config.curves;
+       if( ci >= 0 && ci < curves.size() ) {
+               curves.remove_object_number(ci--);
+               if( ci < 0 ) ci = 0;
+               if( !curves.size() )
+                       ci = plugin->new_curve();
+               gui->curve_list->update(ci);
                gui->point_list->update(-1);
                gui->send_configure_change();
        }
@@ -894,14 +905,14 @@ SketcherCurveUp::~SketcherCurveUp()
 
 int SketcherCurveUp::handle_event()
 {
-       SketcherCurves &curves = gui->plugin->config.curves;
-       int hot_curve = gui->curve_list->get_selection_number(0, 0);
-
-       if( hot_curve > 0 && hot_curve < curves.size() ) {
-               SketcherCurve *&cv0 = curves[hot_curve];
-               SketcherCurve *&cv1 = curves[--hot_curve];
+       SketcherConfig &config = gui->plugin->config;
+       int ci = config.cv_selected;
+       SketcherCurves &curves = config.curves;
+       if( ci > 0 && ci < curves.size() ) {
+               SketcherCurve *&cv0 = curves[ci];
+               SketcherCurve *&cv1 = curves[--ci];
                SketcherCurve *t = cv0;  cv0 = cv1;  cv1 = t;
-               gui->curve_list->update(hot_curve);
+               gui->curve_list->update(ci);
        }
        gui->send_configure_change();
        return 1;
@@ -918,28 +929,82 @@ SketcherCurveDn::~SketcherCurveDn()
 
 int SketcherCurveDn::handle_event()
 {
-       SketcherCurves &curves = gui->plugin->config.curves;
-       int hot_curve = gui->curve_list->get_selection_number(0, 0);
-
-       if( hot_curve >= 0 && hot_curve < curves.size()-1 ) {
-               SketcherCurve *&cv0 = curves[hot_curve];
-               SketcherCurve *&cv1 = curves[++hot_curve];
+       SketcherConfig &config = gui->plugin->config;
+       int ci = config.cv_selected;
+       SketcherCurves &curves = config.curves;
+       if( ci >= 0 && ci < curves.size()-1 ) {
+               SketcherCurve *&cv0 = curves[ci];
+               SketcherCurve *&cv1 = curves[++ci];
                SketcherCurve *t = cv0;  cv0 = cv1;  cv1 = t;
-               gui->curve_list->update(hot_curve);
+               gui->curve_list->update(ci);
        }
        gui->send_configure_change();
        return 1;
 }
 
 
+SketcherPointTypeItem::SketcherPointTypeItem(int pty)
+ : BC_MenuItem(_(pt_type[pty]))
+{
+       this->pty = pty;
+}
+int SketcherPointTypeItem::handle_event()
+{
+       SketcherPointType *popup = (SketcherPointType*)get_popup_menu();
+       popup->update(pty);
+       SketcherWindow *gui = popup->gui;
+       SketcherConfig &config = gui->plugin->config;
+       SketcherCurves &curves = config.curves;
+       int ci = config.cv_selected;
+       if( ci < 0 || ci >= curves.size() )
+               return 1;
+       SketcherCurve *cv = curves[ci];
+       SketcherPoints &points = cv->points;
+       int pi = config.pt_selected;
+
+       ArrayList<int> selected;
+       for( int v,i=0; (v=gui->point_list->get_selection_number(0, i))>=0; ++i )
+               selected.append(v);
+
+       for( int i=selected.size(); --i>=0; ) {
+               int k = selected[i];
+               if( k < 0 || k >= points.size() ) continue;
+               SketcherPoint *pt = cv->points[k];
+               pt->pty = pty;
+               gui->point_list->set_point(k, PT_TY, _(pt_type[pty]));
+       }
+
+       gui->point_list->update_list(pi);
+       gui->send_configure_change();
+       return 1;
+}
+
+SketcherPointType::SketcherPointType(SketcherWindow *gui, int x, int y, int pty)
+ : BC_PopupMenu(x,y,64,_(pt_type[pty]))
+{
+       this->gui = gui;
+}
+void SketcherPointType::create_objects()
+{
+       for( int pty=0; pty<PT_SZ; ++pty )
+               add_item(new SketcherPointTypeItem(pty));
+}
+void SketcherPointType::update(int pty)
+{
+       set_text(_(pt_type[pty]));
+}
+
+
 SketcherPointList::SketcherPointList(SketcherWindow *gui, Sketcher *plugin, int x, int y)
  : BC_ListBox(x, y, 360, 130, LISTBOX_TEXT)
 {
        this->gui = gui;
        this->plugin = plugin;
-       titles[PT_X] = _("X");    widths[PT_X] = 90;
-       titles[PT_Y] = _("Y");    widths[PT_Y] = 90;
-       titles[PT_ID] = _("ID");  widths[PT_ID] = 50;
+       titles[PT_ID] = _("ID");    widths[PT_ID] = 50;
+       titles[PT_TY] = _("Type");  widths[PT_TY] = 80;
+       titles[PT_X] = _("X");      widths[PT_X] = 90;
+       titles[PT_Y] = _("Y");      widths[PT_Y] = 90;
+       set_selection_mode(LISTBOX_MULTIPLE);
 }
 SketcherPointList::~SketcherPointList()
 {
@@ -961,6 +1026,7 @@ int SketcherPointList::column_resize_event()
 int SketcherPointList::handle_event()
 {
        int pi = get_selection_number(0, 0);
+       if( get_selection_number(0, 1) >= 0 ) pi = -1;
        set_selected(pi);
        gui->send_configure_change();
        return 1;
@@ -972,9 +1038,10 @@ int SketcherPointList::selection_changed()
        return 1;
 }
 
-void SketcherPointList::add_point(const char *id, const char *xp, const char *yp)
+void SketcherPointList::add_point(const char *id, const char *ty, const char *xp, const char *yp)
 {
        cols[PT_ID].append(new BC_ListBoxItem(id));
+       cols[PT_TY].append(new BC_ListBoxItem(ty));
        cols[PT_X].append(new BC_ListBoxItem(xp));
        cols[PT_Y].append(new BC_ListBoxItem(yp));
 }
@@ -998,17 +1065,16 @@ void SketcherPointList::set_selected(int k)
                SketcherCurve *cv = plugin->config.curves[ci];
                pt = k >= 0 && k < cv->points.size() ? cv->points[pi=k] : 0;
        }
+       gui->point_type->update(pt ? pt->pty : PTY_OFF);
        gui->point_x->update(pt ? pt->x : 0.f);
        gui->point_y->update(pt ? pt->y : 0.f);
        plugin->config.pt_selected = pi;
-       update_selection(&cols[0], pi);
-       update_list(k);
+       update_list(pi);
 }
 void SketcherPointList::update_list(int k)
 {
        int xpos = get_xposition(), ypos = get_yposition();
-       if( k < 0 ) k = get_selection_number(0, 0);
-       update_selection(&cols[0], k);
+       if( k >= 0 ) update_selection(&cols[0], k);
        BC_ListBox::update(&cols[0], &titles[0],&widths[0],PT_SZ, xpos,ypos,k);
        center_selection();
 }
@@ -1023,9 +1089,10 @@ void SketcherPointList::update(int k)
                for( int i=0; i<sz; ++i ) {
                        SketcherPoint *pt = points[i];
                        char itxt[BCSTRLEN];  sprintf(itxt,"%d", pt->id);
+                       char ttxt[BCSTRLEN];  sprintf(ttxt,"%s", _(pt_type[pt->pty]));
                        char xtxt[BCSTRLEN];  sprintf(xtxt,"%d", pt->x);
                        char ytxt[BCSTRLEN];  sprintf(ytxt,"%d", pt->y);
-                       add_point(itxt, xtxt, ytxt);
+                       add_point(itxt, ttxt, xtxt, ytxt);
                }
        }
        set_selected(k);
@@ -1040,9 +1107,8 @@ void SketcherWindow::update_gui()
        point_list->update(pi);
        SketcherCurve *cv = ci >= 0 ? config.curves[ci] : 0;
        curve_radius->update(cv ? cv->radius : 1);
-       curve_type->update(cv ? cv->ty : TYP_OFF);
        curve_pen->update(cv ? cv->pen : PEN_SQUARE);
-       curve_color->set_color(cv ? cv->color : BLACK);
+       curve_color->set_color(cv ? cv->color : CV_COLOR);
        SketcherPoint *pt = pi >= 0 ? cv->points[pi] : 0;
        point_x->update(pt ? pt->x : 0);
        point_y->update(pt ? pt->y : 0);
@@ -1067,15 +1133,23 @@ int SketcherPointUp::handle_event()
                return 1;
        SketcherCurve *cv = config.curves[ci];
        SketcherPoints &points = cv->points;
-       int sz = points.size();
-       int hot_point = gui->point_list->get_selection_number(0, 0);
+       if( points.size() < 2 )
+               return 1;
+       int pi = config.pt_selected;
+
+       ArrayList<int> selected;
+       for( int v,i=0; (v=gui->point_list->get_selection_number(0, i))>=0; ++i )
+               selected.append(v);
 
-       if( sz > 1 && hot_point > 0 ) {
-               SketcherPoint *&pt0 = points[hot_point];
-               SketcherPoint *&pt1 = points[--hot_point];
+       for( int i=0; i<selected.size(); ++i ) {
+               int k = selected[i];
+               if( k <= 0 ) continue;
+               if( k == pi ) --pi;
+               SketcherPoint *&pt0 = points[k];
+               SketcherPoint *&pt1 = points[--k];
                SketcherPoint *t = pt0;  pt0 = pt1;  pt1 = t;
-               gui->point_list->update(hot_point);
        }
+       gui->point_list->update(pi);
        gui->send_configure_change();
        return 1;
 }
@@ -1097,14 +1171,24 @@ int SketcherPointDn::handle_event()
                return 1;
        SketcherCurve *cv = config.curves[ci];
        SketcherPoints &points = cv->points;
-       int sz = points.size();
-       int hot_point = gui->point_list->get_selection_number(0, 0);
-       if( sz > 1 && hot_point < sz-1 ) {
-               SketcherPoint *&pt0 = points[hot_point];
-               SketcherPoint *&pt1 = points[++hot_point];
+       int sz1 = points.size()-1;
+       if( sz1 < 1 )
+               return 1;
+       int pi = config.pt_selected;
+
+       ArrayList<int> selected;
+       for( int v,i=0; (v=gui->point_list->get_selection_number(0, i))>=0; ++i )
+               selected.append(v);
+
+       for( int i=selected.size(); --i>=0; ) {
+               int k = selected[i];
+               if( k >= sz1 ) continue;
+               if( k == pi ) ++pi;
+               SketcherPoint *&pt0 = points[k];
+               SketcherPoint *&pt1 = points[++k];
                SketcherPoint *t = pt0;  pt0 = pt1;  pt1 = t;
-               gui->point_list->update(hot_point);
        }
+       gui->point_list->update(pi);
        gui->send_configure_change();
        return 1;
 }
@@ -1142,7 +1226,8 @@ SketcherNewPoint::~SketcherNewPoint()
 }
 int SketcherNewPoint::handle_event()
 {
-       int k = plugin->new_point();
+       int pi = plugin->config.pt_selected;
+       int k = plugin->new_point(pi+1);
        gui->point_list->update(k);
        gui->send_configure_change();
        return 1;
@@ -1160,17 +1245,26 @@ SketcherDelPoint::~SketcherDelPoint()
 int SketcherDelPoint::handle_event()
 {
        SketcherConfig &config = gui->plugin->config;
+       SketcherCurves &curves = config.curves;
        int ci = config.cv_selected;
-       if( ci >= 0 && ci < config.curves.size() ) {
-               SketcherCurve *cv = config.curves[ci];
-               SketcherPoints &points = cv->points;
-               int hot_point = gui->point_list->get_selection_number(0, 0);
-               if( hot_point >= 0 && hot_point < points.size() ) {
-                       points.remove_object_number(hot_point);
-                       gui->point_list->update(--hot_point);
-                       gui->send_configure_change();
-               }
+       if( ci < 0 || ci >= curves.size() )
+               return 1;
+       SketcherCurve *cv = curves[ci];
+       SketcherPoints &points = cv->points;
+       int pi = config.pt_selected;
+
+       ArrayList<int> selected;
+       for( int v,i=0; (v=gui->point_list->get_selection_number(0, i))>=0; ++i )
+               selected.append(v);
+
+       for( int i=selected.size(); --i>=0; ) {
+               int k = selected[i];
+               if( k < 0 || k >= points.size() ) continue;
+               points.remove_object_number(k);
+               if( k == pi && --pi < 0 && points.size() > 0 ) pi = 0;
        }
+       gui->point_list->update(pi);
+       gui->send_configure_change();
        return 1;
 }
 
@@ -1187,7 +1281,7 @@ int SketcherResetCurves::handle_event()
 {
        SketcherConfig &config = plugin->config;
        config.curves.remove_all_objects();
-       int ci = plugin->new_curve(0, 1, 0, BLACK);
+       int ci = plugin->new_curve();
        gui->curve_list->update(ci);
        gui->point_list->update(-1);
        gui->send_configure_change();
index a0cc4ae21044ad6349e80e30f6a5d5031c38b436..35e7e898346ef6feb712722d4a7bea4c8aee20ca 100644 (file)
@@ -42,6 +42,8 @@ class SketcherCurveList;
 class SketcherPointX;
 class SketcherPointY;
 class SketcherDrag;
+class SketcherPointTypeItem;
+class SketcherPointType;
 class SketcherPointList;
 class SketcherNewPoint;
 class SketcherDelPoint;
@@ -51,6 +53,7 @@ class SketcherResetCurves;
 class SketcherResetPoints;
 class SketcherWindow;
 
+
 class SketcherNum : public BC_TumbleTextBox
 {
 public:
@@ -62,24 +65,6 @@ public:
        int update(int v) { return BC_TumbleTextBox::update((int64_t)v); }
 };
 
-class SketcherCurveTypeItem : public BC_MenuItem
-{
-public:
-       SketcherCurveTypeItem(int ty);
-       int handle_event();
-       int ty;
-};
-
-class SketcherCurveType : public BC_PopupMenu
-{
-public:
-       SketcherCurveType(SketcherWindow *gui, int x, int y, int ty);
-       void create_objects();
-       void update(int ty);
-
-       SketcherWindow *gui;
-};
-
 class SketcherCurvePenItem : public BC_MenuItem
 {
 public:
@@ -93,7 +78,7 @@ class SketcherCurvePen : public BC_PopupMenu
 public:
        SketcherCurvePen(SketcherWindow *gui, int x, int y, int pen);
        void create_objects();
-       void update(int ty);
+       void update(int pen);
 
        SketcherWindow *gui;
 };
@@ -101,7 +86,7 @@ public:
 class SketcherCurveColor : public BC_Button
 {
 public:
-       SketcherCurveColor(SketcherWindow *gui, int x, int y, int w);
+       SketcherCurveColor(SketcherWindow *gui, int x, int y, int w, int h);
        ~SketcherCurveColor();
 
        void set_color(int color);
@@ -211,9 +196,10 @@ public:
        int column_resize_event();
        ArrayList<BC_ListBoxItem*> cols[CV_SZ];
        void clear();
-       void add_curve(const char *id, const char *type,
-               const char *radius, const char *pen, const char *color);
+       void add_curve(const char *id, const char *pen,
+               const char *radius, const char *color);
        void del_curve(int i);
+       void set_curve(int i, int c, const char *cp);
        void set_selected(int k);
        void update(int k);
        void update_list(int k);
@@ -254,6 +240,24 @@ public:
        SketcherWindow *gui;
 };
 
+class SketcherPointTypeItem : public BC_MenuItem
+{
+public:
+       SketcherPointTypeItem(int pty);
+       int handle_event();
+       int pty;
+};
+
+class SketcherPointType : public BC_PopupMenu
+{
+public:
+       SketcherPointType(SketcherWindow *gui, int x, int y, int pty);
+       void create_objects();
+       void update(int pty);
+
+       SketcherWindow *gui;
+};
+
 
 class SketcherPointList : public BC_ListBox
 {
@@ -266,7 +270,7 @@ public:
        int column_resize_event();
        ArrayList<BC_ListBoxItem*> cols[PT_SZ];
        void clear();
-       void add_point(const char *id, const char *xp, const char *yp);
+       void add_point(const char *id, const char *ty, const char *xp, const char *yp);
        void set_point(int i, int c, int v);
        void set_point(int i, int c, const char *cp);
        void set_selected(int k);
@@ -368,8 +372,7 @@ public:
 
        Sketcher *plugin;
 
-       BC_Title *title_type, *title_pen;
-       BC_Title *title_color, *title_radius;
+       BC_Title *title_pen, *title_color, *title_radius;
        SketcherCurveType *curve_type;
        SketcherCurvePen *curve_pen;
        SketcherCurveColor *curve_color;
@@ -382,6 +385,10 @@ public:
        SketcherCurveList *curve_list;
        SketcherResetCurves *reset_curves;
 
+       SketcherResetPoints *reset_points;
+       SketcherDrag *drag;
+       SketcherPointType *point_type;
+       SketcherPointList *point_list;
        BC_Title *title_x, *title_y;
        SketcherPointX *point_x;
        SketcherPointY *point_y;
@@ -392,9 +399,6 @@ public:
        int dragging, pending_config;
        int new_points;
        float last_x, last_y;
-       SketcherDrag *drag;
-       SketcherPointList *point_list;
-       SketcherResetPoints *reset_points;
        BC_Title *notes0, *notes1, *notes2;
 };
 #endif