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