LCOV - code coverage report
Current view: top level - fontforgeexe - cvaddpoints.c (source / functions) Hit Total Coverage
Test: FontForge coverage report 2017-08-04 01:21:11+02:00 (commit d35f7e4107a9e1db65cce47c468fcc914cecb8fd) Lines: 0 562 0.0 %
Date: 2017-08-04 Functions: 0 14 0.0 %

          Line data    Source code
       1             : /* Copyright (C) 2000-2012 by George Williams */
       2             : /*
       3             :  * Redistribution and use in source and binary forms, with or without
       4             :  * modification, are permitted provided that the following conditions are met:
       5             : 
       6             :  * Redistributions of source code must retain the above copyright notice, this
       7             :  * list of conditions and the following disclaimer.
       8             : 
       9             :  * Redistributions in binary form must reproduce the above copyright notice,
      10             :  * this list of conditions and the following disclaimer in the documentation
      11             :  * and/or other materials provided with the distribution.
      12             : 
      13             :  * The name of the author may not be used to endorse or promote products
      14             :  * derived from this software without specific prior written permission.
      15             : 
      16             :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
      17             :  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
      18             :  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
      19             :  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
      20             :  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
      21             :  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
      22             :  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
      23             :  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      24             :  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
      25             :  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      26             :  */
      27             : #include "cvundoes.h"
      28             : #include "fontforgeui.h"
      29             : #include <math.h>
      30             : #include "spiro.h"
      31             : #include "splinefont.h"
      32             : #include "splineorder2.h"
      33             : #include "splineutil.h"
      34             : #include "splineutil2.h"
      35             : #include "ustring.h"
      36             : 
      37           0 : int CVOneThingSel(CharView *cv, SplinePoint **sp, SplinePointList **_spl,
      38             :         RefChar **ref, ImageList **img, AnchorPoint **ap, spiro_cp **scp) {
      39             :     /* if there is exactly one thing selected return it */
      40           0 :     SplinePointList *spl, *found=NULL;
      41             :     Spline *spline;
      42           0 :     SplinePoint *foundsp=NULL;
      43           0 :     RefChar *refs, *foundref=NULL;
      44           0 :     ImageList *imgs, *foundimg=NULL;
      45           0 :     AnchorPoint *aps, *foundap=NULL;
      46           0 :     spiro_cp *foundcp = NULL;
      47             :     int i;
      48             : 
      49           0 :     *sp = NULL; *_spl=NULL; *ref=NULL; *img = NULL; *scp = NULL;
      50           0 :     if ( ap ) *ap = NULL;
      51           0 :     for ( spl= cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL; spl=spl->next ) {
      52           0 :         if ( !cv->b.sc->inspiro || !hasspiro()) {
      53           0 :             if ( spl->first->selected ) {
      54           0 :                 if ( found!=NULL )
      55           0 : return( 0 );                    /* At least two points */
      56           0 :                 found = spl; foundsp = spl->first;
      57             :             }
      58           0 :             for ( spline = spl->first->next; spline!=NULL ; spline=spline->to->next ) {
      59           0 :                 if ( spline->to==spl->first )
      60           0 :             break;
      61           0 :                 if ( spline->to->selected ) {
      62           0 :                     if ( found!=NULL )
      63           0 : return( 0 );
      64           0 :                     found = spl; foundsp = spline->to;
      65             :                 }
      66             :             }
      67             :         } else {
      68           0 :             for ( i=0; i<spl->spiro_cnt-1; ++i ) {
      69           0 :                 if ( SPIRO_SELECTED(&spl->spiros[i])) {
      70           0 :                     if ( found )
      71           0 : return( 0 );
      72           0 :                     found = spl;
      73           0 :                     foundcp = &spl->spiros[i];
      74             :                 }
      75             :             }
      76             :         }
      77             :     }
      78           0 :     *sp = foundsp; *scp = foundcp; *_spl = found;
      79             : 
      80           0 :     if ( cv->b.drawmode!=dm_grid ) {
      81           0 :         for ( refs=cv->b.layerheads[cv->b.drawmode]->refs; refs!=NULL; refs = refs->next ) {
      82           0 :             if ( refs->selected ) {
      83           0 :                 if ( found!=NULL || foundref!=NULL )
      84           0 : return( 0 );
      85           0 :                 foundref = refs;
      86             :             }
      87             :         }
      88           0 :         *ref = foundref;
      89           0 :         if ( cv->showanchor && ap!=NULL ) {
      90           0 :             for ( aps=cv->b.sc->anchor; aps!=NULL; aps=aps->next ) {
      91           0 :                 if ( aps->selected ) {
      92           0 :                     if ( found!=NULL || foundref!=NULL || foundap!=NULL )
      93           0 : return( 0 );
      94           0 :                     foundap = aps;
      95             :                 }
      96             :             }
      97           0 :             *ap = foundap;
      98             :         }
      99             :     }
     100             : 
     101           0 :     for ( imgs=cv->b.layerheads[cv->b.drawmode]->images; imgs!=NULL; imgs = imgs->next ) {
     102           0 :         if ( imgs->selected ) {
     103           0 :             if ( found!=NULL || foundimg!=NULL )
     104           0 : return( 0 );
     105           0 :             foundimg = imgs;
     106             :         }
     107             :     }
     108           0 :     *img = foundimg;
     109             : 
     110           0 :     if ( found )
     111           0 : return( foundimg==NULL && foundref==NULL && foundap==NULL );
     112           0 :     else if ( foundref || foundimg || foundap )
     113           0 : return( true );
     114             : 
     115           0 : return( false );
     116             : }
     117             : 
     118           0 : int CVOneContourSel(CharView *cv, SplinePointList **_spl,
     119             :         RefChar **ref, ImageList **img) {
     120             :     /* if there is exactly one contour/image/reg selected return it */
     121           0 :     SplinePointList *spl, *found=NULL;
     122             :     Spline *spline;
     123           0 :     RefChar *refs, *foundref=NULL;
     124           0 :     ImageList *imgs, *foundimg=NULL;
     125             :     int i;
     126             : 
     127           0 :     *_spl=NULL; *ref=NULL; *img = NULL;
     128           0 :     for ( spl= cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL; spl=spl->next ) {
     129           0 :         if ( !cv->b.sc->inspiro || !hasspiro()) {
     130           0 :             if ( spl->first->selected ) {
     131           0 :                 if ( found!=NULL && found!=spl )
     132           0 : return( 0 );                    /* At least two contours */
     133           0 :                 found = spl;
     134             :             }
     135           0 :             for ( spline = spl->first->next; spline!=NULL ; spline=spline->to->next ) {
     136           0 :                 if ( spline->to==spl->first )
     137           0 :             break;
     138           0 :                 if ( spline->to->selected ) {
     139           0 :                     if ( found!=NULL && found!=spl )
     140           0 : return( 0 );
     141           0 :                     found = spl;
     142             :                 }
     143             :             }
     144             :         } else {
     145           0 :             for ( i=0; i<spl->spiro_cnt-1; ++i ) {
     146           0 :                 if ( SPIRO_SELECTED(&spl->spiros[i])) {
     147           0 :                     if ( found!=NULL && found!=spl )
     148           0 : return( 0 );
     149           0 :                     found = spl;
     150             :                 }
     151             :             }
     152             :         }
     153             :     }
     154           0 :     *_spl = found;
     155             : 
     156           0 :     if ( cv->b.drawmode==dm_fore ) {
     157           0 :         for ( refs=cv->b.layerheads[cv->b.drawmode]->refs; refs!=NULL; refs = refs->next ) {
     158           0 :             if ( refs->selected ) {
     159           0 :                 if ( found!=NULL || foundref!=NULL )
     160           0 : return( 0 );
     161           0 :                 foundref = refs;
     162             :             }
     163             :         }
     164           0 :         *ref = foundref;
     165             :     }
     166             : 
     167           0 :     for ( imgs=cv->b.layerheads[cv->b.drawmode]->images; imgs!=NULL; imgs = imgs->next ) {
     168           0 :         if ( imgs->selected ) {
     169           0 :             if ( found!=NULL || foundimg!=NULL )
     170           0 : return( 0 );
     171           0 :             foundimg = imgs;
     172             :         }
     173             :     }
     174           0 :     *img = foundimg;
     175             : 
     176           0 :     if ( found )
     177           0 : return( foundimg==NULL && foundref==NULL );
     178           0 :     else if ( foundref || foundimg )
     179           0 : return( true );
     180             : 
     181           0 : return( false );
     182             : }
     183             : 
     184           0 : SplinePointList *CVAnySelPointList(CharView *cv) {
     185             :     /* if there is exactly one point selected and it is on an open splineset */
     186             :     /*  and it is one of the endpoints of the splineset, then return that */
     187             :     /*  splineset */
     188           0 :     SplinePointList *spl, *found=NULL;
     189             :     Spline *spline, *first;
     190             :     int i;
     191             : 
     192           0 :     for ( spl= cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL; spl=spl->next ) {
     193           0 :         if ( cv->b.sc->inspiro && hasspiro()) {
     194           0 :             for ( i = 0; i<spl->spiro_cnt-1; ++i ) {
     195           0 :                 if ( SPIRO_SELECTED(&spl->spiros[i])) {
     196             :                     /* Only interesting if the single selection is at the */
     197             :                     /* start/end of an open contour */
     198           0 :                     if (( i!=0 && i!=spl->spiro_cnt-2 ) ||
     199           0 :                             !SPIRO_SPL_OPEN(spl))
     200           0 : return( NULL );
     201           0 :                     else if ( found==NULL )
     202           0 :                         found = spl;
     203             :                     else
     204           0 : return( NULL );
     205             :                 }
     206             :             }
     207             :         } else {
     208           0 :             if ( spl->first->selected ) {
     209           0 :                 if ( found!=NULL )
     210           0 : return( NULL );                 /* At least two points */
     211           0 :                 if ( spl->first->prev!=NULL )
     212           0 : return( NULL );                 /* Not an open splineset */
     213           0 :                 found = spl;
     214             :             }
     215           0 :             first = NULL;
     216           0 :             for ( spline = spl->first->next; spline!=NULL && spline!=first; spline=spline->to->next ) {
     217           0 :                 if ( spline->to->selected ) {
     218           0 :                     if ( found!=NULL )
     219           0 : return( NULL );
     220           0 :                     if ( spline->to->next!=NULL )
     221           0 : return( NULL );                 /* Selected point is not at end of a splineset */
     222           0 :                     found = spl;
     223             :                 }
     224           0 :                 if ( first==NULL ) first = spline;
     225             :             }
     226             :         }
     227             :     }
     228           0 : return( found );
     229             : }
     230             : 
     231           0 : int CVAnySelPoint(CharView *cv,SplinePoint **sp, spiro_cp **cp) {
     232             :     /* if there is exactly one point selected */
     233             :     SplinePointList *spl;
     234           0 :     Spline *spline, *first; SplinePoint *found = NULL;
     235           0 :     spiro_cp *foundcp = NULL;
     236             :     int i;
     237             : 
     238           0 :     *sp = NULL; *cp = NULL;
     239           0 :     if ( cv->b.sc->inspiro && hasspiro()) {
     240           0 :         for ( spl= cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL; spl=spl->next ) {
     241           0 :             for ( i=0; i<spl->spiro_cnt-1; ++i )
     242           0 :                 if ( SPIRO_SELECTED( &spl->spiros[i]) ) {
     243           0 :                     if ( foundcp )
     244           0 : return( false );
     245           0 :                     foundcp = &spl->spiros[i];
     246             :                 }
     247             :         }
     248           0 :         *cp = foundcp;
     249           0 : return( foundcp!=NULL );
     250             :     } else {
     251           0 :         for ( spl= cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL; spl=spl->next ) {
     252           0 :             if ( spl->first->selected ) {
     253           0 :                 if ( found!=NULL )
     254           0 : return( false );                        /* At least two points */
     255           0 :                 found = spl->first;
     256             :             }
     257           0 :             first = NULL;
     258           0 :             for ( spline = spl->first->next; spline!=NULL && spline!=first; spline=spline->to->next ) {
     259           0 :                 if ( spline->to->selected ) {
     260           0 :                     if ( found!=NULL )
     261           0 : return( false );
     262           0 :                     found = spline->to;
     263             :                 }
     264           0 :                 if ( first==NULL ) first = spline;
     265             :             }
     266             :         }
     267           0 :         *sp = found;
     268           0 : return( found!=NULL );
     269             :     }
     270             : }
     271             : 
     272           0 : static void CVMergeSPLS(CharView *cv,SplineSet *ss, SplinePoint *base,SplinePoint *sp) {
     273           0 :     int order2 = cv->b.layerheads[cv->b.drawmode]->order2;
     274             : 
     275           0 :     cv->joinvalid = true;
     276           0 :     cv->joinpos = *sp; cv->joinpos.selected = false;
     277           0 :     if ( sp->prev!=NULL )
     278           0 :         SplineSetReverse(cv->p.spl);
     279           0 :     if ( sp->prev!=NULL )
     280           0 :         IError("Base point not at start of splineset in CVMouseDownPoint");
     281             :     /* remove the old spl entry from the chain */
     282           0 :     if ( cv->p.spl==cv->b.layerheads[cv->b.drawmode]->splines )
     283           0 :         cv->b.layerheads[cv->b.drawmode]->splines = cv->p.spl->next;
     284             :     else { SplineSet *temp;
     285           0 :         for ( temp = cv->b.layerheads[cv->b.drawmode]->splines; temp->next!=cv->p.spl; temp = temp->next );
     286           0 :         temp->next = cv->p.spl->next;
     287             :     }
     288           0 :     if ( order2 && (!RealNear(base->nextcp.x,sp->prevcp.x) ||
     289           0 :             !RealNear(base->nextcp.y,sp->prevcp.y)) ) {
     290           0 :         base->nonextcp = sp->noprevcp = true;
     291           0 :         base->nextcp = base->me;
     292           0 :         sp->prevcp = sp->me;
     293             :     }
     294           0 :     SplineMake(base,sp,order2);
     295           0 :     SplineCharDefaultNextCP(base);
     296           0 :     SplineCharDefaultPrevCP(sp);
     297           0 :     if ( sp->pointtype==pt_tangent ) {
     298           0 :         SplineCharTangentNextCP(sp);
     299           0 :         if ( sp->next ) SplineRefigure(sp->next );
     300             :     }
     301           0 :     ss->last = cv->p.spl->last;
     302           0 :     if ( ss->spiros && cv->p.spl->spiros ) {
     303           0 :         if ( ss->spiro_cnt+cv->p.spl->spiro_cnt > ss->spiro_max )
     304           0 :             ss->spiros = realloc(ss->spiros,
     305           0 :                     (ss->spiro_max = ss->spiro_cnt+cv->p.spl->spiro_cnt)*sizeof(spiro_cp));
     306           0 :         memcpy(ss->spiros+ss->spiro_cnt-1,
     307           0 :                 cv->p.spl->spiros+1, (cv->p.spl->spiro_cnt-1)*sizeof(spiro_cp));
     308           0 :         ss->spiro_cnt += cv->p.spl->spiro_cnt-2;
     309             :     } else
     310           0 :         SplineSetSpirosClear(ss);
     311           0 :     cv->p.spl->last = cv->p.spl->first = NULL;
     312           0 :     cv->p.spl->spiros = 0;
     313           0 :     SplinePointListFree(cv->p.spl);
     314           0 :     cv->p.spl = NULL;
     315           0 : }
     316             : 
     317           0 : static void CVMouseDownSpiroPoint(CharView *cv, GEvent *event) {
     318             :     SplineSet *sel, *ss;
     319           0 :     SplineChar *sc = cv->b.sc;
     320             :     spiro_cp *base, *cp;
     321             :     int base_index, cp_index, i;
     322           0 :     char ty = (cv->active_tool==cvt_curve?SPIRO_G4:
     323           0 :                             cv->active_tool==cvt_hvcurve?SPIRO_G2:
     324           0 :                             cv->active_tool==cvt_corner?SPIRO_CORNER:
     325           0 :                             cv->active_tool==cvt_tangent?SPIRO_LEFT:
     326             :                             /*cv->active_tool==cvt_pen?*/SPIRO_RIGHT);
     327             : 
     328           0 :     cv->active_spl = NULL;
     329           0 :     cv->active_sp = NULL;
     330             : 
     331           0 :     sel = CVAnySelPointList(cv);
     332           0 :     if ( sel!=NULL ) {
     333           0 :         if ( SPIRO_SELECTED(&sel->spiros[0]) ) base_index = 0;
     334           0 :         else base_index = sel->spiro_cnt-2;
     335           0 :         base = &sel->spiros[base_index];
     336           0 :         if ( base==cv->p.spiro )
     337           0 : return;                 /* We clicked on the active point, that's a no-op */
     338             :     }
     339           0 :     CVPreserveState(&cv->b);
     340           0 :     CVClearSel(cv);
     341           0 :     if ( sel!=NULL ) {
     342           0 :         if ( (cp = cv->p.spiro)!=NULL )
     343           0 :             cp_index = cp-cv->p.spl->spiros;
     344           0 :         cv->lastselcp = base;
     345           0 :         ss = sel;
     346           0 :         if ( base_index!=sel->spiro_cnt-2 ) {
     347           0 :             SplineSetReverse(sel);
     348           0 :             base = &sel->spiros[sel->spiro_cnt-2];
     349           0 :             if ( cv->p.spl==sel ) {
     350           0 :                 cp_index = sel->spiro_cnt-2-cp_index;
     351           0 :                 cp = &sel->spiros[cp_index];
     352             :             }
     353             :         }
     354           0 :         if ( cp==NULL || (cp_index!=0 && cp_index!=cv->p.spl->spiro_cnt-2) ||
     355           0 :                 cp==base || !SPIRO_SPL_OPEN(cv->p.spl)) {
     356             :             /* Add a new point */
     357           0 :             if ( sel->spiro_cnt>=sel->spiro_max )
     358           0 :                 sel->spiros = realloc(sel->spiros,(sel->spiro_max += 10)*sizeof(spiro_cp));
     359           0 :             cp = &sel->spiros[sel->spiro_cnt-1];
     360           0 :             cp[1] = cp[0];              /* Move the final 'z' */
     361           0 :             cp->x = cv->p.cx;
     362           0 :             cp->y = cv->p.cy;
     363           0 :             cp->ty = ty;
     364           0 :             SPIRO_DESELECT(cp-1);
     365           0 :             ++sel->spiro_cnt;
     366           0 :         } else if ( cv->p.spl==sel ) {
     367             :             /* Close the current spline set */
     368           0 :             sel->spiros[0].ty = ty;
     369           0 :             cv->joinvalid = true;
     370           0 :             cv->joincp = *cp; SPIRO_DESELECT(&cv->joincp);
     371             :         } else {
     372             :             /* Merge two spline sets */
     373           0 :             SplinePoint *sp = cp_index==0 ? cv->p.spl->first : cv->p.spl->last;
     374           0 :             SplinePoint *basesp = base_index==0 ? sel->first : sel->last;
     375           0 :             cv->joincp = *cp; SPIRO_DESELECT(&cv->joincp);
     376           0 :             CVMergeSPLS(cv,ss,basesp,sp);
     377             :         }
     378           0 :     } else if ( cv->p.spline!=NULL ) {
     379             :         /* Add an intermediate point on an already existing spline */
     380           0 :         ss = cv->p.spl;
     381           0 :         if ( ss->spiro_cnt>=ss->spiro_max )
     382           0 :             ss->spiros = realloc(ss->spiros,(ss->spiro_max += 10)*sizeof(spiro_cp));
     383           0 :         for ( i=ss->spiro_cnt-1; i>cv->p.spiro_index; --i )
     384           0 :             ss->spiros[i+1] = ss->spiros[i];
     385           0 :         ++ss->spiro_cnt;
     386           0 :         cp = &ss->spiros[cv->p.spiro_index+1];
     387           0 :         cp->x = cv->p.cx;
     388           0 :         cp->y = cv->p.cy;
     389           0 :         cp->ty = ty;
     390           0 :         ss = cv->p.spl;
     391           0 :         cv->joinvalid = true;
     392           0 :         cv->joincp = *cp; SPIRO_DESELECT(&cv->joincp);
     393             :     } else {
     394             :         /* A new point on a new (open) contour */
     395           0 :         ss = chunkalloc(sizeof(SplineSet));
     396           0 :         ss->next = cv->b.layerheads[cv->b.drawmode]->splines;
     397           0 :         cv->b.layerheads[cv->b.drawmode]->splines = ss;
     398           0 :         ss->spiros = malloc((ss->spiro_max=10)*sizeof(spiro_cp));
     399           0 :         cp = &ss->spiros[0];
     400           0 :         cp->x = cv->p.cx;
     401           0 :         cp->y = cv->p.cy;
     402           0 :         cp->ty = SPIRO_OPEN_CONTOUR;
     403           0 :         cp[1].x = cp[1].y = 0; cp[1].ty = 'z';
     404           0 :         ss->spiro_cnt = 2;
     405             :     }
     406           0 :     SPIRO_SELECT(cp);
     407             : 
     408           0 :     SSRegenerateFromSpiros(ss);
     409             : 
     410           0 :     cv->active_spl = ss;
     411           0 :     cv->active_cp = cp;
     412           0 :     CVSetCharChanged(cv,true);
     413           0 :     CVInfoDraw(cv,cv->gw);
     414           0 :     SCUpdateAll(sc);
     415             : }
     416             : 
     417             : /* When the user tries to add a point (by doing a mouse down with a point tool
     418             :   selected) there are several cases to be looked at:
     419             :         If there is a single point selected and it is at the begining/end of an open spline set
     420             :             if we clicked on another point which is the begining/end of an open splineset
     421             :                 draw a spline connecting the two spline sets and merge them
     422             :                         (or if it's the same spline set, then close it)
     423             :             else
     424             :                 create a new point where we clicked
     425             :                 draw a spline between the selected point and the new one
     426             :                 deselect the old point
     427             :                 select the new one
     428             :             endif
     429             :         else if they clicked on a spline
     430             :             split the spline into two bits at the point where they clicked
     431             :         else
     432             :             create a new point where they clicked
     433             :             put it on a new splineset
     434             :             select it
     435             :         endif
     436             : 
     437             :         and, if the old point is a tangent, we may need to adjust its control pt
     438             : 
     439             :     With the introduction of spiro mode (Raph Levien's clothoid splines)
     440             :       we've got to worry about all the above cases for spiro points too.
     441             : */
     442           0 : void CVMouseDownPoint(CharView *cv, GEvent *event) {
     443             :     SplineSet *sel, *ss;
     444           0 :     SplinePoint *sp, *base = NULL;
     445           0 :     SplineChar *sc = cv->b.sc;
     446           0 :     enum pointtype ptype = (cv->active_tool==cvt_curve?pt_curve:
     447           0 :                             cv->active_tool==cvt_hvcurve?pt_hvcurve:
     448           0 :                             cv->active_tool==cvt_corner?pt_corner:
     449           0 :                             cv->active_tool==cvt_tangent?pt_tangent:
     450             :                             /*cv->active_tool==cvt_pen?*/pt_corner);
     451           0 :     int order2 = cv->b.layerheads[cv->b.drawmode]->order2;
     452           0 :     int order2_style = (order2 && !(event->u.mouse.state&ksm_meta)) ||
     453           0 :                     (!order2 && (event->u.mouse.state&ksm_meta));
     454             : 
     455           0 :     cv->active_spl = NULL;
     456           0 :     cv->active_sp = NULL;
     457             : 
     458           0 :     if ( cv->b.sc->inspiro && hasspiro()) {
     459           0 :         CVMouseDownSpiroPoint(cv, event);
     460           0 : return;
     461             :     }
     462             : 
     463           0 :     sel = CVAnySelPointList(cv);
     464           0 :     if ( sel!=NULL ) {
     465           0 :         if ( sel->first->selected ) base = sel->first;
     466           0 :         else base = sel->last;
     467           0 :         if ( base==cv->p.sp )
     468           0 : return;                 /* We clicked on the active point, that's a no-op */
     469             :     }
     470           0 :     CVPreserveState(&cv->b);
     471           0 :     CVClearSel(cv);
     472           0 :     if ( sel!=NULL ) {
     473           0 :         sp = cv->p.sp;
     474           0 :         cv->lastselpt = base;
     475           0 :         ss = sel;
     476           0 :         if ( base->next!=NULL )
     477           0 :             SplineSetReverse(sel);
     478           0 :         if ( base->next!=NULL )
     479           0 :             IError("Base point not at end of splineset in CVMouseDownPoint");
     480           0 :         if ( sp==NULL || (sp->next!=NULL && sp->prev!=NULL) || sp==base ) {
     481             :             /* Add a new point */
     482           0 :             SplineSetSpirosClear(sel);
     483           0 :             sp = SplinePointCreate( cv->p.cx, cv->p.cy );
     484           0 :             sp->noprevcp = sp->nonextcp = 1;
     485           0 :             sp->nextcpdef = sp->prevcpdef = 1;
     486           0 :             sp->pointtype = ptype;
     487           0 :             sp->selected = true;
     488           0 :             if ( !base->nonextcp && order2_style &&
     489           0 :                     cv->active_tool==cvt_pen ) {
     490           0 :                 sp->prevcp = base->nextcp;
     491           0 :                 sp->noprevcp = false;
     492           0 :                 sp->me.x = ( sp->prevcp.x + sp->nextcp.x )/2;
     493           0 :                 sp->me.y = ( sp->prevcp.y + sp->nextcp.y )/2;
     494           0 :                 sp->nonextcp = false;
     495           0 :                 sp->pointtype = pt_curve;
     496           0 :             } else if ( order2 && !base->nonextcp ) {
     497           0 :                 sp->prevcp = base->nextcp;
     498           0 :                 sp->noprevcp = false;
     499           0 :                 if (  cv->active_tool==cvt_pen ) {
     500           0 :                     sp->nextcp.x = sp->me.x - (sp->prevcp.x-sp->me.x);
     501           0 :                     sp->nextcp.y = sp->me.y - (sp->prevcp.y-sp->me.y);
     502           0 :                     sp->nonextcp = false;
     503           0 :                     sp->pointtype = pt_curve;
     504             :                 }
     505             :             }
     506           0 :             if ( base->nonextcp )
     507           0 :                 base->nextcpdef = true;
     508           0 :             SplineMake(base,sp,order2);
     509           0 :             if ( cv->active_tool!=cvt_pen ) {
     510           0 :                 SplineCharDefaultNextCP(base);
     511           0 :                 SplineCharDefaultPrevCP(sp);
     512             :             }
     513           0 :             ss->last = sp;
     514           0 :         } else if ( cv->p.spl==sel ) {
     515             :             /* Close the current spline set */
     516           0 :             SplineSetSpirosClear(sel);
     517           0 :             cv->joinvalid = true;
     518           0 :             cv->joinpos = *sp; cv->joinpos.selected = false;
     519           0 :             if ( order2 ) {
     520           0 :                 if ( base->nonextcp || sp->noprevcp ) {
     521           0 :                     base->nonextcp = sp->noprevcp = true;
     522           0 :                     base->nextcp = base->me;
     523           0 :                     sp->prevcp = sp->me;
     524             :                 } else {
     525           0 :                     base->nextcp.x = sp->prevcp.x = (base->nextcp.x+sp->prevcp.x)/2;
     526           0 :                     base->nextcp.y = sp->prevcp.y = (base->nextcp.y+sp->prevcp.y)/2;
     527             :                 }
     528           0 :                 base->nextcpdef = sp->prevcpdef = true;
     529             :             }
     530           0 :             SplineMake(base,sp,order2);
     531           0 :             if ( cv->active_tool!=cvt_pen )
     532           0 :                 SplineCharDefaultNextCP(base);
     533           0 :             SplineCharDefaultPrevCP(sp);
     534           0 :             ss->last = sp;
     535           0 :             if ( sp->pointtype==pt_tangent ) {
     536           0 :                 SplineCharTangentNextCP(sp);
     537           0 :                 if ( sp->next ) SplineRefigure(sp->next );
     538             :             }
     539             :         } else {
     540             :             /* Merge two spline sets */
     541           0 :             SplineSetSpirosClear(sel);
     542           0 :             CVMergeSPLS(cv,sel, base,sp);
     543             :         }
     544           0 :         sp->selected = true;
     545           0 :         if ( base->pointtype==pt_tangent ) {
     546           0 :             SplineCharTangentPrevCP(base);
     547           0 :             if ( base->prev!=NULL )
     548           0 :                 SplineRefigure(base->prev);
     549             :         }
     550           0 :     } else if ( cv->p.spline!=NULL ) {
     551           0 :         sp = SplineBisect(cv->p.spline,cv->p.t);
     552           0 :         cv->joinvalid = true;
     553           0 :         cv->joinpos = *sp; cv->joinpos.selected = false;
     554           0 :         if (  cv->active_tool==cvt_pen )
     555           0 :             ptype = pt_curve;
     556           0 :         sp->pointtype = ptype;
     557           0 :         if ( ptype==pt_hvcurve ) {
     558           0 :             SPHVCurveForce(sp);
     559             :         }
     560           0 :         sp->selected = true;
     561           0 :         ss = cv->p.spl;
     562             :     } else {
     563           0 :         ss = chunkalloc(sizeof(SplineSet));
     564           0 :         sp = SplinePointCreate( cv->p.cx, cv->p.cy );
     565             :         
     566           0 :         ss->first = ss->last = sp;
     567           0 :         ss->next = cv->b.layerheads[cv->b.drawmode]->splines;
     568           0 :         cv->b.layerheads[cv->b.drawmode]->splines = ss;
     569           0 :         sp->nonextcp = sp->noprevcp = 1;
     570           0 :         sp->nextcpdef = sp->prevcpdef = 1;
     571           0 :         sp->pointtype = ptype;
     572           0 :         sp->selected = true;
     573             :     }
     574             : 
     575           0 :     cv->active_spl = ss;
     576           0 :     cv->active_sp = sp;
     577           0 :     CVSetCharChanged(cv,true);
     578           0 :     CVInfoDraw(cv,cv->gw);
     579           0 :     SCUpdateAll(sc);
     580             : 
     581           0 :     if ( cv->active_tool == cvt_pen )
     582           0 :         cv->p.constrain = sp->me;
     583             : }
     584             : 
     585           0 : void AdjustControls(SplinePoint *sp) {
     586           0 :     if ( sp->next!=NULL ) {
     587           0 :         SplineCharDefaultNextCP(sp);    /* also fixes up tangents */
     588           0 :         SplineCharDefaultPrevCP(sp->next->to);
     589           0 :         SplineRefigure(sp->next);
     590           0 :         if ( sp->next->to->pointtype==pt_tangent && sp->next->to->next!=NULL ) {
     591           0 :             SplineCharTangentNextCP(sp->next->to);
     592           0 :             SplineRefigure(sp->next->to->next);
     593             :         }
     594             :     }
     595           0 :     if ( sp->prev!=NULL ) {
     596           0 :         SplineCharDefaultPrevCP(sp);
     597           0 :         SplineCharDefaultNextCP(sp->prev->from);
     598           0 :         SplineRefigure(sp->prev);
     599           0 :         if ( sp->prev->from->pointtype==pt_tangent && sp->prev->from->prev!=NULL ) {
     600           0 :             SplineCharTangentPrevCP(sp->prev->from);
     601           0 :             SplineRefigure(sp->prev->from->prev);
     602             :         }
     603             :     }
     604           0 : }
     605             : 
     606           0 : void CVAdjustPoint(CharView *cv, SplinePoint *sp) {
     607             : 
     608           0 :     if ( cv->info.x==sp->me.x && cv->info.y==sp->me.y )
     609           0 : return;
     610           0 :     sp->nextcp.x += (cv->info.x-sp->me.x);
     611           0 :     sp->nextcp.y += (cv->info.y-sp->me.y);
     612           0 :     sp->prevcp.x += (cv->info.x-sp->me.x);
     613           0 :     sp->prevcp.y += (cv->info.y-sp->me.y);
     614           0 :     sp->me.x = cv->info.x;
     615           0 :     sp->me.y = cv->info.y;
     616           0 :     AdjustControls(sp);
     617           0 :     CVSetCharChanged(cv,true);
     618             : }
     619             : 
     620           0 : void CVMergeSplineSets(CharView *cv, SplinePoint *active, SplineSet *activess,
     621             :         SplinePoint *merge, SplineSet *mergess) {
     622             :     SplinePointList *spl;
     623             : 
     624           0 :     cv->joinvalid = true;
     625           0 :     cv->joinpos = *merge; cv->joinpos.selected = false;
     626             : 
     627           0 :     if ( active->prev==NULL )
     628           0 :         SplineSetReverse(activess);
     629           0 :     if ( merge->next==NULL )
     630           0 :         SplineSetReverse(mergess);
     631           0 :     active->nextcp = merge->nextcp;
     632           0 :     active->nonextcp = merge->nonextcp;
     633           0 :     active->nextcpdef = merge->nextcpdef;
     634           0 :     active->next = merge->next;
     635           0 :     if ( merge->next!= NULL ) {
     636           0 :         active->next->from = active;
     637           0 :         activess->last = mergess->last;
     638             :     }
     639           0 :     merge->next = NULL;
     640           0 :     if ( mergess==activess ) {
     641           0 :         activess->first = activess->last = active;
     642           0 :         SplinePointMDFree(cv->b.sc,merge);
     643           0 :         if ( activess->spiro_cnt!=0 ) {
     644           0 :             activess->spiros[0].ty = activess->spiros[activess->spiro_cnt-2].ty;
     645           0 :             activess->spiros[activess->spiro_cnt-2] = activess->spiros[activess->spiro_cnt-1];
     646           0 :             --activess->spiro_cnt;
     647             :         }
     648             :     } else {
     649           0 :         mergess->last = merge;
     650           0 :         if ( mergess==cv->b.layerheads[cv->b.drawmode]->splines )
     651           0 :             cv->b.layerheads[cv->b.drawmode]->splines = mergess->next;
     652             :         else {
     653           0 :             for ( spl = cv->b.layerheads[cv->b.drawmode]->splines; spl->next!=mergess; spl=spl->next );
     654           0 :             spl->next = mergess->next;
     655             :         }
     656           0 :         if ( activess->spiros && mergess->spiros ) {
     657           0 :             if ( activess->spiro_cnt+mergess->spiro_cnt > activess->spiro_max )
     658           0 :                 activess->spiros = realloc(activess->spiros,
     659           0 :                         (activess->spiro_max = activess->spiro_cnt+mergess->spiro_cnt)*sizeof(spiro_cp));
     660           0 :             memcpy(activess->spiros+activess->spiro_cnt-1,
     661           0 :                     mergess->spiros+1, (mergess->spiro_cnt-1)*sizeof(spiro_cp));
     662           0 :             activess->spiro_cnt += mergess->spiro_cnt-2;
     663             :         } else
     664           0 :             SplineSetSpirosClear(activess);
     665           0 :         SplinePointListMDFree(cv->b.sc,mergess);
     666             :     }
     667           0 :     if (( active->pointtype==pt_curve || active->pointtype==pt_hvcurve ) &&
     668           0 :             !active->nonextcp && !active->noprevcp &&
     669           0 :             !active->nextcpdef && !active->prevcpdef &&
     670           0 :             !BpColinear(&active->prevcp,&active->me,&active->nextcp))
     671           0 :         active->nextcpdef = active->prevcpdef = true;
     672           0 :     SplineSetJoinCpFixup(active);
     673           0 : }
     674             : 
     675           0 : static void CVMouseMoveSpiroPoint(CharView *cv, PressedOn *p) {
     676           0 :     spiro_cp *active = cv->active_cp, *merge = p->spiro;
     677           0 :     SplineSet *activess = cv->active_spl;
     678             :     int active_index;
     679             : 
     680           0 :     if ( active==NULL )
     681           0 : return;
     682           0 :     if ( cv->info.x==active->x && cv->info.y==active->y )
     683           0 : return;
     684             : 
     685           0 :     if ( !cv->recentchange ) CVPreserveState(&cv->b);
     686             : 
     687           0 :     active->x = cv->info.x;
     688           0 :     active->y = cv->info.y;
     689           0 :     CVSetCharChanged(cv,true);
     690             : 
     691           0 :     active_index = active-activess->spiros;
     692             : 
     693           0 :     if ( active!=merge && merge!=NULL && p->spl!=NULL &&
     694           0 :             SPIRO_SPL_OPEN(activess) &&
     695           0 :             SPIRO_SPL_OPEN(p->spl) &&
     696           0 :             (active_index==0 || active_index==activess->spiro_cnt-2) &&
     697           0 :             ((merge-p->spl->spiros)==0 || (merge-p->spl->spiros)==p->spl->spiro_cnt-2) ) {
     698           0 :         SplinePoint *activesp = active_index==0 ? activess->first : activess->last;
     699           0 :         SplinePoint *mergesp = (merge-p->spl->spiros)==0 ? p->spl->first : p->spl->last;
     700           0 :         CVMergeSplineSets(cv,activesp,activess,mergesp,p->spl);
     701             :     }
     702           0 :     SSRegenerateFromSpiros(activess);
     703           0 :     SCUpdateAll(cv->b.sc);
     704             : }
     705             : 
     706             : /* We move the active point around following the mouse. */
     707             : /*  There's one special case. If the active point is an end point on its splineset */
     708             : /*  and we've just moved on top of another splineset end-point, then join the */
     709             : /*  two splinesets at the active point. Of course we might close up our own */
     710             : /*  spline set... */
     711           0 : void CVMouseMovePoint(CharView *cv, PressedOn *p) {
     712           0 :     SplinePoint *active = cv->active_sp, *merge = p->sp;
     713           0 :     SplineSet *activess = cv->active_spl;
     714             : 
     715           0 :     if ( cv->b.sc->inspiro && hasspiro()) {
     716           0 :         CVMouseMoveSpiroPoint(cv,p);
     717           0 : return;
     718             :     }
     719             : 
     720           0 :     if ( active==NULL )
     721           0 : return;
     722           0 :     if ( cv->info.x==active->me.x && cv->info.y==active->me.y )
     723           0 : return;
     724             : 
     725           0 :     if ( !cv->recentchange ) CVPreserveState(&cv->b);
     726             : 
     727           0 :     CVAdjustPoint(cv,active);
     728           0 :     SplineSetSpirosClear(activess);
     729           0 :     if (( active->next==NULL || active->prev==NULL ) && merge!=NULL && p->spl!=NULL &&
     730           0 :             merge!=active &&
     731           0 :             (merge->next==NULL || merge->prev==NULL )) {
     732           0 :         CVMergeSplineSets(cv,active,activess,merge,p->spl);
     733             :     }
     734           0 :     SCUpdateAll(cv->b.sc);
     735             : }
     736             : 
     737           0 : void CVMouseMovePen(CharView *cv, PressedOn *p, GEvent *event) {
     738           0 :     SplinePoint *active = cv->active_sp;
     739           0 :     int order2 = cv->b.layerheads[cv->b.drawmode]->order2;
     740           0 :     int order2_style = (order2 && !(event->u.mouse.state&ksm_meta)) ||
     741           0 :                     (!order2 && (event->u.mouse.state&ksm_meta));
     742             : 
     743           0 :     if ( cv->b.sc->inspiro && hasspiro()) {
     744           0 :         CVMouseMoveSpiroPoint(cv,p);
     745           0 : return;
     746             :     }
     747             : 
     748           0 :     if ( active==NULL )
     749           0 : return;
     750           0 :     if ( cv->info.x==active->nextcp.x && cv->info.y==active->nextcp.y )
     751           0 : return;
     752             :     /* In order2 fonts when the user clicks with the pen tool we'd like to */
     753             :     /*  leave it with the default cp (ie. the cp which makes the current point*/
     754             :     /*  implicit) rather than moving the cp to the base point and losing the */
     755             :     /*  curve */
     756           0 :     if ( cv->info.x==active->me.x && cv->info.y==active->me.y &&
     757           0 :             event->type==et_mouseup && cv->b.layerheads[cv->b.drawmode]->order2 )
     758           0 : return;
     759           0 :     SplineSetSpirosClear(cv->active_spl);
     760           0 :     cv->lastselpt = cv->active_sp;
     761             : 
     762           0 :     active->nextcp.x = cv->info.x;
     763           0 :     active->nextcp.y = cv->info.y;
     764           0 :     if ( order2_style && active->next==NULL ) {
     765           0 :         active->me.x = (active->nextcp.x + active->prevcp.x)/2;
     766           0 :         active->me.y = (active->nextcp.y + active->prevcp.y)/2;
     767           0 :         if ( active->me.x == active->nextcp.x && active->me.y == active->nextcp.y ) {
     768           0 :             active->nonextcp = active->noprevcp = true;
     769             :         } else {
     770           0 :             active->nonextcp = active->noprevcp = false;
     771           0 :             active->pointtype = pt_curve;
     772             :         }
     773           0 :         if ( active->prev!=NULL )
     774           0 :             SplineRefigure(active->prev);
     775           0 :         SCUpdateAll(cv->b.sc);
     776           0 : return;
     777           0 :     } else if ( active->nextcp.x==active->me.x && active->nextcp.y==active->me.y ) {
     778           0 :         active->prevcp = active->me;
     779           0 :         active->nonextcp = active->noprevcp = true;
     780           0 :         active->pointtype = pt_corner;
     781             :     } else {
     782           0 :         active->prevcp.x = active->me.x - (active->nextcp.x-active->me.x);
     783           0 :         active->prevcp.y = active->me.y - (active->nextcp.y-active->me.y);
     784           0 :         active->nonextcp = active->noprevcp = false;
     785           0 :         active->nextcpdef = active->prevcpdef = false;
     786           0 :         active->pointtype = pt_curve;
     787             :     }
     788           0 :     if ( cv->b.layerheads[cv->b.drawmode]->order2 ) {
     789           0 :         if ( active->prev!=NULL ) {
     790           0 :             if ( active->noprevcp )
     791           0 :                 active->prev->from->nonextcp = true;
     792             :             else {
     793           0 :                 active->prev->from->nextcp = active->prevcp;
     794           0 :                 active->prev->from->nonextcp = false;
     795             :             }
     796           0 :             SplinePointNextCPChanged2(active->prev->from);
     797           0 :             SplineRefigureFixup(active->prev);
     798             :         }
     799           0 :         if ( active->next!=NULL ) {
     800           0 :             if ( active->nonextcp )
     801           0 :                 active->next->to->noprevcp = true;
     802             :             else {
     803           0 :                 active->next->to->prevcp = active->nextcp;
     804           0 :                 active->next->to->noprevcp = false;
     805             :             }
     806           0 :             SplineRefigureFixup(active->next);
     807             :         }
     808             :     } else {
     809           0 :         if ( active->prev!=NULL )
     810           0 :             SplineRefigure(active->prev);
     811           0 :         if ( active->next!=NULL )
     812           0 :             SplineRefigure(active->next);
     813             :     }
     814           0 :     CPUpdateInfo(cv,event);
     815           0 :     SCUpdateAll(cv->b.sc);
     816             : }
     817             : 
     818           0 : void CVMouseUpPoint(CharView *cv,GEvent *event) {
     819           0 :     SplinePoint *active = cv->active_sp;
     820           0 :     cv->lastselpt = active;
     821           0 :     cv->active_spl = NULL;
     822           0 :     cv->active_sp = NULL;
     823           0 :     cv->active_cp = NULL;
     824           0 :     cv->joinvalid = false;
     825           0 :     CVInfoDraw(cv,cv->gw);
     826           0 :     CPEndInfo(cv);
     827           0 :     if ( event->u.mouse.clicks>1 )
     828           0 :         CVGetInfo(cv);
     829           0 : }

Generated by: LCOV version 1.10