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

          Line data    Source code
       1             : /* -*- coding: utf-8 -*- */
       2             : /* Copyright (C) 2000-2012 by George Williams */
       3             : /*
       4             :  * Redistribution and use in source and binary forms, with or without
       5             :  * modification, are permitted provided that the following conditions are met:
       6             : 
       7             :  * Redistributions of source code must retain the above copyright notice, this
       8             :  * list of conditions and the following disclaimer.
       9             : 
      10             :  * Redistributions in binary form must reproduce the above copyright notice,
      11             :  * this list of conditions and the following disclaimer in the documentation
      12             :  * and/or other materials provided with the distribution.
      13             : 
      14             :  * The name of the author may not be used to endorse or promote products
      15             :  * derived from this software without specific prior written permission.
      16             : 
      17             :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
      18             :  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
      19             :  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
      20             :  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
      21             :  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
      22             :  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
      23             :  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
      24             :  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      25             :  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
      26             :  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      27             :  */
      28             : #include "cvundoes.h"
      29             : #include "fontforgeui.h"
      30             : #include <math.h>
      31             : #include "splinefont.h"
      32             : #include "ustring.h"
      33             : 
      34           0 : static void SpAdjustTo(SplinePoint *sp,real newx, real newy) {
      35           0 :     sp->prevcp.x += newx-sp->me.x;
      36           0 :     sp->nextcp.x += newx-sp->me.x;
      37           0 :     sp->prevcp.y += newy-sp->me.y;
      38           0 :     sp->nextcp.y += newy-sp->me.y;
      39           0 :     sp->me.x = newx;
      40           0 :     sp->me.y = newy;
      41           0 : }
      42             : 
      43           0 : static void SpaceOne(CharView *cv,SplinePoint *sp) {
      44             :     SplinePoint *prev, *next;
      45             :     BasePoint v, new;
      46             :     real len, off;
      47             :     /* Rotate the coordinate system so that one axis is parallel to the */
      48             :     /*  line between sp->next->to and sp->prev->from. Position sp so that */
      49             :     /*  it is mid-way between the two on that axis while its distance from */
      50             :     /*  the axis (ie. the other coord) remains unchanged */
      51             :     /* Of course we do this with dot products rather than actual rotations */
      52             : 
      53           0 :     if ( sp->next==NULL || sp->prev==NULL )
      54           0 : return;
      55             : 
      56           0 :     prev = sp->prev->from; next = sp->next->to;
      57           0 :     if ( prev==next )
      58           0 : return;
      59             : 
      60           0 :     v.x = next->me.x - prev->me.x;
      61           0 :     v.y = next->me.y - prev->me.y;
      62           0 :     len = sqrt(v.x*v.x + v.y*v.y);
      63           0 :     if ( len==0 )
      64           0 : return;
      65           0 :     v.x /= len; v.y /= len;
      66           0 :     off = (sp->me.x-prev->me.x)*v.y - (sp->me.y-prev->me.y)*v.x;
      67           0 :     new.x = (next->me.x + prev->me.x)/2 + off*v.y;
      68           0 :     new.y = (next->me.y + prev->me.y)/2 - off*v.x;
      69             : 
      70           0 :     CVPreserveState((CharViewBase *) cv);
      71           0 :     SpAdjustTo(sp,new.x,new.y);
      72           0 :     SplineRefigure(sp->prev); SplineRefigure(sp->next);
      73           0 :     CVCharChangedUpdate(&cv->b);
      74             : }
      75             : 
      76           0 : static void SpaceMany(CharView *cv,DBounds *b, int dir, int region_size, int cnt) {
      77             :     SplinePoint *sp;
      78             :     SplineSet *spl;
      79             :     struct region { real begin, end, offset; } *regions;
      80             :     int rcnt,i,j;
      81             :     real range, rtot, space, rpos;
      82             : 
      83           0 :     if ( dir==-1 ) {
      84           0 :         if ( b->maxx - b->minx > b->maxy - b->miny )
      85           0 :             dir = 0;            /* Space out along x axis */
      86             :         else
      87           0 :             dir = 1;            /* Space out along y axis */
      88             :     }
      89             : 
      90           0 :     regions = malloc(cnt*sizeof(struct region));
      91           0 :     rcnt = 0;
      92           0 :     for ( spl= cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL; spl=spl->next ) {
      93           0 :         sp=spl->first;
      94             :         while ( 1 ) {
      95           0 :             if ( sp->selected ) {
      96           0 :                 real coord = dir?sp->me.y:sp->me.x;
      97           0 :                 for ( i=0; i<rcnt && coord>regions[i].end+region_size; ++i );
      98           0 :                 if ( i==rcnt ) {
      99           0 :                     regions[i].begin = regions[i].end = coord;
     100           0 :                     ++rcnt;
     101           0 :                 } else if ( coord<regions[i].begin-region_size ) {
     102           0 :                     for ( j=++rcnt; j>i; --j )
     103           0 :                         regions[j] = regions[j-1];
     104           0 :                     regions[i].begin = regions[i].end = coord;
     105             :                 } else {
     106           0 :                     if ( regions[i].begin>coord )
     107           0 :                         regions[i].begin = coord;
     108           0 :                     else if ( regions[i].end < coord ) {
     109           0 :                         regions[i].end = coord;
     110           0 :                         if ( i<rcnt-1 && regions[i].end+region_size>=regions[i+1].begin ) {
     111             :                             /* Merge two regions */
     112           0 :                             regions[i].end = regions[i+1].end;
     113           0 :                             --rcnt;
     114           0 :                             for ( j=i+1; j<rcnt; ++j )
     115           0 :                                 regions[j] = regions[j+1];
     116             :                         }
     117             :                     }
     118             :                 }
     119             :             }
     120           0 :             if ( sp->next==NULL )
     121           0 :         break;
     122           0 :             sp = sp->next->to;
     123           0 :             if ( sp==spl->first )
     124           0 :         break;
     125           0 :         }
     126             :     }
     127             : 
     128             :     /* we need at least three regions to space things out */
     129           0 :     if ( rcnt<3 )
     130           0 : return;
     131             : 
     132             :     /* Now should I allow equal spaces between regions, or spaces between */
     133             :     /*  region mid-points? I think spaces between regions */
     134           0 :     range = regions[rcnt-1].end-regions[0].begin;
     135           0 :     rtot = 0;
     136           0 :     for ( j=0; j<rcnt; ++j )
     137           0 :         rtot += regions[j].end-regions[j].begin;
     138           0 :     space = (range-rtot)/(rcnt-1);
     139           0 :     rpos = regions[0].begin;
     140           0 :     for ( j=0; j<rcnt-1; ++j ) {
     141           0 :         regions[j].offset = rpos-regions[j].begin;
     142           0 :         rpos += regions[j].end-regions[j].begin+space;
     143             :     }
     144           0 :     regions[rcnt-1].offset = 0;
     145             : 
     146           0 :     CVPreserveState((CharViewBase *) cv);
     147           0 :     for ( spl= cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL; spl=spl->next ) {
     148           0 :         sp=spl->first;
     149             :         while ( 1 ) {
     150           0 :             if ( sp->selected ) {
     151           0 :                 real coord = dir?sp->me.y:sp->me.x;
     152           0 :                 for ( i=0; i<rcnt && coord>regions[i].end; ++i );
     153           0 :                 if ( i==rcnt )
     154           0 :                     IError( "Region list is screwed up");
     155             :                 else {
     156           0 :                     if ( dir==0 ) {
     157           0 :                         sp->me.x += regions[i].offset;
     158           0 :                         sp->prevcp.x += regions[i].offset;
     159           0 :                         sp->nextcp.x += regions[i].offset;
     160             :                     } else {
     161           0 :                         sp->me.y += regions[i].offset;
     162           0 :                         sp->prevcp.y += regions[i].offset;
     163           0 :                         sp->nextcp.y += regions[i].offset;
     164             :                     }
     165           0 :                     if ( sp->prev!=NULL )
     166           0 :                         SplineRefigure(sp->prev);
     167           0 :                     if ( sp->next!=NULL )
     168           0 :                         SplineRefigure(sp->next);
     169             :                 }
     170             :             }
     171           0 :             if ( sp->next==NULL )
     172           0 :         break;
     173           0 :             sp = sp->next->to;
     174           0 :             if ( sp==spl->first )
     175           0 :         break;
     176           0 :         }
     177             :     }
     178           0 :     CVCharChangedUpdate(&cv->b);
     179           0 :     free(regions);
     180             : }
     181             : 
     182             : 
     183           0 : static void AlignTwoMaybeAsk(CharView *cv,SplinePoint *sp1, SplinePoint *sp2)
     184             : {
     185             :     real xoff, yoff, xpos, ypos;
     186           0 :     int HorizontalAlignment = 0;
     187             : 
     188           0 :     xoff = sp1->me.x - sp2->me.x;
     189           0 :     yoff = sp1->me.y - sp2->me.y;
     190           0 :     printf("AlignTwo() %f %f, %f %f,   xoff:%f  yoff:%f\n",
     191             :            sp1->me.x, sp2->me.x,
     192             :            sp1->me.y, sp2->me.y,
     193             :            xoff, yoff );
     194             : 
     195           0 :     if ( fabs(yoff)<fabs(xoff)/2 ) {
     196           0 :         printf("average y\n");
     197             :         /* average y */
     198           0 :         HorizontalAlignment = 0;
     199           0 :     } else if ( fabs(xoff)<fabs(yoff)/2 ) {
     200             :         /* average x */
     201           0 :         printf("average x\n");
     202           0 :         HorizontalAlignment = 1;
     203             :     }
     204             :     else {
     205             :         char *buts[5];
     206             : 
     207           0 :         buts[0] = _("_Horizontal");
     208           0 :         buts[1] = _("_Vertical");
     209           0 :         buts[2] = _("_Cancel");
     210           0 :         buts[3] = NULL;
     211             : 
     212           0 :         int asked = gwwv_ask(_("Align Points"),(const char **) buts,0,3,_("How to align these points?"));
     213           0 :         HorizontalAlignment = asked;
     214           0 :         if( asked == 2 )
     215           0 :             return;
     216             :     }
     217             : 
     218           0 :     CVPreserveState((CharViewBase *) cv);
     219           0 :     if ( HorizontalAlignment == 0 )
     220             :     {
     221           0 :         printf("average y\n");
     222             :         /* average y */
     223           0 :         ypos = rint( (sp1->me.y+sp2->me.y)/2 );
     224           0 :         sp1->prevcp.y += ypos-sp1->me.y;
     225           0 :         sp1->nextcp.y += ypos-sp1->me.y;
     226           0 :         sp2->prevcp.y += ypos-sp2->me.y;
     227           0 :         sp2->nextcp.y += ypos-sp2->me.y;
     228           0 :         sp1->me.y = sp2->me.y = ypos;
     229             :     }
     230             :     else
     231             :     {
     232             :         /* average x */
     233           0 :         printf("average x\n");
     234           0 :         xpos = rint( (sp1->me.x+sp2->me.x)/2 );
     235           0 :         sp1->prevcp.x += xpos-sp1->me.x;
     236           0 :         sp1->nextcp.x += xpos-sp1->me.x;
     237           0 :         sp2->prevcp.x += xpos-sp2->me.x;
     238           0 :         sp2->nextcp.x += xpos-sp2->me.x;
     239           0 :         sp1->me.x = sp2->me.x = xpos;
     240             :     }
     241             : 
     242           0 :     if ( sp1->prev ) SplineRefigure(sp1->prev);
     243           0 :     if ( sp1->next ) SplineRefigure(sp1->next);
     244           0 :     if ( sp2->prev ) SplineRefigure(sp2->prev);
     245           0 :     if ( sp2->next ) SplineRefigure(sp2->next);
     246           0 :     CVCharChangedUpdate(&cv->b);
     247             : }
     248             : 
     249           0 : static void AlignManyMaybeAsk(CharView *cv,DBounds *b) {
     250             :     real xoff, yoff, xpos, ypos;
     251             :     SplinePoint *sp;
     252             :     SplineSet *spl;
     253           0 :     int HorizontalAlignment = 0;
     254             : 
     255           0 :     xoff = b->maxx - b->minx;
     256           0 :     yoff = b->maxy - b->miny;
     257             : 
     258           0 :     if ( yoff<xoff )
     259             :     {
     260             :         /* average y */
     261           0 :         HorizontalAlignment = 0;
     262             :     }
     263           0 :     else if ( xoff<yoff/2 )
     264             :     {
     265             :         /* constrain x */
     266           0 :         HorizontalAlignment = 1;
     267             :     }
     268             :     else
     269             :     {
     270             :         char *buts[5];
     271             : 
     272           0 :         buts[0] = _("_Horizontal");
     273           0 :         buts[1] = _("_Vertical");
     274           0 :         buts[2] = _("_Cancel");
     275           0 :         buts[3] = NULL;
     276             : 
     277           0 :         int asked = gwwv_ask(_("Align Points"),(const char **) buts,0,3,_("How to align these points?"));
     278           0 :         HorizontalAlignment = asked;
     279           0 :         if( asked == 2 )
     280           0 :             return;
     281             :     }
     282             : 
     283           0 :     CVPreserveState((CharViewBase *) cv);
     284           0 :     if ( HorizontalAlignment == 0 )
     285             :     {
     286             :         /* average y */
     287           0 :         ypos = rint( (b->maxy+b->miny)/2 );
     288           0 :         for ( spl= cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL; spl=spl->next )
     289             :         {
     290           0 :             sp=spl->first;
     291             :             while ( 1 ) {
     292           0 :                 if ( sp->selected ) {
     293           0 :                     sp->prevcp.y += ypos-sp->me.y;
     294           0 :                     sp->nextcp.y += ypos-sp->me.y;
     295           0 :                     sp->me.y = ypos;
     296           0 :                     if ( sp->prev ) SplineRefigure(sp->prev);
     297           0 :                     if ( sp->next ) SplineRefigure(sp->next);
     298             :                 }
     299           0 :                 if ( sp->next==NULL )
     300           0 :             break;
     301           0 :                 sp = sp->next->to;
     302           0 :                 if ( sp==spl->first )
     303           0 :             break;
     304           0 :             }
     305             :         }
     306             :     }
     307             :     else
     308             :     {
     309             :         /* constrain x */
     310           0 :         xpos = rint( (b->maxx+b->minx)/2 );
     311           0 :         for ( spl= cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL; spl=spl->next )
     312             :         {
     313           0 :             sp=spl->first;
     314             :             while ( 1 ) {
     315           0 :                 if ( sp->selected ) {
     316           0 :                     sp->prevcp.x += xpos-sp->me.x;
     317           0 :                     sp->nextcp.x += xpos-sp->me.x;
     318           0 :                     sp->me.x = xpos;
     319           0 :                     if ( sp->prev ) SplineRefigure(sp->prev);
     320           0 :                     if ( sp->next ) SplineRefigure(sp->next);
     321             :                 }
     322           0 :                 if ( sp->next==NULL )
     323           0 :             break;
     324           0 :                 sp = sp->next->to;
     325           0 :                 if ( sp==spl->first )
     326           0 :             break;
     327           0 :             }
     328             :         }
     329             :     }
     330           0 :     CVCharChangedUpdate(&cv->b);
     331             : }
     332             : 
     333             : 
     334             : struct rcd {
     335             :     CharView *cv;
     336             :     int done;
     337             :     DBounds *b;
     338             :     int cnt;
     339             : };
     340             : static double lastsize = 100;
     341             : 
     342             : #define CID_Y           1001
     343             : #define CID_X           1002
     344             : #define CID_Size        1003
     345             : 
     346             : 
     347           0 : static int RC_OK(GGadget *g, GEvent *e) {
     348           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
     349           0 :         GWindow gw = GGadgetGetWindow(g);
     350           0 :         struct rcd *rcd = GDrawGetUserData(gw);
     351           0 :         int err=false;
     352             :         real size;
     353           0 :         int dir = GGadgetIsChecked(GWidgetGetControl(gw,CID_Y));
     354           0 :         size = GetReal8(gw,CID_Size,_("_Size:"),&err);
     355           0 :         if ( err )
     356           0 : return(true);
     357           0 :         SpaceMany(rcd->cv,rcd->b, dir, size, rcd->cnt);
     358             : 
     359           0 :         rcd->done = true;
     360             :     }
     361           0 : return( true );
     362             : }
     363             : 
     364           0 : static int RC_Cancel(GGadget *g, GEvent *e) {
     365           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
     366           0 :         struct rcd *rcd = GDrawGetUserData(GGadgetGetWindow(g));
     367           0 :         rcd->done = true;
     368             :     }
     369           0 : return( true );
     370             : }
     371             : 
     372           0 : static int rcd_e_h(GWindow gw, GEvent *event) {
     373           0 :     if ( event->type==et_close ) {
     374           0 :         struct rcd *rcd = GDrawGetUserData(gw);
     375           0 :         rcd->done = true;
     376             :     }
     377           0 : return( event->type!=et_char );
     378             : }
     379             : 
     380           0 : static void RegionControl(CharView *cv,DBounds *b,int cnt) {
     381             :     GRect pos;
     382             :     GWindow gw;
     383             :     GWindowAttrs wattrs;
     384             :     GGadgetCreateData gcd[9], boxes[5], *rarray[5], *narray[5], *barray[10], *hvarray[7][2];
     385             :     GTextInfo label[9];
     386             :     struct rcd rcd;
     387             :     char buffer[20];
     388             : 
     389           0 :     rcd.cv = cv;
     390           0 :     rcd.b = b;
     391           0 :     rcd.cnt = cnt;
     392           0 :     rcd.done = false;
     393             : 
     394           0 :         memset(&wattrs,0,sizeof(wattrs));
     395           0 :         wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict;
     396           0 :         wattrs.event_masks = ~(1<<et_charup);
     397           0 :         wattrs.restrict_input_to_me = 1;
     398           0 :         wattrs.undercursor = 1;
     399           0 :         wattrs.cursor = ct_pointer;
     400           0 :         wattrs.utf8_window_title = _("Space Regions");
     401           0 :         wattrs.is_dlg = true;
     402           0 :         pos.x = pos.y = 0;
     403           0 :         pos.width = GGadgetScale(GDrawPointsToPixels(NULL,225));
     404           0 :         pos.height = GDrawPointsToPixels(NULL,115);
     405           0 :         gw = GDrawCreateTopWindow(NULL,&pos,rcd_e_h,&rcd,&wattrs);
     406             : 
     407           0 :         memset(&label,0,sizeof(label));
     408           0 :         memset(&gcd,0,sizeof(gcd));
     409           0 :         memset(&boxes,0,sizeof(boxes));
     410             : 
     411           0 :         label[0].text = (unichar_t *) _("Coordinate along which to space");
     412           0 :         label[0].text_is_1byte = true;
     413           0 :         gcd[0].gd.label = &label[0];
     414           0 :         gcd[0].gd.pos.x = 5; gcd[0].gd.pos.y = 6;
     415           0 :         gcd[0].gd.flags = gg_enabled|gg_visible;
     416           0 :         gcd[0].creator = GLabelCreate;
     417           0 :         hvarray[0][0] = &gcd[0]; hvarray[0][1] = NULL;
     418             : 
     419           0 :         label[1].text = (unichar_t *) _("_X");
     420           0 :         label[1].text_is_1byte = true;
     421           0 :         label[1].text_in_resource = true;
     422           0 :         gcd[1].gd.label = &label[1];
     423           0 :         gcd[1].gd.pos.x = 25; gcd[1].gd.pos.y = gcd[0].gd.pos.y+13;
     424           0 :         gcd[1].gd.flags = gg_enabled|gg_visible;
     425           0 :         gcd[1].creator = GRadioCreate;
     426           0 :         gcd[1].gd.cid = CID_X;
     427           0 :         rarray[0] = GCD_HPad10; rarray[1] = &gcd[1];
     428             : 
     429           0 :         label[2].text = (unichar_t *) _("_Y");
     430           0 :         label[2].text_is_1byte = true;
     431           0 :         label[2].text_in_resource = true;
     432           0 :         gcd[2].gd.label = &label[2];
     433           0 :         gcd[2].gd.pos.x = 60; //FIXME: gcd[2].gd.pos.y = gcd[2].gd.pos.y;
     434           0 :         gcd[2].gd.flags = gg_enabled|gg_visible;
     435           0 :         gcd[2].gd.cid = CID_Y;
     436           0 :         gcd[2].creator = GRadioCreate;
     437           0 :         rarray[2] = &gcd[2];
     438           0 :         rarray[3] = GCD_Glue; rarray[4] = NULL;
     439             : 
     440           0 :         boxes[2].gd.flags = gg_enabled | gg_visible;
     441           0 :         boxes[2].gd.u.boxelements = rarray;
     442           0 :         boxes[2].creator = GHBoxCreate;
     443           0 :         hvarray[1][0] = &boxes[2]; hvarray[1][1] = NULL;
     444             : 
     445           0 :         if ( b->maxx-b->minx > b->maxy-b->miny )
     446           0 :             gcd[1].gd.flags |= gg_cb_on;
     447             :         else
     448           0 :             gcd[2].gd.flags |= gg_cb_on;
     449             : 
     450           0 :         label[3].text = (unichar_t *) _("_Maximum distance between points in a region");
     451           0 :         label[3].text_is_1byte = true;
     452           0 :         label[3].text_in_resource = true;
     453           0 :         gcd[3].gd.label = &label[3];
     454           0 :         gcd[3].gd.pos.x = 5; gcd[3].gd.pos.y = gcd[1].gd.pos.y+16;
     455           0 :         gcd[3].gd.flags = gg_enabled|gg_visible;
     456           0 :         gcd[3].creator = GLabelCreate;
     457           0 :         hvarray[2][0] = &gcd[3]; hvarray[2][1] = NULL;
     458             : 
     459           0 :         sprintf( buffer, "%g", lastsize );
     460           0 :         label[4].text = (unichar_t *) buffer;
     461           0 :         label[4].text_is_1byte = true;
     462           0 :         gcd[4].gd.label = &label[4];
     463           0 :         gcd[4].gd.pos.x = gcd[1].gd.pos.x; gcd[4].gd.pos.y = gcd[3].gd.pos.y+14;  gcd[4].gd.pos.width = 40;
     464           0 :         gcd[4].gd.flags = gg_enabled|gg_visible;
     465           0 :         gcd[4].gd.cid = CID_Size;
     466           0 :         gcd[4].creator = GNumericFieldCreate;
     467           0 :         narray[0] = GCD_HPad10; narray[1] = &gcd[4]; narray[2] = GCD_Glue; narray[3] = NULL;
     468             : 
     469           0 :         boxes[3].gd.flags = gg_enabled | gg_visible;
     470           0 :         boxes[3].gd.u.boxelements = narray;
     471           0 :         boxes[3].creator = GHBoxCreate;
     472           0 :         hvarray[3][0] = &boxes[3]; hvarray[3][1] = NULL;
     473             : 
     474           0 :         gcd[5].gd.pos.x = 20-3; gcd[5].gd.pos.y = gcd[4].gd.pos.y+35-3;
     475           0 :         gcd[5].gd.flags = gg_visible | gg_enabled | gg_but_default;
     476           0 :         label[5].text = (unichar_t *) _("_OK");
     477           0 :         label[5].text_is_1byte = true;
     478           0 :         label[5].text_in_resource = true;
     479           0 :         gcd[5].gd.mnemonic = 'O';
     480           0 :         gcd[5].gd.label = &label[5];
     481           0 :         gcd[5].gd.handle_controlevent = RC_OK;
     482           0 :         gcd[5].creator = GButtonCreate;
     483           0 :         barray[0] = GCD_Glue; barray[1] = &gcd[5]; barray[2] = barray[3] = barray[4] = barray[5] = GCD_Glue;
     484             : 
     485           0 :         gcd[6].gd.pos.x = -20; gcd[6].gd.pos.y = gcd[5].gd.pos.y+3;
     486           0 :         gcd[6].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
     487           0 :         label[6].text = (unichar_t *) _("_Cancel");
     488           0 :         label[6].text_is_1byte = true;
     489           0 :         label[6].text_in_resource = true;
     490           0 :         gcd[6].gd.label = &label[6];
     491           0 :         gcd[6].gd.mnemonic = 'C';
     492           0 :         gcd[6].gd.handle_controlevent = RC_Cancel;
     493           0 :         gcd[6].creator = GButtonCreate;
     494           0 :         barray[5] = &gcd[6]; barray[6] = GCD_Glue; barray[7] = NULL;
     495             : 
     496           0 :         boxes[4].gd.flags = gg_enabled | gg_visible;
     497           0 :         boxes[4].gd.u.boxelements = barray;
     498           0 :         boxes[4].creator = GHBoxCreate;
     499           0 :         hvarray[4][0] = GCD_Glue; hvarray[4][1] = NULL;
     500           0 :         hvarray[5][0] = &boxes[4]; hvarray[5][1] = NULL;
     501           0 :         hvarray[6][0] = NULL;
     502             : 
     503           0 :         boxes[0].gd.pos.x = boxes[0].gd.pos.y = 2;
     504           0 :         boxes[0].gd.flags = gg_enabled | gg_visible;
     505           0 :         boxes[0].gd.u.boxelements = hvarray[0];
     506           0 :         boxes[0].creator = GHVGroupCreate;
     507             : 
     508           0 :         GGadgetsCreate(gw,boxes);
     509           0 :         GHVBoxSetExpandableRow(boxes[0].ret,gb_expandglue);
     510           0 :         GHVBoxSetExpandableCol(boxes[2].ret,gb_expandglue);
     511           0 :         GHVBoxSetExpandableCol(boxes[3].ret,gb_expandglue);
     512           0 :         GHVBoxSetExpandableCol(boxes[4].ret,gb_expandgluesame);
     513           0 :         GHVBoxFitWindow(boxes[0].ret);
     514             : 
     515           0 :     GTextFieldSelect(GWidgetGetControl(gw,CID_Size),0,-1);
     516             : 
     517           0 :     GDrawSetVisible(gw,true);
     518           0 :     while ( !rcd.done )
     519           0 :         GDrawProcessOneEvent(NULL);
     520           0 :     GDrawDestroyWindow(gw);
     521           0 : }
     522             : 
     523           0 : void CVConstrainSelection(CharView *cv,constrainSelection_t type) {
     524             :     DBounds b;
     525           0 :     SplinePoint *first=NULL, *second=NULL, *other=NULL, *sp;
     526             :     SplineSet *spl;
     527           0 :     int cnt=0;
     528             : 
     529           0 :     for ( spl= cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL; spl=spl->next ) {
     530           0 :         sp=spl->first;
     531             :         while ( 1 ) {
     532           0 :             if ( sp->selected ) {
     533           0 :                 ++cnt;
     534           0 :                 if ( first == NULL ) {
     535           0 :                     first = sp;
     536           0 :                     b.minx = b.maxx = sp->me.x;
     537           0 :                     b.miny = b.maxy = sp->me.y;
     538             :                 } else {
     539           0 :                     if ( second==NULL ) second = sp;
     540           0 :                     else other = sp;
     541           0 :                     if ( b.minx>sp->me.x ) b.minx = sp->me.x;
     542           0 :                     if ( b.maxx<sp->me.x ) b.maxx = sp->me.x;
     543           0 :                     if ( b.miny>sp->me.y ) b.miny = sp->me.y;
     544           0 :                     if ( b.maxy<sp->me.y ) b.maxy = sp->me.y;
     545             :                 }
     546             :             }
     547           0 :             if ( sp->next==NULL )
     548           0 :         break;
     549           0 :             sp = sp->next->to;
     550           0 :             if ( sp==spl->first )
     551           0 :         break;
     552           0 :         }
     553             :     }
     554             : 
     555           0 :     if ( type == constrainSelection_AveragePoints ) {
     556             :         /* Average points */
     557           0 :         if ( second==NULL )
     558             :             /* Do Nothing */;
     559           0 :         else if ( !other )
     560           0 :             AlignTwoMaybeAsk(cv,first,second);
     561             :         else
     562           0 :             AlignManyMaybeAsk(cv,&b);
     563           0 :     } else if ( type == constrainSelection_SpacePoints ) {
     564             :         /* Space points */
     565           0 :         if ( other!=NULL )
     566           0 :             SpaceMany(cv,&b,-1,0,cnt);
     567           0 :         else if ( second!=NULL )
     568             :             /* Can't deal with it */;
     569           0 :         else if ( first!=NULL )
     570           0 :             SpaceOne(cv,first);
     571             :         else {
     572             :             /* Nothing selected */;
     573             :         }
     574           0 :     } else if ( type == constrainSelection_SpaceSelectedRegions ) {
     575             :         /* Space selected regions */
     576           0 :         if ( other==NULL )
     577           0 : return;         /* Do nothing, need at least three regions */
     578           0 :         RegionControl(cv,&b,cnt);
     579             :     }
     580             : }
     581             : 
     582           0 : static void MakeParallel(Spline *e1, Spline *e2, SplinePoint *mobile) {
     583             :     /* Splines e1&e2 are to be made parallel */
     584             :     /* The spline containing mobile is the one which is to be moved */
     585             :     Spline *temp;
     586             :     double xdiff, ydiff, axdiff, aydiff;
     587             :     SplinePoint *other;
     588             : 
     589           0 :     if ( e1->to==mobile || e1->from==mobile ) {
     590           0 :         temp = e1;
     591           0 :         e1 = e2;
     592           0 :         e2 = temp;
     593             :     }
     594             :     /* Now the spline to be moved is e2 */
     595           0 :     other = e2->from==mobile ? e2->to : e2->from;
     596             : 
     597           0 :     if ( (axdiff = xdiff = e1->to->me.x-e1->from->me.x)<0 ) axdiff = -axdiff;
     598           0 :     if ( (aydiff = ydiff = e1->to->me.y-e1->from->me.y)<0 ) aydiff = -aydiff;
     599           0 :     if ( aydiff > axdiff ) {
     600             :         /* Hold the y coordinate fixed in e2 and move the x coord appropriately */
     601           0 :         int oldx = mobile->me.x;
     602           0 :         mobile->me.x = (mobile->me.y-other->me.y)*xdiff/ydiff + other->me.x;
     603           0 :         mobile->nextcp.x += mobile->me.x-oldx;
     604           0 :         mobile->prevcp.x += mobile->me.x-oldx;
     605             :     } else {
     606           0 :         int oldy = mobile->me.y;
     607           0 :         mobile->me.y = (mobile->me.x-other->me.x)*ydiff/xdiff + other->me.y;
     608           0 :         mobile->nextcp.y += mobile->me.y-oldy;
     609           0 :         mobile->prevcp.y += mobile->me.y-oldy;
     610             :     }
     611           0 :     if ( mobile->next!=NULL )
     612           0 :         SplineRefigure(mobile->prev);
     613           0 :     if ( mobile->prev!=NULL )
     614           0 :         SplineRefigure(mobile->next);
     615           0 : }
     616             : 
     617           0 : static void MakeParallelogram(Spline *e11, Spline *e12, Spline *e21, Spline *e22,
     618             :         SplinePoint *mobile) {
     619             :     /* Splines e11&e12 are to be made parallel, as are e21&e22 */
     620             :     /* The spline containing mobile is the one which is to be moved */
     621             :     Spline *temp;
     622             :     SplinePoint *other1, *other2, *unconnected;
     623             :     double denom;
     624             : 
     625           0 :     if ( e11->to==mobile || e11->from==mobile ) {
     626           0 :         temp = e11;
     627           0 :         e11 = e12;
     628           0 :         e12 = temp;
     629             :     }
     630           0 :     if ( e21->to==mobile || e21->from==mobile ) {
     631           0 :         temp = e21;
     632           0 :         e21 = e22;
     633           0 :         e22 = temp;
     634             :     }
     635             :     /* Now the splines to be moved are e?2, while e?1 is held fixed */
     636           0 :     other1 = e12->from==mobile ? e12->to : e12->from;
     637           0 :     other2 = e22->from==mobile ? e22->to : e22->from;
     638           0 :     unconnected = e11->from==other2 ? e11->to : e11->from;
     639             : 
     640           0 :     denom = (unconnected->me.y-other1->me.y)*(unconnected->me.x-other2->me.x) -
     641           0 :             (unconnected->me.y-other2->me.y)*(unconnected->me.x-other1->me.x);
     642           0 :     if ( denom>-.0001 && denom<.0001 ) {
     643             :         /* The two splines e11 and e21 are essentially parallel, so we can't */
     644             :         /*  move mobile to the place where they intersect */
     645           0 :         mobile->me = unconnected->me;
     646             :     } else {
     647           0 :         mobile->me.y =
     648           0 :             ((other2->me.x-other1->me.x)*(unconnected->me.y-other1->me.y)*
     649           0 :                     (unconnected->me.y-other2->me.y) -
     650           0 :                 other2->me.y*(unconnected->me.y-other2->me.y)*(unconnected->me.x-other1->me.x) +
     651           0 :                 other1->me.y*(unconnected->me.y-other1->me.y)*(unconnected->me.x-other2->me.x))/
     652             :              denom;
     653           0 :         if ( unconnected->me.y-other1->me.y==0 )
     654           0 :             mobile->me.x = other1->me.x + (unconnected->me.x-other2->me.x)/(unconnected->me.y-other2->me.y)*
     655           0 :                     (mobile->me.y-other1->me.y);
     656             :         else
     657           0 :             mobile->me.x = other2->me.x + (unconnected->me.x-other1->me.x)/(unconnected->me.y-other1->me.y)*
     658           0 :                     (mobile->me.y-other2->me.y);
     659             :     }
     660           0 :     mobile->nextcp = mobile->prevcp = mobile->me;
     661           0 :     SplineRefigure(mobile->prev);
     662           0 :     SplineRefigure(mobile->next);
     663           0 : }
     664             : 
     665           0 : static int CommonEndPoint(Spline *s1, Spline *s2) {
     666           0 : return( s1->to==s2->to || s1->to==s2->from || s1->from==s2->to || s1->from==s2->from );
     667             : }
     668             : 
     669           0 : void CVMakeParallel(CharView *cv) {
     670             :     /* takes exactly four selected points and tries to find two lines between */
     671             :     /*  them which it then makes parallel */
     672             :     /* If the points are a quadralateral then we make it a parallelogram */
     673             :     /* If the points define 3 lines then throw out the middle one */
     674             :     /* If the points define 2 lines then good */
     675             :     /* Else complain */
     676             :     /* If possible, fix things by moving the lastselpt */
     677             :     SplinePoint *pts[4];
     678             :     Spline *edges[4];
     679           0 :     int cnt=0, mobilis;
     680             :     SplineSet *ss;
     681             :     SplinePoint *sp;
     682             : 
     683           0 :     for ( ss = cv->b.layerheads[cv->b.drawmode]->splines; ss!=NULL; ss=ss->next ) {
     684           0 :         for ( sp=ss->first; ; ) {
     685           0 :             if ( sp->selected ) {
     686           0 :                 if ( cnt>=4 )
     687           0 : return;
     688           0 :                 pts[cnt++] = sp;
     689             :             }
     690           0 :             if ( sp->next==NULL )
     691           0 :         break;
     692           0 :             sp = sp->next->to;
     693           0 :             if ( sp == ss->first )
     694           0 :         break;
     695           0 :         }
     696             :     }
     697           0 :     if ( cnt!=4 )
     698           0 : return;
     699             : 
     700           0 :     for ( mobilis=0; mobilis<4; ++mobilis )
     701           0 :         if ( pts[mobilis]==cv->lastselpt )
     702           0 :     break;
     703           0 :     if ( mobilis==4 ) mobilis=3;                /* lastselpt didn't match, pick one */
     704             : 
     705           0 :     cnt=0;
     706           0 :     if ( pts[0]->next!=NULL && pts[0]->next->islinear &&
     707           0 :             (pts[0]->next->to==pts[1] ||
     708           0 :              pts[0]->next->to==pts[2] ||
     709           0 :              pts[0]->next->to==pts[3]) &&
     710           0 :              (pts[0]->me.x!=pts[0]->next->to->me.x || pts[0]->me.y!=pts[0]->next->to->me.y))
     711           0 :          edges[cnt++] = pts[0]->next;
     712           0 :     if ( pts[1]->next!=NULL && pts[1]->next->islinear &&
     713           0 :             (pts[1]->next->to==pts[0] ||
     714           0 :              pts[1]->next->to==pts[2] ||
     715           0 :              pts[1]->next->to==pts[3]) &&
     716           0 :              (pts[1]->me.x!=pts[1]->next->to->me.x || pts[1]->me.y!=pts[1]->next->to->me.y))
     717           0 :          edges[cnt++] = pts[1]->next;
     718           0 :     if ( pts[2]->next!=NULL && pts[2]->next->islinear &&
     719           0 :             (pts[2]->next->to==pts[0] ||
     720           0 :              pts[2]->next->to==pts[1] ||
     721           0 :              pts[2]->next->to==pts[3]) &&
     722           0 :              (pts[2]->me.x!=pts[2]->next->to->me.x || pts[2]->me.y!=pts[2]->next->to->me.y))
     723           0 :          edges[cnt++] = pts[2]->next;
     724           0 :     if ( pts[3]->next!=NULL && pts[3]->next->islinear &&
     725           0 :             (pts[3]->next->to==pts[0] ||
     726           0 :              pts[3]->next->to==pts[1] ||
     727           0 :              pts[3]->next->to==pts[2]) &&
     728           0 :              (pts[3]->me.x!=pts[3]->next->to->me.x || pts[3]->me.y!=pts[3]->next->to->me.y))
     729           0 :          edges[cnt++] = pts[3]->next;
     730             : 
     731           0 :     if ( cnt<2 ) {
     732           0 :         ff_post_error(_("Not enough lines"),_("Not enough lines"));
     733           0 : return;
     734           0 :     } else if ( cnt==2 && CommonEndPoint(edges[0],edges[1]) ) {
     735           0 :         ff_post_error(_("Can't Parallel"),_("These two lines share a common endpoint, I can't make them parallel"));
     736           0 : return;
     737             :     }
     738             : 
     739           0 :     CVPreserveState((CharViewBase *) cv);
     740           0 :     if ( cnt==4 ) {
     741           0 :         int second=3, third=1, fourth=2;
     742           0 :         if ( !CommonEndPoint(edges[0],edges[1])) {
     743           0 :             second = 1; third = 3;
     744           0 :         } else if ( !CommonEndPoint(edges[0],edges[2])) {
     745           0 :             second = 2;
     746           0 :             fourth = 3;
     747             :         }
     748           0 :         MakeParallelogram(edges[0],edges[second], edges[third],edges[fourth],
     749             :                 pts[mobilis]);
     750           0 :     } else if ( cnt==3 ) {
     751           0 :         if ( !CommonEndPoint(edges[0],edges[1]) )
     752           0 :             MakeParallel(edges[0],edges[1],pts[mobilis]);
     753           0 :         else if ( !CommonEndPoint(edges[0],edges[2]) )
     754           0 :             MakeParallel(edges[0],edges[2],pts[mobilis]);
     755             :         else
     756           0 :             MakeParallel(edges[1],edges[2],pts[mobilis]);
     757             :     } else {
     758           0 :         MakeParallel(edges[0],edges[1],pts[mobilis]);
     759             :     }
     760           0 :     CVCharChangedUpdate(&cv->b);
     761             : }

Generated by: LCOV version 1.10