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 : }
|