Line data Source code
1 : /* Copyright (C) 2000-2012 by George Williams */
2 : /*
3 : * Redistribution and use in source and binary forms, with or without
4 : * modification, are permitted provided that the following conditions are met:
5 :
6 : * Redistributions of source code must retain the above copyright notice, this
7 : * list of conditions and the following disclaimer.
8 :
9 : * Redistributions in binary form must reproduce the above copyright notice,
10 : * this list of conditions and the following disclaimer in the documentation
11 : * and/or other materials provided with the distribution.
12 :
13 : * The name of the author may not be used to endorse or promote products
14 : * derived from this software without specific prior written permission.
15 :
16 : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 : * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 : * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 : * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 : * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 : * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 : * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 : * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 : * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 : * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 : */
27 : #include "cvundoes.h"
28 : #include "fontforgeui.h"
29 : #include "fvfonts.h"
30 : #include "splineutil.h"
31 : #include <math.h>
32 : #include <ustring.h>
33 : #include <utype.h>
34 : #include <gkeysym.h>
35 : #include "search.h"
36 :
37 : static SearchView *searcher=NULL;
38 :
39 : #define CID_Allow 1000
40 : #define CID_Flipping 1001
41 : #define CID_Scaling 1002
42 : #define CID_Rotating 1003
43 : #define CID_Selected 1004
44 : #define CID_Find 1005
45 : #define CID_FindAll 1006
46 : #define CID_Replace 1007
47 : #define CID_ReplaceAll 1008
48 : #define CID_Cancel 1009
49 : #define CID_TopBox 1010
50 : #define CID_Fuzzy 1011
51 : #define CID_Endpoints 1012
52 :
53 : static double old_fudge = .001;
54 :
55 0 : static void SVSelectSC(SearchView *sv) {
56 0 : SplineChar *sc = sv->sd.curchar;
57 : SplinePointList *spl;
58 : SplinePoint *sp;
59 : RefChar *rf;
60 : int i;
61 0 : int layer = sv->sd.fv->active_layer;
62 :
63 : /* Deselect all */;
64 0 : for ( spl = sc->layers[layer].splines; spl!=NULL; spl = spl->next ) {
65 0 : for ( sp=spl->first ;; ) {
66 0 : sp->selected = false;
67 0 : if ( sp->next == NULL )
68 0 : break;
69 0 : sp = sp->next->to;
70 0 : if ( sp==spl->first )
71 0 : break;
72 0 : }
73 : }
74 0 : for ( rf=sc->layers[layer].refs; rf!=NULL; rf = rf->next )
75 0 : if ( rf->selected ) rf->selected = false;
76 :
77 0 : if ( sv->sd.subpatternsearch ) {
78 0 : spl = sv->sd.matched_spl;
79 0 : for ( sp = sv->sd.matched_sp; ; ) {
80 0 : sp->selected = true;
81 0 : if ( sp->next == NULL || sv->sd.last_sp==NULL || sp==sv->sd.last_sp )
82 : break;
83 0 : sp = sp->next->to;
84 : /* Ok to wrap back to first */
85 0 : }
86 : } else {
87 0 : for ( rf=sc->layers[layer].refs, i=0; rf!=NULL; rf=rf->next, ++i )
88 0 : if ( sv->sd.matched_refs&(1<<i) )
89 0 : rf->selected = true;
90 0 : for ( spl = sc->layers[layer].splines,i=0; spl!=NULL; spl = spl->next, ++i ) {
91 0 : if ( sv->sd.matched_ss&(1<<i) ) {
92 0 : for ( sp=spl->first ;; ) {
93 0 : sp->selected = true;
94 0 : if ( sp->next == NULL )
95 0 : break;
96 0 : sp = sp->next->to;
97 0 : if ( sp==spl->first )
98 0 : break;
99 0 : }
100 : }
101 : }
102 : }
103 0 : SCUpdateAll(sc);
104 0 : sc->changed_since_search = false;
105 0 : }
106 :
107 0 : static int DoFindOne(SearchView *sv,int startafter) {
108 : int i, gid;
109 0 : SplineChar *startcur = sv->sd.curchar;
110 :
111 : /* It is possible that some idiot deleted the current character since */
112 : /* the last search... do some mild checks */
113 0 : if ( sv->sd.curchar!=NULL &&
114 0 : sv->sd.curchar->parent == sv->sd.fv->sf &&
115 0 : sv->sd.curchar->orig_pos>=0 && sv->sd.curchar->orig_pos<sv->sd.fv->sf->glyphcnt &&
116 0 : sv->sd.curchar==sv->sd.fv->sf->glyphs[sv->sd.curchar->orig_pos] )
117 : /* Looks ok */;
118 : else
119 0 : sv->sd.curchar=startcur=NULL;
120 :
121 0 : if ( !sv->sd.subpatternsearch ) startafter = false;
122 :
123 0 : if ( sv->showsfindnext && sv->sd.curchar!=NULL )
124 0 : i = sv->sd.fv->map->backmap[sv->sd.curchar->orig_pos]+1-startafter;
125 : else {
126 0 : startafter = false;
127 0 : if ( !sv->sd.onlyselected )
128 0 : i = 0;
129 : else {
130 0 : for ( i=0; i<sv->sd.fv->map->enccount; ++i )
131 0 : if ( sv->sd.fv->selected[i] && (gid=sv->sd.fv->map->map[i])!=-1 &&
132 0 : sv->sd.fv->sf->glyphs[gid]!=NULL )
133 0 : break;
134 : }
135 : }
136 :
137 0 : for ( ; i<sv->sd.fv->map->enccount; ++i ) {
138 0 : if (( !sv->sd.onlyselected || sv->sd.fv->selected[i]) && (gid=sv->sd.fv->map->map[i])!=-1 &&
139 0 : sv->sd.fv->sf->glyphs[gid]!=NULL ) {
140 0 : SCSplinePointsUntick(sv->sd.fv->sf->glyphs[gid],sv->sd.fv->active_layer);
141 0 : if ( SearchChar(&sv->sd,gid,startafter) )
142 0 : break;
143 : }
144 0 : startafter = false;
145 : }
146 0 : if ( i>=sv->sd.fv->map->enccount ) {
147 0 : ff_post_notice(_("Not Found"),sv->showsfindnext?_("The search pattern was not found again in the font %.100s"):_("The search pattern was not found in the font %.100s"),sv->sd.fv->sf->fontname);
148 0 : sv->sd.curchar = startcur;
149 0 : GGadgetSetTitle8(GWidgetGetControl(sv->gw,CID_Find),_("Find"));
150 0 : sv->showsfindnext = false;
151 0 : return( false );
152 : }
153 0 : SVSelectSC(sv);
154 0 : if ( sv->lastcv!=NULL && sv->lastcv->b.sc==startcur && sv->lastcv->b.fv== sv->sd.fv ) {
155 0 : CVChangeSC(sv->lastcv,sv->sd.curchar);
156 0 : GDrawSetVisible(sv->lastcv->gw,true);
157 0 : GDrawRaise(sv->lastcv->gw);
158 : } else
159 0 : sv->lastcv = CharViewCreate(sv->sd.curchar,(FontView *) sv->sd.fv,-1);
160 0 : GGadgetSetTitle8(GWidgetGetControl(sv->gw,CID_Find),_("Find Next"));
161 0 : sv->showsfindnext = true;
162 0 : return( true );
163 : }
164 :
165 0 : static void DoFindAll(SearchView *sv) {
166 : int any;
167 :
168 0 : any = _DoFindAll(&sv->sd);
169 0 : GDrawRequestExpose(((FontView *) (sv->sd.fv))->v,NULL,false);
170 0 : if ( !any )
171 0 : ff_post_notice(_("Not Found"),_("The search pattern was not found in the font %.100s"),sv->sd.fv->sf->fontname);
172 0 : }
173 :
174 0 : static int pathpointcnt(SplineSet *ss) {
175 : SplinePoint *sp;
176 : int cnt;
177 :
178 0 : if ( ss==NULL ) /* No paths */
179 0 : return( 0 );
180 0 : if ( ss->next!=NULL ) /* more than one path */
181 0 : return( -1 );
182 0 : if ( ss->first->prev!=NULL )/* single path, but it is closed */
183 0 : return( -2 );
184 0 : for ( sp=ss->first, cnt=1; sp->next!=NULL; sp=sp->next->to, ++cnt );
185 0 : return( cnt );
186 : }
187 :
188 0 : static int SVParseDlg(SearchView *sv, int check_replace ) {
189 0 : int err=false;
190 : double fudge;
191 :
192 0 : fudge = GetReal8(sv->gw,CID_Fuzzy,_("Match Fuzziness:"),&err);
193 0 : if ( err )
194 0 : return( false );
195 0 : old_fudge = fudge;
196 :
197 0 : sv->sd.tryreverse = true;
198 0 : sv->sd.tryflips = GGadgetIsChecked(GWidgetGetControl(sv->gw,CID_Flipping));
199 0 : sv->sd.tryscale = GGadgetIsChecked(GWidgetGetControl(sv->gw,CID_Scaling));
200 0 : sv->sd.tryrotate = GGadgetIsChecked(GWidgetGetControl(sv->gw,CID_Rotating));
201 0 : sv->sd.endpoints = GGadgetIsChecked(GWidgetGetControl(sv->gw,CID_Endpoints));
202 0 : sv->sd.onlyselected = GGadgetIsChecked(GWidgetGetControl(sv->gw,CID_Selected));
203 :
204 0 : SVResetPaths(&sv->sd);
205 0 : if ( pathpointcnt(sv->sd.path)==0 )
206 0 : ff_post_error(_("Bad search pattern"),_("Nothing to match."));
207 0 : else if ( sv->sd.endpoints ) {
208 0 : if ( pathpointcnt(sv->sd.path)<3 ||
209 0 : (check_replace && pathpointcnt(sv->sd.replacepath)<3 && pathpointcnt(sv->sd.replacepath)!=0 )) {
210 0 : if ( pathpointcnt(sv->sd.path)<0 )
211 0 : ff_post_error(_("Bad search pattern"),_("When \"Endpoints specify minimum length and direction only\" is checked, the search pattern must be a single open contour."));
212 0 : else if ( pathpointcnt(sv->sd.path)<3 )
213 0 : ff_post_error(_("Bad search pattern"),_("When \"Endpoints specify minimum length and direction only\" is checked, the search pattern must be a single open contour with at least 3 points on it (otherwise there is nothing to match)."));
214 : else
215 0 : ff_post_error(_("Bad replace pattern"),_("When \"Endpoints specify minimum length and direction only\" is checked, the replace pattern must be a single open contour with at least 3 points on it."));
216 0 : return( false );
217 : }
218 0 : } else if ( pathpointcnt(sv->sd.path)>0 ) {
219 : /* It might make sense not to do a sub-pattern search if the */
220 : /* replace pattern is closed... but that's kind of weird */
221 0 : if ( check_replace && pathpointcnt(sv->sd.replacepath)<0 ) {
222 0 : ff_post_error(_("Bad replace pattern"),_("When the search path is a single open contour, the replace pattern must also be."));
223 0 : return( false );
224 : }
225 : }
226 :
227 0 : sv->sd.fudge = fudge;
228 0 : sv->sd.fudge_percent = sv->sd.tryrotate ? .01 : .001;
229 0 : return( true );
230 : }
231 :
232 0 : static int SV_Find(GGadget *g, GEvent *e) {
233 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
234 0 : SearchView *sv = (SearchView *) ((CharViewBase *) GDrawGetUserData(GGadgetGetWindow(g)))->container;
235 0 : if ( !SVParseDlg(sv,false))
236 0 : return( true );
237 0 : sv->sd.findall = sv->sd.replaceall = false;
238 0 : DoFindOne(sv,false);
239 : }
240 0 : return( true );
241 : }
242 :
243 0 : static int SV_FindAll(GGadget *g, GEvent *e) {
244 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
245 0 : SearchView *sv = (SearchView *) ((CharViewBase *) GDrawGetUserData(GGadgetGetWindow(g)))->container;
246 0 : if ( !SVParseDlg(sv,false))
247 0 : return( true );
248 0 : sv->sd.findall = true;
249 0 : sv->sd.replaceall = false;
250 0 : DoFindAll(sv);
251 : }
252 0 : return( true );
253 : }
254 :
255 0 : static int SV_RplFind(GGadget *g, GEvent *e) {
256 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
257 0 : SearchView *sv = (SearchView *) ((CharViewBase *) GDrawGetUserData(GGadgetGetWindow(g)))->container;
258 : RefChar *rf;
259 0 : if ( !SVParseDlg(sv,true))
260 0 : return( true );
261 0 : sv->sd.findall = sv->sd.replaceall = false;
262 0 : for ( rf=sv->sd.sc_rpl.layers[ly_fore].refs; rf!=NULL; rf = rf->next ) {
263 0 : if ( SCDependsOnSC(rf->sc,sv->sd.curchar)) {
264 0 : ff_post_error(_("Self-referential glyph"),_("Attempt to make a glyph that refers to itself"));
265 0 : return( true );
266 : }
267 : }
268 0 : DoRpl(&sv->sd);
269 0 : DoFindOne(sv,sv->sd.subpatternsearch);
270 : }
271 0 : return( true );
272 : }
273 :
274 0 : static int SV_RplAll(GGadget *g, GEvent *e) {
275 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
276 0 : SearchView *sv = (SearchView *) ((CharViewBase *) GDrawGetUserData(GGadgetGetWindow(g)))->container;
277 0 : if ( !SVParseDlg(sv,true))
278 0 : return( true );
279 0 : sv->sd.findall = false;
280 0 : sv->sd.replaceall = true;
281 0 : DoFindAll(sv);
282 : }
283 0 : return( true );
284 : }
285 :
286 : /* ************************************************************************** */
287 :
288 0 : void SV_DoClose(struct cvcontainer *cvc) {
289 0 : GDrawSetVisible(((SearchView *) cvc)->gw,false);
290 0 : }
291 :
292 0 : static int SV_Cancel(GGadget *g, GEvent *e) {
293 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate )
294 0 : SV_DoClose(((CharViewBase *) GDrawGetUserData(GGadgetGetWindow(g)))->container);
295 0 : return( true );
296 : }
297 :
298 0 : static void SVResize(SearchView *sv, GEvent *event) {
299 : int width, height;
300 :
301 0 : if ( !event->u.resize.sized )
302 0 : return;
303 :
304 0 : GGadgetMove(GWidgetGetControl(sv->gw,CID_TopBox),4,4);
305 0 : GGadgetResize(GWidgetGetControl(sv->gw,CID_TopBox),
306 0 : event->u.resize.size.width-8,
307 0 : event->u.resize.size.height-12);
308 :
309 0 : width = (event->u.resize.size.width-40)/2;
310 0 : height = (event->u.resize.size.height-sv->cv_y-sv->button_height-8);
311 0 : if ( width<70 || height<80 ) {
312 0 : if ( width<70 ) width = 70;
313 0 : width = 2*width+40;
314 0 : if ( height<80 ) height = 80;
315 0 : height += sv->cv_y+sv->button_height+8;
316 0 : GDrawResize(sv->gw,width,height);
317 0 : return;
318 : }
319 0 : if ( width!=sv->cv_width || height!=sv->cv_height ) {
320 0 : GDrawResize(sv->cv_srch.gw,width,height);
321 0 : GDrawResize(sv->cv_rpl.gw,width,height);
322 0 : sv->cv_width = width; sv->cv_height = height;
323 0 : sv->rpl_x = 30+width;
324 0 : GDrawMove(sv->cv_rpl.gw,sv->rpl_x,sv->cv_y);
325 : }
326 :
327 0 : GDrawSync(NULL);
328 0 : GDrawProcessPendingEvents(NULL);
329 0 : GDrawRequestExpose(sv->gw,NULL,false);
330 : }
331 :
332 0 : void SVMakeActive(SearchView *sv,CharView *cv) {
333 : GRect r;
334 0 : if ( sv==NULL )
335 0 : return;
336 0 : sv->cv_srch.inactive = sv->cv_rpl.inactive = true;
337 0 : cv->inactive = false;
338 0 : GDrawSetUserData(sv->gw,cv);
339 0 : GDrawRequestExpose(sv->cv_srch.v,NULL,false);
340 0 : GDrawRequestExpose(sv->cv_rpl.v,NULL,false);
341 0 : GDrawGetSize(sv->gw,&r);
342 0 : r.x = 0;
343 0 : r.y = sv->mbh;
344 0 : r.height = sv->fh+10;
345 0 : GDrawRequestExpose(sv->gw,&r,false);
346 : }
347 :
348 0 : static void SVChar(SearchView *sv, GEvent *event) {
349 0 : if ( event->u.chr.keysym==GK_Tab || event->u.chr.keysym==GK_BackTab )
350 0 : SVMakeActive(sv,sv->cv_srch.inactive ? &sv->cv_srch : &sv->cv_rpl);
351 : else
352 0 : CVChar(sv->cv_srch.inactive ? &sv->cv_rpl : &sv->cv_srch,event);
353 0 : }
354 :
355 0 : static void SVDraw(SearchView *sv, GWindow pixmap, GEvent *event) {
356 : GRect r;
357 :
358 0 : GDrawSetLineWidth(pixmap,0);
359 0 : if ( sv->cv_srch.inactive )
360 0 : GDrawSetFont(pixmap,sv->plain);
361 : else
362 0 : GDrawSetFont(pixmap,sv->bold);
363 0 : GDrawDrawText8(pixmap,10,sv->mbh+5+sv->as,
364 0 : _("Search Pattern:"),-1,0);
365 0 : if ( sv->cv_rpl.inactive )
366 0 : GDrawSetFont(pixmap,sv->plain);
367 : else
368 0 : GDrawSetFont(pixmap,sv->bold);
369 0 : GDrawDrawText8(pixmap,sv->rpl_x,sv->mbh+5+sv->as,
370 0 : _("Replace Pattern:"),-1,0);
371 0 : r.x = 10-1; r.y=sv->cv_y-1;
372 0 : r.width = sv->cv_width+1; r.height = sv->cv_height+1;
373 0 : GDrawDrawRect(pixmap,&r,0);
374 0 : r.x = sv->rpl_x-1;
375 0 : GDrawDrawRect(pixmap,&r,0);
376 0 : }
377 :
378 0 : static void SVCheck(SearchView *sv) {
379 0 : int show = ( sv->sd.sc_srch.layers[ly_fore].splines!=NULL || sv->sd.sc_srch.layers[ly_fore].refs!=NULL );
380 0 : int showrplall=show, showrpl;
381 :
382 0 : if ( sv->sd.sc_srch.changed_since_autosave && sv->showsfindnext ) {
383 0 : GGadgetSetTitle8(GWidgetGetControl(sv->gw,CID_Find),_("Find"));
384 0 : sv->showsfindnext = false;
385 : }
386 0 : if ( showrplall ) {
387 0 : if ( sv->sd.sc_srch.layers[ly_fore].splines!=NULL && sv->sd.sc_srch.layers[ly_fore].splines->next==NULL &&
388 0 : sv->sd.sc_srch.layers[ly_fore].splines->first->prev==NULL &&
389 0 : sv->sd.sc_rpl.layers[ly_fore].splines==NULL && sv->sd.sc_rpl.layers[ly_fore].refs==NULL )
390 0 : showrplall = false;
391 : }
392 0 : showrpl = showrplall;
393 0 : if ( !sv->showsfindnext || sv->sd.curchar==NULL || sv->sd.curchar->parent!=sv->sd.fv->sf ||
394 0 : sv->sd.curchar->orig_pos<0 || sv->sd.curchar->orig_pos>=sv->sd.fv->sf->glyphcnt ||
395 0 : sv->sd.curchar!=sv->sd.fv->sf->glyphs[sv->sd.curchar->orig_pos] ||
396 0 : sv->sd.curchar->changed_since_search )
397 0 : showrpl = false;
398 :
399 0 : if ( sv->findenabled != show ) {
400 0 : GGadgetSetEnabled(GWidgetGetControl(sv->gw,CID_Find),show);
401 0 : GGadgetSetEnabled(GWidgetGetControl(sv->gw,CID_FindAll),show);
402 0 : sv->findenabled = show;
403 : }
404 0 : if ( sv->rplallenabled != showrplall ) {
405 0 : GGadgetSetEnabled(GWidgetGetControl(sv->gw,CID_ReplaceAll),showrplall);
406 0 : sv->rplallenabled = showrplall;
407 : }
408 0 : if ( sv->rplenabled != showrpl ) {
409 0 : GGadgetSetEnabled(GWidgetGetControl(sv->gw,CID_Replace),showrpl);
410 0 : sv->rplenabled = showrpl;
411 : }
412 0 : }
413 :
414 0 : static void SearchViewFree(SearchView *sv) {
415 0 : SplinePointListsFree(sv->sd.sc_srch.layers[ly_fore].splines);
416 0 : SplinePointListsFree(sv->sd.sc_rpl.layers[ly_fore].splines);
417 0 : RefCharsFree(sv->sd.sc_srch.layers[ly_fore].refs);
418 0 : RefCharsFree(sv->sd.sc_rpl.layers[ly_fore].refs);
419 0 : free(sv);
420 0 : }
421 :
422 0 : static int sv_e_h(GWindow gw, GEvent *event) {
423 0 : SearchView *sv = (SearchView *) ((CharViewBase *) GDrawGetUserData(gw))->container;
424 :
425 0 : switch ( event->type ) {
426 : case et_expose:
427 0 : SVDraw(sv,gw,event);
428 0 : break;
429 : case et_resize:
430 0 : if ( event->u.resize.sized )
431 0 : SVResize(sv,event);
432 0 : break;
433 : case et_char:
434 0 : SVChar(sv,event);
435 0 : break;
436 : case et_timer:
437 0 : SVCheck(sv);
438 0 : break;
439 : case et_close:
440 0 : SV_DoClose((struct cvcontainer *) sv);
441 0 : break;
442 : case et_create:
443 0 : break;
444 : case et_destroy:
445 0 : SearchViewFree(sv);
446 0 : break;
447 : case et_map:
448 0 : if ( event->u.map.is_visible )
449 0 : CVPaletteActivate(sv->cv_srch.inactive?&sv->cv_rpl:&sv->cv_srch);
450 : else
451 0 : CVPalettesHideIfMine(sv->cv_srch.inactive?&sv->cv_rpl:&sv->cv_srch);
452 0 : sv->isvisible = event->u.map.is_visible;
453 0 : break;
454 : }
455 0 : return( true );
456 : }
457 :
458 0 : static void SVSetTitle(SearchView *sv) {
459 : char ubuf[150];
460 0 : sprintf(ubuf,_("Find in %.100s"),sv->sd.fv->sf->fontname);
461 0 : GDrawSetWindowTitles8(sv->gw,ubuf,_("Find"));
462 0 : }
463 :
464 0 : int SVAttachFV(FontView *fv,int ask_if_difficult) {
465 0 : int i, doit, pos, any=0, gid;
466 : RefChar *r, *rnext, *rprev;
467 :
468 0 : if ( searcher==NULL )
469 0 : return( false );
470 :
471 0 : if ( searcher->sd.fv==(FontViewBase *) fv )
472 0 : return( true );
473 0 : if ( searcher->sd.fv!=NULL && searcher->sd.fv->sf==fv->b.sf ) {
474 0 : ((FontView *) searcher->sd.fv)->sv = NULL;
475 0 : fv->sv = searcher;
476 0 : searcher->sd.fv = (FontViewBase *) fv;
477 0 : SVSetTitle(searcher);
478 0 : searcher->sd.curchar = NULL;
479 0 : return( true );
480 : }
481 :
482 0 : if ( searcher->dummy_sf.layers[ly_fore].order2 != fv->b.sf->layers[ly_fore].order2 ) {
483 0 : SCClearContents(&searcher->sd.sc_srch,ly_fore);
484 0 : SCClearContents(&searcher->sd.sc_rpl,ly_fore);
485 0 : for ( i=0; i<searcher->sd.sc_srch.layer_cnt; ++i )
486 0 : UndoesFree(searcher->sd.sc_srch.layers[i].undoes);
487 0 : for ( i=0; i<searcher->sd.sc_rpl.layer_cnt; ++i )
488 0 : UndoesFree(searcher->sd.sc_rpl.layers[i].undoes);
489 : }
490 :
491 0 : for ( doit=!ask_if_difficult; doit<=1; ++doit ) {
492 0 : for ( i=0; i<2; ++i ) {
493 0 : rprev = NULL;
494 0 : for ( r = searcher->chars[i]->layers[ly_fore].refs; r!=NULL; r=rnext ) {
495 0 : rnext = r->next;
496 0 : pos = SFFindSlot(fv->b.sf,fv->b.map,r->sc->unicodeenc,r->sc->name);
497 0 : gid = -1;
498 0 : if ( pos!=-1 )
499 0 : gid = fv->b.map->map[pos];
500 0 : if ( (gid==-1 || fv->b.sf->glyphs[gid]!=NULL) && !doit ) {
501 : char *buttons[3];
502 0 : buttons[0] = _("Yes");
503 0 : buttons[1] = _("Cancel");
504 0 : buttons[2] = NULL;
505 0 : if ( ask_if_difficult==2 && !searcher->isvisible )
506 0 : return( false );
507 0 : if ( gwwv_ask(_("Bad Reference"),(const char **) buttons,1,1,
508 0 : _("The %1$s in the search dialog contains a reference to %2$.20hs which does not exist in the new font.\nShould I remove the reference?"),
509 : i==0?_("Search Pattern"):_("Replace Pattern"),
510 0 : r->sc->name)==1 )
511 0 : return( false );
512 0 : } else if ( !doit )
513 : /* Do Nothing */;
514 0 : else if ( gid==-1 || fv->b.sf->glyphs[gid]!=NULL ) {
515 0 : if ( rprev==NULL )
516 0 : searcher->chars[i]->layers[ly_fore].refs = rnext;
517 : else
518 0 : rprev->next = rnext;
519 0 : RefCharFree(r);
520 0 : any = true;
521 : } else {
522 : /*SplinePointListsFree(r->layers[0].splines); r->layers[0].splines = NULL;*/
523 0 : r->sc = fv->b.sf->glyphs[gid];
524 0 : r->orig_pos = gid;
525 0 : SCReinstanciateRefChar(searcher->chars[i],r,fv->b.active_layer);
526 0 : any = true;
527 0 : rprev = r;
528 : }
529 : }
530 : }
531 : }
532 0 : fv->sv = searcher;
533 0 : searcher->sd.fv = (FontViewBase *) fv;
534 0 : searcher->sd.curchar = NULL;
535 0 : if ( any ) {
536 0 : GDrawRequestExpose(searcher->cv_srch.v,NULL,false);
537 0 : GDrawRequestExpose(searcher->cv_rpl.v,NULL,false);
538 : }
539 0 : SVSetTitle(searcher);
540 0 : return( true );
541 : }
542 :
543 0 : void SVDetachFV(FontView *fv) {
544 : FontView *other;
545 :
546 0 : fv->sv = NULL;
547 0 : if ( searcher==NULL || searcher->sd.fv!=(FontViewBase *) fv )
548 0 : return;
549 0 : SV_DoClose((struct cvcontainer *) searcher);
550 0 : for ( other=fv_list; other!=NULL; other=(FontView *) other->b.next ) {
551 0 : if ( other!=fv ) {
552 0 : SVAttachFV(fv,false);
553 0 : return;
554 : }
555 : }
556 : }
557 :
558 0 : static int SV_Can_Navigate(struct cvcontainer *cvc, enum nav_type type) {
559 0 : return( false );
560 : }
561 :
562 0 : static int SV_Can_Open(struct cvcontainer *cvc) {
563 0 : return( true );
564 : }
565 :
566 0 : static void SV_Do_Navigate(struct cvcontainer *cvc, enum nav_type type) {
567 0 : }
568 :
569 0 : static SplineFont *SF_Of_SV(struct cvcontainer *cvc) {
570 0 : return( ((SearchView *) cvc)->sd.fv->sf );
571 : }
572 :
573 : struct cvcontainer_funcs searcher_funcs = {
574 : cvc_searcher,
575 : (void (*) (struct cvcontainer *cvc,CharViewBase *cv)) SVMakeActive,
576 : (void (*) (struct cvcontainer *cvc,void *)) SVChar,
577 : SV_Can_Navigate,
578 : SV_Do_Navigate,
579 : SV_Can_Open,
580 : SV_DoClose,
581 : SF_Of_SV
582 : };
583 :
584 0 : static SearchView *SVFillup(SearchView *sv, FontView *fv) {
585 :
586 0 : SDFillup(&sv->sd,(FontViewBase *) fv);
587 0 : sv->base.funcs = &searcher_funcs;
588 :
589 0 : sv->chars[0] = &sv->sd.sc_srch;
590 0 : sv->chars[1] = &sv->sd.sc_rpl;
591 0 : sv->dummy_sf.glyphs = sv->chars;
592 0 : sv->dummy_sf.glyphcnt = sv->dummy_sf.glyphmax = 2;
593 0 : sv->dummy_sf.pfminfo.fstype = -1;
594 0 : sv->dummy_sf.pfminfo.stylemap = -1;
595 0 : sv->dummy_sf.fontname = sv->dummy_sf.fullname = sv->dummy_sf.familyname = "dummy";
596 0 : sv->dummy_sf.weight = "Medium";
597 0 : sv->dummy_sf.origname = "dummy";
598 0 : sv->dummy_sf.ascent = fv->b.sf->ascent;
599 0 : sv->dummy_sf.descent = fv->b.sf->descent;
600 0 : sv->dummy_sf.layers = sv->layerinfo;
601 0 : sv->dummy_sf.layer_cnt = 2;
602 0 : sv->layerinfo[ly_back].order2 = fv->b.sf->layers[ly_back].order2;
603 0 : sv->layerinfo[ly_back].name = _("Back");
604 0 : sv->layerinfo[ly_fore].order2 = fv->b.sf->layers[ly_fore].order2;
605 0 : sv->layerinfo[ly_fore].name = _("Fore");
606 0 : sv->dummy_sf.grid.order2 = fv->b.sf->grid.order2;
607 0 : sv->dummy_sf.anchor = fv->b.sf->anchor;
608 0 : sv->sd.sc_srch.width = sv->sd.sc_srch.vwidth = sv->sd.sc_rpl.vwidth = sv->sd.sc_rpl.width =
609 0 : sv->dummy_sf.ascent + sv->dummy_sf.descent;
610 0 : sv->sd.sc_srch.parent = sv->sd.sc_rpl.parent = &sv->dummy_sf;
611 :
612 0 : sv->dummy_sf.fv = (FontViewBase *) &sv->dummy_fv;
613 0 : sv->dummy_fv.b.active_layer = ly_fore;
614 0 : sv->dummy_fv.b.sf = &sv->dummy_sf;
615 0 : sv->dummy_fv.b.selected = sv->sel;
616 0 : sv->dummy_fv.cbw = sv->dummy_fv.cbh = default_fv_font_size+1;
617 0 : sv->dummy_fv.magnify = 1;
618 :
619 0 : sv->cv_srch.b.container = (struct cvcontainer *) sv;
620 0 : sv->cv_rpl.inactive = true;
621 0 : sv->cv_rpl.b.container = (struct cvcontainer *) sv;
622 :
623 0 : sv->dummy_fv.b.map = &sv->dummy_map;
624 0 : sv->dummy_map.map = sv->map;
625 0 : sv->dummy_map.backmap = sv->backmap;
626 0 : sv->dummy_map.enccount = sv->dummy_map.encmax = sv->dummy_map.backmax = 2;
627 0 : sv->dummy_map.enc = &custom;
628 :
629 0 : sv->sd.fv = (FontViewBase *) fv;
630 0 : if ( fv!=NULL )
631 0 : fv->sv = sv;
632 0 : return( sv );
633 : }
634 :
635 0 : SearchView *SVCreate(FontView *fv) {
636 : SearchView *sv;
637 : GRect pos;
638 : GWindow gw;
639 : GWindowAttrs wattrs;
640 : GGadgetCreateData gcd[14], boxes[6], *butarray[14], *allowarray[6],
641 : *fudgearray[4], *halfarray[3], *varray[14];
642 : GTextInfo label[14];
643 : FontRequest rq;
644 : int as, ds, ld;
645 : char fudgebuf[20];
646 : int k, sel_pos, efdo_pos;
647 : static GFont *plainfont = NULL, *boldfont=NULL;
648 :
649 0 : if ( searcher!=NULL ) {
650 0 : if ( SVAttachFV(fv,true)) {
651 0 : GDrawSetVisible(fv->sv->gw,true);
652 0 : GDrawRaise(fv->sv->gw);
653 0 : return( searcher );
654 : } else
655 0 : return( NULL );
656 : }
657 :
658 0 : searcher = sv = SVFillup( calloc(1,sizeof(SearchView)), fv );
659 :
660 0 : memset(&wattrs,0,sizeof(wattrs));
661 0 : wattrs.mask = wam_events|wam_cursor|wam_isdlg/*|wam_icon*/;
662 0 : wattrs.is_dlg = true;
663 0 : wattrs.event_masks = -1;
664 0 : wattrs.event_masks = -1;
665 0 : wattrs.cursor = ct_pointer;
666 : /*wattrs.icon = icon;*/
667 0 : pos.width = 600;
668 0 : pos.height = 400;
669 0 : pos.x = GGadgetScale(104)+6;
670 0 : DefaultY(&pos);
671 0 : sv->gw = gw = GDrawCreateTopWindow(NULL,&pos,sv_e_h,&sv->cv_srch,&wattrs);
672 0 : SVSetTitle(sv);
673 :
674 0 : if ( plainfont==NULL ) {
675 0 : memset(&rq,0,sizeof(rq));
676 0 : rq.utf8_family_name = SANS_UI_FAMILIES;
677 0 : rq.point_size = 12;
678 0 : rq.weight = 400;
679 0 : plainfont = GDrawInstanciateFont(NULL,&rq);
680 0 : plainfont = GResourceFindFont("SearchView.Font",plainfont);
681 0 : GDrawDecomposeFont(plainfont, &rq);
682 0 : rq.weight = 700;
683 0 : boldfont = GDrawInstanciateFont(NULL,&rq);
684 0 : boldfont = GResourceFindFont("SearchView.BoldFont",boldfont);
685 : }
686 0 : sv->plain = plainfont; sv->bold = boldfont;
687 0 : GDrawWindowFontMetrics(sv->gw,sv->plain,&as,&ds,&ld);
688 0 : sv->fh = as+ds; sv->as = as;
689 :
690 0 : SVCharViewInits(sv);
691 :
692 0 : memset(&label,0,sizeof(label));
693 0 : memset(&gcd,0,sizeof(gcd));
694 0 : memset(&boxes,0,sizeof(boxes));
695 :
696 0 : k=0;
697 :
698 0 : label[k].text = (unichar_t *) _("Allow:");
699 0 : label[k].text_is_1byte = true;
700 0 : gcd[k].gd.label = &label[k];
701 0 : gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = GDrawPixelsToPoints(NULL,sv->cv_y+sv->cv_height+8);
702 0 : gcd[k].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
703 0 : gcd[k].gd.cid = CID_Allow;
704 0 : gcd[k].gd.popup_msg = (unichar_t *) _("Allow a match even if the search pattern has\nto be transformed by a combination of the\nfollowing transformations.");
705 0 : gcd[k].creator = GLabelCreate;
706 0 : allowarray[k] = &gcd[k]; ++k;
707 :
708 0 : label[k].text = (unichar_t *) _("Flipping");
709 0 : label[k].text_is_1byte = true;
710 0 : gcd[k].gd.label = &label[k];
711 0 : gcd[k].gd.pos.x = 35; gcd[k].gd.pos.y = gcd[0].gd.pos.y-3;
712 0 : gcd[k].gd.flags = gg_enabled|gg_visible|gg_cb_on|gg_utf8_popup;
713 0 : gcd[k].gd.cid = CID_Flipping;
714 0 : gcd[k].gd.popup_msg = (unichar_t *) _("Allow a match even if the search pattern has\nto be transformed by a combination of the\nfollowing transformations.");
715 0 : gcd[k].creator = GCheckBoxCreate;
716 0 : allowarray[k] = &gcd[k]; ++k;
717 :
718 0 : label[k].text = (unichar_t *) _("Scaling");
719 0 : label[k].text_is_1byte = true;
720 0 : gcd[k].gd.label = &label[k];
721 0 : gcd[k].gd.pos.x = 100; gcd[k].gd.pos.y = gcd[1].gd.pos.y;
722 0 : gcd[k].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
723 0 : gcd[k].gd.cid = CID_Scaling;
724 0 : gcd[k].gd.popup_msg = (unichar_t *) _("Allow a match even if the search pattern has\nto be transformed by a combination of the\nfollowing transformations.");
725 0 : gcd[k].creator = GCheckBoxCreate;
726 0 : allowarray[k] = &gcd[k]; ++k;
727 :
728 0 : label[k].text = (unichar_t *) _("Rotating");
729 0 : label[k].text_is_1byte = true;
730 0 : gcd[k].gd.label = &label[k];
731 0 : gcd[k].gd.pos.x = 170; gcd[k].gd.pos.y = gcd[1].gd.pos.y;
732 0 : gcd[k].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
733 0 : gcd[k].gd.cid = CID_Rotating;
734 0 : gcd[k].gd.popup_msg = (unichar_t *) _("Allow a match even if the search pattern has\nto be transformed by a combination of the\nfollowing transformations.");
735 0 : gcd[k].creator = GCheckBoxCreate;
736 0 : allowarray[k] = &gcd[k]; allowarray[++k] = GCD_Glue; allowarray[5] = NULL;
737 :
738 0 : label[k].text = (unichar_t *) _("_Match Fuzziness:");
739 0 : label[k].text_is_1byte = true;
740 0 : label[k].text_in_resource = true;
741 0 : gcd[k].gd.label = &label[k];
742 0 : gcd[k].gd.flags = gg_enabled|gg_visible;
743 0 : gcd[k].creator = GLabelCreate;
744 0 : fudgearray[0] = &gcd[k++];
745 :
746 0 : sprintf(fudgebuf,"%g",old_fudge);
747 0 : label[k].text = (unichar_t *) fudgebuf;
748 0 : label[k].text_is_1byte = true;
749 0 : label[k].text_in_resource = true;
750 0 : gcd[k].gd.label = &label[k];
751 0 : gcd[k].gd.flags = gg_enabled|gg_visible;
752 0 : gcd[k].gd.cid = CID_Fuzzy;
753 0 : gcd[k].creator = GTextFieldCreate;
754 0 : fudgearray[1] = &gcd[k++]; fudgearray[2] = GCD_Glue; fudgearray[3] = NULL;
755 :
756 0 : efdo_pos = k;
757 0 : label[k].text = (unichar_t *) _("Endpoints specify minimum length and direction only");
758 0 : label[k].text_is_1byte = true;
759 0 : gcd[k].gd.label = &label[k];
760 0 : gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = gcd[1].gd.pos.y+18;
761 0 : gcd[k].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
762 0 : gcd[k].gd.cid = CID_Endpoints;
763 0 : gcd[k].gd.popup_msg = (unichar_t *) _(
764 : "If the search pattern is a single open contour\n"
765 : "then do not match the end points. They merely\n"
766 : "specify the direction from which the curve should\n"
767 : "move toward the next point (which will be matched),\n"
768 : "and the minimum distance between the first matched\n"
769 : "point and the one before it. The endpoints of the\n"
770 : "replace contour will also only be used for positioning.\n"
771 : "\n"
772 : "This allows you to match a right angle corner\n"
773 : "without needed to specify exactly how long the edges\n"
774 : "are which form the right angle.");
775 0 : gcd[k++].creator = GCheckBoxCreate;
776 :
777 0 : sel_pos = k;
778 0 : label[k].text = (unichar_t *) _("Search Selected Chars Only");
779 0 : label[k].text_is_1byte = true;
780 0 : gcd[k].gd.label = &label[k];
781 0 : gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = gcd[1].gd.pos.y+18;
782 0 : gcd[k].gd.flags = gg_enabled|gg_visible|gg_utf8_popup;
783 0 : gcd[k].gd.cid = CID_Selected;
784 0 : gcd[k].gd.popup_msg = (unichar_t *) _("Only search characters selected in the fontview.\nNormally we search all characters in the font.");
785 0 : gcd[k++].creator = GCheckBoxCreate;
786 :
787 0 : label[k].text = (unichar_t *) _("Find Next"); /* Start with this to allow sufficient space */
788 0 : label[k].text_is_1byte = true;
789 0 : gcd[k].gd.label = &label[k];
790 0 : gcd[k].gd.pos.x = 5; gcd[k].gd.pos.y = gcd[sel_pos].gd.pos.y+24;
791 0 : gcd[k].gd.flags = gg_visible|gg_but_default;
792 0 : gcd[k].gd.cid = CID_Find;
793 0 : gcd[k].gd.handle_controlevent = SV_Find;
794 0 : gcd[k].creator = GButtonCreate;
795 0 : butarray[0] = GCD_Glue; butarray[1] = GCD_Glue; butarray[2] = &gcd[k++];
796 :
797 0 : label[k].text = (unichar_t *) _("Find All");
798 0 : label[k].text_is_1byte = true;
799 0 : gcd[k].gd.label = &label[k];
800 0 : gcd[k].gd.pos.x = 0; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y+3;
801 0 : gcd[k].gd.flags = gg_visible;
802 0 : gcd[k].gd.cid = CID_FindAll;
803 0 : gcd[k].gd.handle_controlevent = SV_FindAll;
804 0 : gcd[k].creator = GButtonCreate;
805 0 : butarray[3] = GCD_Glue; butarray[4] = &gcd[k++];
806 :
807 0 : label[k].text = (unichar_t *) _("Replace");
808 0 : label[k].text_is_1byte = true;
809 0 : gcd[k].gd.label = &label[k];
810 0 : gcd[k].gd.pos.x = 0; gcd[k].gd.pos.y = gcd[k-1].gd.pos.y;
811 0 : gcd[k].gd.flags = gg_visible;
812 0 : gcd[k].gd.cid = CID_Replace;
813 0 : gcd[k].gd.handle_controlevent = SV_RplFind;
814 0 : gcd[k].creator = GButtonCreate;
815 0 : butarray[5] = GCD_Glue; butarray[6] = &gcd[k++];
816 :
817 0 : label[k].text = (unichar_t *) _("Replace All");
818 0 : label[k].text_is_1byte = true;
819 0 : gcd[k].gd.label = &label[k];
820 0 : gcd[k].gd.pos.x = 0; gcd[k].gd.pos.y = gcd[k-2].gd.pos.y;
821 0 : gcd[k].gd.flags = gg_visible;
822 0 : gcd[k].gd.cid = CID_ReplaceAll;
823 0 : gcd[k].gd.handle_controlevent = SV_RplAll;
824 0 : gcd[k].creator = GButtonCreate;
825 0 : butarray[7] = GCD_Glue; butarray[8] = &gcd[k++];
826 :
827 0 : label[k].text = (unichar_t *) _("_Cancel");
828 0 : label[k].text_is_1byte = true;
829 0 : label[k].text_in_resource = true;
830 0 : gcd[k].gd.label = &label[k];
831 0 : gcd[k].gd.pos.x = 0; gcd[k].gd.pos.y = gcd[k-3].gd.pos.y;
832 0 : gcd[k].gd.flags = gg_enabled|gg_visible|gg_but_cancel;
833 0 : gcd[k].gd.cid = CID_Cancel;
834 0 : gcd[k].gd.handle_controlevent = SV_Cancel;
835 0 : gcd[k].creator = GButtonCreate;
836 0 : butarray[9] = GCD_Glue; butarray[10] = &gcd[k++];
837 0 : butarray[11] = GCD_Glue; butarray[12] = GCD_Glue; butarray[13] = NULL;
838 :
839 0 : boxes[2].gd.flags = gg_enabled|gg_visible;
840 0 : boxes[2].gd.u.boxelements = allowarray;
841 0 : boxes[2].creator = GHBoxCreate;
842 :
843 0 : boxes[3].gd.flags = gg_enabled|gg_visible;
844 0 : boxes[3].gd.u.boxelements = fudgearray;
845 0 : boxes[3].creator = GHBoxCreate;
846 0 : halfarray[0] = &boxes[2]; halfarray[1] = &boxes[3]; halfarray[2] = NULL;
847 :
848 0 : boxes[4].gd.flags = gg_enabled|gg_visible;
849 0 : boxes[4].gd.u.boxelements = halfarray;
850 0 : boxes[4].creator = GHBoxCreate;
851 :
852 0 : boxes[5].gd.flags = gg_enabled|gg_visible;
853 0 : boxes[5].gd.u.boxelements = butarray;
854 0 : boxes[5].creator = GHBoxCreate;
855 :
856 0 : varray[0] = GCD_Glue; varray[1] = NULL;
857 0 : varray[2] = &boxes[4]; varray[3] = NULL;
858 0 : varray[4] = &gcd[efdo_pos]; varray[5] = NULL;
859 0 : varray[6] = GCD_Glue; varray[7] = NULL;
860 0 : varray[8] = &gcd[sel_pos]; varray[9] = NULL;
861 0 : varray[10] = &boxes[5]; varray[11]= NULL;
862 0 : varray[12] = NULL;
863 :
864 0 : boxes[0].gd.pos.x = boxes[0].gd.pos.y = 2;
865 0 : boxes[0].gd.flags = gg_enabled|gg_visible;
866 0 : boxes[0].gd.u.boxelements = varray;
867 0 : boxes[0].gd.cid = CID_TopBox;
868 0 : boxes[0].creator = GHVGroupCreate;
869 :
870 0 : GGadgetsCreate(gw,boxes);
871 :
872 0 : GHVBoxSetExpandableRow(boxes[0].ret,0);
873 0 : GHVBoxSetPadding(boxes[2].ret,6,3);
874 0 : GHVBoxSetExpandableCol(boxes[2].ret,gb_expandglue);
875 0 : GHVBoxSetExpandableCol(boxes[3].ret,gb_expandglue);
876 0 : GHVBoxSetExpandableCol(boxes[5].ret,gb_expandglue);
877 0 : GGadgetResize(boxes[0].ret,pos.width,pos.height);
878 :
879 0 : GGadgetSetTitle8(GWidgetGetControl(gw,CID_Find),_("Find"));
880 0 : sv->showsfindnext = false;
881 0 : GDrawRequestTimer(gw,1000,1000,NULL);
882 0 : sv->button_height = GDrawPointsToPixels(gw,100);
883 0 : GDrawResize(gw,650,400); /* Force a resize event */
884 :
885 0 : GDrawSetVisible(sv->gw,true);
886 0 : return( sv );
887 : }
888 :
889 0 : void SVDestroy(SearchView *sv) {
890 :
891 0 : if ( sv==NULL )
892 0 : return;
893 :
894 0 : SDDestroy(&sv->sd);
895 0 : free(sv);
896 : }
897 :
898 0 : void FVReplaceOutlineWithReference( FontView *fv, double fudge ) {
899 :
900 0 : if ( fv->v!=NULL )
901 0 : GDrawSetCursor(fv->v,ct_watch);
902 :
903 0 : FVBReplaceOutlineWithReference((FontViewBase *) fv, fudge);
904 :
905 0 : if ( fv->v!=NULL ) {
906 0 : GDrawRequestExpose(fv->v,NULL,false);
907 0 : GDrawSetCursor(fv->v,ct_pointer);
908 : }
909 0 : }
|