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