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