LCOV - code coverage report
Current view: top level - fontforgeexe - cvpointer.c (source / functions) Hit Total Coverage
Test: FontForge coverage report 2017-08-04 01:21:11+02:00 (commit d35f7e4107a9e1db65cce47c468fcc914cecb8fd) Lines: 0 1314 0.0 %
Date: 2017-08-04 Functions: 0 45 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             : 
      28             : #include "cvundoes.h"
      29             : #include "fontforgeui.h"
      30             : #include "spiro.h"
      31             : #include "splineutil.h"
      32             : #include "splineutil2.h"
      33             : #include <utype.h>
      34             : #include <math.h>
      35             : #include "collabclient.h"
      36             : extern void BackTrace( const char* msg );
      37             : 
      38             : int stop_at_join = false;
      39             : extern int interpCPsOnMotion;
      40             : 
      41           0 : int CVAnySel(CharView *cv, int *anyp, int *anyr, int *anyi, int *anya) {
      42           0 :     int anypoints = 0, anyrefs=0, anyimages=0, anyanchor=0;
      43             :     SplinePointList *spl;
      44             :     Spline *spline, *first;
      45             :     RefChar *rf;
      46             :     ImageList *il;
      47             :     AnchorPoint *ap;
      48             :     int i;
      49             : 
      50           0 :     for ( spl = cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL && !anypoints; spl = spl->next ) {
      51           0 :         if ( cv->b.sc->inspiro && hasspiro()) {
      52           0 :             for ( i=0; i<spl->spiro_cnt-1; ++i )
      53           0 :                 if ( SPIRO_SELECTED(&spl->spiros[i])) {
      54           0 :                     anypoints = true;
      55           0 :             break;
      56             :                 }
      57             :         } else {
      58           0 :             first = NULL;
      59           0 :             if ( spl->first->selected ) anypoints = true;
      60           0 :             for ( spline=spl->first->next; spline!=NULL && spline!=first && !anypoints; spline = spline->to->next ) {
      61           0 :                 if ( spline->to->selected ) anypoints = true;
      62           0 :                 if ( first == NULL ) first = spline;
      63             :             }
      64             :         }
      65             :     }
      66           0 :     for ( rf=cv->b.layerheads[cv->b.drawmode]->refs; rf!=NULL && !anyrefs; rf=rf->next )
      67           0 :         if ( rf->selected ) anyrefs = true;
      68           0 :     if ( cv->b.drawmode==dm_fore ) {
      69           0 :         if ( cv->showanchor && anya!=NULL )
      70           0 :             for ( ap=cv->b.sc->anchor; ap!=NULL && !anyanchor; ap=ap->next )
      71           0 :                 if ( ap->selected ) anyanchor = true;
      72             :     }
      73           0 :     for ( il=cv->b.layerheads[cv->b.drawmode]->images; il!=NULL && !anyimages; il=il->next )
      74           0 :         if ( il->selected ) anyimages = true;
      75           0 :     if ( anyp!=NULL ) *anyp = anypoints;
      76           0 :     if ( anyr!=NULL ) *anyr = anyrefs;
      77           0 :     if ( anyi!=NULL ) *anyi = anyimages;
      78           0 :     if ( anya!=NULL ) *anya = anyanchor;
      79           0 : return( anypoints || anyrefs || anyimages || anyanchor );
      80             : }
      81             : 
      82           0 : int CVAnySelPoints(CharView *cv) {
      83             :     /* if there are any points selected */
      84             :     SplinePointList *spl;
      85             :     Spline *spline, *first;
      86             :     int i;
      87             : 
      88           0 :     for ( spl= cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL; spl=spl->next ) {
      89           0 :         if ( cv->b.sc->inspiro && hasspiro()) {
      90           0 :             for ( i=0; i<spl->spiro_cnt-1; ++i )
      91           0 :                 if ( SPIRO_SELECTED(&spl->spiros[i]))
      92           0 : return( true );
      93             :         } else {
      94           0 :             if ( spl->first->selected )
      95           0 : return( true );
      96           0 :             first = NULL;
      97           0 :             for ( spline = spl->first->next; spline!=NULL && spline!=first; spline=spline->to->next ) {
      98           0 :                 if ( spline->to->selected )
      99           0 : return( true );
     100           0 :                 if ( first==NULL ) first = spline;
     101             :             }
     102             :         }
     103             :     }
     104           0 : return( false );
     105             : }
     106             : 
     107             : GList_Glib*
     108           0 : CVGetSelectedPoints(CharView *cv)
     109             : {
     110           0 :     GList_Glib* ret = 0;
     111             :     /* if there are any points selected */
     112             :     SplinePointList *spl;
     113             :     Spline *spline, *first;
     114             :     int i;
     115             : 
     116           0 :     for ( spl= cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL; spl=spl->next )
     117             :     {
     118           0 :         if ( cv->b.sc->inspiro && hasspiro())
     119             :         {
     120           0 :             for ( i=0; i<spl->spiro_cnt-1; ++i )
     121           0 :                 if ( SPIRO_SELECTED(&spl->spiros[i]))
     122           0 :                     ret = g_list_append( ret, &spl->spiros[i] );
     123             :         }
     124             :         else
     125             :         {
     126           0 :             if ( spl->first->selected )
     127           0 :                 ret = g_list_append( ret, spl->first );
     128           0 :             first = NULL;
     129           0 :             for ( spline = spl->first->next; spline!=NULL && spline!=first; spline=spline->to->next )
     130             :             {
     131           0 :                 if ( spline->to->selected )
     132           0 :                     ret = g_list_append( ret, spline->to );
     133           0 :                 if ( first==NULL ) first = spline;
     134             :             }
     135             :         }
     136             :     }
     137           0 :     return ret;
     138             : }
     139             : 
     140             : 
     141             : 
     142           0 : int CVClearSel(CharView *cv) {
     143             :     SplinePointList *spl;
     144             :     int i;
     145             :     Spline *spline, *first;
     146             :     RefChar *rf;
     147             :     ImageList *img;
     148           0 :     int needsupdate = 0;
     149             :     AnchorPoint *ap;
     150             : 
     151           0 :     CVFreePreTransformSPL( cv );
     152             :     
     153           0 :     cv->lastselpt = NULL; cv->lastselcp = NULL;
     154           0 :     for ( spl = cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL; spl = spl->next )
     155             :     {
     156           0 :         if ( spl->first->selected )
     157             :         {
     158           0 :             needsupdate = true;
     159           0 :             spl->first->selected = false;
     160           0 :             spl->first->nextcpselected = false;
     161           0 :             spl->first->prevcpselected = false;
     162             :         }
     163           0 :         first = NULL;
     164           0 :         for ( spline = spl->first->next; spline!=NULL && spline!=first; spline=spline->to->next )
     165             :         {
     166           0 :             if ( spline->to->selected )
     167             :             {
     168           0 :                 needsupdate = true;
     169           0 :                 spline->to->selected = false;
     170           0 :                 spline->to->nextcpselected = false;
     171           0 :                 spline->to->prevcpselected = false;
     172             :             }
     173           0 :             if ( first==NULL )
     174           0 :                 first = spline;
     175             :         }
     176           0 :         for ( i=0 ; i<spl->spiro_cnt-1; ++i )
     177           0 :             if ( SPIRO_SELECTED(&spl->spiros[i]))
     178             :             {
     179           0 :                 needsupdate = true;
     180           0 :                 SPIRO_DESELECT(&spl->spiros[i]);
     181             :             }
     182             :     }
     183           0 :     for ( rf=cv->b.layerheads[cv->b.drawmode]->refs; rf!=NULL; rf = rf->next )
     184           0 :         if ( rf->selected )
     185             :         {
     186           0 :             needsupdate = true;
     187           0 :             rf->selected = false;
     188             :         }
     189           0 :     if ( cv->b.drawmode == dm_fore )
     190           0 :         for ( ap=cv->b.sc->anchor; ap!=NULL; ap = ap->next )
     191           0 :             if ( ap->selected )
     192             :             {
     193           0 :                 if ( cv->showanchor )
     194           0 :                     needsupdate = true;
     195           0 :                 ap->selected = false;
     196             :             }
     197           0 :     for ( img=cv->b.layerheads[cv->b.drawmode]->images; img!=NULL; img = img->next )
     198           0 :         if ( img->selected )
     199             :         {
     200           0 :             needsupdate = true;
     201           0 :             img->selected = false;
     202             :         }
     203           0 :     if ( cv->p.nextcp || cv->p.prevcp || cv->widthsel || cv->vwidthsel ||
     204           0 :             cv->icsel || cv->tah_sel )
     205             :     {
     206           0 :         needsupdate = true;
     207             :     }
     208           0 :     cv->p.nextcp = cv->p.prevcp = false;
     209           0 :     cv->widthsel = cv->vwidthsel = cv->lbearingsel = cv->icsel = cv->tah_sel = false;
     210             : 
     211           0 :     needsupdate = 1;
     212           0 :     return( needsupdate );
     213             : }
     214             : 
     215           0 : int CVSetSel(CharView *cv,int mask) {
     216             :     SplinePointList *spl;
     217             :     Spline *spline, *first;
     218             :     RefChar *rf;
     219             :     ImageList *img;
     220           0 :     int needsupdate = 0;
     221             :     AnchorPoint *ap;
     222           0 :     RefChar *usemymetrics = HasUseMyMetrics(cv->b.sc,CVLayer((CharViewBase *) cv));
     223             :     int i;
     224             : 
     225           0 :     cv->lastselpt = NULL; cv->lastselcp = NULL;
     226           0 :     if ( mask&1 ) {
     227           0 :         if ( !cv->b.sc->inspiro || !hasspiro()) {
     228           0 :             for ( spl = cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL; spl = spl->next ) {
     229           0 :                 if ( !spl->first->selected ) { needsupdate = true; spl->first->selected = true; }
     230           0 :                 first = NULL;
     231           0 :                 for ( spline = spl->first->next; spline!=NULL && spline!=first; spline=spline->to->next ) {
     232           0 :                     if ( !spline->to->selected )
     233           0 :                         { needsupdate = true; spline->to->selected = true; }
     234           0 :                     cv->lastselpt = spline->to;
     235           0 :                     if ( first==NULL ) first = spline;
     236             :                 }
     237             :             }
     238             :         } else {
     239           0 :             for ( spl = cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL; spl = spl->next ) {
     240           0 :                 for ( i=0; i<spl->spiro_cnt-1; ++i ) {
     241           0 :                     if ( !SPIRO_SELECTED(&spl->spiros[i])) {
     242           0 :                         needsupdate = true;
     243           0 :                         SPIRO_SELECT(&spl->spiros[i]);
     244             :                     }
     245           0 :                     cv->lastselcp = &spl->spiros[i];
     246             :                 }
     247             :             }
     248             :         }
     249           0 :         for ( rf=cv->b.layerheads[cv->b.drawmode]->refs; rf!=NULL; rf = rf->next )
     250           0 :             if ( !rf->selected ) { needsupdate = true; rf->selected = true; }
     251           0 :         for ( img=cv->b.layerheads[cv->b.drawmode]->images; img!=NULL; img = img->next )
     252           0 :             if ( !img->selected ) { needsupdate = true; img->selected = true; }
     253             :     }
     254           0 :     if ( (mask&2) && cv->showanchor ) {
     255           0 :         for ( ap=cv->b.sc->anchor; ap!=NULL; ap=ap->next )
     256           0 :             if ( !ap->selected ) { needsupdate = true; ap->selected = true; }
     257             :     }
     258           0 :     if ( cv->p.nextcp || cv->p.prevcp )
     259           0 :         needsupdate = true;
     260           0 :     cv->p.nextcp = cv->p.prevcp = false;
     261           0 :     if ( cv->showhmetrics && !cv->widthsel && (mask&4) && usemymetrics==NULL ) {
     262           0 :         cv->widthsel = needsupdate = true;
     263           0 :         cv->oldwidth = cv->b.sc->width;
     264             :     }
     265           0 :     if ( cv->showvmetrics && cv->b.sc->parent->hasvmetrics && !cv->vwidthsel && (mask&4) && usemymetrics==NULL ) {
     266           0 :         cv->vwidthsel = needsupdate = true;
     267           0 :         cv->oldvwidth = cv->b.sc->vwidth;
     268             :     }
     269           0 : return( needsupdate );
     270             : }
     271             : 
     272           0 : void CVInvertSel(CharView *cv) {
     273             :     SplinePointList *spl;
     274             :     Spline *spline, *first;
     275             :     RefChar *rf;
     276             :     ImageList *img;
     277             :     int i;
     278             : 
     279           0 :     cv->lastselpt = NULL; cv->lastselcp = NULL;
     280             : 
     281           0 :     for ( spl = cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL; spl = spl->next ) {
     282           0 :         if ( cv->b.sc->inspiro && hasspiro()) {
     283           0 :             for ( i=0; i<spl->spiro_cnt-1; ++i )
     284           0 :                 spl->spiros[i].ty ^= 0x80;
     285             :         } else {
     286           0 :             spl->first->selected = !spl->first->selected;
     287           0 :             first = NULL;
     288           0 :             for ( spline = spl->first->next; spline!=NULL && spline!=first; spline=spline->to->next ) {
     289           0 :                 spline->to->selected = !spline->to->selected;
     290           0 :                 if ( spline->to->selected )
     291           0 :                     cv->lastselpt = spline->to;
     292           0 :                 if ( first==NULL ) first = spline;
     293             :             }
     294             :             /* in circular case, first point is toggled twice in above code     */
     295             :             /* so fix it here                                           */
     296           0 :             if ( spline==first && spline != NULL)
     297           0 :                 spl->first->selected = !spl->first->selected;
     298             :         }
     299             :     }
     300           0 :     for ( rf=cv->b.layerheads[cv->b.drawmode]->refs; rf!=NULL; rf = rf->next )
     301           0 :         rf->selected = !rf->selected;
     302           0 :     for ( img=cv->b.layerheads[cv->b.drawmode]->images; img!=NULL; img = img->next )
     303           0 :         img->selected = !img->selected;
     304           0 :     cv->p.nextcp = cv->p.prevcp = false;
     305           0 : }
     306             : 
     307           0 : int CVAllSelected(CharView *cv) {
     308             :     SplinePointList *spl;
     309             :     Spline *spline, *first;
     310             :     RefChar *rf;
     311             :     ImageList *img;
     312             :     int i;
     313             : 
     314           0 :     for ( spl = cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL; spl = spl->next ) {
     315           0 :         if ( cv->b.sc->inspiro && hasspiro()) {
     316           0 :             for ( i=0; i<spl->spiro_cnt-1; ++i )
     317           0 :                 if ( !SPIRO_SELECTED(&spl->spiros[i]))
     318           0 : return( false );
     319             :         } else {
     320           0 :             if ( !spl->first->selected )
     321           0 : return( false );
     322           0 :             first = NULL;
     323           0 :             for ( spline = spl->first->next; spline!=NULL && spline!=first; spline=spline->to->next ) {
     324           0 :                 if ( !spline->to->selected )
     325           0 : return( false );
     326           0 :                 if ( first==NULL ) first = spline;
     327             :             }
     328             :         }
     329             :     }
     330           0 :     for ( rf=cv->b.layerheads[cv->b.drawmode]->refs; rf!=NULL; rf = rf->next )
     331           0 :         if ( !rf->selected )
     332           0 : return( false );
     333           0 :     for ( img=cv->b.layerheads[cv->b.drawmode]->images; img!=NULL; img = img->next )
     334           0 :         if ( !img->selected )
     335           0 : return( false );
     336           0 : return( true );
     337             : }
     338             : 
     339           0 : static void SplineSetFindSelBounds(SplinePointList *spl, DBounds *bounds,
     340             :         int nosel, int inspiro) {
     341             :     SplinePoint *sp, *first;
     342             :     int i;
     343             : 
     344           0 :     for ( ; spl!=NULL; spl = spl->next ) {
     345           0 :         if ( !inspiro ) {
     346           0 :             first = NULL;
     347           0 :             for ( sp = spl->first; sp!=first; sp = sp->next->to ) {
     348           0 :                 if ( nosel || sp->selected ) {
     349           0 :                     if ( bounds->minx==0 && bounds->maxx==0 &&
     350           0 :                          bounds->miny==0 && bounds->maxy == 0 ) {
     351           0 :                         bounds->minx = bounds->maxx = sp->me.x;
     352           0 :                         bounds->miny = bounds->maxy = sp->me.y;
     353             :                     } else {
     354           0 :                         if ( sp->me.x<bounds->minx ) bounds->minx = sp->me.x;
     355           0 :                         if ( sp->me.x>bounds->maxx ) bounds->maxx = sp->me.x;
     356           0 :                         if ( sp->me.y<bounds->miny ) bounds->miny = sp->me.y;
     357           0 :                         if ( sp->me.y>bounds->maxy ) bounds->maxy = sp->me.y;
     358             :                     }
     359             :                 }
     360           0 :                 if ( first==NULL ) first = sp;
     361           0 :                 if ( sp->next==NULL )
     362           0 :             break;
     363             :             }
     364             :         } else {
     365           0 :             for ( i=0; i<spl->spiro_cnt-1; ++i ) {
     366           0 :                 if ( nosel || SPIRO_SELECTED(&spl->spiros[i])) {
     367           0 :                     if ( bounds->minx==0 && bounds->maxx==0 &&
     368           0 :                          bounds->miny==0 && bounds->maxy == 0 ) {
     369           0 :                         bounds->minx = bounds->maxx = spl->spiros[i].x;
     370           0 :                         bounds->miny = bounds->maxy = spl->spiros[i].y;
     371             :                     } else {
     372           0 :                         if ( spl->spiros[i].x<bounds->minx ) bounds->minx = spl->spiros[i].x;
     373           0 :                         if ( spl->spiros[i].x>bounds->maxx ) bounds->maxx = spl->spiros[i].x;
     374           0 :                         if ( spl->spiros[i].y<bounds->miny ) bounds->miny = spl->spiros[i].y;
     375           0 :                         if ( spl->spiros[i].y>bounds->maxy ) bounds->maxy = spl->spiros[i].y;
     376             :                     }
     377             :                 }
     378             :             }
     379             :         }
     380             :     }
     381           0 : }
     382             : 
     383           0 : void CVFindCenter(CharView *cv, BasePoint *bp, int nosel) {
     384             :     DBounds b;
     385             :     ImageList *img;
     386             : 
     387           0 :     b.minx = b.miny = b.maxx = b.maxy = 0;
     388           0 :     SplineSetFindSelBounds(cv->b.layerheads[cv->b.drawmode]->splines,&b,nosel,cv->b.sc->inspiro&& hasspiro());
     389           0 :     if ( cv->b.drawmode==dm_fore ) {
     390             :         RefChar *rf;
     391           0 :         for ( rf=cv->b.layerheads[cv->b.drawmode]->refs; rf!=NULL; rf=rf->next ) {
     392           0 :             if ( nosel || rf->selected ) {
     393           0 :                 if ( b.minx==0 && b.maxx==0 )
     394           0 :                     b = rf->bb;
     395             :                 else {
     396           0 :                     if ( rf->bb.minx<b.minx ) b.minx = rf->bb.minx;
     397           0 :                     if ( rf->bb.miny<b.miny ) b.miny = rf->bb.miny;
     398           0 :                     if ( rf->bb.maxx>b.maxx ) b.maxx = rf->bb.maxx;
     399           0 :                     if ( rf->bb.maxy>b.maxy ) b.maxy = rf->bb.maxy;
     400             :                 }
     401             :             }
     402             :         }
     403             :     }
     404           0 :     for ( img=cv->b.layerheads[cv->b.drawmode]->images; img!=NULL; img=img->next ) {
     405           0 :         if ( nosel || img->selected ) {
     406           0 :             if ( b.minx==0 && b.maxx==0 )
     407           0 :                 b = img->bb;
     408             :             else {
     409           0 :                 if ( img->bb.minx<b.minx ) b.minx = img->bb.minx;
     410           0 :                 if ( img->bb.miny<b.miny ) b.miny = img->bb.miny;
     411           0 :                 if ( img->bb.maxx>b.maxx ) b.maxx = img->bb.maxx;
     412           0 :                 if ( img->bb.maxy>b.maxy ) b.maxy = img->bb.maxy;
     413             :             }
     414             :         }
     415             :     }
     416           0 :     bp->x = (b.minx+b.maxx)/2;
     417           0 :     bp->y = (b.miny+b.maxy)/2;
     418           0 : }
     419             : 
     420           0 : static int OnBB(CharView *cv, DBounds *bb, real fudge) {
     421             : 
     422           0 :     if ( cv->info.y < bb->miny-fudge || cv->info.y > bb->maxy+fudge ||
     423           0 :             cv->info.x < bb->minx-fudge || cv->info.x > bb->maxx+fudge )
     424           0 : return( ee_none );
     425             : 
     426           0 :     cv->expandorigin.x = (cv->info.x-bb->minx)<(bb->maxx-cv->info.x) ?
     427           0 :                 bb->maxx : bb->minx;
     428           0 :     cv->expandorigin.y = (cv->info.y-bb->miny)<(bb->maxy-cv->info.y) ?
     429           0 :                 bb->maxy : bb->miny;
     430           0 :     cv->expandwidth = cv->expandorigin.x==bb->maxx? bb->minx-bb->maxx : bb->maxx-bb->minx;
     431           0 :     cv->expandheight = cv->expandorigin.y==bb->maxy? bb->miny-bb->maxy : bb->maxy-bb->miny;
     432             : 
     433           0 :     if (( cv->info.x < bb->minx + fudge && cv->info.y < bb->miny+ 4*fudge ) ||
     434           0 :             ( cv->info.x < bb->minx + 4*fudge && cv->info.y < bb->miny+ fudge )) {
     435           0 : return( ee_sw );
     436             :     }
     437           0 :     if (( cv->info.x < bb->minx + fudge && cv->info.y > bb->maxy- 4*fudge ) ||
     438           0 :             ( cv->info.x < bb->minx + 4*fudge && cv->info.y > bb->maxy- fudge ))
     439           0 : return( ee_nw );
     440           0 :     if (( cv->info.x > bb->maxx - fudge && cv->info.y < bb->miny+ 4*fudge ) ||
     441           0 :             ( cv->info.x > bb->maxx - 4*fudge && cv->info.y < bb->miny+ fudge ))
     442           0 : return( ee_se );
     443           0 :     if (( cv->info.x > bb->maxx - fudge && cv->info.y > bb->maxy- 4*fudge ) ||
     444           0 :             ( cv->info.x > bb->maxx - 4*fudge && cv->info.y > bb->maxy- fudge ))
     445           0 : return( ee_ne );
     446           0 :     if ( cv->info.x < bb->minx + fudge )
     447           0 : return( ee_right );
     448           0 :     if ( cv->info.x > bb->maxx - fudge )
     449           0 : return( ee_left );
     450           0 :     if ( cv->info.y < bb->miny + fudge )
     451           0 : return( ee_down );
     452           0 :     if ( cv->info.y > bb->maxy - fudge )
     453           0 : return( ee_up );
     454             : 
     455           0 : return( ee_none );
     456             : }
     457             : 
     458           0 : static void SetCur(CharView *cv) {
     459             :     static GCursor cursors[ee_max];
     460             : 
     461           0 :     if ( cursors[ee_nw]==0 ) {
     462           0 :         cursors[ee_none] = ct_mypointer;
     463           0 :         cursors[ee_nw]   = cursors[ee_se] = ct_nwse; cursors[ee_ne] = cursors[ee_sw] = ct_nesw;
     464           0 :         cursors[ee_left] = cursors[ee_right] = ct_leftright;
     465           0 :         cursors[ee_up]   = cursors[ee_down] = ct_updown;
     466             :     }
     467           0 :     GDrawSetCursor(cv->v,cursors[cv->expandedge]);
     468           0 : }
     469             : 
     470           0 : static int NearCaret(SplineChar *sc,real x,real fudge ) {
     471             :     PST *pst;
     472             :     int i;
     473             : 
     474           0 :     for ( pst=sc->possub; pst!=NULL && pst->type!=pst_lcaret; pst=pst->next );
     475           0 :     if ( pst==NULL )
     476           0 : return( -1 );
     477           0 :     for ( i=0; i<pst->u.lcaret.cnt; ++i ) {
     478           0 :         if ( x>pst->u.lcaret.carets[i]-fudge && x<pst->u.lcaret.carets[i]+fudge )
     479           0 : return( i );
     480             :     }
     481           0 : return( -1 );
     482             : }
     483             : 
     484           0 : int CVNearRBearingLine( CharView* cv, real x, real fudge )
     485             : {
     486           0 :     RefChar *usemymetrics = HasUseMyMetrics(cv->b.sc,CVLayer((CharViewBase *) cv));
     487           0 :     return( cv->showhmetrics
     488           0 :             && x>cv->b.sc->width-fudge
     489           0 :             && x<cv->b.sc->width+fudge
     490           0 :             && !cv->b.container
     491           0 :             && !usemymetrics );
     492             : }
     493           0 : int CVNearLBearingLine( CharView* cv, real x, real fudge )
     494             : {
     495           0 :     RefChar *usemymetrics = HasUseMyMetrics(cv->b.sc,CVLayer((CharViewBase *) cv));
     496           0 :     return( cv->showhmetrics
     497           0 :             && x>0-fudge
     498           0 :             && x<0+fudge
     499           0 :             && !cv->b.container && !usemymetrics );
     500             : }
     501             : 
     502             : 
     503           0 : void CVCheckResizeCursors(CharView *cv) {
     504             :     RefChar *ref;
     505             :     ImageList *img;
     506           0 :     int old_ee = cv->expandedge;
     507           0 :     real fudge = 3.5/cv->scale;
     508             : 
     509           0 :     cv->expandedge = ee_none;
     510           0 :     if ( cv->b.drawmode!=dm_grid ) {
     511           0 :         for ( ref=cv->b.layerheads[cv->b.drawmode]->refs; ref!=NULL; ref=ref->next ) if ( ref->selected ) {
     512           0 :             if (( cv->expandedge = OnBB(cv,&ref->bb,fudge))!=ee_none )
     513           0 :         break;
     514             :         }
     515           0 :         if ( cv->expandedge == ee_none ) {
     516           0 :             RefChar *usemymetrics = HasUseMyMetrics(cv->b.sc,CVLayer((CharViewBase *) cv));
     517             :             /* if ( cv->showhmetrics && cv->info.x > cv->b.sc->width-fudge && */
     518             :             /*   cv->info.x<cv->b.sc->width+fudge && cv->b.container==NULL && */
     519             :             /*   usemymetrics==NULL ) */
     520           0 :       if ( cv->showhmetrics && NearCaret(cv->b.sc,cv->info.x,fudge)!=-1 &&
     521             :                     usemymetrics==NULL )
     522           0 :                 cv->expandedge = ee_right;
     523           0 :             else if( CVNearRBearingLine( cv, cv->info.x, fudge ))
     524           0 :                 cv->expandedge = ee_right;
     525           0 :             else if( CVNearLBearingLine( cv, cv->info.x, fudge ))
     526           0 :                 cv->expandedge = ee_left;
     527           0 :             if ( cv->showvmetrics && cv->b.sc->parent->hasvmetrics && cv->b.container==NULL &&
     528           0 :                     cv->info.y > /*cv->b.sc->parent->vertical_origin*/-cv->b.sc->vwidth-fudge &&
     529           0 :                     cv->info.y < /*cv->b.sc->parent->vertical_origin*/-cv->b.sc->vwidth+fudge )
     530           0 :                 cv->expandedge = ee_down;
     531             :         }
     532             :     }
     533           0 :     for ( img=cv->b.layerheads[cv->b.drawmode]->images; img!=NULL; img=img->next ) if ( img->selected ) {
     534           0 :         if (( cv->expandedge = OnBB(cv,&img->bb,fudge))!=ee_none )
     535           0 :     break;
     536             :     }
     537           0 :     if ( cv->expandedge!=old_ee )
     538           0 :         SetCur(cv);
     539           0 : }
     540             : 
     541           0 : Undoes *CVPreserveMaybeState(CharView *cv, int isTState) {
     542           0 :     if( isTState )
     543           0 :         return CVPreserveTState( cv );
     544           0 :     return CVPreserveState( &cv->b );
     545             : }
     546             : 
     547           0 : Undoes *CVPreserveTState(CharView *cv) {
     548             :     int anyrefs;
     549             : 
     550           0 :     cv->p.transany = CVAnySel(cv,NULL,&anyrefs,NULL,NULL);
     551           0 :     cv->p.transanyrefs = anyrefs;
     552             : 
     553           0 : return( _CVPreserveTState(&cv->b,&cv->p));
     554             : }
     555             : 
     556           0 : void CVRestoreTOriginalState(CharView *cv) {
     557           0 :     _CVRestoreTOriginalState(&cv->b,&cv->p);
     558           0 : }
     559             : 
     560           0 : void CVUndoCleanup(CharView *cv) {
     561           0 :     _CVUndoCleanup(&cv->b,&cv->p);
     562           0 : }
     563             : 
     564           0 : static int ImgRefEdgeSelected(CharView *cv, FindSel *fs,GEvent *event) {
     565             :     RefChar *ref;
     566             :     ImageList *img;
     567             :     int update;
     568             : 
     569           0 :     cv->expandedge = ee_none;
     570             :     /* Check the bounding box of references if meta is up, or if they didn't */
     571             :     /*  click on a reference edge. Point being to allow people to select */
     572             :     /*  macron or other reference which fills the bounding box */
     573           0 :     if ( !(event->u.mouse.state&ksm_meta) ||
     574           0 :             (fs->p->ref!=NULL && !fs->p->ref->selected)) {
     575           0 :         for ( ref=cv->b.layerheads[cv->b.drawmode]->refs; ref!=NULL; ref=ref->next ) if ( ref->selected ) {
     576           0 :             if (( cv->expandedge = OnBB(cv,&ref->bb,fs->fudge))!=ee_none ) {
     577           0 :                 ref->selected = false;
     578           0 :                 update = CVClearSel(cv);
     579           0 :                 ref->selected = true;
     580           0 :                 if ( update )
     581           0 :                     SCUpdateAll(cv->b.sc);
     582           0 :                 CVPreserveTState(cv);
     583           0 :                 cv->p.ref = ref;
     584           0 :                 SetCur(cv);
     585           0 : return( true );
     586             :             }
     587             :         }
     588             :     }
     589           0 :     for ( img=cv->b.layerheads[cv->b.drawmode]->images; img!=NULL; img=img->next ) if ( img->selected ) {
     590           0 :         if (( cv->expandedge = OnBB(cv,&img->bb,fs->fudge))!=ee_none ) {
     591           0 :             img->selected = false;
     592           0 :             update = CVClearSel(cv);
     593           0 :             img->selected = true;
     594           0 :             if ( update )
     595           0 :                 SCUpdateAll(cv->b.sc);
     596           0 :             CVPreserveTState(cv);
     597           0 :             cv->p.img = img;
     598           0 :             SetCur(cv);
     599           0 : return( true );
     600             :         }
     601             :     }
     602           0 : return( false );
     603             : }
     604             : 
     605           0 : void CVUnselectAllBCP( CharView *cv )
     606             : {
     607           0 :     CVFindAndVisitSelectedControlPoints( cv, false,
     608             :                                          FE_unselectBCP, 0 );
     609             : 
     610             :     // This should happen, but it effects the single selection with mouse
     611             :     // codepaths in bad ways as at 2013.Aug
     612             :     /* cv->p.nextcp = 0; */
     613             :     /* cv->p.prevcp = 0; */
     614             : 
     615           0 : }
     616             : 
     617           0 : void CVMouseDownPointer(CharView *cv, FindSel *fs, GEvent *event) {
     618           0 :     int needsupdate = false;
     619             :     int dowidth, dovwidth, doic, dotah, nearcaret;
     620             :     int dolbearing;
     621           0 :     RefChar *usemymetrics = HasUseMyMetrics(cv->b.sc,CVLayer((CharViewBase *) cv));
     622             :     int i;
     623             : 
     624           0 :     cv->p.splineAdjacentPointsSelected = 0;
     625           0 :     if( cv->p.spline )
     626             :     {
     627           0 :         cv->p.splineAdjacentPointsSelected =
     628           0 :             cv->p.spline->from && cv->p.spline->to
     629           0 :             && cv->p.spline->from->selected && cv->p.spline->to->selected;
     630             :     }
     631             :     
     632           0 :     if ( cv->pressed==NULL )
     633           0 :         cv->pressed = GDrawRequestTimer(cv->v,200,100,NULL);
     634           0 :     cv->last_c.x = cv->info.x; cv->last_c.y = cv->info.y;
     635             :     /* don't clear the selection if the things we clicked on were already */
     636             :     /*  selected, or if the user held the shift key down */
     637           0 :     if ( ImgRefEdgeSelected(cv,fs,event))
     638           0 : return;
     639           0 :     dowidth    = CVNearRBearingLine( cv, cv->p.cx, fs->fudge );
     640           0 :     dolbearing = CVNearLBearingLine( cv, cv->p.cx, fs->fudge );
     641           0 :     doic = ( cv->showhmetrics && cv->b.sc->italic_correction!=TEX_UNDEF &&
     642           0 :                 cv->b.sc->italic_correction!=0 &&
     643           0 :                 cv->p.cx>cv->b.sc->width+cv->b.sc->italic_correction-fs->fudge &&
     644           0 :                 cv->p.cx<cv->b.sc->width+cv->b.sc->italic_correction+fs->fudge &&
     645           0 :                 cv->b.container==NULL );
     646           0 :     dotah = ( cv->showhmetrics && cv->b.sc->top_accent_horiz!=TEX_UNDEF &&
     647           0 :                 cv->p.cx>cv->b.sc->top_accent_horiz-fs->fudge &&
     648           0 :                 cv->p.cx<cv->b.sc->top_accent_horiz+fs->fudge &&
     649           0 :                 cv->b.container==NULL );
     650           0 :     dovwidth = ( cv->showvmetrics && cv->b.sc->parent->hasvmetrics && cv->b.container == NULL &&
     651           0 :                 cv->p.cy>/*cv->b.sc->parent->vertical_origin*/-cv->b.sc->vwidth-fs->fudge &&
     652           0 :                 cv->p.cy</*cv->b.sc->parent->vertical_origin*/-cv->b.sc->vwidth+fs->fudge &&
     653             :                 usemymetrics==NULL );
     654           0 :     cv->nearcaret = nearcaret = -1;
     655           0 :     if ( cv->showhmetrics ) nearcaret = NearCaret(cv->b.sc,cv->p.cx,fs->fudge);
     656           0 :     if ( (fs->p->sp==NULL    || !fs->p->sp->selected) &&
     657           0 :          (fs->p->spiro==NULL || !SPIRO_SELECTED(fs->p->spiro)) &&
     658           0 :          (fs->p->ref==NULL   || !fs->p->ref->selected) &&
     659           0 :          (fs->p->img==NULL   || !fs->p->img->selected) &&
     660           0 :          (fs->p->ap==NULL    || !fs->p->ap->selected) &&
     661           0 :          (!dowidth    || !cv->widthsel) &&
     662           0 :          (!dolbearing || !cv->lbearingsel) && 
     663           0 :          (!dovwidth   || !cv->vwidthsel) &&
     664           0 :          (!doic  || !cv->icsel) &&
     665           0 :          (!dotah || !cv->tah_sel) &&
     666           0 :          !(event->u.mouse.state&ksm_shift))
     667             :     {
     668           0 :         needsupdate = CVClearSel(cv);
     669             :     }
     670             : 
     671             : //    printf("CVMouseDownPointer() dowidth:%d dolbearing:%d\n", dowidth, dolbearing );
     672             : 
     673           0 :     if ( !fs->p->anysel )
     674             :     {
     675             : //      printf("mousedown !anysel dow:%d dov:%d doid:%d dotah:%d nearcaret:%d\n", dowidth, dovwidth, doic, dotah, nearcaret );
     676             :         /* Nothing else... unless they clicked on the width line, check that */
     677           0 :         if ( dowidth )
     678             :         {
     679           0 :             if ( event->u.mouse.state&ksm_shift )
     680           0 :                 cv->widthsel = !cv->widthsel;
     681             :             else
     682           0 :                 cv->widthsel = true;
     683           0 :             if ( cv->widthsel ) {
     684           0 :                 cv->oldwidth = cv->b.sc->width;
     685           0 :                 fs->p->cx = cv->b.sc->width;
     686           0 :                 CVInfoDraw(cv,cv->gw);
     687           0 :                 fs->p->anysel = true;
     688           0 :                 cv->expandedge = ee_right;
     689             :             } else
     690           0 :                 cv->expandedge = ee_none;
     691           0 :             SetCur(cv);
     692           0 :             needsupdate = true;
     693             :         }
     694           0 :         if ( nearcaret!=-1 )
     695             :         {
     696             :             PST *pst;
     697           0 :             for ( pst=cv->b.sc->possub; pst!=NULL && pst->type!=pst_lcaret; pst=pst->next );
     698           0 :             cv->lcarets = pst;
     699           0 :             cv->nearcaret = nearcaret;
     700           0 :             cv->expandedge = ee_right;
     701           0 :             SetCur(cv);
     702             :         }
     703           0 :         else if ( dolbearing )
     704             :         {
     705           0 :             if ( event->u.mouse.state&ksm_shift )
     706           0 :                 cv->lbearingsel = !cv->lbearingsel;
     707             :             else
     708           0 :                 cv->lbearingsel = true;
     709           0 :             if ( cv->lbearingsel ) {
     710             : //              cv->oldlbearing = cv->b.sc->lbearing;
     711           0 :                 fs->p->cx = 0;;
     712           0 :                 CVInfoDraw(cv,cv->gw);
     713           0 :                 fs->p->anysel = true;
     714           0 :                 cv->expandedge = ee_left;
     715             :             } else
     716           0 :                 cv->expandedge = ee_none;
     717           0 :             SetCur(cv);
     718           0 :             needsupdate = true;
     719             :         }
     720           0 :         else if ( dovwidth )
     721             :         {
     722           0 :             if ( event->u.mouse.state&ksm_shift )
     723           0 :                 cv->vwidthsel = !cv->vwidthsel;
     724             :             else
     725           0 :                 cv->vwidthsel = true;
     726           0 :             if ( cv->vwidthsel ) {
     727           0 :                 cv->oldvwidth = cv->b.sc->vwidth;
     728           0 :                 fs->p->cy = /*cv->b.sc->parent->vertical_origin*/-cv->b.sc->vwidth;
     729           0 :                 CVInfoDraw(cv,cv->gw);
     730           0 :                 fs->p->anysel = true;
     731           0 :                 cv->expandedge = ee_down;
     732             :             } else
     733           0 :                 cv->expandedge = ee_none;
     734           0 :             SetCur(cv);
     735           0 :             needsupdate = true;
     736             :         }
     737           0 :         else if ( doic )
     738             :         {
     739           0 :             if ( event->u.mouse.state&ksm_shift )
     740           0 :                 cv->icsel = !cv->icsel;
     741             :             else
     742           0 :                 cv->icsel = true;
     743           0 :             if ( cv->icsel ) {
     744           0 :                 cv->oldic = cv->b.sc->italic_correction+cv->b.sc->width;
     745           0 :                 fs->p->cx = cv->b.sc->italic_correction+cv->b.sc->width;
     746           0 :                 CVInfoDraw(cv,cv->gw);
     747           0 :                 fs->p->anysel = true;
     748           0 :                 cv->expandedge = ee_right;
     749             :             } else
     750           0 :                 cv->expandedge = ee_none;
     751           0 :             SetCur(cv);
     752           0 :             needsupdate = true;
     753             :         }
     754           0 :         else if ( dotah )
     755             :         {
     756           0 :             if ( event->u.mouse.state&ksm_shift )
     757           0 :                 cv->tah_sel = !cv->tah_sel;
     758             :             else
     759           0 :                 cv->tah_sel = true;
     760           0 :             if ( cv->tah_sel ) {
     761           0 :                 cv->oldtah = cv->b.sc->top_accent_horiz;
     762           0 :                 fs->p->cx = cv->b.sc->top_accent_horiz;
     763           0 :                 CVInfoDraw(cv,cv->gw);
     764           0 :                 fs->p->anysel = true;
     765           0 :                 cv->expandedge = ee_right;
     766             :             } else
     767           0 :                 cv->expandedge = ee_none;
     768           0 :             SetCur(cv);
     769           0 :             needsupdate = true;
     770             :         }
     771             :         else
     772             :         {
     773             : //          printf("mousedown !anysel ELSE\n");
     774             :             //
     775             :             // Allow dragging a box around some points to send that information
     776             :             // to the other clients in the collab session
     777             :             //
     778           0 :             if( collabclient_inSession( &cv->b ))
     779           0 :                 CVPreserveState(&cv->b);
     780             :         }
     781             :     }
     782           0 :     else if ( event->u.mouse.clicks<=1 && !(event->u.mouse.state&ksm_shift))
     783             :     {
     784             :         /* printf("CVMouseDownPointer(2) not shifting\n"); */
     785             :         /* printf("CVMouseDownPointer(2) cv->p.sp:%p\n", cv->p.sp ); */
     786             :         /* printf("CVMouseDownPointer(2) n:%p p:%p sp:%p spline:%p ap:%p\n", */
     787             :         /*        fs->p->nextcp,fs->p->prevcp, fs->p->sp, fs->p->spline, fs->p->ap ); */
     788             :         /* printf("CVMouseDownPointer(2) spl:%p\n", fs->p->spl ); */
     789             :         /* SPLFirstVisit( fs->p->spl->first, SPLFirstVisitorDebugSelectionState, 0 ); */
     790           0 :         CVUnselectAllBCP( cv );
     791             : 
     792           0 :         if ( fs->p->nextcp || fs->p->prevcp ) {
     793           0 :             CPStartInfo(cv,event);
     794             :             /* Needs update to draw control points selected */
     795           0 :             needsupdate = true;
     796           0 :         } else if ( fs->p->sp!=NULL ) {
     797           0 :             if ( !fs->p->sp->selected ) needsupdate = true;
     798           0 :             fs->p->sp->selected = true;
     799           0 :         } else if ( fs->p->spiro!=NULL ) {
     800           0 :             if ( !SPIRO_SELECTED(fs->p->spiro) ) needsupdate = true;
     801           0 :             SPIRO_SELECT( fs->p->spiro );
     802           0 :         } else if ( fs->p->spline!=NULL && (!cv->b.sc->inspiro || !hasspiro())) {
     803           0 :             if ( !fs->p->spline->to->selected &&
     804           0 :                     !fs->p->spline->from->selected ) needsupdate = true;
     805           0 :             fs->p->spline->to->selected = true;
     806           0 :             fs->p->spline->from->selected = true;
     807           0 :         } else if ( fs->p->img!=NULL ) {
     808           0 :             if ( !fs->p->img->selected ) needsupdate = true;
     809           0 :             fs->p->img->selected = true;
     810           0 :         } else if ( fs->p->ref!=NULL ) {
     811           0 :             if ( !fs->p->ref->selected ) needsupdate = true;
     812           0 :             fs->p->ref->selected = true;
     813           0 :         } else if ( fs->p->ap!=NULL ) {
     814           0 :             if ( !fs->p->ap->selected ) needsupdate = true;
     815           0 :             fs->p->ap->selected = true;
     816             :         }
     817             :     }
     818           0 :     else if ( event->u.mouse.clicks<=1 )
     819             :     {
     820             :         /* printf("CVMouseDownPointer(3) with shift... n:%p p:%p sp:%p spline:%p ap:%p\n", */
     821             :         /*        fs->p->nextcp,fs->p->prevcp, fs->p->sp, fs->p->spline, fs->p->ap ); */
     822             :         /* printf("CVMouseDownPointer(3) spl:%p\n", fs->p->spl ); */
     823             :         /* SPLFirstVisit( fs->p->spl->first, SPLFirstVisitorDebugSelectionState, 0 ); */
     824             : 
     825           0 :         if ( fs->p->nextcp || fs->p->prevcp ) {
     826             :             /* Needs update to draw control points selected */
     827           0 :             needsupdate = true;
     828           0 :         } else if ( fs->p->sp!=NULL ) {
     829           0 :             needsupdate = true;
     830           0 :             fs->p->sp->selected = !fs->p->sp->selected;
     831           0 :         } else if ( fs->p->spiro!=NULL ) {
     832           0 :             needsupdate = true;
     833           0 :             fs->p->spiro->ty ^= 0x80;
     834           0 :         } else if ( fs->p->spline!=NULL && (!cv->b.sc->inspiro || !hasspiro())) {
     835           0 :             needsupdate = true;
     836           0 :             fs->p->spline->to->selected = !fs->p->spline->to->selected;
     837           0 :             fs->p->spline->from->selected = !fs->p->spline->from->selected;
     838           0 :         } else if ( fs->p->img!=NULL ) {
     839           0 :             needsupdate = true;
     840           0 :             fs->p->img->selected = !fs->p->img->selected;
     841           0 :         } else if ( fs->p->ref!=NULL ) {
     842           0 :             needsupdate = true;
     843           0 :             fs->p->ref->selected = !fs->p->ref->selected;
     844           0 :         } else if ( fs->p->ap!=NULL ) {
     845           0 :             needsupdate = true;
     846           0 :             fs->p->ap->selected = !fs->p->ap->selected;
     847             :         }
     848             :     }
     849           0 :     else if ( event->u.mouse.clicks==2 )
     850             :     {
     851             :         /* printf("mouse down click==2\n"); */
     852           0 :         CPEndInfo(cv);
     853           0 :         if ( fs->p->spl!=NULL ) {
     854           0 :             if ( cv->b.sc->inspiro && hasspiro()) {
     855           0 :                 for ( i=0; i<fs->p->spl->spiro_cnt-1; ++i ) {
     856           0 :                     if ( !SPIRO_SELECTED(&fs->p->spl->spiros[i])) {
     857           0 :                         needsupdate = true;
     858           0 :                         SPIRO_SELECT(&fs->p->spl->spiros[i]);
     859             :                     }
     860             :                 }
     861             :             } else {
     862             :                 Spline *spline, *first;
     863           0 :                 if ( !fs->p->spl->first->selected ) { needsupdate = true; fs->p->spl->first->selected = true; }
     864           0 :                 first = NULL;
     865           0 :                 for ( spline = fs->p->spl->first->next; spline!=NULL && spline!=first; spline=spline->to->next ) {
     866           0 :                     if ( !spline->to->selected )
     867           0 :                         { needsupdate = true; spline->to->selected = true; }
     868           0 :                     if ( first==NULL ) first = spline;
     869             :                 }
     870             :             }
     871           0 :         } else if ( fs->p->ref!=NULL || fs->p->img!=NULL ) {
     872             :             /* Double clicking on a referenced character doesn't do much */
     873           0 :         } else if ( fs->p->ap!=NULL ) {
     874             :             /* Select all Anchor Points at this location */
     875             :             AnchorPoint *ap;
     876           0 :             for ( ap=cv->b.sc->anchor; ap!=NULL; ap=ap->next )
     877           0 :                 if ( ap->me.x==fs->p->ap->me.x && ap->me.y==fs->p->ap->me.y )
     878           0 :                     if ( !ap->selected ) {
     879           0 :                         ap->selected = true;
     880           0 :                         needsupdate = true;
     881             :                     }
     882             :         }
     883             :     }
     884           0 :     else if ( event->u.mouse.clicks==3 )
     885             :     {
     886             :         /* printf("mouse down click==3\n"); */
     887           0 :         if ( CVSetSel(cv,1)) needsupdate = true;
     888             :                 /* don't select width or anchor points for three clicks */
     889             :                 /*  but select all points, refs */
     890             :     }
     891             :     else
     892             :     {
     893             :         /* printf("mouse down ELSE\n"); */
     894             :         /* Select everything */
     895           0 :         if ( CVSetSel(cv,-1)) needsupdate = true;
     896             :     }
     897             : 
     898             :     
     899           0 :     if ( needsupdate )
     900           0 :         SCUpdateAll(cv->b.sc);
     901             : 
     902             :     /* lastselpt is set by our caller */
     903             : }
     904             : 
     905           0 : static int CVRectSelect(CharView *cv, real newx, real newy) {
     906           0 :     int any=false;
     907             :     DBounds old, new;
     908             :     RefChar *rf;
     909             :     ImageList *img;
     910             :     Spline *spline, *first;
     911             :     SplinePointList *spl;
     912             :     BasePoint *bp;
     913             :     AnchorPoint *ap;
     914             :     DBounds bb;
     915             :     int i;
     916             : 
     917           0 :     if ( cv->p.cx<=cv->p.ex ) {
     918           0 :         old.minx = cv->p.cx;
     919           0 :         old.maxx = cv->p.ex;
     920             :     } else {
     921           0 :         old.minx = cv->p.ex;
     922           0 :         old.maxx = cv->p.cx;
     923             :     }
     924           0 :     if ( cv->p.cy<=cv->p.ey ) {
     925           0 :         old.miny = cv->p.cy;
     926           0 :         old.maxy = cv->p.ey;
     927             :     } else {
     928           0 :         old.miny = cv->p.ey;
     929           0 :         old.maxy = cv->p.cy;
     930             :     }
     931             : 
     932           0 :     if ( cv->p.cx<=newx ) {
     933           0 :         new.minx = cv->p.cx;
     934           0 :         new.maxx = newx;
     935             :     } else {
     936           0 :         new.minx = newx;
     937           0 :         new.maxx = cv->p.cx;
     938             :     }
     939           0 :     if ( cv->p.cy<=newy ) {
     940           0 :         new.miny = cv->p.cy;
     941           0 :         new.maxy = newy;
     942             :     } else {
     943           0 :         new.miny = newy;
     944           0 :         new.maxy = cv->p.cy;
     945             :     }
     946             : 
     947           0 :     for ( rf = cv->b.layerheads[cv->b.drawmode]->refs; rf!=NULL; rf=rf->next ) {
     948           0 :         if (( rf->bb.minx>=old.minx && rf->bb.maxx<old.maxx &&
     949           0 :                     rf->bb.miny>=old.miny && rf->bb.maxy<old.maxy ) !=
     950           0 :                 ( rf->bb.minx>=new.minx && rf->bb.maxx<new.maxx &&
     951           0 :                     rf->bb.miny>=new.miny && rf->bb.maxy<new.maxy )) {
     952           0 :             rf->selected = !rf->selected;
     953           0 :             any = true;
     954             :         }
     955             :     }
     956           0 :     if ( cv->b.drawmode==dm_fore ) {
     957           0 :         if ( cv->showanchor ) for ( ap=cv->b.sc->anchor ; ap!=NULL; ap=ap->next ) {
     958           0 :             bp = &ap->me;
     959           0 :             if (( bp->x>=old.minx && bp->x<old.maxx &&
     960           0 :                         bp->y>=old.miny && bp->y<old.maxy ) !=
     961           0 :                     ( bp->x>=new.minx && bp->x<new.maxx &&
     962           0 :                         bp->y>=new.miny && bp->y<new.maxy )) {
     963           0 :                 ap->selected = !ap->selected;
     964           0 :                 any = true;
     965             :             }
     966             :         }
     967             :     }
     968             : 
     969           0 :     for ( img = cv->b.layerheads[cv->b.drawmode]->images; img!=NULL; img=img->next ) {
     970           0 :         bb.minx = img->xoff;
     971           0 :         bb.miny = img->yoff;
     972           0 :         bb.maxx = img->xoff+GImageGetWidth(img->image)*img->xscale;
     973           0 :         bb.maxy = img->yoff+GImageGetHeight(img->image)*img->yscale;
     974           0 :         if (( bb.minx>=old.minx && bb.maxx<old.maxx &&
     975           0 :                     bb.miny>=old.miny && bb.maxy<old.maxy ) !=
     976           0 :                 ( bb.minx>=new.minx && bb.maxx<new.maxx &&
     977           0 :                     bb.miny>=new.miny && bb.maxy<new.maxy )) {
     978           0 :             img->selected = !img->selected;
     979           0 :             any = true;
     980             :         }
     981             :     }
     982             : 
     983           0 :     for ( spl = cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL; spl = spl->next ) {
     984           0 :         if ( !cv->b.sc->inspiro || !hasspiro()) {
     985           0 :             first = NULL;
     986           0 :             if ( spl->first->prev==NULL ) {
     987           0 :                 bp = &spl->first->me;
     988           0 :                 if (( bp->x>=old.minx && bp->x<old.maxx &&
     989           0 :                             bp->y>=old.miny && bp->y<old.maxy ) !=
     990           0 :                         ( bp->x>=new.minx && bp->x<new.maxx &&
     991           0 :                             bp->y>=new.miny && bp->y<new.maxy )) {
     992           0 :                     spl->first->selected = !spl->first->selected;
     993           0 :                     if ( spl->first->selected )
     994           0 :                         cv->lastselpt = spl->first;
     995           0 :                     else if ( spl->first==cv->lastselpt )
     996           0 :                         cv->lastselpt = NULL;
     997           0 :                     any = true;
     998             :                 }
     999             :             }
    1000           0 :             for ( spline = spl->first->next; spline!=NULL && spline!=first; spline=spline->to->next ) {
    1001           0 :                 bp = &spline->to->me;
    1002           0 :                 if (( bp->x>=old.minx && bp->x<old.maxx &&
    1003           0 :                             bp->y>=old.miny && bp->y<old.maxy ) !=
    1004           0 :                         ( bp->x>=new.minx && bp->x<new.maxx &&
    1005           0 :                             bp->y>=new.miny && bp->y<new.maxy )) {
    1006           0 :                     spline->to->selected = !spline->to->selected;
    1007           0 :                     if ( spline->to->selected )
    1008           0 :                         cv->lastselpt = spline->to;
    1009           0 :                     else if ( spline->to==cv->lastselpt )
    1010           0 :                         cv->lastselpt = NULL;
    1011           0 :                     any = true;
    1012             :                 }
    1013           0 :                 if ( first==NULL ) first = spline;
    1014             :             }
    1015             :         } else {
    1016           0 :             for ( i=0; i<spl->spiro_cnt-1; ++i ) {
    1017           0 :                 if (( spl->spiros[i].x>=old.minx && spl->spiros[i].x<old.maxx &&
    1018           0 :                             spl->spiros[i].y>=old.miny && spl->spiros[i].y<old.maxy ) !=
    1019           0 :                         ( spl->spiros[i].x>=new.minx && spl->spiros[i].x<new.maxx &&
    1020           0 :                             spl->spiros[i].y>=new.miny && spl->spiros[i].y<new.maxy )) {
    1021           0 :                     spl->spiros[i].ty ^= 0x80;
    1022           0 :                     if ( SPIRO_SELECTED(&spl->spiros[i]))
    1023           0 :                         cv->lastselcp = &spl->spiros[i];
    1024           0 :                     any = true;
    1025             :                 }
    1026             :             }
    1027             :         }
    1028             :     }
    1029           0 : return( any );
    1030             : }
    1031             : 
    1032           0 : void CVAdjustControl(CharView *cv,BasePoint *cp, BasePoint *to) {
    1033           0 :     SplinePoint *sp = cv->p.sp;
    1034             : 
    1035           0 :     SPAdjustControl(sp,cp,to,cv->b.layerheads[cv->b.drawmode]->order2);
    1036           0 :     CVSetCharChanged(cv,true);
    1037           0 : }
    1038             : 
    1039           0 : bool isSplinePointPartOfGuide( SplineFont *sf, SplinePoint *sp )
    1040             : {
    1041           0 :     if( !sp || !sf )
    1042           0 :         return 0;
    1043           0 :     if( !sf->grid.splines )
    1044           0 :         return 0;
    1045             : 
    1046           0 :     SplinePointList* spl = sf->grid.splines;
    1047           0 :     return SplinePointListContainsPoint( spl, sp );
    1048             : }
    1049             : 
    1050           0 : static void CVAdjustSpline(CharView *cv) {
    1051           0 :     Spline *old = cv->p.spline;
    1052             :     TPoint tp[5];
    1053             :     real t;
    1054           0 :     Spline1D *oldx = &old->splines[0], *oldy = &old->splines[1];
    1055             :     int oldfrompointtype, oldtopointtype;
    1056             : 
    1057           0 :     if ( cv->b.layerheads[cv->b.drawmode]->order2 )
    1058           0 : return;
    1059             : 
    1060             :     //
    1061             :     // Click + drag on a guide moves the guide to where your mouse is at
    1062             :     //
    1063           0 :     if( cv->b.drawmode == dm_grid
    1064           0 :         && isSplinePointPartOfGuide( cv->b.sc->parent, cv->p.spline->from )
    1065           0 :         && isSplinePointPartOfGuide( cv->b.sc->parent, cv->p.spline->to ) )
    1066             :     {
    1067           0 :         if( 0 == cv->p.spline->splines[0].a
    1068           0 :             && 0 == cv->p.spline->splines[0].b
    1069           0 :             && 0 == cv->p.spline->splines[1].a
    1070           0 :             && 0 == cv->p.spline->splines[1].b
    1071           0 :             && ( (cv->p.spline->splines[0].c && cv->p.spline->from->me.y == cv->p.spline->to->me.y)
    1072           0 :                  || (cv->p.spline->splines[1].c && cv->p.spline->from->me.x == cv->p.spline->to->me.x )))
    1073             :         {
    1074           0 :             if( cv->p.spline->from->me.y == cv->p.spline->to->me.y )
    1075             :             {
    1076           0 :                 int newy = cv->info.y;
    1077           0 :                 cv->p.spline->from->me.y = newy;
    1078           0 :                 cv->p.spline->to->me.y = newy;
    1079           0 :                 cv->p.spline->splines[1].d = newy;
    1080             :             }
    1081             :             else
    1082             :             {
    1083           0 :                 int newx = cv->info.x;
    1084           0 :                 cv->p.spline->from->me.x = newx;
    1085           0 :                 cv->p.spline->to->me.x = newx;
    1086           0 :                 cv->p.spline->splines[0].d = newx;
    1087             :             }
    1088           0 :             CVSetCharChanged(cv,true);
    1089           0 :             return;
    1090             :         }
    1091             :     }
    1092             : 
    1093             : 
    1094           0 :     tp[0].x = cv->info.x; tp[0].y = cv->info.y; tp[0].t = cv->p.t;
    1095           0 :     t = cv->p.t/10;
    1096           0 :     tp[1].x = ((oldx->a*t+oldx->b)*t+oldx->c)*t + oldx->d;
    1097           0 :     tp[1].y = ((oldy->a*t+oldy->b)*t+oldy->c)*t + oldy->d;
    1098           0 :     tp[1].t = t;
    1099           0 :     t = 1-(1-cv->p.t)/10;
    1100           0 :     tp[2].x = ((oldx->a*t+oldx->b)*t+oldx->c)*t + oldx->d;
    1101           0 :     tp[2].y = ((oldy->a*t+oldy->b)*t+oldy->c)*t + oldy->d;
    1102           0 :     tp[2].t = t;
    1103           0 :     tp[3] = tp[0];              /* Give more weight to this point than to the others */
    1104           0 :     tp[4] = tp[0];              /*  ditto */
    1105           0 :     cv->p.spline = ApproximateSplineFromPoints(old->from,old->to,tp,5,old->order2);
    1106             : 
    1107             :     /* don't change hvcurves to corners */
    1108           0 :     oldfrompointtype = old->from->pointtype;
    1109           0 :     oldtopointtype = old->to->pointtype;
    1110           0 :     old->from->pointtype = old->to->pointtype = pt_corner;
    1111           0 :     if ( oldfrompointtype == pt_hvcurve )
    1112           0 :         SPChangePointType(old->from, pt_hvcurve);
    1113           0 :     if ( oldtopointtype == pt_hvcurve )
    1114           0 :         SPChangePointType(old->to, pt_hvcurve);
    1115             :     //
    1116             :     // dont go changing pt_curve points into pt_corner without explicit consent.
    1117             :     //
    1118           0 :     if( oldfrompointtype == pt_curve || oldfrompointtype == pt_tangent )
    1119             :     {
    1120           0 :         old->from->pointtype = oldfrompointtype;
    1121           0 :         SPTouchControl( old->from, &old->from->nextcp, cv->b.layerheads[cv->b.drawmode]->order2 );
    1122             :     }
    1123           0 :     if( oldtopointtype == pt_curve || oldtopointtype == pt_tangent )
    1124             :     {
    1125           0 :         old->to->pointtype = oldtopointtype;
    1126           0 :         SPTouchControl( old->to, &old->to->prevcp, cv->b.layerheads[cv->b.drawmode]->order2 );
    1127             :     }
    1128             : 
    1129           0 :     old->from->nextcpdef = old->to->prevcpdef = false;
    1130           0 :     SplineFree(old);
    1131           0 :     CVSetCharChanged(cv,true);
    1132             : }
    1133             : 
    1134           0 : static int Nearish(real a,real fudge) {
    1135           0 : return( a>-fudge && a<fudge );
    1136             : }
    1137             : 
    1138             : /* Are any of the selected points open (that is are they missing either a next*/
    1139             : /*  or a prev spline so that at least one direction is free to make a new link)*/
    1140             : /*  And did any of those selected points move on top of a point which was not */
    1141             : /*  selected but which was also open? if so then merge all cases where this */
    1142             : /*  happened (could be more than one) */
    1143             : /* However if two things merge we must start all over again because we will have */
    1144             : /*  freed one of the splinesets in the merger */
    1145             : /* This is very similar for spiros (because start and end points of open contours */
    1146             : /*  are the same in both representations). The only complication is checking */
    1147             : /*  that they are selected */
    1148           0 : static int CVCheckMerges(CharView *cv ) {
    1149             :     SplineSet *activess, *mergess;
    1150           0 :     real fudge = 2/cv->scale;
    1151           0 :     int cnt= -1;
    1152             :     int firstsel, lastsel;
    1153             :     int mfirstsel, mlastsel;
    1154           0 :     int inspiro = cv->b.sc->inspiro && hasspiro();
    1155             : 
    1156             :   restart:
    1157           0 :     ++cnt;
    1158           0 :     for ( activess=cv->b.layerheads[cv->b.drawmode]->splines; activess!=NULL; activess=activess->next ) {
    1159           0 :         if ( activess->first->prev!=NULL )
    1160           0 :     continue;           /* Closed contour, can't merge with anything */
    1161           0 :         firstsel = (inspiro && SPIRO_SELECTED(&activess->spiros[0])) ||
    1162           0 :                     (!inspiro && activess->first->selected);
    1163           0 :         lastsel = (inspiro && SPIRO_SELECTED(&activess->spiros[activess->spiro_cnt-2])) ||
    1164           0 :                     (!inspiro && activess->last->selected);
    1165           0 :         if ( firstsel || lastsel ) {
    1166           0 :             for ( mergess = cv->b.layerheads[cv->b.drawmode]->splines; mergess!=NULL; mergess=mergess->next ) {
    1167           0 :                 if ( mergess->first->prev!=NULL )
    1168           0 :             continue;           /* Closed contour, can't merge with anything */
    1169           0 :                 mfirstsel = (inspiro && SPIRO_SELECTED(&mergess->spiros[0])) ||
    1170           0 :                             (!inspiro && mergess->first->selected);
    1171           0 :                 mlastsel = (inspiro && SPIRO_SELECTED(&mergess->spiros[mergess->spiro_cnt-2])) ||
    1172           0 :                             (!inspiro && mergess->last->selected);
    1173           0 :                 if ( !mfirstsel || !mlastsel ) {
    1174           0 :                     if ( !mfirstsel && firstsel &&
    1175           0 :                             Nearish(mergess->first->me.x-activess->first->me.x,fudge) &&
    1176           0 :                             Nearish(mergess->first->me.y-activess->first->me.y,fudge)) {
    1177           0 :                         CVMergeSplineSets(cv,activess->first,activess,
    1178             :                                 mergess->first,mergess);
    1179           0 :   goto restart;
    1180             :                     }
    1181           0 :                     if ( !mlastsel && firstsel &&
    1182           0 :                             Nearish(mergess->last->me.x-activess->first->me.x,fudge) &&
    1183           0 :                             Nearish(mergess->last->me.y-activess->first->me.y,fudge)) {
    1184           0 :                         CVMergeSplineSets(cv,activess->first,activess,
    1185             :                                 mergess->last,mergess);
    1186           0 :   goto restart;
    1187             :                     }
    1188           0 :                     if ( !mfirstsel && lastsel &&
    1189           0 :                             Nearish(mergess->first->me.x-activess->last->me.x,fudge) &&
    1190           0 :                             Nearish(mergess->first->me.y-activess->last->me.y,fudge)) {
    1191           0 :                         CVMergeSplineSets(cv,activess->last,activess,
    1192             :                                 mergess->first,mergess);
    1193           0 :   goto restart;
    1194             :                     }
    1195           0 :                     if ( !mlastsel && lastsel &&
    1196           0 :                             Nearish(mergess->last->me.x-activess->last->me.x,fudge) &&
    1197           0 :                             Nearish(mergess->last->me.y-activess->last->me.y,fudge)) {
    1198           0 :                         CVMergeSplineSets(cv,activess->last,activess,
    1199             :                                 mergess->last,mergess);
    1200           0 :   goto restart;
    1201             :                     }
    1202             :                 }
    1203             :             }
    1204             :         }
    1205             :     }
    1206           0 : return( cnt>0 && stop_at_join );
    1207             : }
    1208             : 
    1209           0 : static void adjustLBearing( CharView *cv, SplineChar *sc, real val )
    1210             : {
    1211             :     DBounds bb;
    1212           0 :     SplineCharFindBounds(sc,&bb);
    1213           0 :     if ( val != 0 )
    1214             :     {
    1215             :         real transform[6];
    1216           0 :         transform[0] = transform[3] = 1.0;
    1217           0 :         transform[1] = transform[2] = transform[5] = 0;
    1218           0 :         transform[4] = val;
    1219           0 :         printf("adjustLBearing val:%f min:%f v-min:%f\n",val,bb.minx,(bb.minx+val));
    1220           0 :         FVTrans( (FontViewBase *) cv->b.fv, sc, transform, NULL, 0 | fvt_alllayers );
    1221             :         // We copy and adapt some code from FVTrans in order to adjust the CharView carets.
    1222             :         // We omit the fvt_scalepstpos for FVTrans since other CharView code seems to skip updating the SplineChar.
    1223             :         PST *pst;
    1224           0 :         for ( pst = cv->b.sc->possub; pst!=NULL; pst=pst->next ) {
    1225           0 :             if ( pst->type == pst_lcaret ) {
    1226             :                 int j;
    1227           0 :                 for ( j=0; j<pst->u.lcaret.cnt; ++j )
    1228           0 :                     pst->u.lcaret.carets[j] = rint(pst->u.lcaret.carets[j]+val);
    1229             :             }
    1230             :         }
    1231             :     }
    1232           0 : }
    1233             : 
    1234             : /* Move the selection and return whether we did a merge */
    1235           0 : int CVMoveSelection(CharView *cv, real dx, real dy, uint32 input_state) {
    1236             :     real transform[6];
    1237             :     RefChar *refs;
    1238             :     ImageList *img;
    1239             :     AnchorPoint *ap;
    1240             :     double fudge;
    1241             :     extern float snapdistance;
    1242             :     int i,j;
    1243           0 :     int changed = false, outlinechanged = false;
    1244             :     SplinePointList *spl;
    1245             :     SplinePoint *sp;
    1246             : 
    1247           0 :     transform[0] = transform[3] = 1.0;
    1248           0 :     transform[1] = transform[2] = 0.0;
    1249           0 :     transform[4] = dx; transform[5] = dy;
    1250           0 :     if ( transform[4]==0 && transform[5]==0 )
    1251           0 : return(false);
    1252           0 :     for ( spl=cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL && !outlinechanged; spl=spl->next ) {
    1253           0 :         if ( cv->b.sc->inspiro && hasspiro()) {
    1254           0 :             for ( i=0; i<spl->spiro_cnt-1; ++i )
    1255           0 :                 if ( SPIRO_SELECTED(&spl->spiros[i])) {
    1256           0 :                     outlinechanged = true;
    1257           0 :             break;
    1258             :                 }
    1259             :         } else {
    1260           0 :             for ( sp=spl->first ;; ) {
    1261           0 :                 if ( sp->selected ) {
    1262           0 :                     outlinechanged = true;
    1263           0 :             break;
    1264             :                 }
    1265           0 :                 if ( sp->next==NULL )
    1266           0 :             break;
    1267           0 :                 sp = sp->next->to;
    1268           0 :                 if ( sp==spl->first )
    1269           0 :             break;
    1270           0 :             }
    1271             :         }
    1272             :     }
    1273             : 
    1274           0 :     enum transformPointMask tpmask = 0;
    1275           0 :     tpmask |= tpmask_dontFixControlPoints;
    1276             : 
    1277           0 :     if ( cv->b.sc->inspiro && hasspiro())
    1278           0 :         SplinePointListSpiroTransform(cv->b.layerheads[cv->b.drawmode]->splines,transform,false);
    1279             :     else
    1280             :     {
    1281           0 :         bool interp = CVShouldInterpolateCPsOnMotion( cv );
    1282             : 
    1283           0 :         SplinePointListTransformExtended(cv->b.layerheads[cv->b.drawmode]->splines,transform,
    1284             :                                          interp ? tpt_OnlySelectedInterpCPs : tpt_OnlySelected,
    1285             :                                          tpmask );
    1286             : 
    1287           0 :         if( interp )
    1288             :         {
    1289           0 :             bool preserveState = false;
    1290           0 :             CVVisitAllControlPoints( cv, preserveState,
    1291             :                                      FE_touchControlPoint,
    1292           0 :                                      (void*)(intptr_t)cv->b.layerheads[cv->b.drawmode]->order2 );
    1293             :         }
    1294             :     }
    1295             :     
    1296             : 
    1297           0 :     for ( refs = cv->b.layerheads[cv->b.drawmode]->refs; refs!=NULL; refs=refs->next ) if ( refs->selected ) {
    1298           0 :         refs->transform[4] += transform[4];
    1299           0 :         refs->transform[5] += transform[5];
    1300           0 :         refs->bb.minx += transform[4]; refs->bb.maxx += transform[4];
    1301           0 :         refs->bb.miny += transform[5]; refs->bb.maxy += transform[5];
    1302           0 :         for ( j=0; j<refs->layer_cnt; ++j )
    1303           0 :             SplinePointListTransform(refs->layers[j].splines,transform,tpt_AllPoints);
    1304           0 :         outlinechanged = true;
    1305             :     }
    1306           0 :     if ( CVLayer( (CharViewBase *) cv) > ly_back ) {
    1307           0 :         if ( cv->showanchor ) {
    1308           0 :             for ( ap=cv->b.sc->anchor; ap!=NULL; ap=ap->next ) if ( ap->selected ) {
    1309           0 :                 ap->me.x += transform[4];
    1310           0 :                 ap->me.y += transform[5];
    1311           0 :                 changed = true;
    1312             :             }
    1313             :         }
    1314             :     }
    1315           0 :     for ( img = cv->b.layerheads[cv->b.drawmode]->images; img!=NULL; img=img->next ) if ( img->selected ) {
    1316           0 :         img->xoff += transform[4];
    1317           0 :         img->yoff += transform[5];
    1318           0 :         img->bb.minx += transform[4]; img->bb.maxx += transform[4];
    1319           0 :         img->bb.miny += transform[5]; img->bb.maxy += transform[5];
    1320           0 :         SCOutOfDateBackground(cv->b.sc);
    1321           0 :         changed = true;
    1322             :     }
    1323           0 :     fudge = snapdistance/cv->scale/2;
    1324           0 :     if ( cv->widthsel ) {
    1325           0 :         if ( cv->b.sc->width+dx>0 && ((int16) (cv->b.sc->width+dx))<0 )
    1326           0 :             cv->b.sc->width = 32767;
    1327           0 :         else if ( cv->b.sc->width+dx<0 && ((int16) (cv->b.sc->width+dx))>0 )
    1328           0 :             cv->b.sc->width = -32768;
    1329             :         else
    1330           0 :             cv->b.sc->width += dx;
    1331           0 :         if ( cv->b.sc->width>=-fudge && cv->b.sc->width<fudge )
    1332           0 :             cv->b.sc->width = 0;
    1333           0 :         changed = true;
    1334             :     }
    1335           0 :     if ( cv->lbearingsel ) {
    1336             : 
    1337           0 :         printf("lbearing dx:%f\n", dx );
    1338           0 :         adjustLBearing( cv, cv->b.sc, dx );
    1339           0 :         changed = true;
    1340             :     }
    1341           0 :     if ( cv->vwidthsel ) {
    1342           0 :         if ( cv->b.sc->vwidth-dy>0 && ((int16) (cv->b.sc->vwidth-dy))<0 )
    1343           0 :             cv->b.sc->vwidth = 32767;
    1344           0 :         else if ( cv->b.sc->vwidth-dy<0 && ((int16) (cv->b.sc->vwidth-dy))>0 )
    1345           0 :             cv->b.sc->vwidth = -32768;
    1346             :         else
    1347           0 :             cv->b.sc->vwidth -= dy;
    1348           0 :         if ( cv->b.sc->vwidth>=-fudge && cv->b.sc->vwidth<fudge )
    1349           0 :             cv->b.sc->vwidth = 0;
    1350           0 :         changed = true;
    1351             :     }
    1352           0 :     if ( cv->icsel ) {
    1353           0 :         if ( cv->b.sc->italic_correction+dx>0 && ((int16) (cv->b.sc->italic_correction+dx))<0 )
    1354           0 :             cv->b.sc->italic_correction = 32767-1;
    1355           0 :         else if ( cv->b.sc->italic_correction+dx<0 && ((int16) (cv->b.sc->italic_correction+dx))>0 )
    1356           0 :             cv->b.sc->italic_correction = -32768;
    1357             :         else
    1358           0 :             cv->b.sc->italic_correction += dx;
    1359           0 :         if ( cv->b.sc->italic_correction>=-fudge && cv->b.sc->italic_correction<fudge )
    1360           0 :             cv->b.sc->italic_correction = 0;
    1361           0 :         changed = true;
    1362             :     }
    1363           0 :     if ( cv->tah_sel ) {
    1364           0 :         if ( cv->b.sc->top_accent_horiz+dx>0 && ((int16) (cv->b.sc->top_accent_horiz+dx))<0 )
    1365           0 :             cv->b.sc->top_accent_horiz = 32767-1;
    1366           0 :         else if ( cv->b.sc->top_accent_horiz+dx<0 && ((int16) (cv->b.sc->top_accent_horiz+dx))>0 )
    1367           0 :             cv->b.sc->top_accent_horiz = -32768;
    1368             :         else
    1369           0 :             cv->b.sc->top_accent_horiz += dx;
    1370           0 :         if ( cv->b.sc->top_accent_horiz>=-fudge && cv->b.sc->top_accent_horiz<fudge )
    1371           0 :             cv->b.sc->top_accent_horiz = 0;
    1372           0 :         changed = true;
    1373             :     }
    1374           0 :     if ( outlinechanged )
    1375           0 :         CVSetCharChanged(cv,true);
    1376           0 :     else if ( changed )
    1377           0 :         CVSetCharChanged(cv,2);
    1378           0 :     if ( input_state&ksm_meta )
    1379           0 : return( false );                        /* Don't merge if the meta key is down */
    1380             : 
    1381           0 : return( CVCheckMerges( cv ));
    1382             : }
    1383             : 
    1384           0 : static int CVExpandEdge(CharView *cv) {
    1385             :     real transform[6];
    1386           0 :     real xscale=1.0, yscale=1.0;
    1387             : 
    1388           0 :     CVRestoreTOriginalState(cv);
    1389           0 :     if ( cv->expandedge != ee_up && cv->expandedge != ee_down )
    1390           0 :         xscale = (cv->info.x-cv->expandorigin.x)/cv->expandwidth;
    1391           0 :     if ( cv->expandedge != ee_left && cv->expandedge != ee_right )
    1392           0 :         yscale = (cv->info.y-cv->expandorigin.y)/cv->expandheight;
    1393           0 :     transform[0] = xscale; transform[3] = yscale;
    1394           0 :     transform[1] = transform[2] = 0;
    1395           0 :     transform[4] = (1-xscale)*cv->expandorigin.x;
    1396           0 :     transform[5] = (1-yscale)*cv->expandorigin.y;
    1397           0 :     CVSetCharChanged(cv,true);
    1398           0 :     CVTransFunc(cv,transform,false);
    1399           0 : return( true );
    1400             : }
    1401             : 
    1402           0 : static void touchControlPointsVisitor ( void* key,
    1403             :                                  void* value,
    1404             :                                  SplinePoint* sp,
    1405             :                                  BasePoint *which,
    1406             :                                  bool isnext,
    1407             :                                  void* udata )
    1408             : {
    1409           0 :     SPTouchControl( sp, which, (int)(intptr_t)udata );
    1410           0 : }
    1411             : 
    1412             : #ifndef MAX
    1413             : #define MAX(x,y)   (((x) > (y)) ? (x) : (y))
    1414             : #endif
    1415             : #ifndef MIN
    1416             : #define MIN(x,y)   (((x) < (y)) ? (x) : (y))
    1417             : #endif
    1418             : 
    1419           0 : BasePoint nearest_point_on_line_segment(BasePoint p1, BasePoint p2, BasePoint p3) {
    1420           0 :         double x_diff = p2.x - p1.x;
    1421           0 :         double y_diff = p2.y - p1.y;
    1422           0 :         double slope_1 = (p2.y - p1.y) / (p2.x - p1.x);
    1423           0 :         double inverse_slope_1 = (p2.x - p1.x) / (p2.y - p1.y);
    1424             :         BasePoint output_1;
    1425           0 :         output_1.x = 0;
    1426           0 :         output_1.y = 0;
    1427             :         // Accuracy may be important, so we try to use the longer dimension.
    1428           0 :         if (x_diff == 0) {
    1429             :                 // The line is vertical.
    1430           0 :                 output_1.x = p1.x;
    1431           0 :                 output_1.y = p3.y;
    1432           0 :         } else if (y_diff == 0) {
    1433             :                 // The line is horizontal.
    1434           0 :                 output_1.x = p3.x;
    1435           0 :                 output_1.y = p1.y;
    1436             :         } else {
    1437           0 :                 output_1.x = (p3.x/slope_1 + slope_1*p1.x + p3.y - p1.y)/(slope_1 + 1/slope_1);
    1438           0 :                 output_1.y = (p3.y/inverse_slope_1 + inverse_slope_1*p1.y + p3.x - p1.x)/(inverse_slope_1 + 1/inverse_slope_1);
    1439             :         }
    1440             :         // We are using the segment between p1 and p2, not the line through them, so we must crop.
    1441           0 :         double min_x = MIN(p1.x, p2.x), max_x = MAX(p1.x, p2.x), min_y = MIN(p1.y, p2.y), max_y = MAX(p1.y, p2.y);
    1442           0 :         if (output_1.x < min_x) output_1.x = min_x;
    1443           0 :         if (output_1.x > max_x) output_1.x = max_x;
    1444           0 :         if (output_1.y < min_y) output_1.y = min_y;
    1445           0 :         if (output_1.y > max_y) output_1.y = max_y;
    1446             :         // Note that it is not necessary to conform these points to the line since the corners of the box are on the line.
    1447           0 :         return output_1;
    1448             : }
    1449             : 
    1450           0 : int CVMouseMovePointer(CharView *cv, GEvent *event) {
    1451             :     extern float arrowAmount;
    1452           0 :     int needsupdate = false;
    1453           0 :     int did_a_merge = false;
    1454           0 :     int touch_control_points = false;
    1455             : 
    1456             :     
    1457             :     /* if we haven't moved from the original location (ever) then this is a noop */
    1458           0 :     if ( !cv->p.rubberbanding && !cv->recentchange &&
    1459           0 :             RealNear(cv->info.x,cv->p.cx) && RealNear(cv->info.y,cv->p.cy) )
    1460           0 : return( false );
    1461             : 
    1462             :     /* This can happen if they depress on a control point, move it, then use */
    1463             :     /*  the arrow keys to move the point itself, and then try to move the cp */
    1464             :     /*  again (mouse still depressed) */
    1465           0 :     if (( cv->p.nextcp || cv->p.prevcp ) && cv->p.sp==NULL )
    1466           0 :         cv->p.nextcp = cv->p.prevcp = false;
    1467             : 
    1468             :     /* I used to have special cases for moving width lines, but that's now */
    1469             :     /*  done by move selection */
    1470           0 :     if ( cv->expandedge!=ee_none && !cv->widthsel && !cv->vwidthsel && !cv->lbearingsel
    1471           0 :          && cv->nearcaret==-1 && !cv->icsel && !cv->tah_sel )
    1472             :     {
    1473           0 :         if( !cv->changedActiveGlyph )
    1474             :         {
    1475           0 :             needsupdate = CVExpandEdge(cv);
    1476             :         }
    1477             :     }
    1478           0 :     else if ( cv->nearcaret!=-1 && cv->lcarets!=NULL ) {
    1479           0 :         if ( cv->info.x!=cv->last_c.x ) {
    1480           0 :             if ( !cv->recentchange ) SCPreserveLayer(cv->b.sc,CVLayer((CharViewBase *) cv),2);
    1481           0 :             cv->lcarets->u.lcaret.carets[cv->nearcaret] += cv->info.x-cv->last_c.x;
    1482           0 :             if ( cv->lcarets->u.lcaret.carets[cv->nearcaret]<0 )
    1483           0 :                 cv->lcarets->u.lcaret.carets[cv->nearcaret] = 0;
    1484           0 :             needsupdate = true;
    1485           0 :             CVSetCharChanged(cv,true);
    1486             :         }
    1487           0 :     } else if ( !cv->p.anysel ) {
    1488           0 :         if ( !cv->p.rubberbanding ) {
    1489           0 :             cv->p.ex = cv->p.cx;
    1490           0 :             cv->p.ey = cv->p.cy;
    1491             :         }
    1492           0 :         needsupdate = CVRectSelect(cv,cv->info.x,cv->info.y);
    1493           0 :         if ( !needsupdate && cv->p.rubberbanding )
    1494           0 :             CVDrawRubberRect(cv->v,cv);
    1495             :         /* printf("moving2 cx:%g cy:%g\n", cv->p.cx, cv->p.cy ); */
    1496           0 :         cv->p.ex = cv->info.x;
    1497           0 :         cv->p.ey = cv->info.y;
    1498           0 :         cv->p.rubberbanding = true;
    1499           0 :         if ( !needsupdate )
    1500           0 :             CVDrawRubberRect(cv->v,cv);
    1501             :     }
    1502           0 :     else if ( cv->p.nextcp )
    1503             :     {
    1504           0 :         if ( !cv->recentchange )
    1505           0 :             CVPreserveState(&cv->b);
    1506             : 
    1507             :         FE_adjustBCPByDeltaData d;
    1508           0 :         memset( &d, 0, sizeof(FE_adjustBCPByDeltaData));
    1509           0 :         d.cv = cv;
    1510           0 :         d.dx = (cv->info.x - cv->p.sp->nextcp.x) * arrowAmount;
    1511           0 :         d.dy = (cv->info.y - cv->p.sp->nextcp.y) * arrowAmount;
    1512           0 :         visitSelectedControlPointsVisitor func = FE_adjustBCPByDelta;
    1513             :         /* printf("move sp:%p ncp:%p \n", */
    1514             :         /*        cv->p.sp, &(cv->p.sp->nextcp)  ); */
    1515             :         /* printf("move me.x:%f me.y:%f\n", cv->p.sp->me.x, cv->p.sp->me.y ); */
    1516             :         /* printf("move ncp.x:%f ncp.y:%f ix:%f iy:%f\n", */
    1517             :         /*        cv->p.sp->nextcp.x, cv->p.sp->nextcp.y, */
    1518             :         /*        cv->info.x, cv->info.y ); */
    1519             :         /* printf("move dx:%f dy:%f\n",  d.dx, d.dy ); */
    1520             :         /* printf("move dx:%f \n", cv->info.x - cv->p.sp->nextcp.x ); */
    1521           0 :         if( cv->activeModifierAlt )
    1522           0 :             func = FE_adjustBCPByDeltaWhilePreservingBCPAngle;
    1523             : 
    1524           0 :         CVFindAndVisitSelectedControlPoints( cv, false, func, &d );
    1525           0 :         CPUpdateInfo(cv,event);
    1526           0 :         needsupdate = true;
    1527             :     }
    1528           0 :     else if ( cv->p.prevcp )
    1529             :     {
    1530           0 :         if ( !cv->recentchange )
    1531           0 :             CVPreserveState(&cv->b);
    1532             : 
    1533             :         FE_adjustBCPByDeltaData d;
    1534           0 :         memset( &d, 0, sizeof(FE_adjustBCPByDeltaData));
    1535           0 :         d.cv = cv;
    1536           0 :         d.dx = (cv->info.x - cv->p.sp->prevcp.x) * arrowAmount;
    1537           0 :         d.dy = (cv->info.y - cv->p.sp->prevcp.y) * arrowAmount;
    1538           0 :         visitSelectedControlPointsVisitor func = FE_adjustBCPByDelta;
    1539             :         
    1540           0 :         if( cv->activeModifierAlt )
    1541           0 :             func = FE_adjustBCPByDeltaWhilePreservingBCPAngle;
    1542             :         
    1543           0 :         CVFindAndVisitSelectedControlPoints( cv, false, func, &d );
    1544           0 :         CPUpdateInfo(cv,event);
    1545           0 :         needsupdate = true;
    1546             :     }
    1547           0 :     else if ( cv->p.spline
    1548           0 :                 && !cv->p.splineAdjacentPointsSelected
    1549           0 :                 && (!cv->b.sc->inspiro || !hasspiro()))
    1550             :     {
    1551           0 :         if ( !cv->recentchange )
    1552           0 :             CVPreserveState(&cv->b);
    1553             :         
    1554           0 :         CVAdjustSpline(cv);
    1555           0 :         CVSetCharChanged(cv,true);
    1556           0 :         needsupdate = true;
    1557           0 :         touch_control_points = true;
    1558             :     }
    1559             :     else
    1560             :     {
    1561           0 :         if ( !cv->recentchange )
    1562           0 :             CVPreserveState(&cv->b);
    1563             : 
    1564             :         BasePoint tmpp1;
    1565             :         BasePoint tmpp2;
    1566           0 :         tmpp1.x = cv->info.x;
    1567           0 :         tmpp1.y = cv->info.y;
    1568           0 :         tmpp2.x = cv->info.x;
    1569           0 :         tmpp2.y = cv->info.y;
    1570           0 :         BasePoint cachecp1 = (cv->p.sp ? cv->p.sp->prevcp : (BasePoint){0, 0});
    1571           0 :         BasePoint cachecp2 = (cv->p.sp ? cv->p.sp->nextcp : (BasePoint){0, 0});
    1572           0 :         double xadj = cv->info.x-cv->last_c.x;
    1573           0 :         double yadj = cv->info.y-cv->last_c.y;
    1574           0 :         touch_control_points = true;
    1575             :         // The modifier is wrong.
    1576           0 :         if (cv->p.anysel && cv->p.sp && event->u.mouse.state & ksm_control) {
    1577             :                 // Identify the individual point clicked. Find its control points. Move the selected point on a line between those control points.
    1578           0 :                 tmpp1 = nearest_point_on_line_segment((BasePoint){cv->p.sp->prevcp.x,cv->p.sp->prevcp.y}, \
    1579           0 :                         (BasePoint){cv->p.sp->nextcp.x,cv->p.sp->nextcp.y}, (BasePoint){cv->info.x, cv->info.y});
    1580             :                 // We also need to rebase the original point onto that line segment so that the movement is exactly along the line even if the original click is not.
    1581           0 :                 tmpp2 = nearest_point_on_line_segment((BasePoint){cv->p.sp->prevcp.x,cv->p.sp->prevcp.y}, \
    1582           0 :                         (BasePoint){cv->p.sp->nextcp.x,cv->p.sp->nextcp.y}, (BasePoint){cv->last_c.x, cv->last_c.y});
    1583           0 :                 xadj = tmpp1.x-tmpp2.x;
    1584           0 :                 yadj = tmpp1.y-tmpp2.y;
    1585           0 :                 touch_control_points = false; // We will need to move the control points back (but only for the point dragged).
    1586             :         }
    1587             :         
    1588           0 :         did_a_merge = CVMoveSelection(cv,
    1589             :                 xadj,yadj,
    1590           0 :                 event->u.mouse.state);
    1591             :         // Rather than create a new set of functions for moving points without their control points, we instead just restore them if we did not want them moved.
    1592           0 :         if (cv->p.sp && touch_control_points == false) {
    1593           0 :                 cv->p.sp->prevcp = cachecp1;
    1594           0 :                 cv->p.sp->nextcp = cachecp2;
    1595           0 :                 touch_control_points = true;
    1596           0 :                 AdjustControls(cv->p.sp);
    1597             :         }
    1598           0 :         needsupdate = true;
    1599             : 
    1600             :     }
    1601             : 
    1602             : 
    1603           0 :     if ( needsupdate )
    1604             :     {
    1605           0 :         SCUpdateAll(cv->b.sc);
    1606           0 :         CVGridHandlePossibleFitChar( cv );
    1607             :     }
    1608             : 
    1609           0 :     if ( touch_control_points )
    1610             :     {
    1611             :         // We should really only need to visit the Adjacent CP
    1612             :         // visiting all is a hammer left below in case it might be needed.
    1613           0 :         CVVisitAdjacentToSelectedControlPoints( cv, false,
    1614             :                                                 touchControlPointsVisitor,
    1615           0 :                                                 (void*)(intptr_t)cv->b.layerheads[cv->b.drawmode]->order2 );
    1616             :         /* CVVisitAllControlPoints( cv, false, */
    1617             :         /*                       touchControlPointsVisitor, */
    1618             :         /*                       (void*)cv->b.layerheads[cv->b.drawmode]->order2 ); */
    1619             : 
    1620           0 :         GDrawRequestExpose(cv->v,NULL,false);
    1621             :     }
    1622             : 
    1623           0 :     cv->last_c.x = cv->info.x; cv->last_c.y = cv->info.y;
    1624           0 : return( did_a_merge );
    1625             : }
    1626             : 
    1627             : 
    1628             : 
    1629             : 
    1630           0 : void CVMouseUpPointer(CharView *cv ) {
    1631             :     static char *buts[3];
    1632           0 :     buts[0] = _("_Yes");
    1633           0 :     buts[1] = _("_No");
    1634           0 :     buts[2] = NULL;
    1635             : 
    1636           0 :     if ( cv->widthsel )
    1637             :     {
    1638           0 :         if ( cv->b.sc->width<0 && cv->oldwidth>=0 ) {
    1639           0 :             if ( gwwv_ask(_("Negative Width"), (const char **) buts, 0, 1, _("Negative character widths are not allowed in TrueType.\nDo you really want a negative width?") )==1 )
    1640           0 :                 cv->b.sc->width = cv->oldwidth;
    1641             :         }
    1642           0 :         SCSynchronizeWidth(cv->b.sc,cv->b.sc->width,cv->oldwidth,NULL);
    1643           0 :         cv->expandedge = ee_none;
    1644           0 :         GDrawSetCursor(cv->v,ct_mypointer);
    1645             :     }
    1646           0 :     if ( cv->lbearingsel )
    1647             :     {
    1648           0 :         printf("oldlbearing:%f\n", cv->oldlbearing );
    1649           0 :         cv->expandedge = ee_none;
    1650           0 :         GDrawSetCursor(cv->v,ct_mypointer);
    1651             :     }
    1652           0 :     if ( cv->vwidthsel )
    1653             :     {
    1654           0 :         if ( cv->b.sc->vwidth<0 && cv->oldvwidth>=0 ) {
    1655           0 :             if ( gwwv_ask(_("Negative Width"), (const char **) buts, 0, 1, _("Negative character widths are not allowed in TrueType.\nDo you really want a negative width?") )==1 )
    1656           0 :                 cv->b.sc->vwidth = cv->oldvwidth;
    1657             :         }
    1658           0 :         cv->expandedge = ee_none;
    1659           0 :         GDrawSetCursor(cv->v,ct_mypointer);
    1660             :     }
    1661           0 :     if ( cv->nearcaret!=-1 && cv->lcarets!=NULL )
    1662             :     {
    1663           0 :         cv->nearcaret = -1;
    1664           0 :         cv->expandedge = ee_none;
    1665           0 :         cv->lcarets = NULL;
    1666           0 :         GDrawSetCursor(cv->v,ct_mypointer);
    1667             :     }
    1668           0 :     if( cv->changedActiveGlyph )
    1669             :     {
    1670           0 :         cv->changedActiveGlyph = 0;
    1671             :     }
    1672             :     else
    1673             :     {
    1674           0 :         if ( cv->expandedge!=ee_none )
    1675             :         {
    1676           0 :             CVUndoCleanup(cv);
    1677           0 :             cv->expandedge = ee_none;
    1678           0 :             GDrawSetCursor(cv->v,ct_mypointer);
    1679             :         }
    1680           0 :         else if ( CVAllSelected(cv) && cv->b.drawmode==dm_fore && cv->p.spline==NULL
    1681           0 :                   && !cv->p.prevcp && !cv->p.nextcp && cv->info.y==cv->p.cy )
    1682             :         {
    1683           0 :             SCUndoSetLBearingChange(cv->b.sc,(int) rint(cv->info.x-cv->p.cx));
    1684           0 :             SCSynchronizeLBearing(cv->b.sc,cv->info.x-cv->p.cx,CVLayer((CharViewBase *) cv));
    1685             :         }
    1686             :     }
    1687           0 :     CPEndInfo(cv);
    1688           0 : }
    1689             : 
    1690             : /* ************************************************************************** */
    1691             : /*  ************************** Select Point Dialog *************************  */
    1692             : /* ************************************************************************** */
    1693             : 
    1694           0 : static spiro_cp *SpiroClosest(BasePoint *base,spiro_cp *sp1, spiro_cp *sp2) {
    1695             :     double dx1, dy1, dx2, dy2;
    1696           0 :     if ( sp1==NULL )
    1697           0 : return( sp2 );
    1698           0 :     if ( sp2==NULL )
    1699           0 : return( sp1 );
    1700           0 :     if ( (dx1 = sp1->x-base->x)<0 ) dx1 = -dx1;
    1701           0 :     if ( (dy1 = sp1->y-base->y)<0 ) dy1 = -dy1;
    1702           0 :     if ( (dx2 = sp2->x-base->x)<0 ) dx2 = -dx2;
    1703           0 :     if ( (dy2 = sp2->y-base->y)<0 ) dy2 = -dy2;
    1704           0 :     if ( dx1+dy1 < dx2+dy2 )
    1705           0 : return( sp1 );
    1706             :     else
    1707           0 : return( sp2 );
    1708             : }
    1709             : 
    1710           0 : static SplinePoint *Closest(BasePoint *base,SplinePoint *sp1, SplinePoint *sp2) {
    1711             :     double dx1, dy1, dx2, dy2;
    1712           0 :     if ( sp1==NULL )
    1713           0 : return( sp2 );
    1714           0 :     if ( sp2==NULL )
    1715           0 : return( sp1 );
    1716           0 :     if ( (dx1 = sp1->me.x-base->x)<0 ) dx1 = -dx1;
    1717           0 :     if ( (dy1 = sp1->me.y-base->y)<0 ) dy1 = -dy1;
    1718           0 :     if ( (dx2 = sp2->me.x-base->x)<0 ) dx2 = -dx2;
    1719           0 :     if ( (dy2 = sp2->me.y-base->y)<0 ) dy2 = -dy2;
    1720           0 :     if ( dx1+dy1 < dx2+dy2 )
    1721           0 : return( sp1 );
    1722             :     else
    1723           0 : return( sp2 );
    1724             : }
    1725             : 
    1726           0 : static int SelectPointsWithin(CharView *cv, BasePoint *base, double fuzz, BasePoint *bounds) {
    1727             :     SplineSet *ss;
    1728             :     SplinePoint *sp;
    1729           0 :     SplinePoint *any = NULL;
    1730             :     int i;
    1731           0 :     spiro_cp *anycp = NULL;
    1732             : 
    1733           0 :     CVClearSel(cv);
    1734           0 :     if ( cv->b.sc->inspiro && hasspiro()) {
    1735           0 :         for ( ss= cv->b.layerheads[cv->b.drawmode]->splines; ss!=NULL; ss=ss->next ) {
    1736           0 :             for ( i=0; i<ss->spiro_cnt-1; ++i ) {
    1737           0 :                 spiro_cp *cp = &ss->spiros[i];
    1738           0 :                 if ( bounds!=NULL ) {
    1739           0 :                     if ( cp->x >= base->x && cp->x <= base->x+bounds->x &&
    1740           0 :                             cp->y >= base->y && cp->y <= base->y+bounds->y ) {
    1741           0 :                         SPIRO_SELECT(cp);
    1742           0 :                         anycp = cp;
    1743             :                     }
    1744           0 :                 } else if ( fuzz>0 ) {
    1745           0 :                     if ( RealWithin(cp->x,base->x,fuzz) && RealWithin(cp->y,base->y,fuzz)) {
    1746           0 :                         SPIRO_SELECT(cp);
    1747           0 :                         anycp = SpiroClosest(base,anycp,cp);
    1748             :                     }
    1749             :                 } else {
    1750           0 :                     if ( RealNear(cp->x,base->x) && RealNear(cp->y,base->y)) {
    1751           0 :                         SPIRO_SELECT(cp);
    1752           0 :                         anycp = SpiroClosest(base,anycp,cp);
    1753           0 :       goto cpdone;
    1754             :                     }
    1755             :                 }
    1756             :             }
    1757             :         }
    1758             :       cpdone:
    1759           0 :         if ( any==NULL ) {
    1760           0 :             CVShowPoint(cv,base);
    1761           0 :             GDrawBeep(NULL);
    1762             :         } else {
    1763             :             BasePoint here;
    1764           0 :             here.x = anycp->x;
    1765           0 :             here.y = anycp->y;
    1766           0 :             CVShowPoint(cv,&here);
    1767             :         }
    1768           0 :         SCUpdateAll(cv->b.sc);
    1769           0 : return( anycp!=NULL );
    1770             :     } else {
    1771           0 :         for ( ss= cv->b.layerheads[cv->b.drawmode]->splines; ss!=NULL; ss=ss->next ) {
    1772           0 :             for ( sp=ss->first; ; ) {
    1773           0 :                 if ( bounds!=NULL ) {
    1774           0 :                     if ( sp->me.x >= base->x && sp->me.x <= base->x+bounds->x &&
    1775           0 :                             sp->me.y >= base->y && sp->me.y <= base->y+bounds->y ) {
    1776           0 :                         sp->selected = true;
    1777           0 :                         any = sp;
    1778             :                     }
    1779           0 :                 } else if ( fuzz>0 ) {
    1780           0 :                     if ( RealWithin(sp->me.x,base->x,fuzz) && RealWithin(sp->me.y,base->y,fuzz)) {
    1781           0 :                         sp->selected = true;
    1782           0 :                         any = Closest(base,any,sp);
    1783             :                     }
    1784             :                 } else {
    1785           0 :                     if ( RealNear(sp->me.x,base->x) && RealNear(sp->me.y,base->y)) {
    1786           0 :                         sp->selected = true;
    1787           0 :                         any = Closest(base,any,sp);
    1788           0 :       goto done;
    1789             :                     }
    1790             :                 }
    1791           0 :                 if ( sp->next==NULL )
    1792           0 :             break;
    1793           0 :                 sp = sp->next->to;
    1794           0 :                 if ( sp==ss->first )
    1795           0 :             break;
    1796           0 :             }
    1797             :         }
    1798             :       done:
    1799           0 :         if ( any==NULL ) {
    1800           0 :             CVShowPoint(cv,base);
    1801           0 :             GDrawBeep(NULL);
    1802             :         } else
    1803           0 :             CVShowPoint(cv,&any->me);
    1804           0 :         SCUpdateAll(cv->b.sc);
    1805           0 : return( any!=NULL );
    1806             :     }
    1807             : }
    1808             : 
    1809             : #define CID_X   1001
    1810             : #define CID_Y   1002
    1811             : #define CID_Width       1003
    1812             : #define CID_Height      1004
    1813             : #define CID_Fuzz        1005
    1814             : #define CID_Exact       1006
    1815             : #define CID_Within      1007
    1816             : #define CID_Fuzzy       1008
    1817             : 
    1818             : struct selpt {
    1819             :     int done;
    1820             :     CharView *cv;
    1821             :     GWindow gw;
    1822             : };
    1823             : 
    1824           0 : static void SPA_DoCancel(struct selpt *pa) {
    1825           0 :     pa->done = true;
    1826           0 : }
    1827             : 
    1828           0 : static int SPA_OK(GGadget *g, GEvent *e) {
    1829           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
    1830           0 :         GWindow gw = GGadgetGetWindow(g);
    1831           0 :         struct selpt *pa = GDrawGetUserData(gw);
    1832           0 :         CharView *cv = pa->cv;
    1833             :         BasePoint base, bounds;
    1834             :         double fuzz;
    1835           0 :         int err = false, ret;
    1836             : 
    1837             : /* GT: X is a coordinate */
    1838           0 :         base.x = GetReal8(gw,CID_X,_("X"),&err);
    1839             : /* GT: Y is a coordinate */
    1840           0 :         base.y = GetReal8(gw,CID_Y,_("Y"),&err);
    1841           0 :         if ( err )
    1842           0 : return( true );
    1843           0 :         if ( GGadgetIsChecked(GWidgetGetControl(gw,CID_Exact)) )
    1844           0 :             ret = SelectPointsWithin(cv, &base, 0, NULL );
    1845           0 :         else if ( GGadgetIsChecked(GWidgetGetControl(gw,CID_Fuzzy)) ) {
    1846           0 :             fuzz = GetReal8(gw,CID_Fuzz,_("Search Radius"),&err);
    1847           0 :             if ( err )
    1848           0 : return( true );
    1849           0 :             ret = SelectPointsWithin(cv, &base, fuzz, NULL );
    1850             :         } else {
    1851           0 :             bounds.x = GetReal8(gw,CID_Width,_("Width"),&err);
    1852           0 :             bounds.y = GetReal8(gw,CID_Height,_("Height"),&err);
    1853           0 :             if ( err )
    1854           0 : return( true );
    1855           0 :             if ( bounds.x<0 ) {
    1856           0 :                 base.x += bounds.x;
    1857           0 :                 bounds.x = -bounds.x;
    1858             :             }
    1859           0 :             if ( bounds.y<0 ) {
    1860           0 :                 base.y += bounds.y;
    1861           0 :                 bounds.y = -bounds.y;
    1862             :             }
    1863           0 :             ret = SelectPointsWithin(cv, &base, 0, &bounds );
    1864             :         }
    1865           0 :         pa->done = ret;
    1866             :     }
    1867           0 : return( true );
    1868             : }
    1869             : 
    1870           0 : static int SPA_Cancel(GGadget *g, GEvent *e) {
    1871           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
    1872           0 :         struct selpt *pa = GDrawGetUserData(GGadgetGetWindow(g));
    1873           0 :         SPA_DoCancel(pa);
    1874             :     }
    1875           0 : return( true );
    1876             : }
    1877             : 
    1878           0 : static int SPA_Radius(GGadget *g, GEvent *e) {
    1879           0 :     if ( e->type==et_controlevent ) {
    1880           0 :         GWindow gw = GGadgetGetWindow(g);
    1881           0 :         GGadgetSetChecked(GWidgetGetControl(gw,CID_Fuzzy),true);
    1882             :     }
    1883           0 : return( true );
    1884             : }
    1885             : 
    1886           0 : static int SPA_Rect(GGadget *g, GEvent *e) {
    1887           0 :     if ( e->type==et_controlevent ) {
    1888           0 :         GWindow gw = GGadgetGetWindow(g);
    1889           0 :         GGadgetSetChecked(GWidgetGetControl(gw,CID_Within),true);
    1890             :     }
    1891           0 : return( true );
    1892             : }
    1893             : 
    1894           0 : static int spa_e_h(GWindow gw, GEvent *event) {
    1895           0 :     if ( event->type==et_close ) {
    1896           0 :         SPA_DoCancel( GDrawGetUserData(gw));
    1897           0 :     } else if ( event->type == et_char ) {
    1898           0 : return( false );
    1899             :     }
    1900           0 : return( true );
    1901             : }
    1902             : 
    1903           0 : void CVSelectPointAt(CharView *cv) {
    1904             :     GRect pos;
    1905             :     GWindow gw;
    1906             :     GWindowAttrs wattrs;
    1907             :     GGadgetCreateData gcd[18];
    1908             :     GTextInfo label[18];
    1909             :     static struct selpt pa;
    1910             :     int k;
    1911           0 :     int first = false;
    1912             : 
    1913           0 :     pa.done = false;
    1914           0 :     pa.cv = cv;
    1915             : 
    1916           0 :     if ( pa.gw==NULL ) {
    1917           0 :         memset(&wattrs,0,sizeof(wattrs));
    1918           0 :         wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict;
    1919           0 :         wattrs.event_masks = ~(1<<et_charup);
    1920           0 :         wattrs.restrict_input_to_me = 1;
    1921           0 :         wattrs.undercursor = 1;
    1922           0 :         wattrs.cursor = ct_pointer;
    1923           0 :         wattrs.utf8_window_title = _("Select Point(s) at...");
    1924           0 :         wattrs.is_dlg = true;
    1925           0 :         pos.x = pos.y = 0;
    1926           0 :         pos.width = GGadgetScale(GDrawPointsToPixels(NULL,190));
    1927           0 :         pos.height = GDrawPointsToPixels(NULL,175);
    1928           0 :         pa.gw = gw = GDrawCreateTopWindow(NULL,&pos,spa_e_h,&pa,&wattrs);
    1929             : 
    1930           0 :         memset(&label,0,sizeof(label));
    1931           0 :         memset(&gcd,0,sizeof(gcd));
    1932             : 
    1933           0 :         k = 0;
    1934           0 :         label[k].text = (unichar_t *) _("_X:");
    1935           0 :         label[k].text_is_1byte = true;
    1936           0 :         label[k].text_in_resource = true;
    1937           0 :         gcd[k].gd.label = &label[k];
    1938           0 :         gcd[k].gd.pos.x = 10; gcd[k].gd.pos.y = 8+4;
    1939           0 :         gcd[k].gd.flags = gg_enabled|gg_visible;
    1940           0 :         gcd[k++].creator = GLabelCreate;
    1941             : 
    1942           0 :         gcd[k].gd.pos.x = 30; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y-4;  gcd[k].gd.pos.width = 40;
    1943           0 :         gcd[k].gd.flags = gg_enabled|gg_visible;
    1944           0 :         gcd[k].gd.cid = CID_X;
    1945           0 :         gcd[k++].creator = GTextFieldCreate;
    1946             : 
    1947           0 :         label[k].text = (unichar_t *) _("_Y:");
    1948           0 :         label[k].text_is_1byte = true;
    1949           0 :         label[k].text_in_resource = true;
    1950           0 :         gcd[k].gd.label = &label[k];
    1951           0 :         gcd[k].gd.pos.x = 80; gcd[k].gd.pos.y = gcd[k-2].gd.pos.y;
    1952           0 :         gcd[k].gd.flags = gg_enabled|gg_visible;
    1953           0 :         gcd[k++].creator = GLabelCreate;
    1954             : 
    1955           0 :         gcd[k].gd.pos.x = 100; gcd[k].gd.pos.y = gcd[k-2].gd.pos.y;  gcd[k].gd.pos.width = 40;
    1956           0 :         gcd[k].gd.flags = gg_enabled|gg_visible;
    1957           0 :         gcd[k].gd.cid = CID_Y;
    1958           0 :         gcd[k++].creator = GTextFieldCreate;
    1959             : 
    1960           0 :         label[k].text = (unichar_t *) _("_Exact");
    1961           0 :         label[k].text_is_1byte = true;
    1962           0 :         label[k].text_in_resource = true;
    1963           0 :         gcd[k].gd.label = &label[k];
    1964           0 :         gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+23;
    1965           0 :         gcd[k].gd.flags = gg_enabled|gg_visible|gg_cb_on;
    1966           0 :         gcd[k].gd.cid = CID_Exact;
    1967           0 :         gcd[k++].creator = GRadioCreate;
    1968             : 
    1969           0 :         label[k].text = (unichar_t *) _("_Around");
    1970           0 :         label[k].text_is_1byte = true;
    1971           0 :         label[k].text_in_resource = true;
    1972           0 :         gcd[k].gd.label = &label[k];
    1973           0 :         gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+13;
    1974           0 :         gcd[k].gd.flags = gg_enabled|gg_visible;
    1975           0 :         gcd[k].gd.cid = CID_Fuzzy;
    1976           0 :         gcd[k++].creator = GRadioCreate;
    1977             : 
    1978           0 :         label[k].text = (unichar_t *) _("W_ithin Rectangle");
    1979           0 :         label[k].text_is_1byte = true;
    1980           0 :         label[k].text_in_resource = true;
    1981           0 :         gcd[k].gd.label = &label[k];
    1982           0 :         gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+16+24;
    1983           0 :         gcd[k].gd.flags = gg_enabled|gg_visible;
    1984           0 :         gcd[k].gd.cid = CID_Within;
    1985           0 :         gcd[k++].creator = GRadioCreate;
    1986             : 
    1987           0 :         label[k].text = (unichar_t *) _("_Radius:");
    1988           0 :         label[k].text_is_1byte = true;
    1989           0 :         label[k].text_in_resource = true;
    1990           0 :         gcd[k].gd.label = &label[k];
    1991           0 :         gcd[k].gd.pos.x = 15; gcd[k].gd.pos.y = gcd[k-2].gd.pos.y+17+4;
    1992           0 :         gcd[k].gd.flags = gg_enabled|gg_visible;
    1993           0 :         gcd[k++].creator = GLabelCreate;
    1994             : 
    1995           0 :         label[k].text = (unichar_t *) _("3");
    1996           0 :         label[k].text_is_1byte = true;
    1997           0 :         label[k].text_in_resource = true;
    1998           0 :         gcd[k].gd.label = &label[k];
    1999           0 :         gcd[k].gd.pos.x = 52; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y-4;  gcd[k].gd.pos.width = 40;
    2000           0 :         gcd[k].gd.flags = gg_enabled|gg_visible;
    2001           0 :         gcd[k].gd.cid = CID_Fuzz;
    2002           0 :         gcd[k].gd.handle_controlevent = SPA_Radius;
    2003           0 :         gcd[k++].creator = GTextFieldCreate;
    2004             : 
    2005           0 :         label[k].text = (unichar_t *) _("_Width:");
    2006           0 :         label[k].text_is_1byte = true;
    2007           0 :         label[k].text_in_resource = true;
    2008           0 :         gcd[k].gd.label = &label[k];
    2009           0 :         gcd[k].gd.pos.x = 15; gcd[k].gd.pos.y = gcd[k-3].gd.pos.y+17+4;
    2010           0 :         gcd[k].gd.flags = gg_enabled|gg_visible;
    2011           0 :         gcd[k++].creator = GLabelCreate;
    2012             : 
    2013           0 :         gcd[k].gd.pos.x = 52; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y-4;  gcd[k].gd.pos.width = 40;
    2014           0 :         gcd[k].gd.flags = gg_enabled|gg_visible;
    2015           0 :         gcd[k].gd.cid = CID_Width;
    2016           0 :         gcd[k].gd.handle_controlevent = SPA_Rect;
    2017           0 :         gcd[k++].creator = GTextFieldCreate;
    2018             : 
    2019           0 :         label[k].text = (unichar_t *) _("_Height:");
    2020           0 :         label[k].text_is_1byte = true;
    2021           0 :         label[k].text_in_resource = true;
    2022           0 :         gcd[k].gd.label = &label[k];
    2023           0 :         gcd[k].gd.pos.x = 100; gcd[k].gd.pos.y = gcd[k-2].gd.pos.y;
    2024           0 :         gcd[k].gd.flags = gg_enabled|gg_visible;
    2025           0 :         gcd[k++].creator = GLabelCreate;
    2026             : 
    2027           0 :         gcd[k].gd.pos.x = 138; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y-4;  gcd[k].gd.pos.width = 40;
    2028           0 :         gcd[k].gd.flags = gg_enabled|gg_visible;
    2029           0 :         gcd[k].gd.cid = CID_Height;
    2030           0 :         gcd[k].gd.handle_controlevent = SPA_Rect;
    2031           0 :         gcd[k++].creator = GTextFieldCreate;
    2032             : 
    2033           0 :         gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+28;
    2034           0 :         gcd[k].gd.pos.width = GDrawPixelsToPoints(gw,pos.width)-10;
    2035           0 :         gcd[k].gd.flags = gg_enabled|gg_visible;
    2036           0 :         gcd[k++].creator = GLineCreate;
    2037             : 
    2038           0 :         gcd[k].gd.pos.x = 20-3; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+8;
    2039           0 :         gcd[k].gd.pos.width = -1; gcd[k].gd.pos.height = 0;
    2040           0 :         gcd[k].gd.flags = gg_visible | gg_enabled | gg_but_default;
    2041           0 :         label[k].text = (unichar_t *) _("_OK");
    2042           0 :         label[k].text_is_1byte = true;
    2043           0 :         label[k].text_in_resource = true;
    2044           0 :         gcd[k].gd.label = &label[k];
    2045           0 :         gcd[k].gd.handle_controlevent = SPA_OK;
    2046           0 :         gcd[k++].creator = GButtonCreate;
    2047             : 
    2048           0 :         gcd[k].gd.pos.x = -20; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+3;
    2049           0 :         gcd[k].gd.pos.width = -1; gcd[k].gd.pos.height = 0;
    2050           0 :         gcd[k].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
    2051           0 :         label[k].text = (unichar_t *) _("_Cancel");
    2052           0 :         label[k].text_is_1byte = true;
    2053           0 :         label[k].text_in_resource = true;
    2054           0 :         gcd[k].gd.label = &label[k];
    2055           0 :         gcd[k].gd.handle_controlevent = SPA_Cancel;
    2056           0 :         gcd[k++].creator = GButtonCreate;
    2057             : 
    2058           0 :         gcd[k].gd.pos.x = 2; gcd[k].gd.pos.y = 2;
    2059           0 :         gcd[k].gd.pos.width = pos.width-4; gcd[k].gd.pos.height = pos.height-4;
    2060           0 :         gcd[k].gd.flags = gg_enabled|gg_visible|gg_pos_in_pixels;
    2061           0 :         gcd[k++].creator = GGroupCreate;
    2062             : 
    2063           0 :         GGadgetsCreate(gw,gcd);
    2064           0 :         first = true;
    2065             :     } else {
    2066           0 :         GTextFieldSelect(GWidgetGetControl(pa.gw,CID_X),0,-1);
    2067             :     }
    2068           0 :     GWidgetIndicateFocusGadget(GWidgetGetControl(pa.gw,CID_X));
    2069           0 :     GDrawSetVisible(pa.gw,true);
    2070           0 :     GDrawProcessOneEvent(NULL);
    2071           0 :     if ( first )
    2072           0 :         GGadgetSetChecked(GWidgetGetControl(gw,CID_Exact),true);
    2073           0 :     while ( !pa.done )
    2074           0 :         GDrawProcessOneEvent(NULL);
    2075           0 :     GDrawSetVisible(pa.gw,false);
    2076             : 
    2077           0 : }

Generated by: LCOV version 1.10