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 <fontforge-config.h>
29 
30 #include "bvedit.h"
31 #include "fontforgeui.h"
32 #include "fvmetrics.h"
33 #include "splineutil.h"
34 #include "ustring.h"
35 
36 #include <math.h>
37 
38 typedef struct createwidthdlg {
39     CreateWidthData wd;
40     GWindow gw;
41 } CreateWidthDlg;
42 
43 #define CID_Set		1001
44 #define CID_Incr	1002
45 #define CID_Scale	1003
46 #define CID_SetVal	1011
47 #define CID_IncrVal	1012
48 #define CID_ScaleVal	1013
49 
50 static char *rb1[] = { N_("Set Width To:"), N_("Set LBearing To:"), N_("Set RBearing To:"), N_("Set Bearings To:"), N_("Set Vert. Advance To:") };
51 static char *rb2[] = { N_("Increment Width By:"), N_("Increment LBearing By:"), N_("Increment RBearing By:"), N_("Increment Bearings By:"), N_("Increment V. Adv. By:") };
52 static char *rb3[] = { N_("Scale Width By:"), N_("Scale LBearing By:"), N_("Scale RBearing By:"), N_("Scale Bearings By:"), N_("Scale VAdvance By:") };
53 static char *info[] = { N_("Left Side Bearing does not change."), N_("Advance Width does not change."), N_("Left Side Bearing does not change."), N_("ThisSpaceIntentionallyLeftBlank-PleaseDoNotTranslate-LeaveThisOut|"), N_("Top Bearing does not change.") };
54 
CW_OK(GGadget * g,GEvent * e)55 static int CW_OK(GGadget *g, GEvent *e) {
56 
57     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
58 	int err = false;
59 	CreateWidthDlg *wd = GDrawGetUserData(GGadgetGetWindow(g));
60 	if ( GGadgetIsChecked(GWidgetGetControl(wd->gw,CID_Set)) ) {
61 	    wd->wd.type = st_set;
62 	    wd->wd.setto = GetReal8(wd->gw,CID_SetVal,rb1[wd->wd.wtype],&err);
63 	    if ( wd->wd.setto<0 && wd->wd.wtype==wt_width ) {
64 		char *yesno[3];
65 		yesno[0] = _("_Yes");
66 		yesno[1] = _("_No");
67 		yesno[2] = NULL;
68 		if ( gwwv_ask(_("Negative Width"), (const char **) yesno, 0, 1, _("Negative glyph widths are not allowed in TrueType\nDo you really want a negative width?") )==1 )
69 return( true );
70 	    }
71 	} else if ( GGadgetIsChecked(GWidgetGetControl(wd->gw,CID_Incr)) ) {
72 	    wd->wd.type = st_incr;
73 	    wd->wd.increment = GetReal8(wd->gw,CID_IncrVal,rb2[wd->wd.wtype],&err);
74 	} else {
75 	    wd->wd.type = st_scale;
76 	    wd->wd.scale = GetReal8(wd->gw,CID_ScaleVal,rb2[wd->wd.wtype],&err);
77 	}
78 	if ( err )
79 return(true);
80 	(wd->wd.doit)((CreateWidthData *) wd);
81     }
82 return( true );
83 }
84 
CW_Cancel(GGadget * g,GEvent * e)85 static int CW_Cancel(GGadget *g, GEvent *e) {
86     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
87 	CreateWidthDlg *wd = GDrawGetUserData(GGadgetGetWindow(g));
88 	wd->wd.done = true;
89     }
90 return( true );
91 }
92 
CW_FocusChange(GGadget * g,GEvent * e)93 static int CW_FocusChange(GGadget *g, GEvent *e) {
94     if ( e->type==et_controlevent && e->u.control.subtype == et_textfocuschanged ) {
95 	CreateWidthDlg *wd = GDrawGetUserData(GGadgetGetWindow(g));
96 	int cid = (intpt) GGadgetGetUserData(g);
97 	GGadgetSetChecked(GWidgetGetControl(wd->gw,cid),true);
98     }
99 return( true );
100 }
101 
CW_RadioChange(GGadget * g,GEvent * e)102 static int CW_RadioChange(GGadget *g, GEvent *e) {
103     if ( e->type==et_controlevent && e->u.control.subtype == et_radiochanged ) {
104 	CreateWidthDlg *wd = GDrawGetUserData(GGadgetGetWindow(g));
105 	int cid = (intpt) GGadgetGetUserData(g);
106 	GWidgetIndicateFocusGadget(GWidgetGetControl(wd->gw,cid));
107 	GTextFieldSelect(GWidgetGetControl(wd->gw,cid),0,-1);
108     }
109 return( true );
110 }
111 
cwd_e_h(GWindow gw,GEvent * event)112 static int cwd_e_h(GWindow gw, GEvent *event) {
113     if ( event->type==et_close ) {
114 	CreateWidthDlg *wd = GDrawGetUserData(gw);
115 	wd->wd.done = true;
116     } else if ( event->type == et_char ) {
117 return( false );
118     } else if ( event->type == et_map ) {
119 	/* Above palettes */
120 	GDrawRaise(gw);
121     }
122 return( true );
123 }
124 
FVCreateWidth(void * _fv,SplineChar * _sc,void (* doit)(CreateWidthData *),enum widthtype wtype,char * def)125 static void FVCreateWidth( void *_fv,SplineChar* _sc,void (*doit)(CreateWidthData *),
126 			   enum widthtype wtype, char *def) {
127     GRect pos;
128     GWindowAttrs wattrs;
129     GGadgetCreateData gcd[11], boxes[2], topbox[2], *hvs[17], *varray[8], *buttons[6];
130     GTextInfo label[11];
131     static CreateWidthDlg cwd;
132     static GWindow winds[5] = {NULL, NULL, NULL, NULL, NULL};
133     static char *title[] = { N_("Set Width..."), N_("Set LBearing..."), N_("Set RBearing..."), N_("Set Both Side Bearings..."), N_("Set Vertical Advance...") };
134 
135     cwd.wd.done = false;
136     cwd.wd._fv = _fv;
137     cwd.wd._sc = _sc;
138     cwd.wd.wtype = wtype;
139     cwd.wd.doit = doit;
140     cwd.gw = winds[wtype];
141 
142     if ( cwd.gw==NULL ) {
143 	memset(&wattrs,0,sizeof(wattrs));
144 	wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict;
145 	wattrs.event_masks = ~(1<<et_charup);
146 	wattrs.restrict_input_to_me = 1;
147 	wattrs.undercursor = 1;
148 	wattrs.cursor = ct_pointer;
149 	wattrs.utf8_window_title = _(title[wtype]);
150 	wattrs.is_dlg = true;
151 	pos.x = pos.y = 0;
152 	pos.width = GGadgetScale(GDrawPointsToPixels(NULL,180));
153 	pos.height = GDrawPointsToPixels(NULL,100);
154 	cwd.gw = winds[wtype] = GDrawCreateTopWindow(NULL,&pos,cwd_e_h,&cwd,&wattrs);
155 
156 	memset(&label,0,sizeof(label));
157 	memset(&gcd,0,sizeof(gcd));
158 
159 	label[0].text = (unichar_t *) _(rb1[wtype]);
160 	label[0].text_is_1byte = true;
161 	gcd[0].gd.label = &label[0];
162 	gcd[0].gd.flags = gg_enabled|gg_visible|gg_cb_on;
163 	gcd[0].gd.cid = CID_Set;
164 	gcd[0].gd.handle_controlevent = CW_RadioChange;
165 	gcd[0].data = (void *) CID_SetVal;
166 	gcd[0].creator = GRadioCreate;
167 
168 	label[1].text = (unichar_t *) _(rb2[wtype]);
169 	label[1].text_is_1byte = true;
170 	gcd[1].gd.label = &label[1];
171 	gcd[1].gd.flags = gg_enabled|gg_visible|gg_rad_continueold ;
172 	gcd[1].gd.cid = CID_Incr;
173 	gcd[1].gd.handle_controlevent = CW_RadioChange;
174 	gcd[1].data = (void *) CID_IncrVal;
175 	gcd[1].creator = GRadioCreate;
176 
177 	label[2].text = (unichar_t *) _(rb3[wtype]);
178 	label[2].text_is_1byte = true;
179 	gcd[2].gd.label = &label[2];
180 	gcd[2].gd.flags = gg_enabled|gg_visible|gg_rad_continueold ;
181 	gcd[2].gd.cid = CID_Scale;
182 	gcd[2].gd.handle_controlevent = CW_RadioChange;
183 	gcd[2].data = (void *) CID_ScaleVal;
184 	gcd[2].creator = GRadioCreate;
185 
186 	label[3].text = (unichar_t *) def;
187 	label[3].text_is_1byte = true;
188 	gcd[3].gd.label = &label[3];
189 	gcd[3].gd.pos.width = 60;
190 	gcd[3].gd.flags = gg_enabled|gg_visible;
191 	gcd[3].gd.cid = CID_SetVal;
192 	gcd[3].gd.handle_controlevent = CW_FocusChange;
193 	gcd[3].data = (void *) CID_Set;
194 	gcd[3].creator = GTextFieldCreate;
195 
196 	label[4].text = (unichar_t *) "0";
197 	label[4].text_is_1byte = true;
198 	gcd[4].gd.label = &label[4];
199 	gcd[4].gd.pos.width = 60;
200 	gcd[4].gd.flags = gg_enabled|gg_visible;
201 	gcd[4].gd.cid = CID_IncrVal;
202 	gcd[4].gd.handle_controlevent = CW_FocusChange;
203 	gcd[4].data = (void *) CID_Incr;
204 	gcd[4].creator = GTextFieldCreate;
205 
206 	label[5].text = (unichar_t *) "100";
207 	label[5].text_is_1byte = true;
208 	gcd[5].gd.label = &label[5];
209 	gcd[5].gd.pos.width = 60;
210 	gcd[5].gd.flags = gg_enabled|gg_visible;
211 	gcd[5].gd.cid = CID_ScaleVal;
212 	gcd[5].gd.handle_controlevent = CW_FocusChange;
213 	gcd[5].data = (void *) CID_Scale;
214 	gcd[5].creator = GTextFieldCreate;
215 
216 	gcd[6].gd.flags = gg_visible | gg_enabled | gg_but_default;
217 	label[6].text = (unichar_t *) _("_OK");
218 	label[6].text_is_1byte = true;
219 	label[6].text_in_resource = true;
220 	gcd[6].gd.mnemonic = 'O';
221 	gcd[6].gd.label = &label[6];
222 	gcd[6].gd.handle_controlevent = CW_OK;
223 	gcd[6].creator = GButtonCreate;
224 
225 	gcd[7].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
226 	label[7].text = (unichar_t *) _("_Cancel");
227 	label[7].text_is_1byte = true;
228 	label[7].text_in_resource = true;
229 	gcd[7].gd.label = &label[7];
230 	gcd[7].gd.mnemonic = 'C';
231 	gcd[7].gd.handle_controlevent = CW_Cancel;
232 	gcd[7].creator = GButtonCreate;
233 
234 	label[8].text = (unichar_t *) S_(info[wtype]);
235 	label[8].text_is_1byte = true;
236 	gcd[8].gd.label = &label[8];
237 	gcd[8].gd.pos.x = 5; gcd[8].gd.pos.y = 59;
238 	gcd[8].gd.flags = gg_enabled|gg_visible ;
239 	gcd[8].creator = GLabelCreate;
240 
241 	label[9].text = (unichar_t *) "%";
242 	label[9].text_is_1byte = true;
243 	gcd[9].gd.label = &label[9];
244 	gcd[9].gd.flags = gg_enabled|gg_visible;
245 	gcd[9].creator = GLabelCreate;
246 
247 	hvs[0] = &gcd[0]; hvs[1] = &gcd[3]; hvs[2] = GCD_Glue; hvs[3] = NULL;
248 	hvs[4] = &gcd[1]; hvs[5] = &gcd[4]; hvs[6] = GCD_Glue; hvs[7] = NULL;
249 	hvs[8] = &gcd[2]; hvs[9] = &gcd[5]; hvs[10] = &gcd[9]; hvs[11] = NULL;
250 	hvs[12] = &gcd[8]; hvs[13] = GCD_ColSpan; hvs[14] = GCD_Glue; hvs[15] = NULL;
251 	hvs[16] = NULL;
252 
253 	buttons[0] = buttons[2] = buttons[4] = GCD_Glue; buttons[5] = NULL;
254 	buttons[1] = &gcd[6]; buttons[3] = &gcd[7];
255 
256 	varray[0] = &boxes[1]; varray[1] = NULL;
257 	varray[2] = GCD_Glue; varray[3] = NULL;
258 	varray[4] = &boxes[0]; varray[5] = NULL;
259 	varray[6] = NULL;
260 
261 	memset(boxes,0,sizeof(boxes));
262 	boxes[0].gd.flags = gg_enabled|gg_visible;
263 	boxes[0].gd.u.boxelements = buttons;
264 	boxes[0].creator = GHBoxCreate;
265 
266 	boxes[1].gd.flags = gg_enabled|gg_visible;
267 	boxes[1].gd.u.boxelements = hvs;
268 	boxes[1].creator = GHVBoxCreate;
269 
270 	memset(topbox,0,sizeof(topbox));
271 	topbox[0].gd.pos.x = topbox[0].gd.pos.y = 2;
272 	topbox[0].gd.pos.width = pos.width-4; topbox[0].gd.pos.height = pos.height-4;
273 	topbox[0].gd.flags = gg_enabled|gg_visible;
274 	topbox[0].gd.u.boxelements = varray;
275 	topbox[0].creator = GHVGroupCreate;
276 
277 	GGadgetsCreate(cwd.gw,topbox);
278 	GHVBoxSetExpandableRow(topbox[0].ret,1);
279 	GHVBoxSetExpandableCol(boxes[0].ret,gb_expandgluesame);
280 	GHVBoxSetExpandableCol(boxes[1].ret,1);
281 	GWidgetIndicateFocusGadget(GWidgetGetControl(cwd.gw,CID_SetVal));
282 	GTextFieldSelect(GWidgetGetControl(cwd.gw,CID_SetVal),0,-1);
283 	GHVBoxFitWindow(topbox[0].ret);
284     } else {
285 	unichar_t *temp = uc_copy(def);
286 	GGadgetSetTitle(GWidgetGetControl(cwd.gw,CID_SetVal),temp);
287 	free( temp );
288     }
289 
290     GWidgetHidePalettes();
291     GDrawSetVisible(cwd.gw,true);
292     while ( !cwd.wd.done )
293 	GDrawProcessOneEvent(NULL);
294     GDrawSetVisible(cwd.gw,false);
295 }
296 
BCDefWidthVal(char * buf,BDFChar * bc,FontView * fv,enum widthtype wtype)297 static void BCDefWidthVal(char *buf,BDFChar *bc, FontView *fv, enum widthtype wtype) {
298     IBounds bb;
299 
300     if ( wtype==wt_width )
301 	sprintf( buf, "%d", bc->width );
302     else if ( wtype==wt_vwidth )
303 	sprintf( buf, "%d", fv->show->pixelsize );
304     else {
305 	BDFCharFindBounds(bc,&bb);
306 	if ( wtype==wt_lbearing )
307 	    sprintf( buf, "%d", bb.minx );
308 	else if ( wtype==wt_rbearing )
309 	    sprintf( buf, "%d", bc->width-bb.maxx-1 );
310 	else
311 	    sprintf( buf, "%d", (int) rint( (bc->width-bb.maxx-1 + bb.minx)/2 ));
312     }
313 }
314 
SCDefWidthVal(char * buf,SplineChar * sc,enum widthtype wtype)315 static void SCDefWidthVal(char *buf,SplineChar *sc, enum widthtype wtype) {
316     DBounds bb;
317 
318     if ( wtype==wt_width )
319 	sprintf( buf, "%d", sc->width );
320     else if ( wtype==wt_vwidth )
321 	sprintf( buf, "%d", sc->vwidth );
322     else {
323 	SplineCharFindBounds(sc,&bb);
324 	if ( wtype==wt_lbearing )
325 	    sprintf( buf, "%.4g", (double) bb.minx );
326 	else if ( wtype==wt_rbearing )
327 	    sprintf( buf, "%.4g", sc->width-(double) bb.maxx );
328 	else
329 	    sprintf( buf, "%.4g", rint( (sc->width-(double) bb.maxx + (double) bb.minx)/2 ) );
330     }
331 }
332 
FVSetWidth(FontView * fv,enum widthtype wtype)333 void FVSetWidth(FontView *fv,enum widthtype wtype) {
334     char buffer[12];
335     int em = fv->b.sf->ascent + fv->b.sf->descent;
336     int i, gid;
337 
338     if ( !fv->b.sf->onlybitmaps || fv->b.sf->bitmaps==NULL ) {
339 	sprintf(buffer,"%d",wtype==wt_width?6*em/10:wtype==wt_vwidth?em: em/10 );
340 	for ( i=0; i<fv->b.map->enccount; ++i ) if ( fv->b.selected[i] && (gid=fv->b.map->map[i])!=-1 && fv->b.sf->glyphs[gid]!=NULL ) {
341 	    SCDefWidthVal(buffer,fv->b.sf->glyphs[gid],wtype);
342 	break;
343 	}
344     } else {
345 	int size = fv->show->pixelsize;
346 	sprintf(buffer,"%d",wtype==wt_width?6*size/10:wtype==wt_vwidth?size: size/10 );
347 	for ( i=0; i<fv->b.map->enccount; ++i ) if ( fv->b.selected[i] && (gid=fv->b.map->map[i])!=-1 && fv->show->glyphs[gid]!=NULL ) {
348 	    BCDefWidthVal(buffer,fv->show->glyphs[gid],fv,wtype);
349 	break;
350 	}
351     }
352     FVCreateWidth(fv,0,FVDoit,wtype,buffer);
353 }
354 
CVSetWidth(CharView * cv,enum widthtype wtype)355 void CVSetWidth(CharView *cv,enum widthtype wtype) {
356     char buf[10];
357 
358     SCDefWidthVal(buf,cv->b.sc,wtype);
359     FVCreateWidth(cv,cv->b.sc,CVDoit,wtype,buf);
360 }
361 
362 
GenericVSetWidth(FontView * fv,SplineChar * sc,enum widthtype wtype)363 void GenericVSetWidth(FontView *fv,SplineChar* sc,enum widthtype wtype) {
364     char buf[10];
365 
366     SCDefWidthVal(buf,sc,wtype);
367     FVCreateWidth(fv,sc,GenericVDoit,wtype,buf);
368 }
369 
370