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

          Line data    Source code
       1             : /* Copyright (C) 2000-2012 by George Williams */
       2             : /*
       3             :  * Redistribution and use in source and binary forms, with or without
       4             :  * modification, are permitted provided that the following conditions are met:
       5             : 
       6             :  * Redistributions of source code must retain the above copyright notice, this
       7             :  * list of conditions and the following disclaimer.
       8             : 
       9             :  * Redistributions in binary form must reproduce the above copyright notice,
      10             :  * this list of conditions and the following disclaimer in the documentation
      11             :  * and/or other materials provided with the distribution.
      12             : 
      13             :  * The name of the author may not be used to endorse or promote products
      14             :  * derived from this software without specific prior written permission.
      15             : 
      16             :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
      17             :  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
      18             :  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
      19             :  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
      20             :  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
      21             :  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
      22             :  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
      23             :  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      24             :  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
      25             :  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      26             :  */
      27             : #include "fontforgeui.h"
      28             : #include "splineutil.h"
      29             : #include "splineutil2.h"
      30             : #include <math.h>
      31             : #include <ustring.h>
      32             : 
      33             : #include "cvruler.h"
      34             : 
      35             : int measuretoolshowhorizontolvertical = true;
      36             : Color measuretoollinecol = 0x000000;
      37             : Color measuretoolpointcol = 0xFF0000;
      38             : Color measuretoolpointsnappedcol = 0x00FF00;
      39             : Color measuretoolcanvasnumberscol = 0xFF0000;
      40             : Color measuretoolcanvasnumberssnappedcol = 0x00FF00;
      41             : Color measuretoolwindowforegroundcol = 0x000000;
      42             : Color measuretoolwindowbackgroundcol = 0xe0e0c0;
      43             : 
      44             : BasePoint last_ruler_offset[2] = { {0,0}, {0,0} };
      45             : int infowindowdistance = 30;
      46             : 
      47           0 : static void SlopeToBuf(char *buf,char *label,double dx, double dy) {
      48           0 :     if ( dx==0 && dy==0 )
      49           0 :         sprintf( buf, _("%s No Slope"), label );
      50           0 :     else if ( dx==0 )
      51           0 :         sprintf( buf, "%s dy/dx= ∞, %4g°", label, atan2(dy,dx)*180/3.1415926535897932);
      52             :     else
      53           0 :         sprintf( buf, "%s dy/dx= %4g, %4g°", label, dy/dx, atan2(dy,dx)*180/3.1415926535897932);
      54           0 : }
      55             : 
      56           0 : static void CurveToBuf(char *buf,CharView *cv,Spline *s, double t) {
      57             :     double kappa, emsize;
      58             : 
      59           0 :     kappa = SplineCurvature(s,t);
      60           0 :     if ( kappa==CURVATURE_ERROR )
      61           0 :         strcpy(buf,_("No Curvature"));
      62             :     else {
      63           0 :         emsize = cv->b.sc->parent->ascent + cv->b.sc->parent->descent;
      64           0 :         if ( kappa==0 )
      65           0 :             sprintf(buf,_(" Curvature: %g"), kappa*emsize);
      66             :         else
      67           0 :             sprintf(buf,_(" Curvature: %g  Radius: %g"), kappa*emsize, 1.0/kappa );
      68             :     }
      69           0 : }
      70             : 
      71           0 : static int RulerText(CharView *cv, unichar_t *ubuf, int line) {
      72             :     char buf[80];
      73             :     double len;
      74             :     double dx, dy;
      75             :     Spline *s;
      76             :     double t;
      77             :     BasePoint slope;
      78           0 :     real xoff = cv->info.x-cv->p.cx, yoff = cv->info.y-cv->p.cy;
      79             : 
      80           0 :     buf[0] = '\0';
      81           0 :     switch ( line ) {
      82             :       case 0: {
      83           0 :         real len = sqrt(xoff*xoff+yoff*yoff);
      84             : 
      85           0 :         if ( cv->autonomous_ruler_w ) {
      86           0 :             xoff = last_ruler_offset[0].x;
      87           0 :             yoff = last_ruler_offset[0].y;
      88             :         }
      89             : 
      90           0 :         if ( !cv->autonomous_ruler_w && !cv->p.pressed )
      91             :             /* Give current location accurately */
      92           0 :             sprintf( buf, "%f,%f", (double) cv->info.x, (double) cv->info.y);
      93             :         else
      94           0 :             sprintf( buf, "%f %.0f° (%f,%f)", (double) len,
      95           0 :                     atan2(yoff,xoff)*180/3.1415926535897932,
      96             :                     (double) xoff,(double) yoff);
      97           0 :       break; }
      98             :       case 1:
      99           0 :         if ( cv->p.pressed ) {
     100           0 :             if ( cv->p.spline!=NULL ||
     101           0 :                     (cv->p.sp!=NULL &&
     102           0 :                      ((cv->p.sp->next==NULL && cv->p.sp->prev!=NULL) ||
     103           0 :                       (cv->p.sp->prev==NULL && cv->p.sp->next!=NULL) ||
     104           0 :                       (cv->p.sp->next!=NULL && cv->p.sp->prev!=NULL &&
     105           0 :                         BpColinear(!cv->p.sp->noprevcp ? &cv->p.sp->prevcp : &cv->p.sp->prev->from->me,
     106           0 :                                 &cv->p.sp->me,
     107           0 :                                 !cv->p.sp->nonextcp ? &cv->p.sp->nextcp : &cv->p.sp->next->to->me))) ) ) {
     108             :                 Spline *spline;
     109             :                 double t;
     110             : 
     111           0 :                 if ( cv->p.spline!=NULL ) {
     112           0 :                     spline = cv->p.spline;
     113           0 :                     t = cv->p.t;
     114           0 :                 } else if ( cv->p.sp->next == NULL ) {
     115           0 :                     spline = cv->p.sp->prev;
     116           0 :                     t = 1;
     117             :                 } else {
     118           0 :                     spline = cv->p.sp->next;
     119           0 :                     t = 0;
     120             :                 }
     121           0 :                 slope.x = (3*spline->splines[0].a*t + 2*spline->splines[0].b)*t + spline->splines[0].c;
     122           0 :                 slope.y = (3*spline->splines[1].a*t + 2*spline->splines[1].b)*t + spline->splines[1].c;
     123           0 :                 len = sqrt(slope.x*slope.x + slope.y*slope.y);
     124           0 :                 if ( len!=0 ) {
     125           0 :                     slope.x /= len; slope.y /= len;
     126           0 :                     sprintf( buf, _("Normal Distance: %.2f Along Spline: %.2f"),
     127           0 :                             fabs(slope.y*xoff - slope.x*yoff),
     128           0 :                             slope.x*xoff + slope.y*yoff );
     129             :                 }
     130             :             }
     131           0 :         } else if ( cv->dv!=NULL || cv->b.gridfit!=NULL ) {
     132           0 :             double scalex = (cv->b.sc->parent->ascent+cv->b.sc->parent->descent)/(rint(cv->ft_pointsizex*cv->ft_dpi/72.0));
     133           0 :             double scaley = (cv->b.sc->parent->ascent+cv->b.sc->parent->descent)/(rint(cv->ft_pointsizey*cv->ft_dpi/72.0));
     134           0 :             sprintf( buf, "%.2f,%.2f", (double) (cv->info.x/scalex), (double) (cv->info.y/scaley));
     135           0 :         } else if ( cv->p.spline!=NULL ) {
     136           0 :             s = cv->p.spline;
     137           0 :             t = cv->p.t;
     138           0 :             sprintf( buf, _("Near (%f,%f)"),
     139           0 :                     (double) (((s->splines[0].a*t+s->splines[0].b)*t+s->splines[0].c)*t+s->splines[0].d),
     140           0 :                     (double) (((s->splines[1].a*t+s->splines[1].b)*t+s->splines[1].c)*t+s->splines[1].d) );
     141           0 :         } else if ( cv->p.sp!=NULL ) {
     142           0 :             sprintf( buf, _("Near (%f,%f)"),(double) cv->p.sp->me.x,(double) cv->p.sp->me.y );
     143             :         } else
     144           0 : return( false );
     145           0 :       break;
     146             :       case 2:
     147           0 :         if ( cv->p.pressed ) {
     148           0 :             if ( cv->p.sp!=NULL && cv->info_sp!=NULL &&
     149           0 :                     ((cv->p.sp->next!=NULL && cv->p.sp->next->to==cv->info_sp) ||
     150           0 :                      (cv->p.sp->prev!=NULL && cv->p.sp->prev->from==cv->info_sp)) ) {
     151           0 :                 if ( cv->p.sp->next!=NULL && cv->p.sp->next->to==cv->info_sp )
     152           0 :                     len = SplineLength(cv->p.sp->next);
     153             :                 else
     154           0 :                     len = SplineLength(cv->p.sp->prev);
     155           0 :             } else if ( cv->p.spline == cv->info_spline && cv->info_spline!=NULL )
     156           0 :                 len = SplineLengthRange(cv->info_spline,cv->p.t,cv->info_t);
     157           0 :             else if ( cv->p.sp!=NULL && cv->info_spline!=NULL &&
     158           0 :                     cv->p.sp->next == cv->info_spline )
     159           0 :                 len = SplineLengthRange(cv->info_spline,0,cv->info_t);
     160           0 :             else if ( cv->p.sp!=NULL && cv->info_spline!=NULL &&
     161           0 :                     cv->p.sp->prev == cv->info_spline )
     162           0 :                 len = SplineLengthRange(cv->info_spline,cv->info_t,1);
     163           0 :             else if ( cv->info_sp!=NULL && cv->p.spline!=NULL &&
     164           0 :                     cv->info_sp->next == cv->p.spline )
     165           0 :                 len = SplineLengthRange(cv->p.spline,0,cv->p.t);
     166           0 :             else if ( cv->info_sp!=NULL && cv->p.spline!=NULL &&
     167           0 :                     cv->info_sp->prev == cv->p.spline )
     168           0 :                 len = SplineLengthRange(cv->p.spline,cv->p.t,1);
     169             :             else
     170           0 : return( false );
     171           0 :             if ( len>1 )
     172           0 :                 sprintf( buf, _("Spline Length=%.1f"), len);
     173             :             else
     174           0 :                 sprintf( buf, _("Spline Length=%g"), len);
     175           0 :         } else if ( cv->p.spline!=NULL ) {
     176           0 :             s = cv->p.spline;
     177           0 :             t = cv->p.t;
     178           0 :             dx = (3*s->splines[0].a*t+2*s->splines[0].b)*t+s->splines[0].c;
     179           0 :             dy = (3*s->splines[1].a*t+2*s->splines[1].b)*t+s->splines[1].c;
     180           0 :             SlopeToBuf(buf,"",dx,dy);
     181           0 :         } else if ( cv->p.sp!=NULL ) {
     182           0 :             if ( cv->p.sp->nonextcp )
     183           0 :                 strcpy(buf,_("No Next Control Point"));
     184             :             else
     185           0 :                 sprintf(buf,_("Next CP: (%f,%f)"), (double) cv->p.sp->nextcp.x, (double) cv->p.sp->nextcp.y);
     186             :         } else
     187           0 : return( false );
     188           0 :       break;
     189             :       case 3:
     190           0 :         if ( cv->p.pressed )
     191           0 : return( false );
     192           0 :         else if ( cv->p.spline!=NULL ) {
     193           0 :             CurveToBuf(buf,cv,cv->p.spline,cv->p.t);
     194           0 :         } else if ( cv->p.sp!=NULL && cv->p.sp->next!=NULL ) {
     195           0 :             s = cv->p.sp->next;
     196           0 :             dx = s->splines[0].c;
     197           0 :             dy = s->splines[1].c;
     198           0 :             SlopeToBuf(buf,_(" Next"),dx,dy);
     199           0 :         } else if ( cv->p.sp!=NULL ) {
     200           0 :             if ( cv->p.sp->noprevcp )
     201           0 :                 strcpy(buf,_("No Previous Control Point"));
     202             :             else
     203           0 :                 sprintf(buf,_("Prev CP: (%f,%f)"), (double) cv->p.sp->prevcp.x, (double) cv->p.sp->prevcp.y);
     204             :         } else
     205           0 : return( false );
     206           0 :       break;
     207             :       case 4:
     208           0 :         if ( cv->p.spline!=NULL )
     209           0 : return( false );
     210           0 :         else if ( cv->p.sp->next!=NULL ) {
     211           0 :             CurveToBuf(buf,cv,cv->p.sp->next,0);
     212           0 :         } else if ( cv->p.sp->prev!=NULL ) {
     213           0 :             s = cv->p.sp->prev;
     214           0 :             dx = (3*s->splines[0].a*1+2*s->splines[0].b)*1+s->splines[0].c;
     215           0 :             dy = (3*s->splines[1].a*1+2*s->splines[1].b)*1+s->splines[1].c;
     216           0 :             SlopeToBuf(buf,_(" Prev"),dx,dy);
     217             :         } else
     218           0 : return( false );
     219           0 :       break;
     220             :       case 5:
     221           0 :         if ( cv->p.sp->next!=NULL ) {
     222           0 :             if ( cv->p.sp->noprevcp )
     223           0 :                 strcpy(buf,_("No Previous Control Point"));
     224             :             else
     225           0 :                 sprintf(buf,_("Prev CP: (%f,%f)"), (double) cv->p.sp->prevcp.x, (double) cv->p.sp->prevcp.y);
     226             :         } else {
     227           0 :             CurveToBuf(buf,cv,cv->p.sp->prev,1);
     228             :         }
     229           0 :       break;
     230             :       case 6:
     231           0 :         if ( cv->p.sp->next!=NULL && cv->p.sp->prev!=NULL ) {
     232           0 :             s = cv->p.sp->prev;
     233           0 :             dx = (3*s->splines[0].a*1+2*s->splines[0].b)*1+s->splines[0].c;
     234           0 :             dy = (3*s->splines[1].a*1+2*s->splines[1].b)*1+s->splines[1].c;
     235           0 :             SlopeToBuf(buf,_(" Prev"),dx,dy);
     236             :         } else
     237           0 : return( false );
     238           0 :       break;
     239             :       case 7:
     240           0 :         if ( cv->p.sp->next!=NULL && cv->p.sp->prev!=NULL ) {
     241           0 :             CurveToBuf(buf,cv,cv->p.sp->prev,1);
     242             :         } else
     243           0 : return( false );
     244           0 :       break;
     245             :       default:
     246           0 : return( false );
     247             :     }
     248           0 :     utf82u_strcpy(ubuf,buf);
     249           0 : return( true );
     250             : }
     251             : 
     252           0 : static int RulerTextIntersection(CharView *cv, unichar_t *ubuf, int i) {
     253             :     char buf[80];
     254             : 
     255           0 :     if ( i==0 && cv->num_ruler_intersections>4 ) {
     256           0 :         real xoff = cv->ruler_intersections[cv->num_ruler_intersections-2].x - cv->ruler_intersections[1].x;
     257           0 :         real yoff = cv->ruler_intersections[cv->num_ruler_intersections-2].y - cv->ruler_intersections[1].y;
     258           0 :         real len = sqrt(xoff*xoff+yoff*yoff);
     259           0 :         snprintf(buf,sizeof buf, _("First Edge to Last Edge: %g x %g length %f"),fabs(xoff),fabs(yoff),len);
     260           0 :         utf82u_strcpy(ubuf,buf);
     261           0 : return( 1 );
     262           0 :     } else if ( cv->num_ruler_intersections>4 )
     263           0 :         i -= 1;
     264             : 
     265           0 :     if ( i>=cv->num_ruler_intersections )
     266           0 : return( 0 );
     267             : 
     268           0 :     if ( i==0 ) {
     269           0 :         snprintf(buf,sizeof buf,"[%d] (%g,%g)",i,cv->ruler_intersections[i].x,cv->ruler_intersections[i].y);
     270           0 :         if ( cv->p.sp ) {
     271           0 :             strcat(buf, _(" snapped"));
     272           0 :             cv->start_intersection_snapped = 1;
     273             :         } else {
     274           0 :             cv->start_intersection_snapped = 0;
     275             :         }
     276             :     } else {
     277           0 :         real xoff = cv->ruler_intersections[i].x - cv->ruler_intersections[i-1].x;
     278           0 :         real yoff = cv->ruler_intersections[i].y - cv->ruler_intersections[i-1].y;
     279           0 :         real len = sqrt(xoff*xoff+yoff*yoff);
     280           0 :         snprintf(buf,sizeof buf, _("[%d] (%g,%g) %g x %g length %g"),i,cv->ruler_intersections[i].x,cv->ruler_intersections[i].y,fabs(xoff),fabs(yoff),len);
     281           0 :         if ( i==(cv->num_ruler_intersections-1) ) {
     282           0 :             if ( cv->info_sp ) {
     283           0 :                 strcat(buf, _(" snapped"));
     284           0 :                 cv->end_intersection_snapped = 1;
     285             :             } else {
     286           0 :                 cv->end_intersection_snapped = 0;
     287             :             }
     288             :         }
     289             :     }
     290             : 
     291           0 :     utf82u_strcpy(ubuf,buf);
     292           0 : return( 1 );
     293             : }
     294             : 
     295           0 : static int ruler_e_h(GWindow gw, GEvent *event) {
     296           0 :     CharView *cv = (CharView *) GDrawGetUserData(gw);
     297             :     unichar_t ubuf[80];
     298             :     int line;
     299             :     int i;
     300             : 
     301           0 :     switch ( event->type ) {
     302             :       case et_expose:
     303           0 :         GDrawSetFont(gw,cv->rfont);
     304           0 :         for ( line=0; RulerText(cv,ubuf,line); ++line )
     305           0 :             GDrawDrawText(gw,2,line*cv->rfh+cv->ras+1,ubuf,-1,measuretoolwindowforegroundcol);
     306           0 :         if ( cv->p.pressed ) for ( i=0; RulerTextIntersection(cv,ubuf,i); ++i )
     307           0 :             GDrawDrawText(gw,2,(line+i)*cv->rfh+cv->ras+1,ubuf,-1,measuretoolwindowforegroundcol);
     308           0 :       break;
     309             :       case et_mousedown:
     310           0 :         cv->autonomous_ruler_w = false;
     311           0 :         GDrawDestroyWindow(gw);
     312           0 :         cv->ruler_w = NULL;
     313           0 :       break;
     314             :     }
     315           0 : return( true );
     316             : }
     317             : 
     318           0 : static int ruler_linger_e_h(GWindow gw, GEvent *event) {
     319           0 :     CharView *cv = (CharView *) GDrawGetUserData(gw);
     320             :     int i;
     321             : 
     322           0 :     switch ( event->type ) {
     323             :       case et_expose:
     324           0 :         GDrawSetFont(gw,cv->rfont);
     325           0 :         for ( i=0; i < cv->ruler_linger_num_lines ; ++i )
     326           0 :             GDrawDrawText(gw,2,i*cv->rfh+cv->ras+1,cv->ruler_linger_lines[i],-1,measuretoolwindowforegroundcol);
     327           0 :       break;
     328             :       case et_mousedown:
     329             :         // TBD
     330             :         // cv->autonomous_ruler_w = false;
     331             :         // GDrawDestroyWindow(gw);
     332             :         // cv->ruler_linger_w = NULL;
     333           0 :       break;
     334             :     }
     335           0 : return( true );
     336             : }
     337             :         
     338             : static GFont *rvfont=NULL;
     339             : 
     340             : /*
     341             :  * Comparison function for use with qsort.
     342             :  */
     343           0 : static int BasePointCompare(const void *_l, const void *_r) {
     344           0 :         const BasePoint *l = _l, *r = _r;
     345           0 :         if ( l->x>r->x)
     346           0 : return( 1 );
     347           0 :         if ( l->x<r->x)
     348           0 : return( -1 );
     349           0 :         if ( l->y>r->y)
     350           0 : return( 1 );
     351           0 :         if ( l->y<r->y)
     352           0 : return( -1 );
     353           0 : return( 0 );
     354             : }
     355             : 
     356           0 : static int ReverseBasePointCompare(const void *l, const void *r) {
     357           0 : return( -BasePointCompare(l,r) );
     358             : }
     359             : 
     360             : /*
     361             :  * Fill buffer with intersects on a line (from,to).
     362             :  * return number found, buf fill the buffer only up to a max_intersections.
     363             :  *
     364             :  * The points from and to are also put in the buffer. 
     365             :  *
     366             :  * Copied somewhat from CVMouseUpKnife(), perhaps they should be consolidated
     367             :  */
     368           0 : static int GetIntersections(CharView *cv,BasePoint from,BasePoint to,BasePoint *all_intersections,int max_intersections) {
     369             :     SplineSet *spl;
     370             :     Spline *s, *nexts;
     371             :     Spline dummy;
     372             :     SplinePoint dummyfrom, dummyto;
     373             :     BasePoint inters[9];        /* These bounds are hard coded in the SplinesIntersect function */
     374             :     extended t1s[10], t2s[10];
     375             :     int i;
     376           0 :     int total_intersections = 0;
     377             : 
     378           0 :     memset(&dummy,0,sizeof(dummy));
     379           0 :     memset(&dummyfrom,0,sizeof(dummyfrom));
     380           0 :     memset(&dummyto,0,sizeof(dummyto));
     381           0 :     dummyfrom.me.x = from.x; dummyfrom.me.y = from.y;
     382           0 :     dummyto.me.x = to.x; dummyto.me.y = to.y;
     383           0 :     dummyfrom.nextcp = dummyfrom.prevcp = dummyfrom.me;
     384           0 :     dummyto.nextcp = dummyto.prevcp = dummyto.me;
     385           0 :     dummyfrom.nonextcp = dummyfrom.noprevcp = dummyto.nonextcp = dummyto.noprevcp = true;
     386           0 :     dummy.splines[0].d = from.x; dummy.splines[0].c = to.x-from.x;
     387           0 :     dummy.splines[1].d = from.y; dummy.splines[1].c = to.y-from.y;
     388           0 :     dummy.from = &dummyfrom; dummy.to = &dummyto;
     389           0 :     dummy.islinear = dummy.knownlinear = true;
     390           0 :     dummyfrom.next = dummyto.prev = &dummy;
     391             : 
     392           0 :     all_intersections[total_intersections++] = from;
     393             : 
     394           0 :     for ( spl = cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL; spl = spl->next ) {
     395           0 :         for ( s = spl->first->next; s!=NULL ; ) {
     396           0 :             nexts = NULL;
     397           0 :             if ( s->to!=spl->first )
     398           0 :                 nexts = s->to->next;
     399             : 
     400           0 :             if ( SplinesIntersect(s,&dummy,inters,t1s,t2s)>0 ) {
     401             :                 /* TBD, why is 4 used here (copied from CVMouseUpKnife()) */
     402           0 :                 for ( i=0; i<4 && t1s[i]!=-1; ++i ) {
     403           0 :                     if ( (total_intersections+1)<max_intersections )
     404           0 :                         all_intersections[total_intersections] = inters[i];
     405           0 :                     total_intersections++;
     406             :                 }
     407             :             }
     408           0 :             s = nexts;
     409             :         }
     410             :     }
     411             : 
     412           0 :     if ( total_intersections<max_intersections )
     413           0 :         all_intersections[total_intersections++] = to;
     414             : 
     415           0 :     qsort(all_intersections,
     416           0 :         total_intersections > max_intersections ? max_intersections : total_intersections,
     417             :         sizeof(all_intersections[0]),
     418           0 :         BasePointCompare(&from,&to)<=0 ? BasePointCompare : ReverseBasePointCompare );
     419             : 
     420             :     /*
     421             :      * Filter out intersectsions that are too close.
     422             :      * This is for snapped points, but we get more than one extra per snap,
     423             :      * so do them all for now.
     424             :      */
     425           0 :     for ( i = 1 ; i<total_intersections && i<max_intersections ; ) {
     426           0 :         if ( (0.00001 > fabs(all_intersections[i].x-all_intersections[i-1].x)) &&
     427           0 :              (0.00001 > fabs(all_intersections[i].y-all_intersections[i-1].y)) ) {
     428             :             int j;
     429             : 
     430           0 :             for( j = i+1 ; j<total_intersections &&  j<max_intersections ; j++ )
     431           0 :                 all_intersections[j-1] = all_intersections[j];
     432           0 :             if ( total_intersections < max_intersections )
     433           0 :                 total_intersections--;
     434             :         } else {
     435           0 :             i++;
     436             :         }
     437             :     }
     438             : 
     439           0 : return( total_intersections );  /* note that it could be greater than max */
     440             : }
     441             : 
     442           0 : static void RulerPlace(CharView *cv, GEvent *event) {
     443             :     unichar_t ubuf[80];
     444             :     int width, x, y;
     445             :     GRect size;
     446             :     GPoint pt;
     447             :     int i,h,w;
     448             :     GWindowAttrs wattrs;
     449             :     GRect pos;
     450             :     FontRequest rq;
     451             :     int as, ds, ld;
     452             : 
     453           0 :     if ( cv->ruler_w==NULL ) {
     454           0 :         memset(&wattrs,0,sizeof(wattrs));
     455           0 :         wattrs.mask = wam_events|wam_cursor|wam_positioned|wam_nodecor|wam_backcol|wam_bordwidth;
     456           0 :         wattrs.event_masks = (1<<et_expose)|(1<<et_resize)|(1<<et_mousedown);
     457           0 :         wattrs.cursor = ct_mypointer;
     458           0 :         wattrs.background_color = measuretoolwindowbackgroundcol;
     459           0 :         wattrs.nodecoration = 1;
     460           0 :         wattrs.border_width = 1;
     461           0 :         pos.x = pos.y = 0; pos.width=pos.height = 20;
     462           0 :         cv->ruler_w = GWidgetCreateTopWindow(NULL,&pos,ruler_e_h,cv,&wattrs);
     463             : 
     464           0 :         if ( rvfont==NULL ) {
     465           0 :             memset(&rq,0,sizeof(rq));
     466           0 :             rq.utf8_family_name = FIXED_UI_FAMILIES;
     467           0 :             rq.point_size = -12;
     468           0 :             rq.weight = 400;
     469           0 :             rvfont = GDrawInstanciateFont(cv->ruler_w,&rq);
     470           0 :             rvfont = GResourceFindFont("CharView.Measure.Font",rvfont);
     471             :         }
     472           0 :         cv->rfont = rvfont;
     473           0 :         GDrawWindowFontMetrics(cv->ruler_w,cv->rfont,&as,&ds,&ld);
     474           0 :         cv->rfh = as+ds; cv->ras = as;
     475             :     } else
     476           0 :         GDrawRaise(cv->ruler_w);
     477             : 
     478           0 :     if ( cv->p.pressed ) {
     479             :         BasePoint from;
     480             : 
     481           0 :         from.x = cv->p.cx;
     482           0 :         from.y = cv->p.cy;
     483             : 
     484           0 :         if ( !cv->ruler_intersections ) {
     485           0 :             cv->allocated_ruler_intersections = 32;
     486           0 :             cv->ruler_intersections = malloc(cv->allocated_ruler_intersections * sizeof(cv->ruler_intersections[0]));
     487             :         }
     488             :         for(;;) {
     489           0 :             cv->num_ruler_intersections = GetIntersections(cv,from,cv->info,cv->ruler_intersections,cv->allocated_ruler_intersections);
     490           0 :             if ( cv->num_ruler_intersections>cv->allocated_ruler_intersections ) {
     491           0 :                 cv->allocated_ruler_intersections = cv->num_ruler_intersections * 2;
     492           0 :                 cv->ruler_intersections = realloc(cv->ruler_intersections,cv->allocated_ruler_intersections * sizeof(cv->ruler_intersections[0]));
     493             :             } else
     494           0 :                 break;
     495           0 :         }
     496             :     }
     497             : 
     498           0 :     GDrawSetFont(cv->ruler_w,cv->rfont);
     499           0 :     width = h = 0;
     500           0 :     for ( i=0; RulerText(cv,ubuf,i); ++i ) {
     501           0 :         w = GDrawGetTextWidth(cv->ruler_w,ubuf,-1);
     502           0 :         if ( w>width ) width = w;
     503           0 :         h += cv->rfh;
     504             :     }
     505           0 :     if ( cv->p.pressed ) for ( i=0; RulerTextIntersection(cv,ubuf,i); ++i ) {
     506           0 :         w = GDrawGetTextWidth(cv->ruler_w,ubuf,-1);
     507           0 :         if ( w>width ) width = w;
     508           0 :         h += cv->rfh;
     509             :     }
     510             : 
     511           0 :     GDrawGetSize(GDrawGetRoot(NULL),&size);
     512           0 :     pt.x = event->u.mouse.x; pt.y = event->u.mouse.y;
     513           0 :     GDrawTranslateCoordinates(cv->v,GDrawGetRoot(NULL),&pt);
     514           0 :     x = pt.x + infowindowdistance;
     515           0 :     if ( x+width > size.width )
     516           0 :         x = pt.x - width-infowindowdistance;
     517           0 :     y = pt.y -cv->ras-2;
     518           0 :     if ( y+h > size.height )
     519           0 :         y = pt.y - h - cv->ras -10;
     520           0 :     GDrawMoveResize(cv->ruler_w,x,y,width+4,h+4);
     521           0 : }
     522             : 
     523           0 : static void RulerLingerPlace(CharView *cv, GEvent *event) {
     524             :     int width, x, y;
     525             :     GRect size;
     526             :     GPoint pt;
     527             :     int i,h,w;
     528             :     GWindowAttrs wattrs;
     529             :     GRect pos;
     530             :     FontRequest rq;
     531             :     int as, ds, ld;
     532             :     int line;
     533             :     int old_pressed;
     534             : 
     535           0 :     if ( cv->ruler_linger_w==NULL ) {
     536           0 :         memset(&wattrs,0,sizeof(wattrs));
     537           0 :         wattrs.mask = wam_events|wam_cursor|wam_positioned|wam_nodecor|wam_backcol|wam_bordwidth;
     538           0 :         wattrs.event_masks = (1<<et_expose)|(1<<et_resize)|(1<<et_mousedown);
     539           0 :         wattrs.cursor = ct_mypointer;
     540           0 :         wattrs.background_color = measuretoolwindowbackgroundcol;
     541           0 :         wattrs.nodecoration = 1;
     542           0 :         wattrs.border_width = 1;
     543           0 :         pos.x = pos.y = 0; pos.width=pos.height = 20;
     544           0 :         cv->ruler_linger_w = GWidgetCreateTopWindow(NULL,&pos,ruler_linger_e_h,cv,&wattrs);
     545             : 
     546           0 :         if ( rvfont==NULL ) {
     547           0 :             memset(&rq,0,sizeof(rq));
     548           0 :             rq.utf8_family_name = FIXED_UI_FAMILIES;
     549           0 :             rq.point_size = -12;
     550           0 :             rq.weight = 400;
     551           0 :             rvfont = GDrawInstanciateFont(cv->ruler_w,&rq);
     552           0 :             rvfont = GResourceFindFont("CharView.Measure.Font",rvfont);
     553             :         }
     554           0 :         cv->rfont = rvfont;
     555           0 :         GDrawWindowFontMetrics(cv->ruler_linger_w,cv->rfont,&as,&ds,&ld);
     556           0 :         cv->rfh = as+ds; cv->ras = as;
     557             :     } else
     558           0 :         GDrawRaise(cv->ruler_linger_w);
     559             : 
     560           0 :     GDrawSetFont(cv->ruler_linger_w,cv->rfont);
     561           0 :     width = h = 0;
     562           0 :     line = 0;
     563           0 :     old_pressed = cv->p.pressed;
     564           0 :     cv->p.pressed = true;
     565             : 
     566           0 :     for ( i=0; line<sizeof(cv->ruler_linger_lines)/sizeof(cv->ruler_linger_lines[0]) && RulerText(cv,cv->ruler_linger_lines[line],i) ; ++i,++line ) {
     567           0 :         w = GDrawGetTextWidth(cv->ruler_linger_w,cv->ruler_linger_lines[line],-1);
     568           0 :         if ( w>width ) width = w;
     569           0 :         h += cv->rfh;
     570             :     }
     571           0 :     cv->p.pressed = old_pressed;
     572           0 :     for ( i=0; line<sizeof(cv->ruler_linger_lines)/sizeof(cv->ruler_linger_lines[0]) && RulerTextIntersection(cv,cv->ruler_linger_lines[line],i); ++i,++line ) {
     573           0 :         w = GDrawGetTextWidth(cv->ruler_linger_w,cv->ruler_linger_lines[line],-1);
     574           0 :         if ( w>width ) width = w;
     575           0 :         h += cv->rfh;
     576             :     }
     577           0 :     cv->ruler_linger_num_lines = line;
     578             : 
     579           0 :     GDrawGetSize(GDrawGetRoot(NULL),&size);
     580           0 :     pt.x = event->u.mouse.x; pt.y = event->u.mouse.y;
     581           0 :     GDrawTranslateCoordinates(cv->v,GDrawGetRoot(NULL),&pt);
     582           0 :     x = pt.x + infowindowdistance;
     583           0 :     if ( x+width > size.width )
     584           0 :         x = pt.x - width-infowindowdistance;
     585           0 :     y = pt.y -cv->ras-2;
     586           0 :     if ( y+h > size.height )
     587           0 :         y = pt.y - h - cv->ras -10;
     588           0 :     GDrawMoveResize(cv->ruler_linger_w,x,y,width+4,h+4);
     589           0 :     GDrawSetVisible(cv->ruler_linger_w,true);
     590           0 : }
     591             : 
     592           0 : static void RulerLingerMove(CharView *cv) {
     593           0 :     if ( cv->ruler_linger_w ) {
     594             :         int x, y;
     595             :         GRect size;
     596             :         GRect rsize;
     597             :         GRect csize;
     598             :         GPoint pt;
     599             : 
     600           0 :         GDrawGetSize(GDrawGetRoot(NULL),&size);
     601           0 :         GDrawGetSize(cv->ruler_linger_w,&rsize);
     602           0 :         GDrawGetSize(cv->gw,&csize);
     603             : 
     604           0 :         pt.x = cv->xoff + rint(cv->ruler_intersections[cv->num_ruler_intersections-1].x*cv->scale);
     605           0 :         pt.y = -cv->yoff + cv->height - rint(cv->ruler_intersections[cv->num_ruler_intersections-1].y*cv->scale);
     606           0 :         GDrawTranslateCoordinates(cv->v,GDrawGetRoot(NULL),&pt);
     607           0 :         x = pt.x + infowindowdistance;
     608           0 :         if ( x+rsize.width>size.width )
     609           0 :             x = pt.x - rsize.width-infowindowdistance;
     610           0 :         y = pt.y -cv->ras-2;
     611           0 :         if ( y+rsize.height>size.height )
     612           0 :             y = pt.y - rsize.height - cv->ras -10;
     613             : 
     614           0 :         if ( x>=csize.x && x<=(csize.x+csize.width) && y>=csize.y && y<=(csize.y+csize.height) ) {
     615           0 :             GDrawMove(cv->ruler_linger_w,x,y);
     616           0 :             GDrawSetVisible(cv->ruler_linger_w,true);
     617             :         } else {
     618           0 :             GDrawSetVisible(cv->ruler_linger_w,false);
     619             :         }
     620             :     }
     621           0 : }
     622             : 
     623           0 : void CVMouseDownRuler(CharView *cv, GEvent *event) {
     624             : 
     625           0 :     cv->autonomous_ruler_w = false;
     626             : 
     627           0 :     RulerPlace(cv,event);
     628           0 :     cv->p.rubberlining = true;
     629           0 :     GDrawSetVisible(cv->ruler_w,true);
     630           0 :     if ( cv->ruler_linger_w ) {
     631           0 :         GDrawDestroyWindow(cv->ruler_linger_w);
     632           0 :         cv->ruler_linger_w = NULL;
     633             :     }
     634           0 : }
     635             : 
     636           0 : void CVMouseMoveRuler(CharView *cv, GEvent *event) {
     637           0 :     if ( cv->autonomous_ruler_w )
     638           0 : return;
     639             : 
     640           0 :     if ( !cv->p.pressed && (event->u.mouse.state&ksm_meta) ) {
     641           0 :         if ( cv->ruler_w!=NULL && GDrawIsVisible(cv->ruler_w)) {
     642           0 :             GDrawDestroyWindow(cv->ruler_w);
     643           0 :             cv->ruler_w = NULL;
     644             :         }
     645           0 : return;
     646             :     }
     647           0 :     if ( !cv->p.pressed )
     648           0 :         CVMouseAtSpline(cv,event);
     649           0 :     RulerPlace(cv,event);
     650           0 :     if ( !cv->p.pressed )
     651           0 :         GDrawSetVisible(cv->ruler_w,true);
     652           0 :     GDrawSync(NULL);
     653             : // The following code may be unnecessary, and it can cause an infinite stack loop.
     654             : // One would hope that the event queue can take care of these things when we return to it.
     655             : // We'll find out.
     656             : //#if 0
     657             : //    GDrawProcessPendingEvents(NULL);          /* The resize needs to happen before the expose */
     658             : //    if ( !cv->p.pressed && (event->u.mouse.state&ksm_meta) ) /* but a mouse up might sneak in... */
     659             : //return;
     660           0 :     GDrawRequestExpose(cv->ruler_w,NULL,false);
     661             : //    GDrawRequestExpose(cv->v,NULL,false);
     662             : //#endif // 0
     663             : }
     664             : 
     665           0 : void CVMouseUpRuler(CharView *cv, GEvent *event) {
     666           0 :     if ( cv->ruler_w!=NULL ) {
     667             :         GRect size;
     668             : 
     669           0 :         last_ruler_offset[1] = last_ruler_offset[0];
     670           0 :         last_ruler_offset[0].x = cv->info.x-cv->p.cx;
     671           0 :         last_ruler_offset[0].y = cv->info.y-cv->p.cy;
     672             : 
     673             :         /* if we have gone out of bounds abandon the window */
     674           0 :         GDrawGetSize(cv->v,&size);
     675           0 :         if ( event->u.mouse.x<0 || event->u.mouse.y<0 || event->u.mouse.x>=size.width || event->u.mouse.y>=size.height ) {
     676           0 :             GDrawDestroyWindow(cv->ruler_w);
     677           0 :             cv->ruler_w = NULL;
     678           0 : return;
     679             :         }
     680             : 
     681           0 :         if ( !(event->u.mouse.state & ksm_meta) ) {
     682             :             /*cv->autonomous_ruler_w = true;*/
     683             : 
     684           0 :             if ( cv->ruler_linger_w ) {
     685           0 :                 GDrawDestroyWindow(cv->ruler_linger_w);
     686           0 :                 cv->ruler_linger_w = NULL;
     687             :             }
     688           0 :             if ( cv->num_ruler_intersections>1 ) {
     689           0 :                 RulerLingerPlace(cv,event);
     690             :             }
     691           0 : return;
     692             :         }
     693             : 
     694           0 :         GDrawDestroyWindow(cv->ruler_w);
     695           0 :         cv->ruler_w = NULL;
     696             :     }
     697             : }
     698             : 
     699             : /* ************************************************************************** */
     700             : 
     701           0 : static char *PtInfoText(CharView *cv, int lineno, int active, char *buffer, int blen) {
     702             :     BasePoint *cp;
     703             :     double t;
     704             :     Spline *s;
     705           0 :     SplinePoint *sp = cv->p.sp;
     706             :     extern char *coord_sep;
     707             :     double dx, dy, kappa, kappa2;
     708             :     int emsize;
     709             : 
     710           0 :     if ( !cv->p.prevcp && !cv->p.nextcp ) {
     711           0 :         sp = cv->active_sp;
     712           0 :         if ( sp==NULL )
     713           0 : return( NULL );
     714             :     }
     715             : 
     716           0 :     if ( active==-1 ) {
     717           0 :         if ( lineno>0 )
     718           0 : return( NULL );
     719           0 :         if ( sp->next==NULL || sp->prev==NULL )
     720           0 : return( NULL );
     721           0 :         kappa = SplineCurvature(sp->next,0);
     722           0 :         kappa2 = SplineCurvature(sp->prev,1);
     723           0 :         emsize = cv->b.sc->parent->ascent + cv->b.sc->parent->descent;
     724           0 :         if ( kappa == CURVATURE_ERROR || kappa2 == CURVATURE_ERROR )
     725           0 :             strncpy(buffer,_("No curvature info"), blen);
     726             :         else
     727           0 :             snprintf( buffer, blen, U_("∆Curvature: %g"), (kappa-kappa2)*emsize );
     728           0 : return( buffer );
     729             :     }
     730             : 
     731           0 :     if ( (!cv->p.prevcp && active ) || (!cv->p.nextcp && !active)) {
     732           0 :         cp = &sp->nextcp;
     733           0 :         t = 0;
     734           0 :         s = sp->next;
     735             :     } else {
     736           0 :         cp = &sp->prevcp;
     737           0 :         t = 1;
     738           0 :         s = sp->prev;
     739             :     }
     740             :         
     741           0 :     switch( lineno ) {
     742             :       case 0:
     743           0 :         if ( t==0 )
     744           0 :             strncpy( buffer, _(" Next CP"), blen);
     745             :         else
     746           0 :             strncpy( buffer, _(" Prev CP"), blen);
     747           0 :       break;
     748             :       case 1:
     749           0 :         snprintf( buffer, blen, "(%g%s%g)", (double) cp->x, coord_sep, (double) cp->y);
     750           0 :       break;
     751             :       case 2:
     752           0 :         snprintf( buffer, blen, "∆ (%g%s%g)", (double) (cp->x-sp->me.x), coord_sep, (double) (cp->y-sp->me.y));
     753           0 :       break;
     754             :       case 3:
     755           0 :         dx = cp->x - sp->me.x; dy = cp->y - sp->me.y;
     756           0 :         if ( dx==0 && dy==0 )
     757           0 :             snprintf( buffer, blen, "%s", _("No Slope") );
     758           0 :         else if ( dx==0 )
     759           0 :             snprintf( buffer, blen, "∆y/∆x= ∞" );
     760             :         else
     761           0 :             snprintf( buffer, blen, "∆y/∆x= %g", dy/dx );
     762           0 :       break;
     763             :       case 4:
     764           0 :         dx = cp->x - sp->me.x; dy = cp->y - sp->me.y;
     765           0 :         snprintf( buffer, blen, "∠ %g°", atan2(dy,dx)*180/3.1415926535897932 );
     766           0 :       break;
     767             :       case 5:
     768           0 :         if ( s==NULL )
     769           0 : return( NULL );
     770           0 :         kappa = SplineCurvature(s,t);
     771           0 :         if ( kappa==CURVATURE_ERROR )
     772           0 : return( NULL );
     773           0 :         emsize = cv->b.sc->parent->ascent + cv->b.sc->parent->descent;
     774             :         /* If we normalize by the em-size, the curvature is often more */
     775             :         /*  readable */
     776           0 :         snprintf( buffer, blen, _("Curvature: %g"), kappa*emsize);
     777           0 :       break;
     778             :       default:
     779           0 : return( NULL );
     780             :     }
     781           0 : return( buffer );
     782             : }
     783             : 
     784           0 : static int cpinfo_e_h(GWindow gw, GEvent *event) {
     785           0 :     CharView *cv = (CharView *) GDrawGetUserData(gw);
     786             :     char buf[100];
     787             :     int line, which, y;
     788             : 
     789           0 :     switch ( event->type ) {
     790             :       case et_expose:
     791           0 :         y = cv->ras+1;
     792           0 :         GDrawSetFont(gw,cv->rfont);
     793           0 :         for ( which = 1; which>=0; --which ) {
     794           0 :             for ( line=0; PtInfoText(cv,line,which,buf,sizeof(buf))!=NULL; ++line ) {
     795           0 :                 GDrawDrawText8(gw,2,y,buf,-1,0x000000);
     796           0 :                 y += cv->rfh+1;
     797             :             }
     798           0 :             GDrawDrawLine(gw,0,y+2-cv->ras,2000,y+2-cv->ras,0x000000);
     799           0 :             y += 4;
     800             :         }
     801           0 :         if ( PtInfoText(cv,0,-1,buf,sizeof(buf))!=NULL )
     802           0 :             GDrawDrawText8(gw,2,y,buf,-1,0x000000);
     803           0 :       break;
     804             :     }
     805           0 : return( true );
     806             : }
     807             :         
     808           0 : static void CpInfoPlace(CharView *cv, GEvent *event) {
     809             :     char buf[100];
     810             :     int line, which;
     811             :     int width, x, y;
     812             :     GRect size;
     813             :     GPoint pt, pt2;
     814             :     int h,w;
     815             :     GWindowAttrs wattrs;
     816             :     GRect pos;
     817             :     FontRequest rq;
     818             :     int as, ds, ld;
     819             :     SplinePoint *sp;
     820             : 
     821           0 :     if ( cv->ruler_w==NULL ) {
     822           0 :         memset(&wattrs,0,sizeof(wattrs));
     823           0 :         wattrs.mask = wam_events|wam_cursor|wam_positioned|wam_nodecor|wam_backcol|wam_bordwidth;
     824           0 :         wattrs.event_masks = (1<<et_expose)|(1<<et_resize)|(1<<et_mousedown);
     825           0 :         wattrs.cursor = ct_mypointer;
     826           0 :         wattrs.background_color = 0xe0e0c0;
     827           0 :         wattrs.nodecoration = 1;
     828           0 :         wattrs.border_width = 1;
     829           0 :         pos.x = pos.y = 0; pos.width=pos.height = 20;
     830           0 :         cv->ruler_w = GWidgetCreateTopWindow(NULL,&pos,cpinfo_e_h,cv,&wattrs);
     831             : 
     832           0 :         if ( rvfont==NULL ) {
     833           0 :             memset(&rq,0,sizeof(rq));
     834           0 :             rq.utf8_family_name = FIXED_UI_FAMILIES;
     835           0 :             rq.point_size = -12;
     836           0 :             rq.weight = 400;
     837           0 :             rvfont = GDrawInstanciateFont(cv->ruler_w,&rq);
     838           0 :             rvfont = GResourceFindFont("CharView.Measure.Font",rvfont);
     839             :         }
     840           0 :         cv->rfont = rvfont;
     841           0 :         GDrawWindowFontMetrics(cv->ruler_w,cv->rfont,&as,&ds,&ld);
     842           0 :         cv->rfh = as+ds; cv->ras = as;
     843             :     } else
     844           0 :         GDrawRaise(cv->ruler_w);
     845             : 
     846           0 :     GDrawSetFont(cv->ruler_w,cv->rfont);
     847           0 :     h = 0; width = 0;
     848           0 :     for ( which = 0; which<2; ++which ) {
     849           0 :         for ( line=0; PtInfoText(cv,line,which,buf,sizeof(buf))!=NULL; ++line ) {
     850           0 :             w = GDrawGetText8Width(cv->ruler_w,buf,-1);
     851           0 :             if ( w>width ) width = w;
     852           0 :             h += cv->rfh+1;
     853             :         }
     854           0 :         h += 4;
     855             :     }
     856           0 :     if ( PtInfoText(cv,0,-1,buf,sizeof(buf))!=NULL ) {
     857           0 :         w = GDrawGetText8Width(cv->ruler_w,buf,-1);
     858           0 :         if ( w>width ) width = w;
     859           0 :         h += cv->rfh+1;
     860             :     }
     861             :     
     862           0 :     GDrawGetSize(GDrawGetRoot(NULL),&size);
     863           0 :     pt.x = event->u.mouse.x; pt.y = event->u.mouse.y;     /* Address of cp */
     864           0 :     GDrawTranslateCoordinates(cv->v,GDrawGetRoot(NULL),&pt);
     865             : 
     866           0 :     sp = cv->p.sp;
     867           0 :     if ( !cv->p.prevcp && !cv->p.nextcp )
     868           0 :         sp = cv->active_sp;
     869           0 :     if ( sp!=NULL ) {
     870           0 :         x =  cv->xoff + rint(sp->me.x*cv->scale);
     871           0 :         y = -cv->yoff + cv->height - rint(sp->me.y*cv->scale);
     872           0 :         if ( x>=0 && y>=0 && x<cv->width && y<cv->height ) {
     873           0 :             pt2.x = x; pt2.y = y;
     874           0 :             GDrawTranslateCoordinates(cv->v,GDrawGetRoot(NULL),&pt2);
     875             :         } else
     876           0 :             sp = NULL;
     877             :     }
     878             : 
     879           0 :     x = pt.x + infowindowdistance;
     880           0 :     y = pt.y - cv->ras-2;
     881           0 :     if ( sp!=NULL && x<=pt2.x-4 && x+width>=pt2.x+4 && y<=pt2.y-4 && y+h>=pt2.y+4 )
     882           0 :         x = pt2.x + 4;
     883           0 :     if ( x+width > size.width ) {
     884           0 :         x = pt.x - width-30;
     885           0 :         if ( sp!=NULL && x<=pt2.x-4 && x+width>=pt2.x+4 && y<=pt2.y-4 && y+h>=pt2.y+4 )
     886           0 :             x = pt2.x - width - 4;
     887           0 :         if ( x<0 ) {
     888           0 :             x = pt.x + 10;
     889           0 :             y = pt.y - h - infowindowdistance;
     890           0 :             if ( sp!=NULL && x<=pt2.x-4 && x+width>=pt2.x+4 && y<=pt2.y-4 && y+h>=pt2.y+4 )
     891           0 :                 y = pt2.y - h - 4;
     892           0 :             if ( y<0 )
     893           0 :                 y = pt.y+infowindowdistance;    /* If this doesn't work we have nowhere else to */
     894             :                                 /* try so don't check */
     895             :         }
     896             :     }
     897           0 :     if ( y+h > size.height )
     898           0 :         y = pt.y - h - cv->ras - 10;
     899           0 :     GDrawMoveResize(cv->ruler_w,x,y,width+4,h+4);
     900           0 : }
     901             : 
     902           0 : void CPStartInfo(CharView *cv, GEvent *event) {
     903           0 :     printf("CPStartInfo() showcp:%d pressed:%d rw:%p\n", cv->showcpinfo, cv->p.pressed, cv->ruler_w );
     904             : 
     905           0 :     if ( !cv->showcpinfo )
     906           0 : return;
     907           0 :     cv->autonomous_ruler_w = false;
     908             : 
     909           0 :     CpInfoPlace(cv,event);
     910           0 :     GDrawSetVisible(cv->ruler_w,true);
     911             : }
     912             : 
     913           0 : void CPUpdateInfo(CharView *cv, GEvent *event) {
     914             : 
     915             : //    printf("CPUpdateInfo() showcp:%d pressed:%d rw:%p\n", cv->showcpinfo, cv->p.pressed, cv->ruler_w );
     916             :     
     917           0 :     if ( !cv->showcpinfo )
     918           0 : return;
     919           0 :     if ( !cv->p.pressed ) {
     920           0 :         if ( cv->ruler_w!=NULL && GDrawIsVisible(cv->ruler_w)) {
     921           0 :             GDrawDestroyWindow(cv->ruler_w);
     922           0 :             cv->ruler_w = NULL;
     923             :         }
     924           0 : return;
     925             :     }
     926           0 :     if ( cv->ruler_w==NULL )
     927           0 :         CPStartInfo(cv,event);
     928             :     else {
     929           0 :         CpInfoPlace(cv,event);
     930           0 :         GDrawSync(NULL);
     931           0 :         GDrawProcessPendingEvents(NULL);                /* The resize needs to happen before the expose */
     932           0 :         if ( !cv->p.pressed  ) /* but a mouse up might sneak in... */
     933           0 : return;
     934           0 :         GDrawRequestExpose(cv->ruler_w,NULL,false);
     935             :     }
     936             : }
     937             : 
     938           0 : void CPEndInfo(CharView *cv) {
     939           0 :     if ( cv->ruler_w!=NULL ) {
     940           0 :         if ( !cv->p.pressed ) {
     941           0 :             GDrawDestroyWindow(cv->ruler_w);
     942           0 :             cv->ruler_w = NULL;
     943             :         }
     944             :     }
     945             :     /* TBD, wrong time to kill? */
     946           0 :     if ( cv->ruler_linger_w!=NULL && cv->b1_tool!=cvt_ruler && cv->b1_tool_old!=cvt_ruler ) {
     947           0 :         GDrawDestroyWindow(cv->ruler_linger_w);
     948           0 :         cv->ruler_linger_w = NULL;
     949             :     }
     950           0 : }
     951             : 
     952           0 : void CVRulerExpose(GWindow pixmap,CharView *cv) {
     953           0 :     if ( cv->b1_tool!=cvt_ruler && cv->b1_tool_old!=cvt_ruler ) {
     954           0 :         cv->num_ruler_intersections = 0;
     955           0 : return;
     956             :     }
     957             : 
     958           0 :     if ( cv->num_ruler_intersections >= 2 ) {
     959           0 :         int x =  cv->xoff + rint(cv->ruler_intersections[0].x*cv->scale);
     960           0 :         int y = -cv->yoff + cv->height - rint(cv->ruler_intersections[0].y*cv->scale);
     961           0 :         int xend =  cv->xoff + rint(cv->ruler_intersections[cv->num_ruler_intersections-1].x*cv->scale);
     962           0 :         int yend = -cv->yoff + cv->height - rint(cv->ruler_intersections[cv->num_ruler_intersections-1].y*cv->scale);
     963           0 :         real xdist = fabs(cv->ruler_intersections[0].x - cv->ruler_intersections[cv->num_ruler_intersections-1].x);
     964           0 :         real ydist = fabs(cv->ruler_intersections[0].y - cv->ruler_intersections[cv->num_ruler_intersections-1].y);
     965             :         int i;
     966             :         int len;
     967           0 :         int charwidth = 6; /* TBD */
     968           0 :         Color textcolor = (cv->start_intersection_snapped && cv->end_intersection_snapped) ? measuretoolcanvasnumberssnappedcol : measuretoolcanvasnumberscol;
     969             :         GRect prev_rect;
     970             : 
     971           0 :         if ( measuretoolshowhorizontolvertical ) {
     972             :             char buf[40];
     973             :             unichar_t ubuf[40];
     974             : 
     975           0 :             if ( xdist*cv->scale>10.0 && ydist*cv->scale>10.0 ) {
     976             : 
     977           0 :                 GDrawSetFont(pixmap,cv->rfont);
     978           0 :                 len = snprintf(buf,sizeof buf,"%g",xdist);
     979           0 :                 utf82u_strcpy(ubuf,buf);
     980           0 :                 GDrawDrawText(pixmap,(x+xend)/2 - len*charwidth/2,y + (y > yend ? 12 : -5),ubuf,-1,textcolor);
     981           0 :                 GDrawDrawLine(pixmap,x,y,xend,y,measuretoollinecol);
     982             : 
     983           0 :                 len = snprintf(buf,sizeof buf,"%g",ydist);
     984           0 :                 utf82u_strcpy(ubuf,buf);
     985           0 :                 GDrawDrawText(pixmap,xend + (x < xend ? charwidth/2 : -(len * charwidth + charwidth/2)),(y+yend)/2,ubuf,-1,textcolor);
     986           0 :                 GDrawDrawLine(pixmap,xend,y,xend,yend,measuretoollinecol);
     987             :             }
     988             :         }
     989             : 
     990           0 :         if ( !cv->p.rubberlining ) {
     991           0 :             GDrawDrawLine(pixmap,x,y,xend,yend,measuretoollinecol);
     992             :         }
     993             : 
     994           0 :         GDrawSetFont(pixmap,cv->rfont);
     995           0 :         for ( i=0 ; i<cv->num_ruler_intersections; ++i ) {
     996             :             GRect rect;
     997             : 
     998           0 :             rect.x = cv->xoff + rint(cv->ruler_intersections[i].x*cv->scale) - 1;
     999           0 :             rect.y = -cv->yoff + cv->height - rint(cv->ruler_intersections[i].y*cv->scale) - 1;
    1000           0 :             rect.width = 3;
    1001           0 :             rect.height = 3;
    1002             : 
    1003           0 :             GDrawFillElipse(pixmap,&rect,((i==(cv->num_ruler_intersections-1) && cv->info_sp) || (i==0 && cv->p.sp)) ? measuretoolpointsnappedcol : measuretoolpointcol);
    1004           0 :             if ( i>0 && (cv->num_ruler_intersections<6 || (prev_rect.x + 10)<rect.x || (prev_rect.y + 10)<rect.y || (prev_rect.y - 10)>rect.y) ) {
    1005           0 :                 real xoff = cv->ruler_intersections[i].x - cv->ruler_intersections[i-1].x;
    1006           0 :                 real yoff = cv->ruler_intersections[i].y - cv->ruler_intersections[i-1].y;
    1007           0 :                 real len = sqrt(xoff*xoff+yoff*yoff);
    1008             :                 char buf[40];
    1009             :                 unichar_t ubuf[40];
    1010             :                 int x,y;
    1011             : 
    1012           0 :                 x = (prev_rect.x + rect.x)/2;
    1013           0 :                 y = (prev_rect.y + rect.y)/2;
    1014             : 
    1015           0 :                 len = snprintf(buf,sizeof buf,"%g",len);
    1016           0 :                 utf82u_strcpy(ubuf,buf);
    1017           0 :                 GDrawDrawText(pixmap,x + (x < xend ? -(len*charwidth) : charwidth/2 ),y + (y < yend ? 12 : -5),ubuf,-1,textcolor);
    1018             :             }
    1019           0 :             prev_rect = rect;
    1020             :         }
    1021           0 :         RulerLingerMove(cv);    /* in case things are moving or scaling */
    1022             :     }
    1023             : }

Generated by: LCOV version 1.10