1 /* Copyright (C) 2009-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 <fontforge-config.h>
29 
30 #include "autowidth2.h"
31 #include "fontforgeui.h"
32 #include "gkeysym.h"
33 #include "ustring.h"
34 #include "utype.h"
35 
36 #include <math.h>
37 
38 static int width_last_em_size=1000;
39 static int width_separation=150;
40 static int width_min_side_bearing=10;
41 static int width_max_side_bearing=300;
42 static int width_chunk_height=10;
43 static int width_loop_cnt=1;
44 
45 #define CID_Separation	1001
46 #define CID_MinSep	1002
47 #define CID_MaxSep	1003
48 #define CID_Height	1004
49 #define CID_Loop	1005
50 
51 struct widthinfo {
52     int done;
53     GWindow gw;
54     FontView *fv;
55     SplineFont *sf;
56 };
57 
AW2_OK(GGadget * g,GEvent * e)58 static int AW2_OK(GGadget *g, GEvent *e) {
59     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
60 	GWindow gw = GGadgetGetWindow(g);
61 	struct widthinfo *wi = GDrawGetUserData(gw);
62 	int err = false;
63 	int separation, min_side, max_side, height, loop;
64 
65 	separation = GetInt8(gw,CID_Separation, _("Separation"),&err);
66 	min_side = GetInt8(gw,CID_MinSep, _("Min Bearing"),&err);
67 	max_side = GetInt8(gw,CID_MaxSep, _("Max Bearing"),&err);
68 	height = GetInt8(gw,CID_Height, _("Height"),&err);
69 	loop = GetInt8(gw,CID_Loop, _("Loop Count"),&err);
70 	if ( err )
71 return( true );
72 
73 	GDrawSetVisible(gw,false);
74 	GDrawSync(NULL);
75 	GDrawProcessPendingEvents(NULL);
76 
77 	width_last_em_size     = wi->sf->ascent + wi->sf->descent;
78 	width_separation       = separation;
79 	wi->sf->width_separation=separation;
80 	if ( wi->sf->italicangle==0 )
81 	    width_min_side_bearing = min_side;
82 	width_max_side_bearing = max_side;
83 	width_chunk_height     = height;
84 	width_loop_cnt         = loop;
85 
86 	AutoWidth2((FontViewBase *) wi->fv,separation,min_side,max_side,
87 		height, loop);
88 	wi->done = true;
89     }
90 return( true );
91 }
92 
AW2_Cancel(GGadget * g,GEvent * e)93 static int AW2_Cancel(GGadget *g, GEvent *e) {
94     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
95 	GWindow gw = GGadgetGetWindow(g);
96 	struct widthinfo *wi = GDrawGetUserData(gw);
97 	wi->done = true;
98     }
99 return( true );
100 }
101 
AW2_e_h(GWindow gw,GEvent * event)102 static int AW2_e_h(GWindow gw, GEvent *event) {
103     if ( event->type==et_close ) {
104 	struct widthinfo *wi = GDrawGetUserData(gw);
105 	wi->done = true;
106     } else if ( event->type == et_char ) {
107 	if ( event->u.chr.keysym == GK_F1 || event->u.chr.keysym == GK_Help ) {
108 	    /*struct widthinfo *wi = GDrawGetUserData(gw);*/
109 	    help("ui/dialogs/autowidth.html", NULL);
110 return( true );
111 	}
112 return( false );
113     }
114 return( true );
115 }
116 
FVAutoWidth2(FontView * fv)117 void FVAutoWidth2(FontView *fv) {
118     struct widthinfo wi;
119     GWindow gw;
120     GWindowAttrs wattrs;
121     GRect pos;
122     GGadgetCreateData *harray1[4], *harray2[6], *harray3[6], *barray[9], *varray[14];
123     GGadgetCreateData gcd[29], boxes[6];
124     GTextInfo label[29];
125     int i,v;
126     char sepbuf[20], minbuf[20], maxbuf[20], hbuf[20], lbuf[20];
127     SplineFont *sf = fv->b.sf;
128     double emsize = (sf->ascent + sf->descent);
129 
130     memset(&wi,0,sizeof(wi));
131     wi.fv = fv;
132     wi.sf = sf;
133 
134     memset(&wattrs,0,sizeof(wattrs));
135     wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_restrict|wam_isdlg;
136     wattrs.event_masks = ~(1<<et_charup);
137     wattrs.restrict_input_to_me = 1;
138     wattrs.is_dlg = 1;
139     wattrs.undercursor = 1;
140     wattrs.cursor = ct_pointer;
141     wattrs.utf8_window_title = _("Auto Width");
142     pos.x = pos.y = 0;
143     pos.width = GGadgetScale(GDrawPointsToPixels(NULL,200));
144     pos.height = GDrawPointsToPixels(NULL,180);
145     wi.gw = gw = GDrawCreateTopWindow(NULL,&pos,AW2_e_h,&wi,&wattrs);
146 
147     memset(&label,0,sizeof(label));
148     memset(&boxes,0,sizeof(boxes));
149     memset(&gcd,0,sizeof(gcd));
150 
151     i = v = 0;
152 
153     label[i].text = (unichar_t *) _(
154 	"FontForge will attempt to adjust the left and right\n"
155 	"sidebearings of the selected glyphs so that the average\n"
156 	"separation between glyphs in a script will be the\n"
157 	"specified amount. You may also specify a minimum and\n"
158 	"maximum value for each glyph's sidebearings." );
159     label[i].text_is_1byte = true;
160     gcd[i].gd.label = &label[i];
161     gcd[i].gd.pos.x = 5; gcd[i].gd.pos.y = 6;
162     gcd[i].gd.flags = gg_visible | gg_enabled;
163     gcd[i++].creator = GLabelCreate;
164     varray[v++] = &gcd[i-1]; varray[v++] = NULL;
165 
166     label[i].text = (unichar_t *) _( "_Separation:" );
167     label[i].text_is_1byte = true;
168     label[i].text_in_resource = true;
169     gcd[i].gd.label = &label[i];
170     gcd[i].gd.pos.x = 5; gcd[i].gd.pos.y = 6;
171     gcd[i].gd.flags = gg_visible | gg_enabled;
172     gcd[i++].creator = GLabelCreate;
173     harray1[0] = &gcd[i-1];
174 
175     if ( sf->width_separation>0 )
176 	sprintf( sepbuf, "%d", sf->width_separation );
177     else
178 	sprintf( sepbuf, "%d", (int) rint( width_separation * emsize / width_last_em_size ));
179     label[i].text = (unichar_t *) sepbuf;
180     label[i].text_is_1byte = true;
181     gcd[i].gd.label = &label[i];
182     gcd[i].gd.pos.x = 5; gcd[i].gd.pos.y = 6;
183     gcd[i].gd.flags = gg_visible | gg_enabled;
184     gcd[i].gd.cid = CID_Separation;
185     gcd[i++].creator = GTextFieldCreate;
186     harray1[1] = &gcd[i-1]; harray1[2] = GCD_Glue; harray1[3] = NULL;
187 
188     boxes[2].gd.flags = gg_enabled|gg_visible;
189     boxes[2].gd.u.boxelements = harray1;
190     boxes[2].creator = GHBoxCreate;
191     varray[v++] = &boxes[2]; varray[v++] = NULL;
192 
193     label[i].text = (unichar_t *) _( "_Min:" );
194     label[i].text_is_1byte = true;
195     label[i].text_in_resource = true;
196     gcd[i].gd.label = &label[i];
197     gcd[i].gd.pos.x = 5; gcd[i].gd.pos.y = 6;
198     gcd[i].gd.flags = gg_visible | gg_enabled;
199     gcd[i++].creator = GLabelCreate;
200     harray2[0] = &gcd[i-1];
201 
202     if ( sf->italicangle<0 )
203 	sprintf( minbuf, "%d", (int) rint( sf->descent*tan(sf->italicangle*FF_PI/180 )) );
204     else if ( sf->italicangle>0 )
205 	sprintf( minbuf, "%d", (int) -rint( sf->ascent*tan(sf->italicangle*FF_PI/180 )) );
206     else
207 	sprintf( minbuf, "%d", (int) rint( width_min_side_bearing * emsize / width_last_em_size ));
208     label[i].text = (unichar_t *) minbuf;
209     label[i].text_is_1byte = true;
210     gcd[i].gd.label = &label[i];
211     gcd[i].gd.pos.x = 5; gcd[i].gd.pos.y = 6;
212     gcd[i].gd.flags = gg_visible | gg_enabled;
213     gcd[i].gd.cid = CID_MinSep;
214     gcd[i++].creator = GTextFieldCreate;
215     harray2[1] = &gcd[i-1];
216 
217     label[i].text = (unichar_t *) _( "Ma_x:" );
218     label[i].text_is_1byte = true;
219     label[i].text_in_resource = true;
220     gcd[i].gd.label = &label[i];
221     gcd[i].gd.pos.x = 5; gcd[i].gd.pos.y = 6;
222     gcd[i].gd.flags = gg_visible | gg_enabled;
223     gcd[i++].creator = GLabelCreate;
224     harray2[2] = &gcd[i-1];
225 
226     sprintf( maxbuf, "%d", (int) rint( width_max_side_bearing * emsize / width_last_em_size ));
227     label[i].text = (unichar_t *) maxbuf;
228     label[i].text_is_1byte = true;
229     gcd[i].gd.label = &label[i];
230     gcd[i].gd.pos.x = 5; gcd[i].gd.pos.y = 6;
231     gcd[i].gd.flags = gg_visible | gg_enabled;
232     gcd[i].gd.cid = CID_MaxSep;
233     gcd[i++].creator = GTextFieldCreate;
234     harray2[3] = &gcd[i-1]; harray2[4] = GCD_Glue; harray2[5] = NULL;
235 
236     boxes[3].gd.flags = gg_enabled|gg_visible;
237     boxes[3].gd.u.boxelements = harray2;
238     boxes[3].creator = GHBoxCreate;
239     varray[v++] = &boxes[3]; varray[v++] = NULL;
240 
241     label[i].text = (unichar_t *) _( "_Height:" );
242     label[i].text_is_1byte = true;
243     label[i].text_in_resource = true;
244     gcd[i].gd.label = &label[i];
245     gcd[i].gd.pos.x = 5; gcd[i].gd.pos.y = 6;
246     gcd[i].gd.flags = /* gg_visible |*/ gg_enabled;
247     gcd[i++].creator = GLabelCreate;
248     harray3[0] = &gcd[i-1];
249 
250     sprintf( hbuf, "%d", (int) rint( width_chunk_height * emsize / width_last_em_size ));
251     label[i].text = (unichar_t *) hbuf;
252     label[i].text_is_1byte = true;
253     gcd[i].gd.label = &label[i];
254     gcd[i].gd.pos.x = 5; gcd[i].gd.pos.y = 6;
255     gcd[i].gd.flags = /* gg_visible |*/ gg_enabled;
256     gcd[i].gd.cid = CID_Height;
257     gcd[i++].creator = GTextFieldCreate;
258     harray3[1] = &gcd[i-1];
259 
260     label[i].text = (unichar_t *) _( "_Loops:" );
261     label[i].text_is_1byte = true;
262     label[i].text_in_resource = true;
263     gcd[i].gd.label = &label[i];
264     gcd[i].gd.pos.x = 5; gcd[i].gd.pos.y = 6;
265     gcd[i].gd.flags = /* gg_visible |*/ gg_enabled;
266     gcd[i++].creator = GLabelCreate;
267     harray3[2] = &gcd[i-1];
268 
269     sprintf( lbuf, "%d", (int) rint( width_loop_cnt * emsize / width_last_em_size ));
270     label[i].text = (unichar_t *) lbuf;
271     label[i].text_is_1byte = true;
272     gcd[i].gd.label = &label[i];
273     gcd[i].gd.pos.x = 5; gcd[i].gd.pos.y = 6;
274     gcd[i].gd.flags = /* gg_visible |*/ gg_enabled;
275     gcd[i].gd.cid = CID_Loop;
276     gcd[i++].creator = GTextFieldCreate;
277     harray3[3] = &gcd[i-1]; harray3[4] = GCD_Glue; harray3[5] = NULL;
278 
279     boxes[4].gd.flags = gg_enabled/*|gg_visible*/;
280     boxes[4].gd.u.boxelements = harray3;
281     boxes[4].creator = GHBoxCreate;
282     varray[v++] = &boxes[4]; varray[v++] = NULL;
283 
284     gcd[i].gd.flags = gg_visible | gg_enabled | gg_but_default;
285     label[i].text = (unichar_t *) _("_OK");
286     label[i].text_is_1byte = true;
287     label[i].text_in_resource = true;
288     gcd[i].gd.label = &label[i];
289     gcd[i].gd.handle_controlevent = AW2_OK;
290     gcd[i++].creator = GButtonCreate;
291     barray[0] = GCD_Glue; barray[1] = &gcd[i-1]; barray[2] = GCD_Glue;
292 
293     gcd[i].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
294     label[i].text = (unichar_t *) _("_Cancel");
295     label[i].text_is_1byte = true;
296     label[i].text_in_resource = true;
297     gcd[i].gd.label = &label[i];
298     gcd[i].gd.handle_controlevent = AW2_Cancel;
299     gcd[i++].creator = GButtonCreate;
300     barray[3] = barray[4] = GCD_Glue;
301     barray[5] = &gcd[i-1]; barray[6] = GCD_Glue; barray[7] = NULL;
302 
303     boxes[5].gd.flags = gg_enabled|gg_visible;
304     boxes[5].gd.u.boxelements = barray;
305     boxes[5].creator = GHBoxCreate;
306     varray[v++] = GCD_Glue; varray[v++] = NULL;
307     varray[v++] = &boxes[5]; varray[v++] = NULL; varray[v++] = NULL;
308 
309     boxes[0].gd.pos.x = gcd[i].gd.pos.y = 2;
310     boxes[0].gd.flags = gg_enabled|gg_visible;
311     boxes[0].gd.u.boxelements = varray;
312     boxes[0].creator = GHVGroupCreate;
313 
314     GGadgetsCreate(gw,boxes);
315     GHVBoxSetExpandableRow(boxes[0].ret,gb_expandglue);
316     GHVBoxSetExpandableCol(boxes[2].ret,gb_expandglue);
317     GHVBoxSetExpandableCol(boxes[3].ret,gb_expandglue);
318     GHVBoxSetExpandableCol(boxes[4].ret,gb_expandglue);
319     GHVBoxSetExpandableCol(boxes[5].ret,gb_expandgluesame);
320     GHVBoxFitWindow(boxes[0].ret);
321 
322     GWidgetIndicateFocusGadget(gcd[2].ret);
323     GTextFieldSelect(gcd[2].ret,0,-1);
324     GWidgetHidePalettes();
325     GDrawSetVisible(gw,true);
326     while ( !wi.done )
327 	GDrawProcessOneEvent(NULL);
328     GDrawDestroyWindow(gw);
329 }
330