1 /* -*- coding: utf-8 -*- */
2 /* Copyright (C) 2000-2012 by George Williams */
3 /*
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6 
7  * Redistributions of source code must retain the above copyright notice, this
8  * list of conditions and the following disclaimer.
9 
10  * Redistributions in binary form must reproduce the above copyright notice,
11  * this list of conditions and the following disclaimer in the documentation
12  * and/or other materials provided with the distribution.
13 
14  * The name of the author may not be used to endorse or promote products
15  * derived from this software without specific prior written permission.
16 
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
18  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
20  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <fontforge-config.h>
30 
31 #include "autotrace.h"
32 #include "charset.h"
33 #include "encoding.h"
34 #include "ffglib.h"
35 #include "fontforgeui.h"
36 #include "gfile.h"
37 #include "gkeysym.h"
38 #include "gresedit.h"
39 #include "gresource.h"
40 #include "groups.h"
41 #include "macenc.h"
42 #include "namelist.h"
43 #include "othersubrs.h"
44 #include "prefs.h"
45 #include "sfd.h"
46 #include "splineutil.h"
47 #include "ttf.h"
48 #include "ustring.h"
49 
50 #include <dirent.h>
51 #include <locale.h>
52 #include <stdlib.h>
53 #include <sys/time.h>
54 #include <sys/types.h>
55 #include <time.h>
56 
57 #if HAVE_LANGINFO_H
58 # include <langinfo.h>
59 #endif
60 
61 #define RAD2DEG	(180/FF_PI)
62 
63 static void change_res_filename(const char *newname);
64 
65 extern int splash;
66 extern int adjustwidth;
67 extern int adjustlbearing;
68 extern Encoding *default_encoding;
69 extern int autohint_before_generate;
70 extern int use_freetype_to_rasterize_fv;
71 extern int use_freetype_with_aa_fill_cv;
72 extern int OpenCharsInNewWindow;
73 extern int ItalicConstrained;
74 extern int accent_offset;
75 extern int GraveAcuteCenterBottom;
76 extern int PreferSpacingAccents;
77 extern int CharCenterHighest;
78 extern int ask_user_for_resolution;
79 #ifndef _NO_LIBPNG
80 extern int WritePNGInSFD;
81 #endif
82 extern int stop_at_join;
83 extern int recognizePUA;
84 extern float arrowAmount;
85 extern float arrowAccelFactor;
86 extern float snapdistance;
87 extern float snapdistancemeasuretool;
88 extern int measuretoolshowhorizontolvertical;
89 extern int snaptoint;
90 extern float joinsnap;
91 extern char *BDFFoundry;
92 extern char *TTFFoundry;
93 extern char *xuid;
94 extern char *SaveTablesPref;
95 /*struct cvshows CVShows = { 1, 1, 1, 1, 1, 0, 1 };*/ /* in charview */
96 /* int default_fv_font_size = 24; */	/* in fontview */
97 /* int default_fv_antialias = false */	/* in fontview */
98 /* int default_fv_bbsized = false */	/* in fontview */
99 extern int default_fv_row_count;	/* in fontview */
100 extern int default_fv_col_count;	/* in fontview */
101 extern int default_fv_showhmetrics;	/* in fontview */
102 extern int default_fv_showvmetrics;	/* in fontview */
103 extern int default_fv_glyphlabel;	/* in fontview */
104 extern int save_to_dir;			/* in fontview, use sfdir rather than sfd */
105 extern int palettes_docked;		/* in cvpalettes */
106 extern int cvvisible[2], bvvisible[3];	/* in cvpalettes.c */
107 extern int maxundoes;			/* in cvundoes */
108 extern int pref_mv_shift_and_arrow_skip;         /* in metricsview.c */
109 extern int pref_mv_control_shift_and_arrow_skip; /* in metricsview.c */
110 extern int mv_type;                              /* in metricsview.c */
111 extern int prefer_cjk_encodings;	/* in parsettf */
112 extern int onlycopydisplayed, copymetadata, copyttfinstr;
113 extern struct cvshows CVShows;
114 extern int infowindowdistance;		/* in cvruler.c */
115 extern int oldformatstate;		/* in savefontdlg.c */
116 extern int oldbitmapstate;		/* in savefontdlg.c */
117 static int old_ttf_flags=0, old_otf_flags=0;
118 extern int old_sfnt_flags;		/* in savefont.c */
119 extern int old_ps_flags;		/* in savefont.c */
120 extern int old_validate;		/* in savefontdlg.c */
121 extern int old_fontlog;			/* in savefontdlg.c */
122 extern int oldsystem;			/* in bitmapdlg.c */
123 extern int preferpotrace;		/* in autotrace.c */
124 extern int autotrace_ask;		/* in autotrace.c */
125 extern int mf_ask;			/* in autotrace.c */
126 extern int mf_clearbackgrounds;		/* in autotrace.c */
127 extern int mf_showerrors;		/* in autotrace.c */
128 extern char *mf_args;			/* in autotrace.c */
129 static int glyph_2_name_map=0;		/* was in tottf.c, now a flag in savefont options dlg */
130 extern int coverageformatsallowed;	/* in tottfgpos.c */
131 extern int debug_wins;			/* in cvdebug.c */
132 extern int gridfit_dpi, gridfit_depth;	/* in cvgridfit.c */
133 extern float gridfit_pointsizey;	/* in cvgridfit.c */
134 extern float gridfit_pointsizex;	/* in cvgridfit.c */
135 extern int gridfit_x_sameas_y;		/* in cvgridfit.c */
136 extern int hint_diagonal_ends;		/* in stemdb.c */
137 extern int hint_diagonal_intersections;	/* in stemdb.c */
138 extern int hint_bounding_boxes;		/* in stemdb.c */
139 extern int detect_diagonal_stems;	/* in stemdb.c */
140 extern float stem_slope_error;		/* in stemdb.c */
141 extern float stub_slope_error;		/* in stemdb.c */
142 extern int instruct_diagonal_stems;	/* in nowakowskittfinstr.c */
143 extern int instruct_serif_stems;		/* in nowakowskittfinstr.c */
144 extern int instruct_ball_terminals;	/* in nowakowskittfinstr.c */
145 extern int interpolate_strong;		/* in nowakowskittfinstr.c */
146 extern int control_counters;		/* in nowakowskittfinstr.c */
147 extern unichar_t *script_menu_names[SCRIPT_MENU_MAX];
148 extern char *script_filenames[SCRIPT_MENU_MAX];
149 static char *xdefs_filename;
150 extern int new_em_size;				/* in splineutil2.c */
151 extern int new_fonts_are_order2;		/* in splineutil2.c */
152 extern int loaded_fonts_same_as_new;		/* in splineutil2.c */
153 extern int use_second_indic_scripts;		/* in tottfgpos.c */
154 static char *othersubrsfile = NULL;
155 extern MacFeat *default_mac_feature_map,	/* from macenc.c */
156 		*user_mac_feature_map;
157 extern int updateflex;				/* in charview.c */
158 extern int default_autokern_dlg;		/* in lookupui.c */
159 extern int allow_utf8_glyphnames;		/* in lookupui.c */
160 extern int add_char_to_name_list;		/* in charinfo.c */
161 extern int clear_tt_instructions_when_needed;	/* in cvundoes.c */
162 extern int export_clipboard;			/* in cvundoes.c */
163 extern int cv_width;			/* in charview.c */
164 extern int cv_height;			/* in charview.c */
165 extern int cv_show_fill_with_space; /* in charview.c */
166 extern int interpCPsOnMotion;			/* in charview.c */
167 extern int DrawOpenPathsWithHighlight;          /* in charview.c */
168 extern float prefs_cvEditHandleSize;            /* in charview.c */
169 extern int prefs_cvInactiveHandleAlpha;         /* in charview.c */
170 extern int mv_width;				/* in metricsview.c */
171 extern int mv_height;				/* in metricsview.c */
172 extern int fvmv_selectmax;			/* in metricsview.c */
173 extern int bv_width;				/* in bitmapview.c */
174 extern int bv_height;				/* in bitmapview.c */
175 extern int ask_user_for_cmap;			/* in parsettf.c */
176 extern int mvshowgrid;				/* in metricsview.c */
177 
178 extern int rectelipse, polystar, regular_star;	/* from cvpalettes.c */
179 extern int center_out[2];			/* from cvpalettes.c */
180 extern float rr_radius;				/* from cvpalettes.c */
181 extern int ps_pointcnt;				/* from cvpalettes.c */
182 extern float star_percent;			/* from cvpalettes.c */
183 extern int home_char;				/* from fontview.c */
184 extern int compact_font_on_open;		/* from fontview.c */
185 extern int aa_pixelsize;			/* from anchorsaway.c */
186 extern enum cvtools cv_b1_tool, cv_cb1_tool, cv_b2_tool, cv_cb2_tool; /* cvpalettes.c */
187 extern int show_kerning_pane_in_class;		/* kernclass.c */
188 extern int AutoSaveFrequency;			/* autosave.c */
189 extern int UndoRedoLimitToSave;  /* sfd.c */
190 extern int UndoRedoLimitToLoad;  /* sfd.c */
191 extern int prefRevisionsToRetain; /* sfd.c */
192 extern int prefs_cv_show_control_points_always_initially; /* from charview.c */
193 extern int prefs_create_dragging_comparison_outline;      /* from charview.c */
194 extern int prefs_cv_outline_thickness; /* from charview.c */
195 
196 extern float OpenTypeLoadHintEqualityTolerance;  /* autohint.c */
197 extern float GenerateHintWidthEqualityTolerance; /* splinesave.c */
198 extern int warn_script_unsaved; /* fontview.c */
199 extern NameList *force_names_when_opening;
200 extern NameList *force_names_when_saving;
201 extern NameList *namelist_for_new_fonts;
202 
203 extern int default_font_filter_index;
204 extern struct openfilefilters *user_font_filters;
205 static int alwaysgenapple=false, alwaysgenopentype=false;
206 
207 static int gfc_showhidden, gfc_dirplace;
208 static char *gfc_bookmarks=NULL;
209 
210 static int prefs_usecairo = true;
211 
212 static int pointless;
213 
214     /* These first three must match the values in macenc.c */
215 #define CID_Features	101
216 #define CID_FeatureDel	103
217 #define CID_FeatureEdit	105
218 
219 #define CID_Mapping	102
220 #define CID_MappingDel	104
221 #define CID_MappingEdit	106
222 
223 #define CID_ScriptMNameBase	200
224 #define CID_ScriptMFileBase	(200+SCRIPT_MENU_MAX)
225 #define CID_ScriptMBrowseBase	(200+2*SCRIPT_MENU_MAX)
226 
227 #define CID_PrefsBase	1000
228 #define CID_PrefsOffset	100
229 #define CID_PrefsBrowseOffset	(CID_PrefsOffset/2)
230 
231 //////////////////////////////////
232 // The _oldval_ are used to cache the setting when the prefs window
233 // is created so that a redraw can be performed only when the
234 // value has changed.
235 float prefs_oldval_cvEditHandleSize = 0;
236 int   prefs_oldval_cvInactiveHandleAlpha = 0;
237 
238 /* ************************************************************************** */
239 /* *****************************    mac data    ***************************** */
240 /* ************************************************************************** */
241 
242 extern struct macsettingname macfeat_otftag[], *user_macfeat_otftag;
243 
UserSettingsFree(void)244 static void UserSettingsFree(void) {
245 
246     free( user_macfeat_otftag );
247     user_macfeat_otftag = NULL;
248 }
249 
UserSettingsDiffer(void)250 static int UserSettingsDiffer(void) {
251     int i,j;
252 
253     if ( user_macfeat_otftag==NULL )
254 return( false );
255 
256     for ( i=0; user_macfeat_otftag[i].otf_tag!=0; ++i );
257     for ( j=0; macfeat_otftag[j].otf_tag!=0; ++j );
258     if ( i!=j )
259 return( true );
260     for ( i=0; user_macfeat_otftag[i].otf_tag!=0; ++i ) {
261 	for ( j=0; macfeat_otftag[j].otf_tag!=0; ++j ) {
262 	    if ( macfeat_otftag[j].mac_feature_type ==
263 		    user_macfeat_otftag[i].mac_feature_type &&
264 		    macfeat_otftag[j].mac_feature_setting ==
265 		    user_macfeat_otftag[i].mac_feature_setting &&
266 		    macfeat_otftag[j].otf_tag ==
267 		    user_macfeat_otftag[i].otf_tag )
268 	break;
269 	}
270 	if ( macfeat_otftag[j].otf_tag==0 )
271 return( true );
272     }
273 return( false );
274 }
275 
276 /**************************************************************************** */
277 
278 
279 /* don't use mnemonics 'C' or 'O' (Cancel & OK) */
280 enum pref_types { pr_int, pr_real, pr_bool, pr_enum, pr_encoding, pr_string,
281 	pr_file, pr_namelist, pr_unicode, pr_angle };
282 struct enums { char *name; int value; };
283 
284 struct enums fvsize_enums[] = { {NULL, 0} };
285 
286 #define PREFS_LIST_EMPTY { NULL, 0, NULL, NULL, NULL, '\0', NULL, 0, NULL }
287 static struct prefs_list {
288     char *name;
289     	/* In the prefs file the untranslated name will always be used, but */
290 	/* in the UI that name may be translated. */
291     enum pref_types type;
292     void *val;
293     void *(*get)(void);
294     void (*set)(void *);
295     char mn;
296     struct enums *enums;
297     unsigned int dontdisplay: 1;
298     char *popup;
299 } general_list[] = {
300 /* GT: The following strings have no spaces and an odd capitalization */
301 /* GT: this is because these strings are used in two different ways, one */
302 /* GT: translated (which the user sees, and should probably have added spaces,*/
303 /* GT: and one untranslated which needs the current odd format */
304 	{ N_("ResourceFile"), pr_file, &xdefs_filename, NULL, NULL, 'R', NULL, 0, N_("When FontForge starts up, it loads the user interface theme from\nthis file. Any changes will only take effect the next time you start FontForge.") },
305 	{ N_("OtherSubrsFile"), pr_file, &othersubrsfile, NULL, NULL, 'O', NULL, 0, N_("If you wish to replace Adobe's OtherSubrs array (for Type1 fonts)\nwith an array of your own, set this to point to a file containing\na list of up to 14 PostScript subroutines. Each subroutine must\nbe preceded by a line starting with '%%%%' (any text before the\nfirst '%%%%' line will be treated as an initial copyright notice).\nThe first three subroutines are for flex hints, the next for hint\nsubstitution (this MUST be present), the 14th (or 13 as the\nnumbering actually starts with 0) is for counter hints.\nThe subroutines should not be enclosed in a [ ] pair.") },
306 	{ N_("FreeTypeInFontView"), pr_bool, &use_freetype_to_rasterize_fv, NULL, NULL, 'O', NULL, 0, N_("Use the FreeType rasterizer (when available)\nto rasterize glyphs in the font view.\nThis generally results in better quality.") },
307 	{ N_("FreeTypeAAFillInOutlineView"), pr_bool, &use_freetype_with_aa_fill_cv, NULL, NULL, 'O', NULL, 0, N_("When filling using freetype in the outline view,\nhave freetype render the glyph antialiased.") },
308 	{ N_("SplashScreen"), pr_bool, &splash, NULL, NULL, 'S', NULL, 0, N_("Show splash screen on start-up") },
309 #ifndef _NO_LIBCAIRO
310 	{ N_("UseCairoDrawing"), pr_bool, &prefs_usecairo, NULL, NULL, '\0', NULL, 0, N_("Use the cairo library for drawing (if available)\nThis makes for prettier (anti-aliased) but slower drawing\nThis applies to any windows created AFTER this is set.\nAlready existing windows will continue as they are.") },
311 #endif
312 	{ N_("ExportClipboard"), pr_bool, &export_clipboard, NULL, NULL, '\0', NULL, 0, N_( "If you are running an X11 clipboard manager you might want\nto turn this off. FF can put things into its internal clipboard\nwhich it cannot export to X11 (things like copying more than\none glyph in the fontview). If you have a clipboard manager\nrunning it will force these to be exported with consequent\nloss of data.") },
313 	{ N_("AutoSaveFrequency"), pr_int, &AutoSaveFrequency, NULL, NULL, '\0', NULL, 0, N_( "The number of seconds between autosaves. If you set this to 0 there will be no autosaves.") },
314 	{ N_("RevisionsToRetain"), pr_int, &prefRevisionsToRetain, NULL, NULL, '\0', NULL, 0, N_( "When Saving, keep this number of previous versions of the file. file.sfd-01 will be the last saved file, file.sfd-02 will be the file saved before that, and so on. If you set this to 0 then no revisions will be retained.") },
315 	{ N_("UndoRedoLimitToSave"), pr_int, &UndoRedoLimitToSave, NULL, NULL, '\0', NULL, 0, N_( "The number of undo and redo operations which will be saved in sfd files.\nIf you set this to 0 undo/redo information is not saved to sfd files.\nIf set to -1 then all available undo/redo information is saved without limit.") },
316 	{ N_("WarnScriptUnsaved"), pr_bool, &warn_script_unsaved, NULL, NULL, '\0', NULL, 0, N_( "Whether or not to warn you if you have an unsaved script in the «Execute Script» dialog.") },
317 	PREFS_LIST_EMPTY
318 },
319   new_list[] = {
320 	{ N_("NewCharset"), pr_encoding, &default_encoding, NULL, NULL, 'N', NULL, 0, N_("Default encoding for\nnew fonts") },
321 	{ N_("NewEmSize"), pr_int, &new_em_size, NULL, NULL, 'S', NULL, 0, N_("The default size of the Em-Square in a newly created font.") },
322 	{ N_("NewFontsQuadratic"), pr_bool, &new_fonts_are_order2, NULL, NULL, 'Q', NULL, 0, N_("Whether new fonts should contain splines of quadratic (truetype)\nor cubic (postscript & opentype).") },
323 	{ N_("LoadedFontsAsNew"), pr_bool, &loaded_fonts_same_as_new, NULL, NULL, 'L', NULL, 0, N_("Whether fonts loaded from the disk should retain their splines\nwith the original order (quadratic or cubic), or whether the\nsplines should be converted to the default order for new fonts\n(see NewFontsQuadratic).") },
324 	PREFS_LIST_EMPTY
325 },
326   open_list[] = {
327 	{ N_("PreferCJKEncodings"), pr_bool, &prefer_cjk_encodings, NULL, NULL, 'C', NULL, 0, N_("When loading a truetype or opentype font which has both a unicode\nand a CJK encoding table, use this flag to specify which\nshould be loaded for the font.") },
328 	{ N_("AskUserForCMap"), pr_bool, &ask_user_for_cmap, NULL, NULL, 'O', NULL, 0, N_("When loading a font in sfnt format (TrueType, OpenType, etc.),\nask the user to specify which cmap to use initially.") },
329 	{ N_("PreserveTables"), pr_string, &SaveTablesPref, NULL, NULL, 'P', NULL, 0, N_("Enter a list of 4 letter table tags, separated by commas.\nFontForge will make a binary copy of these tables when it\nloads a True/OpenType font, and will output them (unchanged)\nwhen it generates the font. Do not include table tags which\nFontForge thinks it understands.") },
330 	{ N_("SeekCharacter"), pr_unicode, &home_char, NULL, NULL, '\0', NULL, 0, N_("When fontforge opens a (non-sfd) font it will try to display this unicode character in the fontview.")},
331 	{ N_("CompactOnOpen"), pr_bool, &compact_font_on_open, NULL, NULL, 'O', NULL, 0, N_("When a font is opened, should it be made compact?")},
332 	{ N_("UndoRedoLimitToLoad"), pr_int, &UndoRedoLimitToLoad, NULL, NULL, '\0', NULL, 0, N_( "The number of undo and redo operations to load from sfd files.\nWith this option you can disregard undo information while loading SFD files.\nIf set to 0 then no undo/redo information is loaded.\nIf set to -1 then all available undo/redo information is loaded without limit.") },
333 	{ N_("OpenTypeLoadHintEqualityTolerance"), pr_real, &OpenTypeLoadHintEqualityTolerance, NULL, NULL, '\0', NULL, 0, N_( "When importing an OpenType font, for the purposes of hinting spline points might not exactly match boundaries. For example, a point might be -0.0002 instead of exactly 0\nThis setting gives the user some control over this allowing a small tolerance value to be fed into the OpenType loading code.\nComparisons are then not performed for raw equality but for equality within tolerance (e.g., values within the range -0.0002 to 0.0002 will be considered equal to 0 when figuring out hints).") },
334 	PREFS_LIST_EMPTY
335 },
336   navigation_list[] = {
337 	{ N_("GlyphAutoGoto"), pr_bool, &cv_auto_goto, NULL, NULL, '\0', NULL, 0, N_("Typing a normal character in the glyph view window changes the window to look at that character.\nEnabling GlyphAutoGoto will disable the shortcut where holding just the ` key will enable Preview mode as long as the key is held.") },
338 	{ N_("OpenCharsInNewWindow"), pr_bool, &OpenCharsInNewWindow, NULL, NULL, '\0', NULL, 0, N_("When double clicking on a character in the font view\nopen that character in a new window, otherwise\nreuse an existing one.") },
339 	{ N_("FontViewMetricsViewSelectMax"), pr_int, &fvmv_selectmax, NULL, NULL, '\0', NULL, 0, N_("When characters are selected in the FontView, how many should be put into the MetricsView if you open one? Negative values mean there's no limit, which should be used sparingly.") },
340 	PREFS_LIST_EMPTY
341 },
342   editing_list[] = {
343 	{ N_("ItalicConstrained"), pr_bool, &ItalicConstrained, NULL, NULL, '\0', NULL, 0, N_("In the Outline View, the Shift key constrains motion to be parallel to the ItalicAngle rather than constraining it to be vertical.") },
344 	{ N_("InterpolateCPsOnMotion"), pr_bool, &interpCPsOnMotion, NULL, NULL, '\0', NULL, 0, N_("When moving one end point of a spline but not the other\ninterpolate the control points between the two.") },
345 	{ N_("SnapDistance"), pr_real, &snapdistance, NULL, NULL, '\0', NULL, 0, N_("When the mouse pointer is within this many pixels\nof one of the various interesting features (baseline,\nwidth, grid splines, etc.) the pointer will snap\nto that feature.") },
346 	{ N_("SnapDistanceMeasureTool"), pr_real, &snapdistancemeasuretool, NULL, NULL, '\0', NULL, 0, N_("When the measure tool is active and when the mouse pointer is within this many pixels\nof one of the various interesting features (baseline,\nwidth, grid splines, etc.) the pointer will snap\nto that feature.") },
347 	{ N_("SnapToInt"), pr_bool, &snaptoint, NULL, NULL, '\0', NULL, 0, N_("When the user clicks in the editing window, round the location to the nearest integers.") },
348 	{ N_("StopAtJoin"), pr_bool, &stop_at_join, NULL, NULL, '\0', NULL, 0, N_("When dragging points in the outline view a join may occur\n(two open contours may connect at their endpoints). When\nthis is On a join will cause FontForge to stop moving the\nselection (as if the user had released the mouse button).\nThis is handy if your fingers are inclined to wiggle a bit.") },
349 	{ N_("JoinSnap"), pr_real, &joinsnap, NULL, NULL, '\0', NULL, 0, N_("The Edit->Join command will join points which are this close together\nA value of 0 means they must be coincident") },
350 	{ N_("CopyMetaData"), pr_bool, &copymetadata, NULL, NULL, '\0', NULL, 0, N_("When copying glyphs from the font view, also copy the\nglyphs' metadata (name, encoding, comment, etc).") },
351 	{ N_("UndoDepth"), pr_int, &maxundoes, NULL, NULL, '\0', NULL, 0, N_("The maximum number of Undoes/Redoes stored in a glyph. Use -1 for infinite Undoes\n(but watch RAM consumption and use the Edit menu's Remove Undoes as needed)") },
352 	{ N_("UpdateFlex"), pr_bool, &updateflex, NULL, NULL, '\0', NULL, 0, N_("Figure out flex hints after every change") },
353 	{ N_("AutoKernDialog"), pr_bool, &default_autokern_dlg, NULL, NULL, '\0', NULL, 0, N_("Open AutoKern dialog for new kerning subtables") },
354 	{ N_("MetricsShiftSkip"), pr_int, &pref_mv_shift_and_arrow_skip, NULL, NULL, '\0', NULL, 0, N_("Number of units to increment/decrement a table value by in the metrics window when shift is held") },
355 	{ N_("MetricsControlShiftSkip"), pr_int, &pref_mv_control_shift_and_arrow_skip, NULL, NULL, '\0', NULL, 0, N_("Number of units to increment/decrement a table value by in the metrics window when both control and shift is held") },
356 	PREFS_LIST_EMPTY
357 },
358   editing_interface_list[] = {
359 	{ N_("ArrowMoveSize"), pr_real, &arrowAmount, NULL, NULL, '\0', NULL, 0, N_("The number of em-units by which an arrow key will move a selected point") },
360 	{ N_("ArrowAccelFactor"), pr_real, &arrowAccelFactor, NULL, NULL, '\0', NULL, 0, N_("Holding down the Shift key will speed up arrow key motion by this factor") },
361 	{ N_("DrawOpenPathsWithHighlight"), pr_bool, &DrawOpenPathsWithHighlight, NULL, NULL, '\0', NULL, 0, N_("Open paths should be drawn in a special highlight color to make them more apparent.") },
362 	{ N_("MeasureToolShowHorizontalVertical"), pr_bool, &measuretoolshowhorizontolvertical, NULL, NULL, '\0', NULL, 0, N_("Have the measure tool show horizontal and vertical distances on the canvas.") },
363 	{ N_("EditHandleSize"), pr_real, &prefs_cvEditHandleSize, NULL, NULL, '\0', NULL, 0, N_("The size of the handles showing control points and other interesting points in the glyph editor (default is 5).") },
364 	{ N_("InactiveHandleAlpha"), pr_int, &prefs_cvInactiveHandleAlpha, NULL, NULL, '\0', NULL, 0, N_("Inactive handles in the glyph editor will be drawn with this alpha value (range: 0-255 default is 255).") },
365 	{ N_("ShowControlPointsAlways"), pr_bool, &prefs_cv_show_control_points_always_initially, NULL, NULL, '\0', NULL, 0, N_("Always show the control points when editing a glyph.\nThis can be turned off in the menu View/Show, this setting will effect if control points are shown initially.\nChange requires a restart of fontforge.") },
366 	{ N_("ShowFillWithSpace"), pr_bool, &cv_show_fill_with_space, NULL, NULL, '\0', NULL, 0, N_("Also enable preview mode when the space bar is pressed.") },
367 	{ N_("OutlineThickness"), pr_int, &prefs_cv_outline_thickness, NULL, NULL, '\0', NULL, 0, N_("Setting above 1 will cause a thick outline to be drawn for glyph paths\n which is only extended inwards from the edge of the glyph.\n See also the ForegroundThickOutlineColor Resource for the color of this outline.") },
368 	PREFS_LIST_EMPTY
369 },
370   sync_list[] = {
371 	{ N_("AutoWidthSync"), pr_bool, &adjustwidth, NULL, NULL, '\0', NULL, 0, N_("Changing the width of a glyph\nchanges the widths of all accented\nglyphs based on it.") },
372 	{ N_("AutoLBearingSync"), pr_bool, &adjustlbearing, NULL, NULL, '\0', NULL, 0, N_("Changing the left side bearing\nof a glyph adjusts the lbearing\nof other references in all accented\nglyphs based on it.") },
373 	PREFS_LIST_EMPTY
374 },
375  tt_list[] = {
376 	{ N_("ClearInstrsBigChanges"), pr_bool, &clear_tt_instructions_when_needed, NULL, NULL, 'C', NULL, 0, N_("Instructions in a TrueType font refer to\npoints by number, so if you edit a glyph\nin such a way that some points have different\nnumbers (add points, remove them, etc.) then\nthe instructions will be applied to the wrong\npoints with disasterous results.\n  Normally FontForge will remove the instructions\nif it detects that the points have been renumbered\nin order to avoid the above problem. You may turn\nthis behavior off -- but be careful!") },
377 	{ N_("CopyTTFInstrs"), pr_bool, &copyttfinstr, NULL, NULL, '\0', NULL, 0, N_("When copying glyphs from the font view, also copy the\nglyphs' truetype instructions.") },
378 	PREFS_LIST_EMPTY
379 },
380   accent_list[] = {
381 	{ N_("AccentOffsetPercent"), pr_int, &accent_offset, NULL, NULL, '\0', NULL, 0, N_("The percentage of an em by which an accent is offset from its base glyph in Build Accent") },
382 	{ N_("AccentCenterLowest"), pr_bool, &GraveAcuteCenterBottom, NULL, NULL, '\0', NULL, 0, N_("When placing grave and acute accents above letters, should\nFontForge center them based on their full width, or\nshould it just center based on the lowest point\nof the accent.") },
383 	{ N_("CharCenterHighest"), pr_bool, &CharCenterHighest, NULL, NULL, '\0', NULL, 0, N_("When centering an accent over a glyph, should the accent\nbe centered on the highest point(s) of the glyph,\nor the middle of the glyph?") },
384 	{ N_("PreferSpacingAccents"), pr_bool, &PreferSpacingAccents, NULL, NULL, '\0', NULL, 0, N_("Use spacing accents (Unicode: 02C0-02FF) rather than\ncombining accents (Unicode: 0300-036F) when\nbuilding accented glyphs.") },
385 	PREFS_LIST_EMPTY
386 },
387  args_list[] = {
388 	{ N_("PreferPotrace"), pr_bool, &preferpotrace, NULL, NULL, '\0', NULL, 0, N_("FontForge supports two different helper applications to do autotracing\n autotrace and potrace\nIf your system only has one it will use that one, if you have both\nuse this option to tell FontForge which to pick.") },
389 	{ N_("AutotraceArgs"), pr_string, NULL, GetAutoTraceArgs, SetAutoTraceArgs, '\0', NULL, 0, N_("Extra arguments for configuring the autotrace program\n(either autotrace or potrace)") },
390 	{ N_("AutotraceAsk"), pr_bool, &autotrace_ask, NULL, NULL, '\0', NULL, 0, N_("Ask the user for autotrace arguments each time autotrace is invoked") },
391 	{ N_("MfArgs"), pr_string, &mf_args, NULL, NULL, '\0', NULL, 0, N_("Commands to pass to mf (metafont) program, the filename will follow these") },
392 	{ N_("MfAsk"), pr_bool, &mf_ask, NULL, NULL, '\0', NULL, 0, N_("Ask the user for mf commands each time mf is invoked") },
393 	{ N_("MfClearBg"), pr_bool, &mf_clearbackgrounds, NULL, NULL, '\0', NULL, 0, N_("FontForge loads large images into the background of each glyph\nprior to autotracing them. You may retain those\nimages to look at after mf processing is complete, or\nremove them to save space") },
394 	{ N_("MfShowErr"), pr_bool, &mf_showerrors, NULL, NULL, '\0', NULL, 0, N_("MetaFont (mf) generates lots of verbiage to stdout.\nMost of the time I find it an annoyance but it is\nimportant to see if something goes wrong.") },
395 	PREFS_LIST_EMPTY
396 },
397  fontinfo_list[] = {
398 	{ N_("FoundryName"), pr_string, &BDFFoundry, NULL, NULL, 'F', NULL, 0, N_("Name used for foundry field in bdf\nfont generation") },
399 	{ N_("TTFFoundry"), pr_string, &TTFFoundry, NULL, NULL, 'T', NULL, 0, N_("Name used for Vendor ID field in\nttf (OS/2 table) font generation.\nMust be no more than 4 characters") },
400 	{ N_("NewFontNameList"), pr_namelist, &namelist_for_new_fonts, NULL, NULL, '\0', NULL, 0, N_("FontForge will use this namelist when assigning\nglyph names to code points in a new font.") },
401 	{ N_("RecognizePUANames"), pr_bool, &recognizePUA, NULL, NULL, 'U', NULL, 0, N_("Once upon a time, Adobe assigned PUA (public use area) encodings\nfor many stylistic variants of characters (small caps, old style\nnumerals, etc.). Adobe no longer believes this to be a good idea,\nand recommends that these encodings be ignored.\n\n The assignments were originally made because most applications\ncould not handle OpenType features for accessing variants. Adobe\nnow believes that all apps that matter can now do so. Applications\nlike Word and OpenOffice still can't handle these features, so\n fontforge's default behavior is to ignore Adobe's current\nrecommendations.\n\nNote: This does not affect figuring out unicode from the font's encoding,\nit just controls determining unicode from a name.") },
402 	{ N_("UnicodeGlyphNames"), pr_bool, &allow_utf8_glyphnames, NULL, NULL, 'O', NULL, 0, N_("Allow the full unicode character set in glyph names.\nThis does not conform to adobe's glyph name standard.\nSuch names should be for internal use only and\nshould NOT end up in production fonts." ) },
403 	{ N_("AddCharToNameList"), pr_bool, &add_char_to_name_list, NULL, NULL, 'O', NULL, 0, N_( "When displaying a list of glyph names\n(or sometimes just a single glyph name)\nFontForge will add the unicode character\nthe name refers to in parenthesis after\nthe name. It does this because some names\nare obscure.\nSome people would prefer not to see this,\nso this preference item lets you turn off\n this behavior" ) },
404 	PREFS_LIST_EMPTY
405 },
406  generate_list[] = {
407 	{ N_("AskBDFResolution"), pr_bool, &ask_user_for_resolution, NULL, NULL, 'B', NULL, 0, N_("When generating a set of BDF fonts ask the user\nto specify the screen resolution of the fonts\notherwise FontForge will guess depending on the pixel size.") },
408 	{ N_("AutoHint"), pr_bool, &autohint_before_generate, NULL, NULL, 'H', NULL, 0, N_("AutoHint changed glyphs before generating a font") },
409 #ifndef _NO_LIBPNG
410     { N_("WritePNGInSFD"), pr_bool, &WritePNGInSFD, NULL, NULL, 'B', NULL, 0, N_("If your SFD contains images, write them as PNG; this results in smaller SFDs; but was not supported in FontForge versions compiled before July 2019, so older FontForge versions cannot read them.") },
411 #endif
412 
413 	{ N_("GenerateHintWidthEqualityTolerance"), pr_real, &GenerateHintWidthEqualityTolerance, NULL, NULL, '\0', NULL, 0, N_( "When generating a font, ignore slight rounding errors for hints that should be at the top or bottom of the glyph. For example, you might like to set this to 0.02 so that 19.999 will be considered 20. But only for the hint width value.") },
414 
415 	PREFS_LIST_EMPTY
416 },
417  hints_list[] = {
418 	{ N_("StandardSlopeError"), pr_angle, &stem_slope_error, NULL, NULL, '\0', NULL, 0, N_("The maximum slope difference which still allows to consider two points \"parallel\".\nEnlarge this to make the autohinter more tolerable to small deviations from straight lines when detecting stem edges.") },
419 	{ N_("SerifSlopeError"), pr_angle, &stub_slope_error, NULL, NULL, '\0', NULL, 0, N_("Same as above, but for terminals of small features (e. g. serifs), which can deviate more significantly from the horizontal or vertical direction.") },
420 	{ N_("HintBoundingBoxes"), pr_bool, &hint_bounding_boxes, NULL, NULL, '\0', NULL, 0, N_("FontForge will place vertical or horizontal hints to describe the bounding boxes of suitable glyphs.") },
421 	{ N_("HintDiagonalEnds"), pr_bool, &hint_diagonal_ends, NULL, NULL, '\0', NULL, 0, N_("FontForge will place vertical or horizontal hints at the ends of diagonal stems.") },
422 	{ N_("HintDiagonalInter"), pr_bool, &hint_diagonal_intersections, NULL, NULL, '\0', NULL, 0, N_("FontForge will place vertical or horizontal hints at the intersections of diagonal stems.") },
423 	{ N_("DetectDiagonalStems"), pr_bool, &detect_diagonal_stems, NULL, NULL, '\0', NULL, 0, N_("FontForge will generate diagonal stem hints, which then can be used by the AutoInstr command.") },
424 	PREFS_LIST_EMPTY
425 },
426  instrs_list[] = {
427 	{ N_("InstructDiagonalStems"), pr_bool, &instruct_diagonal_stems, NULL, NULL, '\0', NULL, 0, N_("Generate instructions for diagonal stem hints.") },
428 	{ N_("InstructSerifs"), pr_bool, &instruct_serif_stems, NULL, NULL, '\0', NULL, 0, N_("Try to detect serifs and other elements protruding from base stems and generate instructions for them.") },
429 	{ N_("InstructBallTerminals"), pr_bool, &instruct_ball_terminals, NULL, NULL, '\0', NULL, 0, N_("Generate instructions for ball terminals.") },
430 	{ N_("InterpolateStrongPoints"), pr_bool, &interpolate_strong, NULL, NULL, '\0', NULL, 0, N_("Interpolate between stem edges some important points, not affected by other instructions.") },
431 	{ N_("CounterControl"), pr_bool, &control_counters, NULL, NULL, '\0', NULL, 0, N_("Make sure similar or equal counters remain the same in gridfitted outlines.\nEnabling this option may result in glyph advance widths being\ninconsistently scaled at some PPEMs.") },
432 	PREFS_LIST_EMPTY
433 },
434  opentype_list[] = {
435 	{ N_("UseNewIndicScripts"), pr_bool, &use_second_indic_scripts, NULL, NULL, 'C', NULL, 0, N_("MS has changed (in August 2006) the inner workings of their Indic shaping\nengine, and to disambiguate this change has created a parallel set of script\ntags (generally ending in '2') for Indic writing systems. If you are working\nwith the new system set this flag, if you are working with the old unset it.\n(if you aren't doing Indic work, this flag is irrelevant).") },
436 	PREFS_LIST_EMPTY
437 },
438 /* These are hidden, so will never appear in preference ui, hence, no "N_(" */
439 /*  They are controled elsewhere AntiAlias is a menu item in the font window's View menu */
440 /*  etc. */
441  hidden_list[] = {
442 	{ "AntiAlias", pr_bool, &default_fv_antialias, NULL, NULL, '\0', NULL, 1, NULL },
443 	{ "DefaultFVShowHmetrics", pr_int, &default_fv_showhmetrics, NULL, NULL, '\0', NULL, 1, NULL },
444 	{ "DefaultFVShowVmetrics", pr_int, &default_fv_showvmetrics, NULL, NULL, '\0', NULL, 1, NULL },
445 	{ "DefaultFVSize", pr_int, &default_fv_font_size, NULL, NULL, 'S', NULL, 1, NULL },
446 	{ "DefaultFVRowCount", pr_int, &default_fv_row_count, NULL, NULL, 'S', NULL, 1, NULL },
447 	{ "DefaultFVColCount", pr_int, &default_fv_col_count, NULL, NULL, 'S', NULL, 1, NULL },
448 	{ "DefaultFVGlyphLabel", pr_int, &default_fv_glyphlabel, NULL, NULL, 'S', NULL, 1, NULL },
449 	{ "SaveToDir", pr_int, &save_to_dir, NULL, NULL, 'S', NULL, 1, NULL },
450 	{ "OnlyCopyDisplayed", pr_bool, &onlycopydisplayed, NULL, NULL, '\0', NULL, 1, NULL },
451 	{ "PalettesDocked", pr_bool, &palettes_docked, NULL, NULL, '\0', NULL, 1, NULL },
452 	{ "DefaultCVWidth", pr_int, &cv_width, NULL, NULL, '\0', NULL, 1, NULL },
453 	{ "DefaultCVHeight", pr_int, &cv_height, NULL, NULL, '\0', NULL, 1, NULL },
454 	{ "CVVisible0", pr_bool, &cvvisible[0], NULL, NULL, '\0', NULL, 1, NULL },
455 	{ "CVVisible1", pr_bool, &cvvisible[1], NULL, NULL, '\0', NULL, 1, NULL },
456 	{ "BVVisible0", pr_bool, &bvvisible[0], NULL, NULL, '\0', NULL, 1, NULL },
457 	{ "BVVisible1", pr_bool, &bvvisible[1], NULL, NULL, '\0', NULL, 1, NULL },
458 	{ "BVVisible2", pr_bool, &bvvisible[2], NULL, NULL, '\0', NULL, 1, NULL },
459 	{ "MarkExtrema", pr_int, &CVShows.markextrema, NULL, NULL, '\0', NULL, 1, NULL },
460 	{ "MarkPointsOfInflect", pr_int, &CVShows.markpoi, NULL, NULL, '\0', NULL, 1, NULL },
461 	{ "ShowRulers", pr_bool, &CVShows.showrulers, NULL, NULL, '\0', NULL, 1, N_("Display rulers in the Outline Glyph View") },
462 	{ "ShowCPInfo", pr_int, &CVShows.showcpinfo, NULL, NULL, '\0', NULL, 1, NULL },
463 	{ "CreateDraggingComparisonOutline", pr_int, &prefs_create_dragging_comparison_outline, NULL, NULL, '\0', NULL, 1, NULL },
464 	{ "InfoWindowDistance", pr_int, &infowindowdistance, NULL, NULL, '\0', NULL, 1, NULL },
465 	{ "ShowSideBearings", pr_int, &CVShows.showsidebearings, NULL, NULL, '\0', NULL, 1, NULL },
466 	{ "ShowRefNames", pr_int, &CVShows.showrefnames, NULL, NULL, '\0', NULL, 1, NULL },
467 	{ "ShowPoints", pr_bool, &CVShows.showpoints, NULL, NULL, '\0', NULL, 1, NULL },
468 	{ "ShowFilled", pr_int, &CVShows.showfilled, NULL, NULL, '\0', NULL, 1, NULL },
469 	{ "ShowTabs", pr_int, &CVShows.showtabs, NULL, NULL, '\0', NULL, 1, NULL },
470  	{ "SnapOutlines", pr_int, &CVShows.snapoutlines, NULL, NULL, '\0', NULL, 1, NULL },
471 	{ "ShowAlmostHVLines", pr_bool, &CVShows.showalmosthvlines, NULL, NULL, '\0', NULL, 1, NULL },
472 	{ "ShowAlmostHVCurves", pr_bool, &CVShows.showalmosthvcurves, NULL, NULL, '\0', NULL, 1, NULL },
473 	{ "AlmostHVBound", pr_int, &CVShows.hvoffset, NULL, NULL, '\0', NULL, 1, NULL },
474 	{ "CheckSelfIntersects", pr_bool, &CVShows.checkselfintersects, NULL, NULL, '\0', NULL, 1, NULL },
475 	{ "ShowDebugChanges", pr_bool, &CVShows.showdebugchanges, NULL, NULL, '\0', NULL, 1, NULL },
476 	{ "DefaultScreenDpiSystem", pr_int, &oldsystem, NULL, NULL, '\0', NULL, 1, NULL },
477 	{ "DefaultOutputFormat", pr_int, &oldformatstate, NULL, NULL, '\0', NULL, 1, NULL },
478 	{ "DefaultBitmapFormat", pr_int, &oldbitmapstate, NULL, NULL, '\0', NULL, 1, NULL },
479 	{ "SaveValidate", pr_int, &old_validate, NULL, NULL, '\0', NULL, 1, NULL },
480 	{ "SaveFontLogAsk", pr_int, &old_fontlog, NULL, NULL, '\0', NULL, 1, NULL },
481 	{ "DefaultSFNTflags", pr_int, &old_sfnt_flags, NULL, NULL, '\0', NULL, 1, NULL },
482 	{ "DefaultPSflags", pr_int, &old_ps_flags, NULL, NULL, '\0', NULL, 1, NULL },
483 	{ "PageWidth", pr_int, &pagewidth, NULL, NULL, '\0', NULL, 1, NULL },
484 	{ "PageHeight", pr_int, &pageheight, NULL, NULL, '\0', NULL, 1, NULL },
485 	{ "PrintType", pr_int, &printtype, NULL, NULL, '\0', NULL, 1, NULL },
486 	{ "PrintCommand", pr_string, &printcommand, NULL, NULL, '\0', NULL, 1, NULL },
487 	{ "PageLazyPrinter", pr_string, &printlazyprinter, NULL, NULL, '\0', NULL, 1, NULL },
488 	{ "RegularStar", pr_bool, &regular_star, NULL, NULL, '\0', NULL, 1, NULL },
489 	{ "PolyStar", pr_bool, &polystar, NULL, NULL, '\0', NULL, 1, NULL },
490 	{ "RectEllipse", pr_bool, &rectelipse, NULL, NULL, '\0', NULL, 1, NULL },
491 	{ "RectCenterOut", pr_bool, &center_out[0], NULL, NULL, '\0', NULL, 1, NULL },
492 	{ "EllipseCenterOut", pr_bool, &center_out[1], NULL, NULL, '\0', NULL, 1, NULL },
493 	{ "PolyStartPointCnt", pr_int, &ps_pointcnt, NULL, NULL, '\0', NULL, 1, NULL },
494 	{ "RoundRectRadius", pr_real, &rr_radius, NULL, NULL, '\0', NULL, 1, NULL },
495 	{ "StarPercent", pr_real, &star_percent, NULL, NULL, '\0', NULL, 1, NULL },
496 	{ "CoverageFormatsAllowed", pr_int, &coverageformatsallowed, NULL, NULL, '\0', NULL, 1, NULL },
497 	{ "DebugWins", pr_int, &debug_wins, NULL, NULL, '\0', NULL, 1, NULL },
498 	{ "GridFitDpi", pr_int, &gridfit_dpi, NULL, NULL, '\0', NULL, 1, NULL },
499 	{ "GridFitDepth", pr_int, &gridfit_depth, NULL, NULL, '\0', NULL, 1, NULL },
500 	{ "GridFitPointSize", pr_real, &gridfit_pointsizey, NULL, NULL, '\0', NULL, 1, NULL },
501 	{ "GridFitPointSizeX", pr_real, &gridfit_pointsizex, NULL, NULL, '\0', NULL, 1, NULL },
502 	{ "GridFitSameAs", pr_int, &gridfit_x_sameas_y, NULL, NULL, '\0', NULL, 1, NULL },
503 	{ "MVShowGrid", pr_int, &mvshowgrid, NULL, NULL, '\0', NULL, 1, NULL },
504 	{ "ForceNamesWhenOpening", pr_namelist, &force_names_when_opening, NULL, NULL, '\0', NULL, 1, NULL },
505 	{ "ForceNamesWhenSaving", pr_namelist, &force_names_when_saving, NULL, NULL, '\0', NULL, 1, NULL },
506 	{ "DefaultFontFilterIndex", pr_int, &default_font_filter_index, NULL, NULL, '\0', NULL, 1, NULL },
507 	{ "FCShowHidden", pr_bool, &gfc_showhidden, NULL, NULL, '\0', NULL, 1, NULL },
508 	{ "FCDirPlacement", pr_int, &gfc_dirplace, NULL, NULL, '\0', NULL, 1, NULL },
509 	{ "FCBookmarks", pr_string, &gfc_bookmarks, NULL, NULL, '\0', NULL, 1, NULL },
510 	{ "DefaultMVType",   pr_int, &mv_type, NULL, NULL, '\0', NULL, 1, NULL },
511 	{ "DefaultMVWidth",  pr_int, &mv_width, NULL, NULL, '\0', NULL, 1, NULL },
512 	{ "DefaultMVHeight", pr_int, &mv_height, NULL, NULL, '\0', NULL, 1, NULL },
513 	{ "DefaultBVWidth", pr_int, &bv_width, NULL, NULL, '\0', NULL, 1, NULL },
514 	{ "DefaultBVHeight", pr_int, &bv_height, NULL, NULL, '\0', NULL, 1, NULL },
515 	{ "AnchorControlPixelSize", pr_int, &aa_pixelsize, NULL, NULL, '\0', NULL, 1, NULL },
516 #ifdef _NO_LIBCAIRO
517 	{ "UseCairoDrawing", pr_bool, &prefs_usecairo, NULL, NULL, '\0', NULL, 0, N_("Use the cairo library for drawing (if available)\nThis makes for prettier (anti-aliased) but slower drawing\nThis applies to any windows created AFTER this is set.\nAlready existing windows will continue as they are.") },
518 #endif
519 	{ "CV_B1Tool", pr_int, (int *) &cv_b1_tool, NULL, NULL, '\0', NULL, 1, NULL },
520 	{ "CV_CB1Tool", pr_int, (int *) &cv_cb1_tool, NULL, NULL, '\0', NULL, 1, NULL },
521 	{ "CV_B2Tool", pr_int, (int *) &cv_b2_tool, NULL, NULL, '\0', NULL, 1, NULL },
522 	{ "CV_CB2Tool", pr_int, (int *) &cv_cb2_tool, NULL, NULL, '\0', NULL, 1, NULL },
523 	{ "XUID-Base", pr_string, &xuid, NULL, NULL, 'X', NULL, 0, N_("If specified this should be a space separated list of integers each\nless than 16777216 which uniquely identify your organization\nFontForge will generate a random number for the final component.") }, /* Obsolete */
524 	{ "ShowKerningPane", pr_int, (int *) &show_kerning_pane_in_class, NULL, NULL, '\0', NULL, 1, NULL },
525 	PREFS_LIST_EMPTY
526 },
527  oldnames[] = {
528 	{ "DumpGlyphMap", pr_bool, &glyph_2_name_map, NULL, NULL, '\0', NULL, 0, N_("When generating a truetype or opentype font it is occasionally\nuseful to know the mapping between truetype glyph ids and\nglyph names. Setting this option will cause FontForge to\nproduce a file (with extension .g2n) containing those data.") },
529 	{ "DefaultTTFApple", pr_int, &pointless, NULL, NULL, '\0', NULL, 1, NULL },
530 	{ "AcuteCenterBottom", pr_bool, &GraveAcuteCenterBottom, NULL, NULL, '\0', NULL, 1, N_("When placing grave and acute accents above letters, should\nFontForge center them based on their full width, or\nshould it just center based on the lowest point\nof the accent.") },
531 	{ "AlwaysGenApple", pr_bool, &alwaysgenapple, NULL, NULL, 'A', NULL, 0, N_("Apple and MS/Adobe differ about the format of truetype and opentype files.\nThis controls the default setting of the Apple checkbox in the\nFile->Generate Font dialog.\nThe main differences are:\n Bitmap data are stored in different tables\n Scaled composite glyphs are treated differently\n Use of GSUB rather than morx(t)/feat\n Use of GPOS rather than kern/opbd\n Use of GDEF rather than lcar/prop\nIf both this and OpenType are set, both formats are generated") },
532 	{ "AlwaysGenOpenType", pr_bool, &alwaysgenopentype, NULL, NULL, 'O', NULL, 0, N_("Apple and MS/Adobe differ about the format of truetype and opentype files.\nThis controls the default setting of the OpenType checkbox in the\nFile->Generate Font dialog.\nThe main differences are:\n Bitmap data are stored in different tables\n Scaled composite glyphs are treated differently\n Use of GSUB rather than morx(t)/feat\n Use of GPOS rather than kern/opbd\n Use of GDEF rather than lcar/prop\nIf both this and Apple are set, both formats are generated") },
533 	{ "DefaultTTFflags", pr_int, &old_ttf_flags, NULL, NULL, '\0', NULL, 1, NULL },
534 	{ "DefaultOTFflags", pr_int, &old_otf_flags, NULL, NULL, '\0', NULL, 1, NULL },
535 	PREFS_LIST_EMPTY
536 },
537  *prefs_list[] = { general_list, new_list, open_list, navigation_list, sync_list, editing_list, editing_interface_list, accent_list, args_list, fontinfo_list, generate_list, tt_list, opentype_list, hints_list, instrs_list,
538  hidden_list, NULL },
539  *load_prefs_list[] = { general_list, new_list, open_list, navigation_list, sync_list, editing_list, editing_interface_list, accent_list, args_list, fontinfo_list, generate_list, tt_list, opentype_list, hints_list, instrs_list,
540  hidden_list, oldnames, NULL };
541 
542 struct visible_prefs_list { char *tab_name; int nest; struct prefs_list *pl; } visible_prefs_list[] = {
543     { N_("Generic"), 0, general_list},
544     { N_("New Font"), 0, new_list},
545     { N_("Open Font"), 0, open_list},
546     { N_("Navigation"), 0, navigation_list},
547     { N_("Editing"), 0, editing_list},
548     { N_("Interface"), 1, editing_interface_list},
549     { N_("Synchronize"), 1, sync_list},
550     { N_("TT"), 1, tt_list},
551     { N_("Accents"), 1, accent_list},
552     { N_("Apps"), 1, args_list},
553     { N_("Font Info"), 0, fontinfo_list},
554     { N_("Generate"), 0, generate_list},
555     { N_("PS Hints"), 1, hints_list},
556     { N_("TT Instrs"), 1, instrs_list},
557     { N_("OpenType"), 1, opentype_list},
558     { NULL, 0, NULL }
559 };
560 
FileChooserPrefsChanged(void * pointless)561 static void FileChooserPrefsChanged(void *pointless) {
562     SavePrefs(true);
563 }
564 
ProcessFileChooserPrefs(void)565 static void ProcessFileChooserPrefs(void) {
566     unichar_t **b;
567     int i;
568 
569     GFileChooserSetShowHidden(gfc_showhidden);
570     GFileChooserSetDirectoryPlacement(gfc_dirplace);
571     if ( gfc_bookmarks==NULL ) {
572 	b = malloc(8*sizeof(unichar_t *));
573 	i = 0;
574 #ifdef __Mac
575 	b[i++] = uc_copy("~/Library/Fonts/");
576 #endif
577 	b[i++] = uc_copy("~/fonts");
578 #ifdef __Mac
579 	b[i++] = uc_copy("/Library/Fonts/");
580 	b[i++] = uc_copy("/System/Library/Fonts/");
581 #endif
582 #if __CygWin
583 	b[i++] = uc_copy("/usr/share/fonts/");
584 	b[i++] = uc_copy("/usr/share/X11/fonts/");
585 #else
586 	b[i++] = uc_copy("/usr/X11R6/lib/X11/fonts/");
587 #endif
588 	b[i++] = NULL;
589 	GFileChooserSetBookmarks(b);
590     } else {
591 	char *pt, *start;
592 	start = gfc_bookmarks;
593 	for ( i=0; ; ++i ) {
594 	    pt = strchr(start,';');
595 	    if ( pt==NULL )
596 	break;
597 	    start = pt+1;
598 	}
599 	start = gfc_bookmarks;
600 	b = malloc((i+2)*sizeof(unichar_t *));
601 	for ( i=0; ; ++i ) {
602 	    pt = strchr(start,';');
603 	    if ( pt!=NULL )
604 		*pt = '\0';
605 	    b[i] = utf82u_copy(start);
606 	    if ( pt==NULL )
607 	break;
608 	    *pt = ';';
609 	    start = pt+1;
610 	}
611 	b[i+1] = NULL;
612 	GFileChooserSetBookmarks(b);
613     }
614     GFileChooserSetPrefsChangedCallback(NULL,FileChooserPrefsChanged);
615 }
616 
GetFileChooserPrefs(void)617 static void GetFileChooserPrefs(void) {
618     unichar_t **foo;
619 
620     gfc_showhidden = GFileChooserGetShowHidden();
621     gfc_dirplace = GFileChooserGetDirectoryPlacement();
622     foo = GFileChooserGetBookmarks();
623     free(gfc_bookmarks);
624     if ( foo==NULL || foo[0]==NULL )
625 	gfc_bookmarks = NULL;
626     else {
627 	int i,len=0;
628 	for ( i=0; foo[i]!=NULL; ++i )
629 	    len += 4*u_strlen(foo[i])+1;
630 	gfc_bookmarks = malloc(len+10);
631 	len = 0;
632 	for ( i=0; foo[i]!=NULL; ++i ) {
633 	    u2utf8_strcpy(gfc_bookmarks+len,foo[i]);
634 	    len += strlen(gfc_bookmarks+len);
635 	    gfc_bookmarks[len++] = ';';
636 	}
637 	if ( len>0 )
638 	    gfc_bookmarks[len-1] = '\0';
639 	else {
640 	    free(gfc_bookmarks);
641 	    gfc_bookmarks = NULL;
642 	}
643     }
644 }
645 
646 #define TOPICS	(sizeof(visible_prefs_list)/sizeof(visible_prefs_list[0])-1)
647 
PrefsUI_GetPrefs(char * name,Val * val)648 static int PrefsUI_GetPrefs(char *name,Val *val) {
649     int i,j;
650 
651     /* Support for obsolete preferences */
652     alwaysgenapple=(old_sfnt_flags&ttf_flag_applemode)?1:0;
653     alwaysgenopentype=(old_sfnt_flags&ttf_flag_otmode)?1:0;
654 
655     for ( i=0; prefs_list[i]!=NULL; ++i ) for ( j=0; prefs_list[i][j].name!=NULL; ++j ) {
656 	if ( strcmp(prefs_list[i][j].name,name)==0 ) {
657 	    struct prefs_list *pf = &prefs_list[i][j];
658 	    if ( pf->type == pr_bool || pf->type == pr_int || pf->type == pr_unicode ) {
659 		val->type = v_int;
660 		val->u.ival = *((int *) (pf->val));
661 	    } else if ( pf->type == pr_string || pf->type == pr_file ) {
662 		val->type = v_str;
663 
664 		char *tmpstr = pf->val ? *((char **) (pf->val)) : (char *) (pf->get)();
665 		val->u.sval = copy( tmpstr ? tmpstr : "" );
666 
667 		if( ! pf->val )
668 		    free( tmpstr );
669 	    } else if ( pf->type == pr_encoding ) {
670 		val->type = v_str;
671 		if ( *((NameList **) (pf->val))==NULL )
672 		    val->u.sval = copy( "NULL" );
673 		else
674 		    val->u.sval = copy( (*((Encoding **) (pf->val)))->enc_name );
675 	    } else if ( pf->type == pr_namelist ) {
676 		val->type = v_str;
677 		val->u.sval = copy( (*((NameList **) (pf->val)))->title );
678 	    } else if ( pf->type == pr_real || pf->type == pr_angle ) {
679 		val->type = v_real;
680 		val->u.fval = *((float *) (pf->val));
681 		if ( pf->type == pr_angle )
682 		    val->u.fval *= RAD2DEG;
683 	    } else
684 return( false );
685 
686 return( true );
687 	}
688     }
689 return( false );
690 }
691 
CheckObsoletePrefs(void)692 static void CheckObsoletePrefs(void) {
693     if ( alwaysgenapple==false ) {
694 	old_sfnt_flags &= ~ttf_flag_applemode;
695     } else if ( alwaysgenapple==true ) {
696 	old_sfnt_flags |= ttf_flag_applemode;
697     }
698     if ( alwaysgenopentype==false ) {
699 	old_sfnt_flags &= ~ttf_flag_otmode;
700     } else if ( alwaysgenopentype==true ) {
701 	old_sfnt_flags |= ttf_flag_otmode;
702     }
703     if ( old_ttf_flags!=0 )
704 	old_sfnt_flags = old_ttf_flags | old_otf_flags;
705 }
706 
PrefsUI_SetPrefs(char * name,Val * val1,Val * val2)707 static int PrefsUI_SetPrefs(char *name,Val *val1, Val *val2) {
708     int i,j;
709 
710     /* Support for obsolete preferences */
711     alwaysgenapple=-1; alwaysgenopentype=-1;
712 
713     for ( i=0; prefs_list[i]!=NULL; ++i ) for ( j=0; prefs_list[i][j].name!=NULL; ++j ) {
714 	if ( strcmp(prefs_list[i][j].name,name)==0 ) {
715 	    struct prefs_list *pf = &prefs_list[i][j];
716 	    if ( pf->type == pr_bool || pf->type == pr_int || pf->type == pr_unicode ) {
717 		if ( (val1->type!=v_int && val1->type!=v_unicode) || val2!=NULL )
718 return( -1 );
719 		*((int *) (pf->val)) = val1->u.ival;
720 	    } else if ( pf->type == pr_real || pf->type == pr_angle ) {
721 		if ( val1->type==v_real && val2==NULL )
722 		    *((float *) (pf->val)) = val1->u.fval;
723 		else if ( val1->type!=v_int || (val2!=NULL && val2->type!=v_int ))
724 return( -1 );
725 		else
726 		    *((float *) (pf->val)) = (val2==NULL ? val1->u.ival : val1->u.ival / (double) val2->u.ival);
727 		if ( pf->type == pr_angle )
728 		    *((float *) (pf->val)) /= RAD2DEG;
729 	    } else if ( pf->type == pr_string || pf->type == pr_file ) {
730 		if ( val1->type!=v_str || val2!=NULL )
731 return( -1 );
732 		if ( pf->set ) {
733 		    pf->set( val1->u.sval );
734 		} else {
735 		    free( *((char **) (pf->val)));
736 		    *((char **) (pf->val)) = copy( val1->u.sval );
737 		}
738 	    } else if ( pf->type == pr_encoding ) {
739 		if ( val2!=NULL )
740 return( -1 );
741 		else if ( val1->type==v_str && pf->val == &default_encoding) {
742 		    Encoding *enc = FindOrMakeEncoding(val1->u.sval);
743 		    if ( enc==NULL )
744 return( -1 );
745 		    *((Encoding **) (pf->val)) = enc;
746 		} else
747 return( -1 );
748 	    } else if ( pf->type == pr_namelist ) {
749 		if ( val2!=NULL )
750 return( -1 );
751 		else if ( val1->type==v_str ) {
752 		    NameList *nl = NameListByName(val1->u.sval);
753 		    if ( strcmp(val1->u.sval,"NULL")==0 && pf->val != &namelist_for_new_fonts )
754 			nl = NULL;
755 		    else if ( nl==NULL )
756 return( -1 );
757 		    *((NameList **) (pf->val)) = nl;
758 		} else
759 return( -1 );
760 	    } else
761 return( false );
762 
763 	    CheckObsoletePrefs();
764 	    SavePrefs(true);
765 return( true );
766 	}
767     }
768 return( false );
769 }
770 
getPfaEditPrefs(void)771 static char *getPfaEditPrefs(void) {
772     static char *prefs=NULL;
773     char buffer[1025];
774     char *ffdir;
775 
776     if ( prefs!=NULL )
777         return prefs;
778     ffdir = getFontForgeUserDir(Config);
779     if ( ffdir==NULL )
780         return NULL;
781     sprintf(buffer,"%s/prefs", ffdir);
782     free(ffdir);
783     prefs = copy(buffer);
784     return prefs;
785 }
786 
PrefsUI_getFontForgeShareDir(void)787 static char *PrefsUI_getFontForgeShareDir(void) {
788     return getShareDir();
789 }
790 
encmatch(const char * enc,int subok)791 static int encmatch(const char *enc,int subok) {
792     static struct { char *name; int enc; } encs[] = {
793 	{ "US-ASCII", e_usascii },
794 	{ "ASCII", e_usascii },
795 	{ "ISO646-NO", e_iso646_no },
796 	{ "ISO646-SE", e_iso646_se },
797 	{ "LATIN10", e_iso8859_16 },
798 	{ "LATIN1", e_iso8859_1 },
799 	{ "ISO-8859-1", e_iso8859_1 },
800 	{ "ISO-8859-2", e_iso8859_2 },
801 	{ "ISO-8859-3", e_iso8859_3 },
802 	{ "ISO-8859-4", e_iso8859_4 },
803 	{ "ISO-8859-5", e_iso8859_4 },
804 	{ "ISO-8859-6", e_iso8859_4 },
805 	{ "ISO-8859-7", e_iso8859_4 },
806 	{ "ISO-8859-8", e_iso8859_4 },
807 	{ "ISO-8859-9", e_iso8859_4 },
808 	{ "ISO-8859-10", e_iso8859_10 },
809 	{ "ISO-8859-11", e_iso8859_11 },
810 	{ "ISO-8859-13", e_iso8859_13 },
811 	{ "ISO-8859-14", e_iso8859_14 },
812 	{ "ISO-8859-15", e_iso8859_15 },
813 	{ "ISO-8859-16", e_iso8859_16 },
814 	{ "ISO_8859-1", e_iso8859_1 },
815 	{ "ISO_8859-2", e_iso8859_2 },
816 	{ "ISO_8859-3", e_iso8859_3 },
817 	{ "ISO_8859-4", e_iso8859_4 },
818 	{ "ISO_8859-5", e_iso8859_4 },
819 	{ "ISO_8859-6", e_iso8859_4 },
820 	{ "ISO_8859-7", e_iso8859_4 },
821 	{ "ISO_8859-8", e_iso8859_4 },
822 	{ "ISO_8859-9", e_iso8859_4 },
823 	{ "ISO_8859-10", e_iso8859_10 },
824 	{ "ISO_8859-11", e_iso8859_11 },
825 	{ "ISO_8859-13", e_iso8859_13 },
826 	{ "ISO_8859-14", e_iso8859_14 },
827 	{ "ISO_8859-15", e_iso8859_15 },
828 	{ "ISO_8859-16", e_iso8859_16 },
829 	{ "ISO8859-1", e_iso8859_1 },
830 	{ "ISO8859-2", e_iso8859_2 },
831 	{ "ISO8859-3", e_iso8859_3 },
832 	{ "ISO8859-4", e_iso8859_4 },
833 	{ "ISO8859-5", e_iso8859_4 },
834 	{ "ISO8859-6", e_iso8859_4 },
835 	{ "ISO8859-7", e_iso8859_4 },
836 	{ "ISO8859-8", e_iso8859_4 },
837 	{ "ISO8859-9", e_iso8859_4 },
838 	{ "ISO8859-10", e_iso8859_10 },
839 	{ "ISO8859-11", e_iso8859_11 },
840 	{ "ISO8859-13", e_iso8859_13 },
841 	{ "ISO8859-14", e_iso8859_14 },
842 	{ "ISO8859-15", e_iso8859_15 },
843 	{ "ISO8859-16", e_iso8859_16 },
844 	{ "ISO88591", e_iso8859_1 },
845 	{ "ISO88592", e_iso8859_2 },
846 	{ "ISO88593", e_iso8859_3 },
847 	{ "ISO88594", e_iso8859_4 },
848 	{ "ISO88595", e_iso8859_4 },
849 	{ "ISO88596", e_iso8859_4 },
850 	{ "ISO88597", e_iso8859_4 },
851 	{ "ISO88598", e_iso8859_4 },
852 	{ "ISO88599", e_iso8859_4 },
853 	{ "ISO885910", e_iso8859_10 },
854 	{ "ISO885911", e_iso8859_11 },
855 	{ "ISO885913", e_iso8859_13 },
856 	{ "ISO885914", e_iso8859_14 },
857 	{ "ISO885915", e_iso8859_15 },
858 	{ "ISO885916", e_iso8859_16 },
859 	{ "8859_1", e_iso8859_1 },
860 	{ "8859_2", e_iso8859_2 },
861 	{ "8859_3", e_iso8859_3 },
862 	{ "8859_4", e_iso8859_4 },
863 	{ "8859_5", e_iso8859_4 },
864 	{ "8859_6", e_iso8859_4 },
865 	{ "8859_7", e_iso8859_4 },
866 	{ "8859_8", e_iso8859_4 },
867 	{ "8859_9", e_iso8859_4 },
868 	{ "8859_10", e_iso8859_10 },
869 	{ "8859_11", e_iso8859_11 },
870 	{ "8859_13", e_iso8859_13 },
871 	{ "8859_14", e_iso8859_14 },
872 	{ "8859_15", e_iso8859_15 },
873 	{ "8859_16", e_iso8859_16 },
874 	{ "KOI8-R", e_koi8_r },
875 	{ "KOI8R", e_koi8_r },
876 	{ "WINDOWS-1252", e_win },
877 	{ "CP1252", e_win },
878 	{ "Big5", e_big5 },
879 	{ "Big-5", e_big5 },
880 	{ "BigFive", e_big5 },
881 	{ "Big-Five", e_big5 },
882 	{ "Big5HKSCS", e_big5hkscs },
883 	{ "Big5-HKSCS", e_big5hkscs },
884 	{ "UTF-8", e_utf8 },
885 	{ "ISO-10646/UTF-8", e_utf8 },
886 	{ "ISO_10646/UTF-8", e_utf8 },
887 	{ "UCS2", e_unicode },
888 	{ "UCS-2", e_unicode },
889 	{ "UCS-2-INTERNAL", e_unicode },
890 	{ "ISO-10646", e_unicode },
891 	{ "ISO_10646", e_unicode },
892 	/* { "eucJP", e_euc }, */
893 	/* { "EUC-JP", e_euc }, */
894 	/* { "ujis", ??? }, */
895 	/* { "EUC-KR", e_euckorean }, */
896 	{ NULL, 0 }
897     };
898 
899     int i;
900     char buffer[80];
901 #if HAVE_ICONV_H
902     static char *last_complaint;
903 
904     iconv_t test;
905     free(iconv_local_encoding_name);
906     iconv_local_encoding_name= NULL;
907 #endif
908 
909     if ( strchr(enc,'@')!=NULL && strlen(enc)<sizeof(buffer)-1 ) {
910 	strcpy(buffer,enc);
911 	*strchr(buffer,'@') = '\0';
912 	enc = buffer;
913     }
914 
915     for ( i=0; encs[i].name!=NULL; ++i )
916 	if ( strmatch(enc,encs[i].name)==0 )
917 return( encs[i].enc );
918 
919     if ( subok ) {
920 	for ( i=0; encs[i].name!=NULL; ++i )
921 	    if ( strstrmatch(enc,encs[i].name)!=NULL )
922 return( encs[i].enc );
923 
924 #if HAVE_ICONV_H
925 	/* I only try to use iconv if the encoding doesn't match one I support*/
926 	/*  loading iconv unicode data takes a while */
927 	test = iconv_open(enc,FindUnicharName());
928 	if ( test==(iconv_t) (-1) || test==NULL ) {
929 	    if ( last_complaint==NULL || strcmp(last_complaint,enc)!=0 ) {
930 		fprintf( stderr, "Neither FontForge nor iconv() supports your encoding (%s) we will pretend\n you asked for latin1 instead.\n", enc );
931 		free( last_complaint );
932 		last_complaint = copy(enc);
933 	    }
934 	} else {
935 	    if ( last_complaint==NULL || strcmp(last_complaint,enc)!=0 ) {
936 		fprintf( stderr, "FontForge does not support your encoding (%s), it will try to use iconv()\n or it will pretend the local encoding is latin1\n", enc );
937 		free( last_complaint );
938 		last_complaint = copy(enc);
939 	    }
940 	    iconv_local_encoding_name= copy(enc);
941 	    iconv_close(test);
942 	}
943 #else
944 	fprintf( stderr, "FontForge does not support your encoding (%s), it will pretend the local encoding is latin1\n", enc );
945 #endif
946 
947 return( e_iso8859_1 );
948     }
949 return( e_unknown );
950 }
951 
DefaultEncoding(void)952 static int DefaultEncoding(void) {
953     const char *loc;
954     int enc;
955 
956 #if HAVE_LANGINFO_H
957     loc = nl_langinfo(CODESET);
958     enc = encmatch(loc,false);
959     if ( enc!=e_unknown )
960 return( enc );
961 #endif
962     loc = getenv("LC_ALL");
963     if ( loc==NULL ) loc = getenv("LC_CTYPE");
964     /*if ( loc==NULL ) loc = getenv("LC_MESSAGES");*/
965     if ( loc==NULL ) loc = getenv("LANG");
966 
967     if ( loc==NULL )
968 return( e_iso8859_1 );
969 
970     enc = encmatch(loc,false);
971     if ( enc==e_unknown ) {
972 	loc = strrchr(loc,'.');
973 	if ( loc==NULL )
974 return( e_iso8859_1 );
975 	enc = encmatch(loc+1,true);
976     }
977     if ( enc==e_unknown )
978 return( e_iso8859_1 );
979 
980 return( enc );
981 }
982 
DefaultXUID(void)983 static void DefaultXUID(void) {
984     /* Adobe has assigned PfaEdit a base XUID of 1021. Each new user is going */
985     /*  to get a couple of random numbers appended to that, hoping that will */
986     /*  make for a fairly safe system. */
987     /* FontForge will use the same scheme */
988     int r1, r2;
989     char buffer[50];
990     struct timeval tv;
991 
992     gettimeofday(&tv,NULL);
993     srand(tv.tv_usec);
994     do {
995 	r1 = rand()&0x3ff;
996     } while ( r1==0 );		/* I reserve "0" for me! */
997     gettimeofday(&tv,NULL);
998     g_random_set_seed(tv.tv_usec+1);
999     r2 = g_random_int();
1000     sprintf( buffer, "1021 %d %d", r1, r2 );
1001     if (xuid != NULL) free(xuid);
1002     xuid = copy(buffer);
1003 }
1004 
PrefsUI_SetDefaults(void)1005 static void PrefsUI_SetDefaults(void) {
1006 
1007     DefaultXUID();
1008     local_encoding = DefaultEncoding();
1009 }
1010 
ParseMacMapping(char * pt,struct macsettingname * ms)1011 static void ParseMacMapping(char *pt,struct macsettingname *ms) {
1012     char *end;
1013 
1014     ms->mac_feature_type = strtol(pt,&end,10);
1015     if ( *end==',' ) ++end;
1016     ms->mac_feature_setting = strtol(end,&end,10);
1017     if ( *end==' ' ) ++end;
1018     ms->otf_tag =
1019 	((end[0]&0xff)<<24) |
1020 	((end[1]&0xff)<<16) |
1021 	((end[2]&0xff)<<8) |
1022 	(end[3]&0xff);
1023 }
1024 
ParseNewMacFeature(FILE * p,char * line)1025 static void ParseNewMacFeature(FILE *p,char *line) {
1026     fseek(p,-(strlen(line)-strlen("MacFeat:")),SEEK_CUR);
1027     line[strlen("MacFeat:")] ='\0';
1028     default_mac_feature_map = SFDParseMacFeatures(p,line);
1029     fseek(p,-strlen(line),SEEK_CUR);
1030     if ( user_mac_feature_map!=NULL )
1031 	MacFeatListFree(user_mac_feature_map);
1032     user_mac_feature_map = default_mac_feature_map;
1033 }
1034 
PrefsUI_LoadPrefs_FromFile(char * filename)1035 static void PrefsUI_LoadPrefs_FromFile( char* filename )
1036 {
1037     FILE *p;
1038     char line[1100];
1039     int i, j, ri=0, mn=0, ms=0, fn=0, ff=0, filt_max=0;
1040     int msp=0, msc=0;
1041     char *pt;
1042     struct prefs_list *pl;
1043 
1044     if ( filename!=NULL && (p=fopen(filename,"r"))!=NULL ) {
1045 	while ( fgets(line,sizeof(line),p)!=NULL ) {
1046 	    if ( *line=='#' )
1047 	continue;
1048 	    pt = strchr(line,':');
1049 	    if ( pt==NULL )
1050 	continue;
1051 	    for ( j=0; load_prefs_list[j]!=NULL; ++j ) {
1052 		for ( i=0; load_prefs_list[j][i].name!=NULL; ++i )
1053 		    if ( strncmp(line,load_prefs_list[j][i].name,pt-line)==0 )
1054 		break;
1055 		if ( load_prefs_list[j][i].name!=NULL )
1056 	    break;
1057 	    }
1058 	    pl = NULL;
1059 	    if ( load_prefs_list[j]!=NULL )
1060 		pl = &load_prefs_list[j][i];
1061 	    for ( ++pt; *pt=='\t'; ++pt );
1062 	    if ( line[strlen(line)-1]=='\n' )
1063 		line[strlen(line)-1] = '\0';
1064 	    if ( line[strlen(line)-1]=='\r' )
1065 		line[strlen(line)-1] = '\0';
1066 	    if ( pl==NULL ) {
1067 		if ( strncmp(line,"Recent:",strlen("Recent:"))==0 && ri<RECENT_MAX )
1068 		    RecentFiles[ri++] = copy(pt);
1069 		else if ( strncmp(line,"MenuScript:",strlen("MenuScript:"))==0 && ms<SCRIPT_MENU_MAX )
1070 		    script_filenames[ms++] = copy(pt);
1071 		else if ( strncmp(line,"MenuName:",strlen("MenuName:"))==0 && mn<SCRIPT_MENU_MAX )
1072 		    script_menu_names[mn++] = utf82u_copy(pt);
1073 		else if ( strncmp(line,"FontFilterName:",strlen("FontFilterName:"))==0 ) {
1074 		    if ( fn>=filt_max )
1075 			user_font_filters = realloc(user_font_filters,((filt_max+=10)+1)*sizeof( struct openfilefilters));
1076 		    user_font_filters[fn].filter = NULL;
1077 		    user_font_filters[fn++].name = copy(pt);
1078 		    user_font_filters[fn].name = NULL;
1079 		} else if ( strncmp(line,"FontFilter:",strlen("FontFilter:"))==0 ) {
1080 		    if ( ff<filt_max )
1081 			user_font_filters[ff++].filter = copy(pt);
1082 		} else if ( strncmp(line,"MacMapCnt:",strlen("MacSetCnt:"))==0 ) {
1083 		    sscanf( pt, "%d", &msc );
1084 		    msp = 0;
1085 		    user_macfeat_otftag = calloc(msc+1,sizeof(struct macsettingname));
1086 		} else if ( strncmp(line,"MacMapping:",strlen("MacMapping:"))==0 && msp<msc ) {
1087 		    ParseMacMapping(pt,&user_macfeat_otftag[msp++]);
1088 		} else if ( strncmp(line,"MacFeat:",strlen("MacFeat:"))==0 ) {
1089 		    ParseNewMacFeature(p,line);
1090 		}
1091 	continue;
1092 	    }
1093 	    switch ( pl->type ) {
1094 	      case pr_encoding:
1095 		{ Encoding *enc = FindOrMakeEncoding(pt);
1096 		    if ( enc==NULL )
1097 			enc = FindOrMakeEncoding("ISO8859-1");
1098 		    if ( enc==NULL )
1099 			enc = &custom;
1100 		    *((Encoding **) (pl->val)) = enc;
1101 		}
1102 	      break;
1103 	      case pr_namelist:
1104 		{ NameList *nl = NameListByName(pt);
1105 		    if ( strcmp(pt,"NULL")==0 && pl->val != &namelist_for_new_fonts )
1106 			*((NameList **) (pl->val)) = NULL;
1107 		    else if ( nl!=NULL )
1108 			*((NameList **) (pl->val)) = nl;
1109 		}
1110 	      break;
1111 	      case pr_bool: case pr_int:
1112 		sscanf( pt, "%d", (int *) pl->val );
1113 	      break;
1114 	      case pr_unicode:
1115 		if ( sscanf( pt, "U+%x", (int *) pl->val )!=1 )
1116 		    if ( sscanf( pt, "u+%x", (int *) pl->val )!=1 )
1117 			sscanf( pt, "%x", (int *) pl->val );
1118 	      break;
1119 	      case pr_real: case pr_angle:
1120 		{ char *end;
1121 		    *((float *) pl->val) = strtod(pt,&end);
1122 		    if (( *end==',' || *end=='.' ) ) {
1123 			*end = (*end=='.')?',':'.';
1124 			*((float *) pl->val) = strtod(pt,NULL);
1125 		    }
1126 		}
1127 		if ( pl->type == pr_angle )
1128 		    *(float *) pl->val /= RAD2DEG;
1129 	      break;
1130 	      case pr_string: case pr_file:
1131 		if ( *pt=='\0' ) pt=NULL;
1132 		if ( pl->val!=NULL )
1133 		    *((char **) (pl->val)) = copy(pt);
1134 		else
1135 		    (pl->set)(copy(pt));
1136 	      break;
1137 	    }
1138 	}
1139 	fclose(p);
1140     }
1141 }
1142 
Prefs_LoadDefaultPreferences(void)1143 void Prefs_LoadDefaultPreferences( void )
1144 {
1145     char filename[PATH_MAX+1];
1146     char* sharedir = getShareDir();
1147 
1148     snprintf(filename,PATH_MAX,"%s/prefs", sharedir );
1149     PrefsUI_LoadPrefs_FromFile( filename );
1150 }
1151 
1152 
PrefsUI_LoadPrefs(void)1153 static void PrefsUI_LoadPrefs(void)
1154 {
1155     char *prefs = getPfaEditPrefs();
1156     FILE *p;
1157     char line[1100], path[PATH_MAX];
1158     int i, j, ri=0, mn=0, ms=0, fn=0, ff=0, filt_max=0;
1159     int msp=0, msc=0;
1160     char *pt, *real_xdefs_filename = NULL;
1161     struct prefs_list *pl;
1162 
1163     LoadPfaEditEncodings();
1164     LoadGroupList();
1165 
1166     if ( prefs!=NULL && (p=fopen(prefs,"r"))!=NULL ) {
1167 	while ( fgets(line,sizeof(line),p)!=NULL ) {
1168 	    if ( *line=='#' )
1169 	continue;
1170 	    pt = strchr(line,':');
1171 	    if ( pt==NULL )
1172 	continue;
1173 	    for ( j=0; load_prefs_list[j]!=NULL; ++j ) {
1174 		for ( i=0; load_prefs_list[j][i].name!=NULL; ++i )
1175 		    if ( strncmp(line,load_prefs_list[j][i].name,pt-line)==0 )
1176 		break;
1177 		if ( load_prefs_list[j][i].name!=NULL )
1178 	    break;
1179 	    }
1180 	    pl = NULL;
1181 	    if ( load_prefs_list[j]!=NULL )
1182 		pl = &load_prefs_list[j][i];
1183 	    for ( ++pt; *pt=='\t'; ++pt );
1184 	    if ( line[strlen(line)-1]=='\n' )
1185 		line[strlen(line)-1] = '\0';
1186 	    if ( line[strlen(line)-1]=='\r' )
1187 		line[strlen(line)-1] = '\0';
1188 	    if ( pl==NULL ) {
1189 		if ( strncmp(line,"Recent:",strlen("Recent:"))==0 && ri<RECENT_MAX )
1190 		    RecentFiles[ri++] = copy(pt);
1191 		else if ( strncmp(line,"MenuScript:",strlen("MenuScript:"))==0 && ms<SCRIPT_MENU_MAX )
1192 		    script_filenames[ms++] = copy(pt);
1193 		else if ( strncmp(line,"MenuName:",strlen("MenuName:"))==0 && mn<SCRIPT_MENU_MAX )
1194 		    script_menu_names[mn++] = utf82u_copy(pt);
1195 		else if ( strncmp(line,"FontFilterName:",strlen("FontFilterName:"))==0 ) {
1196 		    if ( fn>=filt_max )
1197 			user_font_filters = realloc(user_font_filters,((filt_max+=10)+1)*sizeof( struct openfilefilters));
1198 		    user_font_filters[fn].filter = NULL;
1199 		    user_font_filters[fn++].name = copy(pt);
1200 		    user_font_filters[fn].name = NULL;
1201 		} else if ( strncmp(line,"FontFilter:",strlen("FontFilter:"))==0 ) {
1202 		    if ( ff<filt_max )
1203 			user_font_filters[ff++].filter = copy(pt);
1204 		} else if ( strncmp(line,"MacMapCnt:",strlen("MacSetCnt:"))==0 ) {
1205 		    sscanf( pt, "%d", &msc );
1206 		    msp = 0;
1207 		    user_macfeat_otftag = calloc(msc+1,sizeof(struct macsettingname));
1208 		} else if ( strncmp(line,"MacMapping:",strlen("MacMapping:"))==0 && msp<msc ) {
1209 		    ParseMacMapping(pt,&user_macfeat_otftag[msp++]);
1210 		} else if ( strncmp(line,"MacFeat:",strlen("MacFeat:"))==0 ) {
1211 		    ParseNewMacFeature(p,line);
1212 		}
1213 	continue;
1214 	    }
1215 	    switch ( pl->type ) {
1216 	      case pr_encoding:
1217 		{ Encoding *enc = FindOrMakeEncoding(pt);
1218 		    if ( enc==NULL )
1219 			enc = FindOrMakeEncoding("ISO8859-1");
1220 		    if ( enc==NULL )
1221 			enc = &custom;
1222 		    *((Encoding **) (pl->val)) = enc;
1223 		}
1224 	      break;
1225 	      case pr_namelist:
1226 		{ NameList *nl = NameListByName(pt);
1227 		    if ( strcmp(pt,"NULL")==0 && pl->val != &namelist_for_new_fonts )
1228 			*((NameList **) (pl->val)) = NULL;
1229 		    else if ( nl!=NULL )
1230 			*((NameList **) (pl->val)) = nl;
1231 		}
1232 	      break;
1233 	      case pr_bool: case pr_int:
1234 		sscanf( pt, "%d", (int *) pl->val );
1235 	      break;
1236 	      case pr_unicode:
1237 		if ( sscanf( pt, "U+%x", (int *) pl->val )!=1 )
1238 		    if ( sscanf( pt, "u+%x", (int *) pl->val )!=1 )
1239 			sscanf( pt, "%x", (int *) pl->val );
1240 	      break;
1241 	      case pr_real: case pr_angle:
1242 		{ char *end;
1243 		    *((float *) pl->val) = strtod(pt,&end);
1244 		    if (( *end==',' || *end=='.' ) ) {
1245 			*end = (*end=='.')?',':'.';
1246 			*((float *) pl->val) = strtod(pt,NULL);
1247 		    }
1248 		}
1249 		if ( pl->type == pr_angle )
1250 		    *(float *) pl->val /= RAD2DEG;
1251 	      break;
1252 	      case pr_string: case pr_file:
1253 		if ( *pt=='\0' ) pt=NULL;
1254 		if ( pl->val!=NULL )
1255 		    *((char **) (pl->val)) = copy(pt);
1256 		else
1257 		    (pl->set)(copy(pt));
1258 	      break;
1259 	    }
1260 	}
1261 	fclose(p);
1262     }
1263 
1264     //
1265     // If the user has no theme set, then use the default
1266     //
1267     real_xdefs_filename = xdefs_filename;
1268     if ( !real_xdefs_filename )
1269     {
1270 //	fprintf(stderr,"no xdefs_filename!\n");
1271 //	if (!quiet) {
1272 //	    fprintf(stderr,"TESTING: getPixmapDir:%s\n", getPixmapDir() );
1273 //	    fprintf(stderr,"TESTING: getShareDir:%s\n", getShareDir() );
1274 //	}
1275 	snprintf(path, PATH_MAX, "%s/%s", getPixmapDir(), "resources" );
1276 //	if (!quiet)
1277 //	    fprintf(stderr,"trying default theme:%s\n", path );
1278 	real_xdefs_filename = path;
1279     }
1280     GResourceAddResourceFile(real_xdefs_filename,GResourceProgramName,true);
1281 
1282     if ( othersubrsfile!=NULL && ReadOtherSubrsFile(othersubrsfile)<=0 )
1283 	fprintf( stderr, "Failed to read OtherSubrs from %s\n", othersubrsfile );
1284 
1285     if ( glyph_2_name_map )
1286 	old_sfnt_flags |= ttf_flag_glyphmap;
1287     LoadNamelistDir(NULL);
1288     ProcessFileChooserPrefs();
1289     GDrawEnableCairo( prefs_usecairo );
1290 }
1291 
PrefsUI_SavePrefs(int not_if_script)1292 static void PrefsUI_SavePrefs(int not_if_script) {
1293     char *prefs = getPfaEditPrefs();
1294     FILE *p;
1295     int i, j;
1296     char *temp;
1297     struct prefs_list *pl;
1298     extern int running_script;
1299 
1300     if ( prefs==NULL )
1301 return;
1302     if ( not_if_script && running_script )
1303 return;
1304 
1305     if ( (p=fopen(prefs,"w"))==NULL )
1306 return;
1307 
1308     GetFileChooserPrefs();
1309 
1310     for ( j=0; prefs_list[j]!=NULL; ++j ) for ( i=0; prefs_list[j][i].name!=NULL; ++i ) {
1311 	pl = &prefs_list[j][i];
1312 	switch ( pl->type ) {
1313 	  case pr_encoding:
1314 	    fprintf( p, "%s:\t%s\n", pl->name, (*((Encoding **) (pl->val)))->enc_name );
1315 	  break;
1316 	  case pr_namelist:
1317 	    fprintf( p, "%s:\t%s\n", pl->name, *((NameList **) (pl->val))==NULL ? "NULL" :
1318 		    (*((NameList **) (pl->val)))->title );
1319 	  break;
1320 	  case pr_bool: case pr_int:
1321 	    fprintf( p, "%s:\t%d\n", pl->name, *(int *) (pl->val) );
1322 	  break;
1323 	  case pr_unicode:
1324 	    fprintf( p, "%s:\tU+%04x\n", pl->name, *(int *) (pl->val) );
1325 	  break;
1326 	  case pr_real:
1327 	    fprintf( p, "%s:\t%g\n", pl->name, (double) *(float *) (pl->val) );
1328 	  break;
1329 	  case pr_string: case pr_file:
1330 	    if ( (pl->val)!=NULL )
1331 		temp = *(char **) (pl->val);
1332 	    else
1333 		temp = (char *) (pl->get());
1334 	    if ( temp!=NULL )
1335 		fprintf( p, "%s:\t%s\n", pl->name, temp );
1336 	    if ( (pl->val)==NULL )
1337 		free(temp);
1338 	  break;
1339 	  case pr_angle:
1340 	    fprintf( p, "%s:\t%g\n", pl->name, ((double) *(float *) pl->val) * RAD2DEG );
1341 	  break;
1342 	}
1343     }
1344 
1345     for ( i=0; i<RECENT_MAX && RecentFiles[i]!=NULL; ++i )
1346 	fprintf( p, "Recent:\t%s\n", RecentFiles[i]);
1347     for ( i=0; i<SCRIPT_MENU_MAX && script_filenames[i]!=NULL; ++i ) {
1348 	fprintf( p, "MenuScript:\t%s\n", script_filenames[i]);
1349 	fprintf( p, "MenuName:\t%s\n", temp = u2utf8_copy(script_menu_names[i]));
1350 	free(temp);
1351     }
1352     if ( user_font_filters!=NULL ) {
1353 	for ( i=0; user_font_filters[i].name!=NULL; ++i ) {
1354 	    fprintf( p, "FontFilterName:\t%s\n", user_font_filters[i].name);
1355 	    fprintf( p, "FontFilter:\t%s\n", user_font_filters[i].filter);
1356 	}
1357     }
1358     if ( user_macfeat_otftag!=NULL && UserSettingsDiffer()) {
1359 	for ( i=0; user_macfeat_otftag[i].otf_tag!=0; ++i );
1360 	fprintf( p, "MacMapCnt: %d\n", i );
1361 	for ( i=0; user_macfeat_otftag[i].otf_tag!=0; ++i ) {
1362 	    fprintf( p, "MacMapping: %d,%d %c%c%c%c\n",
1363 		    user_macfeat_otftag[i].mac_feature_type,
1364 		    user_macfeat_otftag[i].mac_feature_setting,
1365 			(int) (user_macfeat_otftag[i].otf_tag>>24),
1366 			(int) ((user_macfeat_otftag[i].otf_tag>>16)&0xff),
1367 			(int) ((user_macfeat_otftag[i].otf_tag>>8)&0xff),
1368 			(int) (user_macfeat_otftag[i].otf_tag&0xff) );
1369 	}
1370     }
1371 
1372     if ( UserFeaturesDiffer())
1373 	SFDDumpMacFeat(p,default_mac_feature_map);
1374 
1375     fclose(p);
1376 }
1377 
1378 struct pref_data {
1379     int done;
1380     struct prefs_list* plist;
1381 };
1382 
Prefs_ScriptBrowse(GGadget * g,GEvent * e)1383 static int Prefs_ScriptBrowse(GGadget *g, GEvent *e) {
1384     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
1385 	GWindow gw = GGadgetGetWindow(g);
1386 	GGadget *tf = GWidgetGetControl(gw,GGadgetGetCid(g)-SCRIPT_MENU_MAX);
1387 	char *cur = GGadgetGetTitle8(tf); char *ret;
1388 
1389 	if ( *cur=='\0' ) cur=NULL;
1390 	ret = gwwv_open_filename(_("Call Script"), cur, "*.pe", NULL);
1391 	free(cur);
1392 	if ( ret==NULL )
1393 return(true);
1394 	GGadgetSetTitle8(tf,ret);
1395 	free(ret);
1396     }
1397 return( true );
1398 }
1399 
Prefs_BrowseFile(GGadget * g,GEvent * e)1400 static int Prefs_BrowseFile(GGadget *g, GEvent *e) {
1401     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
1402 	GWindow gw = GGadgetGetWindow(g);
1403 	GGadget *tf = GWidgetGetControl(gw,GGadgetGetCid(g)-CID_PrefsBrowseOffset);
1404 	char *cur = GGadgetGetTitle8(tf); char *ret;
1405 	struct prefs_list *pl = GGadgetGetUserData(tf);
1406 
1407 	ret = gwwv_open_filename(pl->name, *cur=='\0'? NULL : cur, NULL, NULL);
1408 	free(cur);
1409 	if ( ret==NULL )
1410 return(true);
1411 	GGadgetSetTitle8(tf,ret);
1412 	free(ret);
1413     }
1414 return( true );
1415 }
1416 
Pref_MappingList(int use_user)1417 static GTextInfo *Pref_MappingList(int use_user) {
1418     struct macsettingname *msn = use_user && user_macfeat_otftag!=NULL ?
1419 	    user_macfeat_otftag :
1420 	    macfeat_otftag;
1421     GTextInfo *ti;
1422     int i;
1423     char buf[60];
1424 
1425     for ( i=0; msn[i].otf_tag!=0; ++i );
1426     ti = calloc(i+1,sizeof( GTextInfo ));
1427 
1428     for ( i=0; msn[i].otf_tag!=0; ++i ) {
1429 	sprintf(buf,"%3d,%2d %c%c%c%c",
1430 	    msn[i].mac_feature_type, msn[i].mac_feature_setting,
1431 	    (int) (msn[i].otf_tag>>24), (int) ((msn[i].otf_tag>>16)&0xff), (int) ((msn[i].otf_tag>>8)&0xff), (int) (msn[i].otf_tag&0xff) );
1432 	ti[i].text = uc_copy(buf);
1433     }
1434 return( ti );
1435 }
1436 
GListAddStr(GGadget * list,unichar_t * str,void * ud)1437 void GListAddStr(GGadget *list,unichar_t *str, void *ud) {
1438     int32 i,len;
1439     GTextInfo **ti = GGadgetGetList(list,&len);
1440     GTextInfo **replace = malloc((len+2)*sizeof(GTextInfo *));
1441 
1442     replace[len+1] = calloc(1,sizeof(GTextInfo));
1443     for ( i=0; i<len; ++i ) {
1444 	replace[i] = malloc(sizeof(GTextInfo));
1445 	*replace[i] = *ti[i];
1446 	replace[i]->text = u_copy(ti[i]->text);
1447     }
1448     replace[i] = calloc(1,sizeof(GTextInfo));
1449     replace[i]->fg = replace[i]->bg = COLOR_DEFAULT;
1450     replace[i]->text = str;
1451     replace[i]->userdata = ud;
1452     GGadgetSetList(list,replace,false);
1453 }
1454 
GListReplaceStr(GGadget * list,int index,unichar_t * str,void * ud)1455 void GListReplaceStr(GGadget *list,int index, unichar_t *str, void *ud) {
1456     int32 i,len;
1457     GTextInfo **ti = GGadgetGetList(list,&len);
1458     GTextInfo **replace = malloc((len+2)*sizeof(GTextInfo *));
1459 
1460     for ( i=0; i<len; ++i ) {
1461 	replace[i] = malloc(sizeof(GTextInfo));
1462 	*replace[i] = *ti[i];
1463 	if ( i!=index )
1464 	    replace[i]->text = u_copy(ti[i]->text);
1465     }
1466     replace[i] = calloc(1,sizeof(GTextInfo));
1467     replace[index]->text = str;
1468     replace[index]->userdata = ud;
1469     GGadgetSetList(list,replace,false);
1470 }
1471 
1472 struct setdata {
1473     GWindow gw;
1474     GGadget *list;
1475     GGadget *flist;
1476     GGadget *feature;
1477     GGadget *set_code;
1478     GGadget *otf;
1479     GGadget *ok;
1480     GGadget *cancel;
1481     int index;
1482     int done;
1483     unichar_t *ret;
1484 };
1485 
set_e_h(GWindow gw,GEvent * event)1486 static int set_e_h(GWindow gw, GEvent *event) {
1487     struct setdata *sd = GDrawGetUserData(gw);
1488     int i;
1489     int32 len;
1490     GTextInfo **ti;
1491     const unichar_t *ret1; unichar_t *end;
1492     int on, feat, val1, val2;
1493     unichar_t ubuf[4];
1494     char buf[40];
1495 
1496     if ( event->type==et_close ) {
1497 	sd->done = true;
1498     } else if ( event->type==et_char ) {
1499 	if ( event->u.chr.keysym == GK_F1 || event->u.chr.keysym == GK_Help ) {
1500 	    help("ui/dialogs/prefs.html", "#prefs-features");
1501 return( true );
1502 	}
1503 return( false );
1504     } else if ( event->type==et_controlevent && event->u.control.subtype == et_buttonactivate ) {
1505 	if ( event->u.control.g == sd->cancel ) {
1506 	    sd->done = true;
1507 	} else if ( event->u.control.g == sd->ok ) {
1508 	    ret1 = _GGadgetGetTitle(sd->set_code);
1509 	    on = u_strtol(ret1,&end,10);
1510 	    if ( *end!='\0' ) {
1511 		ff_post_error(_("Bad Number"),_("Bad Number"));
1512 return( true );
1513 	    }
1514 	    ret1 = _GGadgetGetTitle(sd->feature);
1515 	    feat = u_strtol(ret1,&end,10);
1516 	    if ( *end!='\0' && *end!=' ' ) {
1517 		ff_post_error(_("Bad Number"),_("Bad Number"));
1518 return( true );
1519 	    }
1520 	    ti = GGadgetGetList(sd->list,&len);
1521 	    for ( i=0; i<len; ++i ) if ( i!=sd->index ) {
1522 		val1 = u_strtol(ti[i]->text,&end,10);
1523 		val2 = u_strtol(end+1,NULL,10);
1524 		if ( val1==feat && val2==on ) {
1525 		    static char *buts[3];
1526 		    buts[0] = _("_Yes");
1527 		    buts[1] = _("_No");
1528 		    buts[2] = NULL;
1529 		    if ( gwwv_ask(_("This feature, setting combination is already used"),(const char **) buts,0,1,
1530 			    _("This feature, setting combination is already used\nDo you really wish to reuse it?"))==1 )
1531 return( true );
1532 		}
1533 	    }
1534 
1535 	    ret1 = _GGadgetGetTitle(sd->otf);
1536 	    if ( (ubuf[0] = ret1[0])==0 )
1537 		ubuf[0] = ubuf[1] = ubuf[2] = ubuf[3] = ' ';
1538 	    else if ( (ubuf[1] = ret1[1])==0 )
1539 		ubuf[1] = ubuf[2] = ubuf[3] = ' ';
1540 	    else if ( (ubuf[2] = ret1[2])==0 )
1541 		ubuf[2] = ubuf[3] = ' ';
1542 	    else if ( (ubuf[3] = ret1[3])==0 )
1543 		ubuf[3] = ' ';
1544 	    len = u_strlen(ret1);
1545 	    if ( len<2 || len>4 || ubuf[0]>=0x7f || ubuf[1]>=0x7f || ubuf[2]>=0x7f || ubuf[3]>=0x7f ) {
1546 		ff_post_error(_("Tag too long"),_("Feature tags must be exactly 4 ASCII characters"));
1547 return( true );
1548 	    }
1549 	    sprintf(buf,"%3d,%2d %c%c%c%c",
1550 		    feat, on,
1551 		    ubuf[0], ubuf[1], ubuf[2], ubuf[3]);
1552 	    sd->done = true;
1553 	    sd->ret = uc_copy(buf);
1554 	}
1555     }
1556 return( true );
1557 }
1558 
AskSetting(struct macsettingname * temp,GGadget * list,int index,GGadget * flist)1559 static unichar_t *AskSetting(struct macsettingname *temp,GGadget *list, int index,GGadget *flist) {
1560     GRect pos;
1561     GWindow gw;
1562     GWindowAttrs wattrs;
1563     GGadgetCreateData gcd[17];
1564     GTextInfo label[17];
1565     struct setdata sd;
1566     char buf[20];
1567     unichar_t ubuf3[6];
1568     int32 len, i;
1569     GTextInfo **ti;
1570 
1571     memset(&sd,0,sizeof(sd));
1572     sd.list = list;
1573     sd.flist = flist;
1574     sd.index = index;
1575 
1576     memset(&wattrs,0,sizeof(wattrs));
1577     wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_restrict|wam_isdlg;
1578     wattrs.event_masks = ~(1<<et_charup);
1579     wattrs.restrict_input_to_me = 1;
1580     wattrs.is_dlg = 1;
1581     wattrs.undercursor = 1;
1582     wattrs.cursor = ct_pointer;
1583     wattrs.utf8_window_title = _("Mapping");
1584     pos.x = pos.y = 0;
1585     pos.width = GGadgetScale(GDrawPointsToPixels(NULL,240));
1586     pos.height = GDrawPointsToPixels(NULL,120);
1587     gw = GDrawCreateTopWindow(NULL,&pos,set_e_h,&sd,&wattrs);
1588     sd.gw = gw;
1589 
1590     memset(gcd,0,sizeof(gcd));
1591     memset(label,0,sizeof(label));
1592 
1593     label[0].text = (unichar_t *) _("_Feature:");
1594     label[0].text_is_1byte = true;
1595     label[0].text_in_resource = true;
1596     gcd[0].gd.label = &label[0];
1597     gcd[0].gd.pos.x = 5; gcd[0].gd.pos.y = 5+4;
1598     gcd[0].gd.flags = gg_enabled|gg_visible;
1599     gcd[0].creator = GLabelCreate;
1600 
1601     gcd[1].gd.pos.x = 50; gcd[1].gd.pos.y = 5; gcd[1].gd.pos.width = 170;
1602     gcd[1].gd.flags = gg_enabled|gg_visible;
1603     gcd[1].creator = GListButtonCreate;
1604 
1605     label[2].text = (unichar_t *) _("Setting");
1606     label[2].text_is_1byte = true;
1607     gcd[2].gd.label = &label[2];
1608     gcd[2].gd.pos.x = 5; gcd[2].gd.pos.y = gcd[0].gd.pos.y+26;
1609     gcd[2].gd.flags = gg_enabled|gg_visible;
1610     gcd[2].creator = GLabelCreate;
1611 
1612     sprintf( buf, "%d", temp->mac_feature_setting );
1613     label[3].text = (unichar_t *) buf;
1614     label[3].text_is_1byte = true;
1615     gcd[3].gd.label = &label[3];
1616     gcd[3].gd.pos.x = gcd[1].gd.pos.x; gcd[3].gd.pos.y = gcd[2].gd.pos.y-4; gcd[3].gd.pos.width = 50;
1617     gcd[3].gd.flags = gg_enabled|gg_visible;
1618     gcd[3].creator = GTextFieldCreate;
1619 
1620     label[4].text = (unichar_t *) _("_Tag:");
1621     label[4].text_is_1byte = true;
1622     label[4].text_in_resource = true;
1623     gcd[4].gd.label = &label[4];
1624     gcd[4].gd.pos.x = 5; gcd[4].gd.pos.y = gcd[3].gd.pos.y+26;
1625     gcd[4].gd.flags = gg_enabled|gg_visible;
1626     gcd[4].creator = GLabelCreate;
1627 
1628     ubuf3[0] = temp->otf_tag>>24; ubuf3[1] = (temp->otf_tag>>16)&0xff; ubuf3[2] = (temp->otf_tag>>8)&0xff; ubuf3[3] = temp->otf_tag&0xff; ubuf3[4] = 0;
1629     label[5].text = ubuf3;
1630     gcd[5].gd.label = &label[5];
1631     gcd[5].gd.pos.x = gcd[3].gd.pos.x; gcd[5].gd.pos.y = gcd[4].gd.pos.y-4; gcd[5].gd.pos.width = 50;
1632     gcd[5].gd.flags = gg_enabled|gg_visible;
1633     /*gcd[5].gd.u.list = tags;*/
1634     gcd[5].creator = GTextFieldCreate;
1635 
1636     gcd[6].gd.pos.x = 13-3; gcd[6].gd.pos.y = gcd[5].gd.pos.y+30;
1637     gcd[6].gd.pos.width = -1; gcd[6].gd.pos.height = 0;
1638     gcd[6].gd.flags = gg_visible | gg_enabled | gg_but_default;
1639     label[6].text = (unichar_t *) _("_OK");
1640     label[6].text_is_1byte = true;
1641     label[6].text_in_resource = true;
1642     gcd[6].gd.label = &label[6];
1643     /*gcd[6].gd.handle_controlevent = Prefs_Ok;*/
1644     gcd[6].creator = GButtonCreate;
1645 
1646     gcd[7].gd.pos.x = -13; gcd[7].gd.pos.y = gcd[7-1].gd.pos.y+3;
1647     gcd[7].gd.pos.width = -1; gcd[7].gd.pos.height = 0;
1648     gcd[7].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
1649     label[7].text = (unichar_t *) _("_Cancel");
1650     label[7].text_is_1byte = true;
1651     label[7].text_in_resource = true;
1652     gcd[7].gd.label = &label[7];
1653     gcd[7].creator = GButtonCreate;
1654 
1655     GGadgetsCreate(gw,gcd);
1656     sd.feature = gcd[1].ret;
1657     sd.set_code = gcd[3].ret;
1658     sd.otf = gcd[5].ret;
1659     sd.ok = gcd[6].ret;
1660     sd.cancel = gcd[7].ret;
1661 
1662     ti = GGadgetGetList(flist,&len);
1663     GGadgetSetList(sd.feature,ti,true);
1664     for ( i=0; i<len; ++i ) {
1665 	int val = u_strtol(ti[i]->text,NULL,10);
1666 	if ( val==temp->mac_feature_type ) {
1667 	    GGadgetSetTitle(sd.feature,ti[i]->text);
1668     break;
1669 	}
1670     }
1671 
1672     GDrawSetVisible(gw,true);
1673     GWidgetIndicateFocusGadget(gcd[1].ret);
1674     while ( !sd.done )
1675 	GDrawProcessOneEvent(NULL);
1676     GDrawDestroyWindow(gw);
1677 
1678 return( sd.ret );
1679 }
1680 
ChangeSetting(GGadget * list,int index,GGadget * flist)1681 static void ChangeSetting(GGadget *list,int index,GGadget *flist) {
1682     struct macsettingname temp;
1683     int32 len;
1684     GTextInfo **ti = GGadgetGetList(list,&len);
1685     char *str;
1686     unichar_t *ustr;
1687 
1688     str = cu_copy(ti[index]->text);
1689     ParseMacMapping(str,&temp);
1690     free(str);
1691     if ( (ustr=AskSetting(&temp,list,index,flist))==NULL )
1692 return;
1693     GListReplaceStr(list,index,ustr,NULL);
1694 }
1695 
Pref_NewMapping(GGadget * g,GEvent * e)1696 static int Pref_NewMapping(GGadget *g, GEvent *e) {
1697     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
1698 	GWindow gw = GGadgetGetWindow(g);
1699 	GGadget *list = GWidgetGetControl(gw,CID_Mapping);
1700 	GGadget *flist = GWidgetGetControl(GDrawGetParentWindow(gw),CID_Features);
1701 	struct macsettingname temp;
1702 	unichar_t *str;
1703 
1704 	memset(&temp,0,sizeof(temp));
1705 	temp.mac_feature_type = -1;
1706 	if ( (str=AskSetting(&temp,list,-1,flist))==NULL )
1707 return( true );
1708 	GListAddStr(list,str,NULL);
1709 	/*free(str);*/
1710     }
1711 return( true );
1712 }
1713 
Pref_DelMapping(GGadget * g,GEvent * e)1714 static int Pref_DelMapping(GGadget *g, GEvent *e) {
1715     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
1716 	GWindow gw = GGadgetGetWindow(g);
1717 	GListDelSelected(GWidgetGetControl(gw,CID_Mapping));
1718 	GGadgetSetEnabled(GWidgetGetControl(gw,CID_MappingDel),false);
1719 	GGadgetSetEnabled(GWidgetGetControl(gw,CID_MappingEdit),false);
1720     }
1721 return( true );
1722 }
1723 
Pref_EditMapping(GGadget * g,GEvent * e)1724 static int Pref_EditMapping(GGadget *g, GEvent *e) {
1725     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
1726 	GWindow gw = GDrawGetParentWindow(GGadgetGetWindow(g));
1727 	GGadget *list = GWidgetGetControl(gw,CID_Mapping);
1728 	GGadget *flist = GWidgetGetControl(gw,CID_Features);
1729 	ChangeSetting(list,GGadgetGetFirstListSelectedItem(list),flist);
1730     }
1731 return( true );
1732 }
1733 
Pref_MappingSel(GGadget * g,GEvent * e)1734 static int Pref_MappingSel(GGadget *g, GEvent *e) {
1735     if ( e->type==et_controlevent && e->u.control.subtype == et_listselected ) {
1736 	int32 len;
1737 	GTextInfo **ti = GGadgetGetList(g,&len);
1738 	GWindow gw = GGadgetGetWindow(g);
1739 	int i, sel_cnt=0;
1740 	for ( i=0; i<len; ++i )
1741 	    if ( ti[i]->selected ) ++sel_cnt;
1742 	GGadgetSetEnabled(GWidgetGetControl(gw,CID_MappingDel),sel_cnt!=0);
1743 	GGadgetSetEnabled(GWidgetGetControl(gw,CID_MappingEdit),sel_cnt==1);
1744     } else if ( e->type==et_controlevent && e->u.control.subtype == et_listdoubleclick ) {
1745 	GGadget *flist = GWidgetGetControl( GDrawGetParentWindow(GGadgetGetWindow(g)),CID_Features);
1746 	ChangeSetting(g,e->u.control.u.list.changed_index!=-1?e->u.control.u.list.changed_index:
1747 		GGadgetGetFirstListSelectedItem(g),flist);
1748     }
1749 return( true );
1750 }
1751 
Pref_DefaultMapping(GGadget * g,GEvent * e)1752 static int Pref_DefaultMapping(GGadget *g, GEvent *e) {
1753     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
1754 	GGadget *list = GWidgetGetControl(GGadgetGetWindow(g),CID_Mapping);
1755 	GTextInfo *ti, **arr;
1756 	uint16 cnt;
1757 
1758 	ti = Pref_MappingList(false);
1759 	arr = GTextInfoArrayFromList(ti,&cnt);
1760 	GGadgetSetList(list,arr,false);
1761 	GTextInfoListFree(ti);
1762     }
1763 return( true );
1764 }
1765 
Prefs_Ok(GGadget * g,GEvent * e)1766 static int Prefs_Ok(GGadget *g, GEvent *e) {
1767     int i, j, mi;
1768     int err=0, enc;
1769     struct pref_data *p;
1770     GWindow gw;
1771     const unichar_t *ret;
1772     const unichar_t *names[SCRIPT_MENU_MAX], *scripts[SCRIPT_MENU_MAX];
1773     struct prefs_list *pl;
1774     GTextInfo **list;
1775     int32 len;
1776     int maxl, t;
1777     char *str;
1778     real dangle;
1779 
1780     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
1781 	gw = GGadgetGetWindow(g);
1782 	p = GDrawGetUserData(gw);
1783 	for ( i=0; i<SCRIPT_MENU_MAX; ++i ) {
1784 	    names[i] = _GGadgetGetTitle(GWidgetGetControl(gw,CID_ScriptMNameBase+i));
1785 	    scripts[i] = _GGadgetGetTitle(GWidgetGetControl(gw,CID_ScriptMFileBase+i));
1786 	    if ( *names[i]=='\0' ) names[i] = NULL;
1787 	    if ( *scripts[i]=='\0' ) scripts[i] = NULL;
1788 	    if ( scripts[i]==NULL && names[i]!=NULL ) {
1789 		ff_post_error(_("Menu name with no associated script"),_("Menu name with no associated script"));
1790 return( true );
1791 	    } else if ( scripts[i]!=NULL && names[i]==NULL ) {
1792 		ff_post_error(_("Script with no associated menu name"),_("Script with no associated menu name"));
1793 return( true );
1794 	    }
1795 	}
1796 	for ( i=mi=0; i<SCRIPT_MENU_MAX; ++i ) {
1797 	    if ( names[i]!=NULL ) {
1798 		names[mi] = names[i];
1799 		scripts[mi] = scripts[i];
1800 		++mi;
1801 	    }
1802 	}
1803 	for ( j=0; visible_prefs_list[j].tab_name!=0; ++j ) for ( i=0; visible_prefs_list[j].pl[i].name!=NULL; ++i ) {
1804 	    pl = &visible_prefs_list[j].pl[i];
1805 	    /* before assigning values, check for any errors */
1806 	    /* if any errors, then NO values should be assigned, in case they cancel */
1807 	    if ( pl->dontdisplay )
1808 	continue;
1809 	    if ( pl->type==pr_int ) {
1810 		GetInt8(gw,j*CID_PrefsOffset+CID_PrefsBase+i,pl->name,&err);
1811 	    } else if ( pl->type==pr_real ) {
1812 		GetReal8(gw,j*CID_PrefsOffset+CID_PrefsBase+i,pl->name,&err);
1813 	    } else if ( pl->type==pr_angle ) {
1814 		dangle = GetReal8(gw,j*CID_PrefsOffset+CID_PrefsBase+i,pl->name,&err);
1815 		if ( dangle > 90 || dangle < 0 ) {
1816 		    GGadgetProtest8(pl->name);
1817 		    err = true;
1818 		}
1819 	    } else if ( pl->type==pr_unicode ) {
1820 		GetUnicodeChar8(gw,j*CID_PrefsOffset+CID_PrefsBase+i,pl->name,&err);
1821 	    }
1822 	}
1823 	if ( err )
1824 return( true );
1825 
1826 	for ( j=0; visible_prefs_list[j].tab_name!=0; ++j ) for ( i=0; visible_prefs_list[j].pl[i].name!=NULL; ++i ) {
1827 	    pl = &visible_prefs_list[j].pl[i];
1828 	    if ( pl->dontdisplay )
1829 	continue;
1830 	    switch( pl->type ) {
1831 	      case pr_int:
1832 	        *((int *) (pl->val)) = GetInt8(gw,j*CID_PrefsOffset+CID_PrefsBase+i,pl->name,&err);
1833 	      break;
1834 	      case pr_unicode:
1835 	        *((int *) (pl->val)) = GetUnicodeChar8(gw,j*CID_PrefsOffset+CID_PrefsBase+i,pl->name,&err);
1836 	      break;
1837 	      case pr_bool:
1838 	        *((int *) (pl->val)) = GGadgetIsChecked(GWidgetGetControl(gw,j*CID_PrefsOffset+CID_PrefsBase+i));
1839 	      break;
1840 	      case pr_real:
1841 	        *((float *) (pl->val)) = GetReal8(gw,j*CID_PrefsOffset+CID_PrefsBase+i,pl->name,&err);
1842 	      break;
1843 	      case pr_encoding:
1844 		{ Encoding *e;
1845 		    e = ParseEncodingNameFromList(GWidgetGetControl(gw,j*CID_PrefsOffset+CID_PrefsBase+i));
1846 		    if ( e!=NULL )
1847 			*((Encoding **) (pl->val)) = e;
1848 		    enc = 1;	/* So gcc doesn't complain about unused. It is unused, but why add the ifdef and make the code even messier? Sigh. icc complains anyway */
1849 		}
1850 	      break;
1851 	      case pr_namelist:
1852 		{ NameList *nl;
1853 		  GTextInfo *ti = GGadgetGetListItemSelected(GWidgetGetControl(gw,j*CID_PrefsOffset+CID_PrefsBase+i));
1854 		  if ( ti!=NULL ) {
1855 			char *name = u2utf8_copy(ti->text);
1856 			nl = NameListByName(name);
1857 			free(name);
1858 			if ( nl!=NULL && nl->uses_unicode && !allow_utf8_glyphnames)
1859 			    ff_post_error(_("Namelist contains non-ASCII names"),_("Glyph names should be limited to characters in the ASCII character set, but there are names in this namelist which use characters outside that range."));
1860 			else if ( nl!=NULL )
1861 			    *((NameList **) (pl->val)) = nl;
1862 		    }
1863 		}
1864 	      break;
1865 	      case pr_string: case pr_file:
1866 	        ret = _GGadgetGetTitle(GWidgetGetControl(gw,j*CID_PrefsOffset+CID_PrefsBase+i));
1867 		if ( pl->val!=NULL ) {
1868 		    free( *((char **) (pl->val)) );
1869 		    *((char **) (pl->val)) = NULL;
1870 		    if ( ret!=NULL && *ret!='\0' )
1871 			*((char **) (pl->val)) = /* u2def_*/ cu_copy(ret);
1872 		} else {
1873 		    char *cret = cu_copy(ret);
1874 		    (pl->set)(cret);
1875 		    free(cret);
1876 		}
1877 	      break;
1878 	      case pr_angle:
1879 	        *((float *) (pl->val)) = GetReal8(gw,j*CID_PrefsOffset+CID_PrefsBase+i,pl->name,&err)/RAD2DEG;
1880 	      break;
1881 	    }
1882 	}
1883 	for ( i=0; i<SCRIPT_MENU_MAX; ++i ) {
1884 	    free(script_menu_names[i]); script_menu_names[i] = NULL;
1885 	    free(script_filenames[i]); script_filenames[i] = NULL;
1886 	}
1887 	for ( i=0; i<mi; ++i ) {
1888 	    script_menu_names[i] = u_copy(names[i]);
1889 	    script_filenames[i] = u2def_copy(scripts[i]);
1890 	}
1891 
1892 	list = GGadgetGetList(GWidgetGetControl(gw,CID_Mapping),&len);
1893 	UserSettingsFree();
1894 	user_macfeat_otftag = malloc((len+1)*sizeof(struct macsettingname));
1895 	user_macfeat_otftag[len].otf_tag = 0;
1896 	maxl = 0;
1897 	for ( i=0; i<len; ++i ) {
1898 	    t = u_strlen(list[i]->text);
1899 	    if ( t>maxl ) maxl = t;
1900 	}
1901 	str = malloc(maxl+3);
1902 	for ( i=0; i<len; ++i ) {
1903 	    u2encoding_strncpy(str,list[i]->text,maxl+1,e_mac);
1904 	    ParseMacMapping(str,&user_macfeat_otftag[i]);
1905 	}
1906 	free(str);
1907 
1908 	Prefs_ReplaceMacFeatures(GWidgetGetControl(gw,CID_Features));
1909 
1910 	if ( xuid!=NULL ) {
1911 	    char *pt;
1912 	    for ( pt=xuid; *pt==' ' ; ++pt );
1913 	    if ( *pt=='[' ) {	/* People who know PS well, might want to put brackets arround the xuid base array, but I don't want them */
1914 		pt = copy(pt+1);
1915 		if (xuid != NULL) free( xuid );
1916 		xuid = pt;
1917 	    }
1918 	    for ( pt=xuid+strlen(xuid)-1; pt>xuid && *pt==' '; --pt );
1919 	    if ( pt >= xuid && *pt==']' ) *pt = '\0';
1920 	}
1921 
1922 	p->done = true;
1923 	PrefsUI_SavePrefs(true);
1924 	if ( maxundoes==0 ) { FontView *fv;
1925 	    for ( fv=fv_list ; fv!=NULL; fv=(FontView *) (fv->b.next) )
1926 		SFRemoveUndoes(fv->b.sf,NULL,NULL);
1927 	}
1928 	if ( othersubrsfile!=NULL && ReadOtherSubrsFile(othersubrsfile)<=0 )
1929 	    fprintf( stderr, "Failed to read OtherSubrs from %s\n", othersubrsfile );
1930 	GDrawEnableCairo(prefs_usecairo);
1931 
1932 	int force_redraw_charviews = 0;
1933 	if( prefs_oldval_cvEditHandleSize != prefs_cvEditHandleSize )
1934 	    force_redraw_charviews = 1;
1935 	if( prefs_oldval_cvInactiveHandleAlpha != prefs_cvInactiveHandleAlpha )
1936 	    force_redraw_charviews = 1;
1937 
1938 
1939 	if( force_redraw_charviews )
1940 	{
1941 	    FontView *fv;
1942 	    for ( fv=fv_list ; fv!=NULL; fv=(FontView *) (fv->b.next) )
1943 	    {
1944 		FVRedrawAllCharViews( fv );
1945 	    }
1946 	}
1947     }
1948 return( true );
1949 }
1950 
Prefs_Cancel(GGadget * g,GEvent * e)1951 static int Prefs_Cancel(GGadget *g, GEvent *e) {
1952     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
1953 	struct pref_data *p = GDrawGetUserData(GGadgetGetWindow(g));
1954 	MacFeatListFree(GGadgetGetUserData((GWidgetGetControl(
1955 		GGadgetGetWindow(g),CID_Features))));
1956 	p->done = true;
1957     }
1958 return( true );
1959 }
1960 
e_h(GWindow gw,GEvent * event)1961 static int e_h(GWindow gw, GEvent *event) {
1962     if ( event->type==et_close ) {
1963 	struct pref_data *p = GDrawGetUserData(gw);
1964 	p->done = true;
1965 	if(GWidgetGetControl(gw,CID_Features)) {
1966 	    MacFeatListFree(GGadgetGetUserData((GWidgetGetControl(gw,CID_Features))));
1967 	}
1968     } else if ( event->type==et_char ) {
1969 	if ( event->u.chr.keysym == GK_F1 || event->u.chr.keysym == GK_Help ) {
1970 	    help("ui/dialogs/prefs.html", NULL);
1971 return( true );
1972 	}
1973 return( false );
1974     }
1975 return( true );
1976 }
1977 
PrefsInit(void)1978 static void PrefsInit(void) {
1979     static int done = false;
1980     int i;
1981 
1982     if ( done )
1983 return;
1984     done = true;
1985     for ( i=0; visible_prefs_list[i].tab_name!=NULL; ++i )
1986 	visible_prefs_list[i].tab_name = _(visible_prefs_list[i].tab_name);
1987 }
1988 
DoPrefs(void)1989 void DoPrefs(void) {
1990     GRect pos;
1991     GWindow gw;
1992     GWindowAttrs wattrs;
1993     GGadgetCreateData *pgcd, gcd[5], sgcd[45], mgcd[3], mfgcd[9], msgcd[9];
1994     GGadgetCreateData mfboxes[3], *mfarray[14];
1995     GGadgetCreateData mpboxes[3], *mparray[14];
1996     GGadgetCreateData sboxes[2], *sarray[50];
1997     GGadgetCreateData mboxes[3], *varray[5], *harray[8];
1998     GTextInfo *plabel, **list, label[5], slabel[45], *plabels[TOPICS+5], mflabels[9], mslabels[9];
1999     GTabInfo aspects[TOPICS+5], subaspects[3];
2000     GGadgetCreateData **hvarray, boxes[2*TOPICS];
2001     struct pref_data p;
2002     int i, gc, sgc, j, k, line, line_max, y, y2, ii, si;
2003     int32 llen;
2004     char buf[20];
2005     int gcnt[20];
2006     static unichar_t nullstr[] = { 0 };
2007     struct prefs_list *pl;
2008     char *tempstr;
2009     FontRequest rq;
2010     GFont *font;
2011 
2012     PrefsInit();
2013 
2014     MfArgsInit();
2015     for ( k=line_max=0; visible_prefs_list[k].tab_name!=0; ++k ) {
2016 	for ( i=line=gcnt[k]=0; visible_prefs_list[k].pl[i].name!=NULL; ++i ) {
2017 	    if ( visible_prefs_list[k].pl[i].dontdisplay )
2018 	continue;
2019 	    gcnt[k] += 2;
2020 	    if ( visible_prefs_list[k].pl[i].type==pr_bool ) ++gcnt[k];
2021 	    else if ( visible_prefs_list[k].pl[i].type==pr_file ) ++gcnt[k];
2022 	    else if ( visible_prefs_list[k].pl[i].type==pr_angle ) ++gcnt[k];
2023 	    ++line;
2024 	}
2025 	if ( visible_prefs_list[k].pl == args_list ) {
2026 	    gcnt[k] += 6;
2027 	    line += 6;
2028 	}
2029 	if ( line>line_max ) line_max = line;
2030     }
2031 
2032     prefs_oldval_cvEditHandleSize = prefs_cvEditHandleSize;
2033     prefs_oldval_cvInactiveHandleAlpha = prefs_cvInactiveHandleAlpha;
2034 
2035     memset(&p,'\0',sizeof(p));
2036     memset(&wattrs,0,sizeof(wattrs));
2037     wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_restrict|wam_isdlg;
2038     wattrs.event_masks = ~(1<<et_charup);
2039     wattrs.restrict_input_to_me = 1;
2040     wattrs.is_dlg = 1;
2041     wattrs.undercursor = 1;
2042     wattrs.cursor = ct_pointer;
2043     wattrs.utf8_window_title = _("Preferences");
2044     pos.x = pos.y = 0;
2045     pos.width = GGadgetScale(GDrawPointsToPixels(NULL,350));
2046     pos.height = GDrawPointsToPixels(NULL,line_max*26+69);
2047     gw = GDrawCreateTopWindow(NULL,&pos,e_h,&p,&wattrs);
2048 
2049     memset(sgcd,0,sizeof(sgcd));
2050     memset(slabel,0,sizeof(slabel));
2051     memset(&mfgcd,0,sizeof(mfgcd));
2052     memset(&msgcd,0,sizeof(msgcd));
2053     memset(&mflabels,0,sizeof(mflabels));
2054     memset(&mslabels,0,sizeof(mslabels));
2055     memset(&mfboxes,0,sizeof(mfboxes));
2056     memset(&mpboxes,0,sizeof(mpboxes));
2057     memset(&sboxes,0,sizeof(sboxes));
2058     memset(&boxes,0,sizeof(boxes));
2059 
2060     GCDFillMacFeat(mfgcd,mflabels,250,default_mac_feature_map, true, mfboxes, mfarray);
2061 
2062     sgc = 0;
2063 
2064     msgcd[sgc].gd.pos.x = 6; msgcd[sgc].gd.pos.y = 6;
2065     msgcd[sgc].gd.pos.width = 250; msgcd[sgc].gd.pos.height = 16*12+10;
2066     msgcd[sgc].gd.flags = gg_visible | gg_enabled | gg_list_alphabetic | gg_list_multiplesel;
2067     msgcd[sgc].gd.cid = CID_Mapping;
2068     msgcd[sgc].gd.u.list = Pref_MappingList(true);
2069     msgcd[sgc].gd.handle_controlevent = Pref_MappingSel;
2070     msgcd[sgc++].creator = GListCreate;
2071     mparray[0] = &msgcd[sgc-1];
2072 
2073     msgcd[sgc].gd.pos.x = 6; msgcd[sgc].gd.pos.y = msgcd[sgc-1].gd.pos.y+msgcd[sgc-1].gd.pos.height+10;
2074     msgcd[sgc].gd.flags = gg_visible | gg_enabled;
2075     mslabels[sgc].text = (unichar_t *) S_("MacMap|_New...");
2076     mslabels[sgc].text_is_1byte = true;
2077     mslabels[sgc].text_in_resource = true;
2078     msgcd[sgc].gd.label = &mslabels[sgc];
2079     msgcd[sgc].gd.handle_controlevent = Pref_NewMapping;
2080     msgcd[sgc++].creator = GButtonCreate;
2081     mparray[4] = GCD_Glue; mparray[5] = &msgcd[sgc-1];
2082 
2083     msgcd[sgc].gd.pos.x = msgcd[sgc-1].gd.pos.x+10+GIntGetResource(_NUM_Buttonsize)*100/GIntGetResource(_NUM_ScaleFactor);
2084     msgcd[sgc].gd.pos.y = msgcd[sgc-1].gd.pos.y;
2085     msgcd[sgc].gd.flags = gg_visible ;
2086     mslabels[sgc].text = (unichar_t *) _("_Delete");
2087     mslabels[sgc].text_is_1byte = true;
2088     mslabels[sgc].text_in_resource = true;
2089     msgcd[sgc].gd.label = &mslabels[sgc];
2090     msgcd[sgc].gd.cid = CID_MappingDel;
2091     msgcd[sgc].gd.handle_controlevent = Pref_DelMapping;
2092     msgcd[sgc++].creator = GButtonCreate;
2093     mparray[5] = GCD_Glue; mparray[6] = &msgcd[sgc-1];
2094 
2095     msgcd[sgc].gd.pos.x = msgcd[sgc-1].gd.pos.x+10+GIntGetResource(_NUM_Buttonsize)*100/GIntGetResource(_NUM_ScaleFactor);
2096     msgcd[sgc].gd.pos.y = msgcd[sgc-1].gd.pos.y;
2097     msgcd[sgc].gd.flags = gg_visible ;
2098     mslabels[sgc].text = (unichar_t *) _("_Edit...");
2099     mslabels[sgc].text_is_1byte = true;
2100     mslabels[sgc].text_in_resource = true;
2101     msgcd[sgc].gd.label = &mslabels[sgc];
2102     msgcd[sgc].gd.cid = CID_MappingEdit;
2103     msgcd[sgc].gd.handle_controlevent = Pref_EditMapping;
2104     msgcd[sgc++].creator = GButtonCreate;
2105     mparray[7] = GCD_Glue; mparray[8] = &msgcd[sgc-1];
2106 
2107     msgcd[sgc].gd.pos.x = msgcd[sgc-1].gd.pos.x+10+GIntGetResource(_NUM_Buttonsize)*100/GIntGetResource(_NUM_ScaleFactor);
2108     msgcd[sgc].gd.pos.y = msgcd[sgc-1].gd.pos.y;
2109     msgcd[sgc].gd.flags = gg_visible | gg_enabled;
2110     mslabels[sgc].text = (unichar_t *) S_("MacMapping|Default");
2111     mslabels[sgc].text_is_1byte = true;
2112     mslabels[sgc].text_in_resource = true;
2113     msgcd[sgc].gd.label = &mslabels[sgc];
2114     msgcd[sgc].gd.handle_controlevent = Pref_DefaultMapping;
2115     msgcd[sgc++].creator = GButtonCreate;
2116     mparray[9] = GCD_Glue; mparray[10] = &msgcd[sgc-1];
2117     mparray[11] = GCD_Glue; mparray[12] = NULL;
2118 
2119     mpboxes[2].gd.flags = gg_enabled|gg_visible;
2120     mpboxes[2].gd.u.boxelements = mparray+4;
2121     mpboxes[2].creator = GHBoxCreate;
2122     mparray[1] = GCD_Glue;
2123     mparray[2] = &mpboxes[2];
2124     mparray[3] = NULL;
2125 
2126     mpboxes[0].gd.flags = gg_enabled|gg_visible;
2127     mpboxes[0].gd.u.boxelements = mparray;
2128     mpboxes[0].creator = GVBoxCreate;
2129 
2130     sgc = 0;
2131     y2=5;
2132     si = 0;
2133 
2134     slabel[sgc].text = (unichar_t *) _("Menu Name");
2135     slabel[sgc].text_is_1byte = true;
2136     sgcd[sgc].gd.label = &slabel[sgc];
2137     sgcd[sgc].gd.popup_msg = _("You may create a script menu containing up to 10 frequently used scripts.\nEach entry in the menu needs both a name to display in the menu and\na script file to execute. The menu name may contain any unicode characters.\nThe button labeled \"...\" will allow you to browse for a script file.");
2138     sgcd[sgc].gd.pos.x = 8;
2139     sgcd[sgc].gd.pos.y = y2;
2140     sgcd[sgc].gd.flags = gg_visible | gg_enabled;
2141     sgcd[sgc++].creator = GLabelCreate;
2142     sarray[si++] = &sgcd[sgc-1];
2143 
2144     slabel[sgc].text = (unichar_t *) _("Script File");
2145     slabel[sgc].text_is_1byte = true;
2146     sgcd[sgc].gd.label = &slabel[sgc];
2147     sgcd[sgc].gd.popup_msg = _("You may create a script menu containing up to 10 frequently used scripts\nEach entry in the menu needs both a name to display in the menu and\na script file to execute. The menu name may contain any unicode characters.\nThe button labeled \"...\" will allow you to browse for a script file.");
2148     sgcd[sgc].gd.pos.x = 110;
2149     sgcd[sgc].gd.pos.y = y2;
2150     sgcd[sgc].gd.flags = gg_visible | gg_enabled;
2151     sgcd[sgc++].creator = GLabelCreate;
2152     sarray[si++] = &sgcd[sgc-1];
2153     sarray[si++] = GCD_Glue;
2154     sarray[si++] = NULL;
2155 
2156     y2 += 14;
2157 
2158     for ( i=0; i<SCRIPT_MENU_MAX; ++i ) {
2159 	sgcd[sgc].gd.pos.x = 8; sgcd[sgc].gd.pos.y = y2;
2160 	sgcd[sgc].gd.flags = gg_visible | gg_enabled | gg_text_xim;
2161 	slabel[sgc].text = script_menu_names[i]==NULL?nullstr:script_menu_names[i];
2162 	sgcd[sgc].gd.label = &slabel[sgc];
2163 	sgcd[sgc].gd.cid = i+CID_ScriptMNameBase;
2164 	sgcd[sgc++].creator = GTextFieldCreate;
2165 	sarray[si++] = &sgcd[sgc-1];
2166 
2167 	sgcd[sgc].gd.pos.x = 110; sgcd[sgc].gd.pos.y = y2;
2168 	sgcd[sgc].gd.flags = gg_visible | gg_enabled;
2169 	slabel[sgc].text = (unichar_t *) (script_filenames[i]==NULL?"":script_filenames[i]);
2170 	slabel[sgc].text_is_1byte = true;
2171 	sgcd[sgc].gd.label = &slabel[sgc];
2172 	sgcd[sgc].gd.cid = i+CID_ScriptMFileBase;
2173 	sgcd[sgc++].creator = GTextFieldCreate;
2174 	sarray[si++] = &sgcd[sgc-1];
2175 
2176 	sgcd[sgc].gd.pos.x = 210; sgcd[sgc].gd.pos.y = y2;
2177 	sgcd[sgc].gd.flags = gg_visible | gg_enabled;
2178 	slabel[sgc].text = (unichar_t *) _("...");
2179 	slabel[sgc].text_is_1byte = true;
2180 	sgcd[sgc].gd.label = &slabel[sgc];
2181 	sgcd[sgc].gd.cid = i+CID_ScriptMBrowseBase;
2182 	sgcd[sgc].gd.handle_controlevent = Prefs_ScriptBrowse;
2183 	sgcd[sgc++].creator = GButtonCreate;
2184 	sarray[si++] = &sgcd[sgc-1];
2185 	sarray[si++] = NULL;
2186 
2187 	y2 += 26;
2188     }
2189     sarray[si++] = GCD_Glue; sarray[si++] = GCD_Glue; sarray[si++] = GCD_Glue;
2190     sarray[si++] = NULL;
2191     sarray[si++] = NULL;
2192 
2193     sboxes[0].gd.flags = gg_enabled|gg_visible;
2194     sboxes[0].gd.u.boxelements = sarray;
2195     sboxes[0].creator = GHVBoxCreate;
2196 
2197     memset(&mgcd,0,sizeof(mgcd));
2198     memset(&mgcd,0,sizeof(mgcd));
2199     memset(&subaspects,'\0',sizeof(subaspects));
2200     memset(&label,0,sizeof(label));
2201     memset(&gcd,0,sizeof(gcd));
2202     memset(&aspects,'\0',sizeof(aspects));
2203     aspects[0].selected = true;
2204 
2205     for ( k=0; visible_prefs_list[k].tab_name!=0; ++k ) {
2206 	pgcd = calloc(gcnt[k]+4,sizeof(GGadgetCreateData));
2207 	plabel = calloc(gcnt[k]+4,sizeof(GTextInfo));
2208 	hvarray = calloc((gcnt[k]+6)*5+2,sizeof(GGadgetCreateData *));
2209 
2210 	aspects[k].text = (unichar_t *) visible_prefs_list[k].tab_name;
2211 	aspects[k].text_is_1byte = true;
2212 	aspects[k].gcd = &boxes[2*k];
2213 	aspects[k].nesting = visible_prefs_list[k].nest;
2214 	plabels[k] = plabel;
2215 
2216 	gc = si = 0;
2217 	for ( i=line=0, y=5; visible_prefs_list[k].pl[i].name!=NULL; ++i ) {
2218 	    pl = &visible_prefs_list[k].pl[i];
2219 	    if ( pl->dontdisplay )
2220 	continue;
2221 	    plabel[gc].text = (unichar_t *) _(pl->name);
2222 	    plabel[gc].text_is_1byte = true;
2223 	    pgcd[gc].gd.label = &plabel[gc];
2224 	    pgcd[gc].gd.mnemonic = '\0';
2225 	    pgcd[gc].gd.popup_msg = _(pl->popup);
2226 	    pgcd[gc].gd.pos.x = 8;
2227 	    pgcd[gc].gd.pos.y = y + 6;
2228 	    pgcd[gc].gd.flags = gg_visible | gg_enabled;
2229 	    pgcd[gc++].creator = GLabelCreate;
2230 	    hvarray[si++] = &pgcd[gc-1];
2231 
2232 	    plabel[gc].text_is_1byte = true;
2233 	    pgcd[gc].gd.label = &plabel[gc];
2234 	    pgcd[gc].gd.mnemonic = '\0';
2235 	    pgcd[gc].gd.popup_msg = _(pl->popup);
2236 	    pgcd[gc].gd.pos.x = 110;
2237 	    pgcd[gc].gd.pos.y = y;
2238 	    pgcd[gc].gd.flags = gg_visible | gg_enabled;
2239 	    pgcd[gc].data = pl;
2240 	    pgcd[gc].gd.cid = k*CID_PrefsOffset+CID_PrefsBase+i;
2241 	    switch ( pl->type ) {
2242 	      case pr_bool:
2243 		plabel[gc].text = (unichar_t *) _("On");
2244 		pgcd[gc].gd.pos.y += 3;
2245 		pgcd[gc++].creator = GRadioCreate;
2246 		hvarray[si++] = &pgcd[gc-1];
2247 		pgcd[gc] = pgcd[gc-1];
2248 		pgcd[gc].gd.pos.x += 50;
2249 		pgcd[gc].gd.cid = 0;
2250 		pgcd[gc].gd.label = &plabel[gc];
2251 		plabel[gc].text = (unichar_t *) _("Off");
2252 		plabel[gc].text_is_1byte = true;
2253 		hvarray[si++] = &pgcd[gc];
2254 		hvarray[si++] = GCD_Glue;
2255 		if ( *((int *) pl->val))
2256 		    pgcd[gc-1].gd.flags |= gg_cb_on;
2257 		else
2258 		    pgcd[gc].gd.flags |= gg_cb_on;
2259 		++gc;
2260 		y += 22;
2261 	      break;
2262 	      case pr_int:
2263 		sprintf(buf,"%d", *((int *) pl->val));
2264 		plabel[gc].text = (unichar_t *) copy( buf );
2265 		pgcd[gc++].creator = GTextFieldCreate;
2266 		hvarray[si++] = &pgcd[gc-1];
2267 		hvarray[si++] = GCD_Glue; hvarray[si++] = GCD_Glue;
2268 		y += 26;
2269 	      break;
2270 	      case pr_unicode:
2271 		/*sprintf(buf,"U+%04x", *((int *) pl->val));*/
2272 		{ char *pt; pt=buf; pt=utf8_idpb(pt,*((int *)pl->val),UTF8IDPB_NOZERO); *pt='\0'; }
2273 		plabel[gc].text = (unichar_t *) copy( buf );
2274 		pgcd[gc++].creator = GTextFieldCreate;
2275 		hvarray[si++] = &pgcd[gc-1];
2276 		hvarray[si++] = GCD_Glue; hvarray[si++] = GCD_Glue;
2277 		y += 26;
2278 	      break;
2279 	      case pr_real:
2280 		sprintf(buf,"%g", *((float *) pl->val));
2281 		plabel[gc].text = (unichar_t *) copy( buf );
2282 		pgcd[gc++].creator = GTextFieldCreate;
2283 		hvarray[si++] = &pgcd[gc-1];
2284 		hvarray[si++] = GCD_Glue; hvarray[si++] = GCD_Glue;
2285 		y += 26;
2286 	      break;
2287 	      case pr_encoding:
2288 		pgcd[gc].gd.u.list = GetEncodingTypes();
2289 		pgcd[gc].gd.label = EncodingTypesFindEnc(pgcd[gc].gd.u.list,
2290 			*(Encoding **) pl->val);
2291 		for ( ii=0; pgcd[gc].gd.u.list[ii].text!=NULL ||pgcd[gc].gd.u.list[ii].line; ++ii )
2292 		    if ( pgcd[gc].gd.u.list[ii].userdata!=NULL &&
2293 			    (strcmp(pgcd[gc].gd.u.list[ii].userdata,"Compacted")==0 ||
2294 			     strcmp(pgcd[gc].gd.u.list[ii].userdata,"Original")==0 ))
2295 			pgcd[gc].gd.u.list[ii].disabled = true;
2296 		pgcd[gc].creator = GListFieldCreate;
2297 		pgcd[gc].gd.pos.width = 160;
2298 		if ( pgcd[gc].gd.label==NULL ) pgcd[gc].gd.label = &encodingtypes[0];
2299 		++gc;
2300 		hvarray[si++] = &pgcd[gc-1];
2301 		hvarray[si++] = GCD_ColSpan; hvarray[si++] = GCD_ColSpan;
2302 		y += 28;
2303 	      break;
2304 	      case pr_namelist:
2305 	        { char **nlnames = AllNamelistNames();
2306 		int cnt;
2307 		GTextInfo *namelistnames;
2308 		for ( cnt=0; nlnames[cnt]!=NULL; ++cnt);
2309 		namelistnames = calloc(cnt+1,sizeof(GTextInfo));
2310 		for ( cnt=0; nlnames[cnt]!=NULL; ++cnt) {
2311 		    namelistnames[cnt].text = (unichar_t *) nlnames[cnt];
2312 		    namelistnames[cnt].text_is_1byte = true;
2313 		    if ( strcmp(_((*(NameList **) (pl->val))->title),nlnames[cnt])==0 ) {
2314 			namelistnames[cnt].selected = true;
2315 			pgcd[gc].gd.label = &namelistnames[cnt];
2316 		    }
2317 		}
2318 		pgcd[gc].gd.u.list = namelistnames;
2319 		pgcd[gc].creator = GListButtonCreate;
2320 		pgcd[gc].gd.pos.width = 160;
2321 		++gc;
2322 		hvarray[si++] = &pgcd[gc-1];
2323 		hvarray[si++] = GCD_ColSpan; hvarray[si++] = GCD_ColSpan;
2324 		y += 28;
2325 	      } break;
2326 	      case pr_string: case pr_file:
2327 		if ( pl->set==SetAutoTraceArgs || ((char **) pl->val)==&mf_args )
2328 		    pgcd[gc].gd.pos.width = 160;
2329 		if ( pl->val!=NULL )
2330 		    tempstr = *((char **) (pl->val));
2331 		else
2332 		    tempstr = (char *) ((pl->get)());
2333 		if ( tempstr!=NULL )
2334 		    plabel[gc].text = /* def2u_*/ uc_copy( tempstr );
2335 		else if ( ((char **) pl->val)==&BDFFoundry )
2336 		    plabel[gc].text = /* def2u_*/ uc_copy( "FontForge" );
2337 		else
2338 		    plabel[gc].text = /* def2u_*/ uc_copy( "" );
2339 		plabel[gc].text_is_1byte = false;
2340 		pgcd[gc++].creator = GTextFieldCreate;
2341 		hvarray[si++] = &pgcd[gc-1];
2342 		if ( pl->type==pr_file ) {
2343 		    pgcd[gc] = pgcd[gc-1];
2344 		    pgcd[gc-1].gd.pos.width = 140;
2345 		    hvarray[si++] = GCD_ColSpan;
2346 		    pgcd[gc].gd.pos.x += 145;
2347 		    pgcd[gc].gd.cid += CID_PrefsBrowseOffset;
2348 		    pgcd[gc].gd.label = &plabel[gc];
2349 		    plabel[gc].text = (unichar_t *) "...";
2350 		    plabel[gc].text_is_1byte = true;
2351 		    pgcd[gc].gd.handle_controlevent = Prefs_BrowseFile;
2352 		    pgcd[gc++].creator = GButtonCreate;
2353 		    hvarray[si++] = &pgcd[gc-1];
2354 		} else if ( pl->set==SetAutoTraceArgs || ((char **) pl->val)==&mf_args ) {
2355 		    hvarray[si++] = GCD_ColSpan;
2356 		    hvarray[si++] = GCD_Glue;
2357 		} else {
2358 		    hvarray[si++] = GCD_Glue;
2359 		    hvarray[si++] = GCD_Glue;
2360 		}
2361 		y += 26;
2362 		if ( pl->val==NULL )
2363 		    free(tempstr);
2364 	      break;
2365 	      case pr_angle:
2366 		sprintf(buf,"%g", *((float *) pl->val) * RAD2DEG);
2367 		plabel[gc].text = (unichar_t *) copy( buf );
2368 		pgcd[gc++].creator = GTextFieldCreate;
2369 		hvarray[si++] = &pgcd[gc-1];
2370 		plabel[gc].text = (unichar_t *) U_("°");
2371 		plabel[gc].text_is_1byte = true;
2372 		pgcd[gc].gd.label = &plabel[gc];
2373 		pgcd[gc].gd.pos.x = pgcd[gc-1].gd.pos.x+gcd[gc-1].gd.pos.width+2; pgcd[gc].gd.pos.y = pgcd[gc-1].gd.pos.y;
2374 		pgcd[gc].gd.flags = gg_enabled|gg_visible;
2375 		pgcd[gc++].creator = GLabelCreate;
2376 		hvarray[si++] = &pgcd[gc-1];
2377 		hvarray[si++] = GCD_Glue;
2378 		y += 26;
2379 	      break;
2380 	    }
2381 	    ++line;
2382 	    hvarray[si++] = NULL;
2383 	}
2384 	if ( visible_prefs_list[k].pl == args_list ) {
2385 	    static char *text[] = {
2386 /* GT: See the long comment at "Property|New" */
2387 /* GT: This and the next few strings show a limitation of my widget set which */
2388 /* GT: cannot handle multi-line text labels. These strings should be concatenated */
2389 /* GT: (after striping off "Prefs_App|") together, translated, and then broken up */
2390 /* GT: to fit the dialog. There is an extra blank line, not used in English, */
2391 /* GT: into which your text may extend if needed. */
2392 		N_("Prefs_App|Normally FontForge will find applications by searching for"),
2393 		N_("Prefs_App|them in your PATH environment variable, if you want"),
2394 		N_("Prefs_App|to alter that behavior you may set an environment"),
2395 		N_("Prefs_App|variable giving the full path spec of the application."),
2396 		N_("Prefs_App|FontForge recognizes BROWSER, MF and AUTOTRACE."),
2397 		N_("Prefs_App| "), /* A blank line */
2398 		NULL };
2399 	    y += 8;
2400 	    for ( i=0; text[i]!=0; ++i ) {
2401 		plabel[gc].text = (unichar_t *) S_(text[i]);
2402 		plabel[gc].text_is_1byte = true;
2403 		pgcd[gc].gd.label = &plabel[gc];
2404 		pgcd[gc].gd.pos.x = 8;
2405 		pgcd[gc].gd.pos.y = y;
2406 		pgcd[gc].gd.flags = gg_visible | gg_enabled;
2407 		pgcd[gc++].creator = GLabelCreate;
2408 		hvarray[si++] = &pgcd[gc-1];
2409 		hvarray[si++] = GCD_ColSpan; hvarray[si++] = GCD_ColSpan;
2410 		hvarray[si++] = NULL;
2411 		y += 12;
2412 	    }
2413 	}
2414 	if ( y>y2 ) y2 = y;
2415 	hvarray[si++] = GCD_Glue; hvarray[si++] = GCD_Glue;
2416 	hvarray[si++] = GCD_Glue; hvarray[si++] = GCD_Glue;
2417 	hvarray[si++] = NULL;
2418 	hvarray[si++] = NULL;
2419 	boxes[2*k].gd.flags = gg_enabled|gg_visible;
2420 	boxes[2*k].gd.u.boxelements = hvarray;
2421 	boxes[2*k].creator = GHVBoxCreate;
2422     }
2423 
2424     aspects[k].text = (unichar_t *) _("Script Menu");
2425     aspects[k].text_is_1byte = true;
2426     aspects[k++].gcd = sboxes;
2427 
2428     subaspects[0].text = (unichar_t *) _("Features");
2429     subaspects[0].text_is_1byte = true;
2430     subaspects[0].gcd = mfboxes;
2431 
2432     subaspects[1].text = (unichar_t *) _("Mapping");
2433     subaspects[1].text_is_1byte = true;
2434     subaspects[1].gcd = mpboxes;
2435 
2436     mgcd[0].gd.pos.x = 4; gcd[0].gd.pos.y = 6;
2437     mgcd[0].gd.pos.width = GDrawPixelsToPoints(NULL,pos.width)-20;
2438     mgcd[0].gd.pos.height = y2;
2439     mgcd[0].gd.u.tabs = subaspects;
2440     mgcd[0].gd.flags = gg_visible | gg_enabled;
2441     mgcd[0].creator = GTabSetCreate;
2442 
2443     aspects[k].text = (unichar_t *) _("Mac");
2444     aspects[k].text_is_1byte = true;
2445     aspects[k++].gcd = mgcd;
2446 
2447     gc = 0;
2448 
2449     gcd[gc].gd.pos.x = gcd[gc].gd.pos.y = 2;
2450     gcd[gc].gd.pos.width = pos.width-4; gcd[gc].gd.pos.height = pos.height-2;
2451     gcd[gc].gd.flags = gg_enabled | gg_visible | gg_pos_in_pixels;
2452     gcd[gc++].creator = GGroupCreate;
2453 
2454     gcd[gc].gd.pos.x = 4; gcd[gc].gd.pos.y = 6;
2455     gcd[gc].gd.pos.width = GDrawPixelsToPoints(NULL,pos.width)-8;
2456     gcd[gc].gd.pos.height = y2+20+18+4;
2457     gcd[gc].gd.u.tabs = aspects;
2458     gcd[gc].gd.flags = gg_visible | gg_enabled | gg_tabset_vert;
2459     gcd[gc++].creator = GTabSetCreate;
2460     varray[0] = &gcd[gc-1]; varray[1] = NULL;
2461 
2462     y = gcd[gc-1].gd.pos.y+gcd[gc-1].gd.pos.height;
2463 
2464     gcd[gc].gd.pos.x = 30-3; gcd[gc].gd.pos.y = y+5-3;
2465     gcd[gc].gd.pos.width = -1; gcd[gc].gd.pos.height = 0;
2466     gcd[gc].gd.flags = gg_visible | gg_enabled | gg_but_default;
2467     label[gc].text = (unichar_t *) _("_OK");
2468     label[gc].text_is_1byte = true;
2469     label[gc].text_in_resource = true;
2470     gcd[gc].gd.mnemonic = 'O';
2471     gcd[gc].gd.label = &label[gc];
2472     gcd[gc].gd.handle_controlevent = Prefs_Ok;
2473     gcd[gc++].creator = GButtonCreate;
2474     harray[0] = GCD_Glue; harray[1] = &gcd[gc-1]; harray[2] = GCD_Glue; harray[3] = GCD_Glue;
2475 
2476     gcd[gc].gd.pos.x = -30; gcd[gc].gd.pos.y = gcd[gc-1].gd.pos.y+3;
2477     gcd[gc].gd.pos.width = -1; gcd[gc].gd.pos.height = 0;
2478     gcd[gc].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
2479     label[gc].text = (unichar_t *) _("_Cancel");
2480     label[gc].text_is_1byte = true;
2481     label[gc].text_in_resource = true;
2482     gcd[gc].gd.label = &label[gc];
2483     gcd[gc].gd.mnemonic = 'C';
2484     gcd[gc].gd.handle_controlevent = Prefs_Cancel;
2485     gcd[gc++].creator = GButtonCreate;
2486     harray[4] = GCD_Glue; harray[5] = &gcd[gc-1]; harray[6] = GCD_Glue; harray[7] = NULL;
2487 
2488     memset(mboxes,0,sizeof(mboxes));
2489     mboxes[2].gd.flags = gg_enabled|gg_visible;
2490     mboxes[2].gd.u.boxelements = harray;
2491     mboxes[2].creator = GHBoxCreate;
2492     varray[2] = &mboxes[2];
2493     varray[3] = NULL;
2494     varray[4] = NULL;
2495 
2496     mboxes[0].gd.pos.x = mboxes[0].gd.pos.y = 2;
2497     mboxes[0].gd.flags = gg_enabled|gg_visible;
2498     mboxes[0].gd.u.boxelements = varray;
2499     mboxes[0].creator = GHVGroupCreate;
2500 
2501     y = GDrawPointsToPixels(NULL,y+37);
2502     gcd[0].gd.pos.height = y-4;
2503 
2504     GGadgetsCreate(gw,mboxes);
2505     GTextInfoListFree(mfgcd[0].gd.u.list);
2506     GTextInfoListFree(msgcd[0].gd.u.list);
2507 
2508     GHVBoxSetExpandableRow(mboxes[0].ret,0);
2509     GHVBoxSetExpandableCol(mboxes[2].ret,gb_expandgluesame);
2510     GHVBoxSetExpandableRow(mfboxes[0].ret,0);
2511     GHVBoxSetExpandableCol(mfboxes[2].ret,gb_expandgluesame);
2512     GHVBoxSetExpandableRow(mpboxes[0].ret,0);
2513     GHVBoxSetExpandableCol(mpboxes[2].ret,gb_expandgluesame);
2514     GHVBoxSetExpandableRow(sboxes[0].ret,gb_expandglue);
2515     for ( k=0; k<TOPICS; ++k )
2516 	GHVBoxSetExpandableRow(boxes[2*k].ret,gb_expandglue);
2517 
2518     memset(&rq,0,sizeof(rq));
2519     rq.utf8_family_name = MONO_UI_FAMILIES;
2520     rq.point_size = 12;
2521     rq.weight = 400;
2522     font = GDrawInstanciateFont(gw,&rq);
2523     GGadgetSetFont(mfgcd[0].ret,font);
2524     GGadgetSetFont(msgcd[0].ret,font);
2525     GHVBoxFitWindow(mboxes[0].ret);
2526 
2527     for ( k=0; visible_prefs_list[k].tab_name!=0; ++k ) for ( gc=0,i=0; visible_prefs_list[k].pl[i].name!=NULL; ++i ) {
2528 	GGadgetCreateData *gcd = aspects[k].gcd[0].gd.u.boxelements[0];
2529 	pl = &visible_prefs_list[k].pl[i];
2530 	if ( pl->dontdisplay )
2531     continue;
2532 	switch ( pl->type ) {
2533 	  case pr_bool:
2534 	    ++gc;
2535 	  break;
2536 	  case pr_encoding: {
2537 	    GGadget *g = gcd[gc+1].ret;
2538 	    list = GGadgetGetList(g,&llen);
2539 	    for ( j=0; j<llen ; ++j ) {
2540 		if ( list[j]->text!=NULL &&
2541 			(void *) (intpt) ( *((int *) pl->val)) == list[j]->userdata )
2542 		    list[j]->selected = true;
2543 		else
2544 		    list[j]->selected = false;
2545 	    }
2546 	    if ( gcd[gc+1].gd.u.list!=encodingtypes )
2547 		GTextInfoListFree(gcd[gc+1].gd.u.list);
2548 	  } break;
2549 	  case pr_namelist:
2550 	    free(gcd[gc+1].gd.u.list);
2551 	  break;
2552 	  case pr_string: case pr_file: case pr_int: case pr_real: case pr_unicode: case pr_angle:
2553 	    free(plabels[k][gc+1].text);
2554 	    if ( pl->type==pr_file || pl->type==pr_angle )
2555 		++gc;
2556 	  break;
2557 	}
2558 	gc += 2;
2559     }
2560 
2561     for ( k=0; visible_prefs_list[k].tab_name!=0; ++k ) {
2562 	free(aspects[k].gcd->gd.u.boxelements[0]);
2563 	free(aspects[k].gcd->gd.u.boxelements);
2564 	free(plabels[k]);
2565     }
2566 
2567     GWidgetHidePalettes();
2568     GDrawSetVisible(gw,true);
2569     while ( !p.done )
2570 	GDrawProcessOneEvent(NULL);
2571     GDrawDestroyWindow(gw);
2572 }
2573 
RecentFilesRemember(char * filename)2574 void RecentFilesRemember(char *filename) {
2575     int i,j;
2576 
2577     for ( i=0; i<RECENT_MAX && RecentFiles[i]!=NULL; ++i )
2578 	if ( strcmp(RecentFiles[i],filename)==0 )
2579     break;
2580 
2581     if ( i<RECENT_MAX && RecentFiles[i]!=NULL ) {
2582 	if ( i!=0 ) {
2583 	    filename = RecentFiles[i];
2584 	    for ( j=i; j>0; --j )
2585 		RecentFiles[j] = RecentFiles[j-1];
2586 	    RecentFiles[0] = filename;
2587 	}
2588     } else {
2589 	if ( RecentFiles[RECENT_MAX-1]!=NULL )
2590 	    free( RecentFiles[RECENT_MAX-1]);
2591 	for ( i=RECENT_MAX-1; i>0; --i )
2592 	    RecentFiles[i] = RecentFiles[i-1];
2593 	RecentFiles[0] = copy(filename);
2594     }
2595 
2596     PrefsUI_SavePrefs(true);
2597 }
2598 
LastFonts_Save(void)2599 void LastFonts_Save(void) {
2600     FontView *fv, *next;
2601     char buffer[1024];
2602     char *ffdir = getFontForgeUserDir(Config);
2603     FILE *preserve = NULL;
2604 
2605     if ( ffdir ) {
2606         sprintf(buffer, "%s/FontsOpenAtLastQuit", ffdir);
2607         preserve = fopen(buffer,"w");
2608         free(ffdir);
2609     }
2610 
2611     for ( fv = fv_list; fv!=NULL; fv = next ) {
2612         next = (FontView *) (fv->b.next);
2613         if ( preserve ) {
2614             SplineFont *sf = fv->b.cidmaster?fv->b.cidmaster:fv->b.sf;
2615             fprintf(preserve, "%s\n", sf->filename?sf->filename:sf->origname);
2616         }
2617     }
2618 
2619     if ( preserve )
2620         fclose(preserve);
2621 }
2622 
2623 struct prefs_interface gdraw_prefs_interface = {
2624     PrefsUI_SavePrefs,
2625     PrefsUI_LoadPrefs,
2626     PrefsUI_GetPrefs,
2627     PrefsUI_SetPrefs,
2628     PrefsUI_getFontForgeShareDir,
2629     PrefsUI_SetDefaults
2630 };
2631 
change_res_filename(const char * newname)2632 static void change_res_filename(const char *newname) {
2633     free(xdefs_filename);
2634     xdefs_filename = copy( newname );
2635     SavePrefs(true);
2636 }
2637 
DoXRes(void)2638 void DoXRes(void) {
2639     extern GResInfo fontview_ri;
2640 
2641     MVColInit();
2642     CVColInit();
2643     BVColInit();
2644     GResEdit(&fontview_ri,xdefs_filename,change_res_filename);
2645 }
2646 
2647 struct prefs_list pointer_dialog_list[] = {
2648     { N_("ArrowMoveSize"), pr_real, &arrowAmount, NULL, NULL, '\0', NULL, 0, N_("The number of em-units by which an arrow key will move a selected point") },
2649     { N_("ArrowAccelFactor"), pr_real, &arrowAccelFactor, NULL, NULL, '\0', NULL, 0, N_("Holding down the Shift key will speed up arrow key motion by this factor") },
2650     { N_("InterpolateCPsOnMotion"), pr_bool, &interpCPsOnMotion, NULL, NULL, '\0', NULL, 0, N_("When moving one end point of a spline but not the other\ninterpolate the control points between the two.") },
2651     PREFS_LIST_EMPTY
2652 };
2653 
2654 struct prefs_list ruler_dialog_list[] = {
2655 	{ N_("SnapDistanceMeasureTool"), pr_real, &snapdistancemeasuretool, NULL, NULL, '\0', NULL, 0, N_("When the measure tool is active and when the mouse pointer is within this many pixels\nof one of the various interesting features (baseline,\nwidth, grid splines, etc.) the pointer will snap\nto that feature.") },
2656 	{ N_("MeasureToolShowHorizontalVertical"), pr_bool, &measuretoolshowhorizontolvertical, NULL, NULL, '\0', NULL, 0, N_("Have the measure tool show horizontal and vertical distances on the canvas.") },
2657     PREFS_LIST_EMPTY
2658 };
2659 
PrefsSubSet_Ok(GGadget * g,GEvent * e)2660 static int PrefsSubSet_Ok(GGadget *g, GEvent *e) {
2661     GWindow gw = GGadgetGetWindow(g);
2662     struct pref_data *p = GDrawGetUserData(GGadgetGetWindow(g));
2663     struct prefs_list* plist = p->plist;
2664     struct prefs_list* pl = plist;
2665     int i=0,j=0;
2666     int err=0, enc;
2667     const unichar_t *ret;
2668 
2669     p->done = true;
2670 
2671     for ( i=0, pl=plist; pl->name; ++i, ++pl ) {
2672 	switch( pl->type ) {
2673 	case pr_int:
2674 	    *((int *) (pl->val)) = GetInt8(gw,j*CID_PrefsOffset+CID_PrefsBase+i,pl->name,&err);
2675 	    break;
2676 	case pr_unicode:
2677 	    *((int *) (pl->val)) = GetUnicodeChar8(gw,j*CID_PrefsOffset+CID_PrefsBase+i,pl->name,&err);
2678 	    break;
2679 	case pr_bool:
2680 	    *((int *) (pl->val)) = GGadgetIsChecked(GWidgetGetControl(gw,j*CID_PrefsOffset+CID_PrefsBase+i));
2681 	    break;
2682 	case pr_real:
2683 	    *((float *) (pl->val)) = GetReal8(gw,j*CID_PrefsOffset+CID_PrefsBase+i,pl->name,&err);
2684 	    break;
2685 	case pr_encoding:
2686 	{ Encoding *e;
2687 		e = ParseEncodingNameFromList(GWidgetGetControl(gw,j*CID_PrefsOffset+CID_PrefsBase+i));
2688 		if ( e!=NULL )
2689 		    *((Encoding **) (pl->val)) = e;
2690 		enc = 1;	/* So gcc doesn't complain about unused. It is unused, but why add the ifdef and make the code even messier? Sigh. icc complains anyway */
2691 	}
2692 	break;
2693 	case pr_namelist:
2694 	{ NameList *nl;
2695 	    GTextInfo *ti = GGadgetGetListItemSelected(GWidgetGetControl(gw,j*CID_PrefsOffset+CID_PrefsBase+i));
2696 	    if ( ti!=NULL ) {
2697 		char *name = u2utf8_copy(ti->text);
2698 		nl = NameListByName(name);
2699 		free(name);
2700 		if ( nl!=NULL && nl->uses_unicode && !allow_utf8_glyphnames)
2701 		    ff_post_error(_("Namelist contains non-ASCII names"),_("Glyph names should be limited to characters in the ASCII character set, but there are names in this namelist which use characters outside that range."));
2702 		else if ( nl!=NULL )
2703 		    *((NameList **) (pl->val)) = nl;
2704 	    }
2705 	}
2706 	break;
2707 	case pr_string: case pr_file:
2708 	    ret = _GGadgetGetTitle(GWidgetGetControl(gw,j*CID_PrefsOffset+CID_PrefsBase+i));
2709 	    if ( pl->val!=NULL ) {
2710 		free( *((char **) (pl->val)) );
2711 		*((char **) (pl->val)) = NULL;
2712 		if ( ret!=NULL && *ret!='\0' )
2713 		    *((char **) (pl->val)) = /* u2def_*/ cu_copy(ret);
2714 	    } else {
2715 		char *cret = cu_copy(ret);
2716 		(pl->set)(cret);
2717 		free(cret);
2718 	    }
2719 	    break;
2720 	case pr_angle:
2721 	    *((float *) (pl->val)) = GetReal8(gw,j*CID_PrefsOffset+CID_PrefsBase+i,pl->name,&err)/RAD2DEG;
2722 	    break;
2723 	}
2724     }
2725 
2726     return( true );
2727 }
2728 
PrefsSubSetDlg(CharView * cv,char * windowTitle,struct prefs_list * plist)2729 static void PrefsSubSetDlg(CharView *cv,char* windowTitle,struct prefs_list* plist) {
2730     struct prefs_list* pl = plist;
2731     GRect pos;
2732     GWindow gw;
2733     GWindowAttrs wattrs;
2734     GGadgetCreateData *pgcd, gcd[20], sgcd[45], mgcd[3], mfgcd[9], msgcd[9];
2735     GGadgetCreateData mfboxes[3], *mfarray[14];
2736     GGadgetCreateData mpboxes[3];
2737     GGadgetCreateData sboxes[2];
2738     GGadgetCreateData mboxes[3], mboxes2[5], *varray[5], *harray[8];
2739     GTextInfo *plabel, label[20], slabel[45], mflabels[9], mslabels[9];
2740     GTabInfo aspects[TOPICS+5], subaspects[3];
2741     GGadgetCreateData **hvarray, boxes[2*TOPICS];
2742     struct pref_data p;
2743     int line = 0,line_max = 3;
2744     int i = 0, gc = 0, ii, y=0, si=0, k=0;
2745     char buf[20];
2746     char *tempstr;
2747 
2748     PrefsInit();
2749     MfArgsInit();
2750 
2751     line_max=0;
2752     for ( i=0, pl=plist; pl->name; ++i, ++pl ) {
2753 	    ++line_max;
2754     }
2755 
2756     int itemCount = 100;
2757     pgcd = calloc(itemCount,sizeof(GGadgetCreateData));
2758     plabel = calloc(itemCount,sizeof(GTextInfo));
2759     hvarray = calloc((itemCount)*5,sizeof(GGadgetCreateData *));
2760     memset(&p,'\0',sizeof(p));
2761     memset(&wattrs,0,sizeof(wattrs));
2762     memset(sgcd,0,sizeof(sgcd));
2763     memset(slabel,0,sizeof(slabel));
2764     memset(&mfgcd,0,sizeof(mfgcd));
2765     memset(&msgcd,0,sizeof(msgcd));
2766     memset(&mflabels,0,sizeof(mflabels));
2767     memset(&mslabels,0,sizeof(mslabels));
2768     memset(&mfboxes,0,sizeof(mfboxes));
2769     memset(&mpboxes,0,sizeof(mpboxes));
2770     memset(&sboxes,0,sizeof(sboxes));
2771     memset(&boxes,0,sizeof(boxes));
2772     memset(&mgcd,0,sizeof(mgcd));
2773     memset(&mgcd,0,sizeof(mgcd));
2774     memset(&subaspects,'\0',sizeof(subaspects));
2775     memset(&label,0,sizeof(label));
2776     memset(&gcd,0,sizeof(gcd));
2777     memset(&aspects,'\0',sizeof(aspects));
2778     GCDFillMacFeat(mfgcd,mflabels,250,default_mac_feature_map, true, mfboxes, mfarray);
2779 
2780     p.plist = plist;
2781     wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_restrict|wam_isdlg;
2782     wattrs.event_masks = ~(1<<et_charup);
2783     wattrs.restrict_input_to_me = 1;
2784     wattrs.is_dlg = 1;
2785     wattrs.undercursor = 1;
2786     wattrs.cursor = ct_pointer;
2787     wattrs.utf8_window_title = windowTitle;
2788     pos.x = pos.y = 0;
2789     pos.width = GGadgetScale(GDrawPointsToPixels(NULL,340));
2790     pos.height = GDrawPointsToPixels(NULL,line_max*26+25);
2791     gw = GDrawCreateTopWindow(NULL,&pos,e_h,&p,&wattrs);
2792 
2793 
2794 
2795     for ( i=0, pl=plist; pl->name; ++i, ++pl ) {
2796 
2797 	    plabel[gc].text = (unichar_t *) _(pl->name);
2798 	    plabel[gc].text_is_1byte = true;
2799 	    pgcd[gc].gd.label = &plabel[gc];
2800 	    pgcd[gc].gd.mnemonic = '\0';
2801 	    pgcd[gc].gd.popup_msg = 0;//_(pl->popup);
2802 	    pgcd[gc].gd.pos.x = 8;
2803 	    pgcd[gc].gd.pos.y = y + 6;
2804 	    pgcd[gc].gd.flags = gg_visible | gg_enabled;
2805 	    pgcd[gc++].creator = GLabelCreate;
2806 	    hvarray[si++] = &pgcd[gc-1];
2807 
2808 	    plabel[gc].text_is_1byte = true;
2809 	    pgcd[gc].gd.label = &plabel[gc];
2810 	    pgcd[gc].gd.mnemonic = '\0';
2811 	    pgcd[gc].gd.popup_msg = 0;//_(pl->popup);
2812 	    pgcd[gc].gd.pos.x = 110;
2813 	    pgcd[gc].gd.pos.y = y;
2814 	    pgcd[gc].gd.flags = gg_visible | gg_enabled;
2815 	    pgcd[gc].data = pl;
2816 	    pgcd[gc].gd.cid = k*CID_PrefsOffset+CID_PrefsBase+i;
2817 	    switch ( pl->type ) {
2818 	      case pr_bool:
2819 		plabel[gc].text = (unichar_t *) _("On");
2820 		pgcd[gc].gd.pos.y += 3;
2821 		pgcd[gc++].creator = GRadioCreate;
2822 		hvarray[si++] = &pgcd[gc-1];
2823 		pgcd[gc] = pgcd[gc-1];
2824 		pgcd[gc].gd.pos.x += 50;
2825 		pgcd[gc].gd.cid = 0;
2826 		pgcd[gc].gd.label = &plabel[gc];
2827 		plabel[gc].text = (unichar_t *) _("Off");
2828 		plabel[gc].text_is_1byte = true;
2829 		hvarray[si++] = &pgcd[gc];
2830 		hvarray[si++] = GCD_Glue;
2831 		if ( *((int *) pl->val))
2832 		    pgcd[gc-1].gd.flags |= gg_cb_on;
2833 		else
2834 		    pgcd[gc].gd.flags |= gg_cb_on;
2835 		++gc;
2836 		y += 22;
2837 	      break;
2838 	      case pr_int:
2839 		sprintf(buf,"%d", *((int *) pl->val));
2840 		plabel[gc].text = (unichar_t *) copy( buf );
2841 		pgcd[gc++].creator = GTextFieldCreate;
2842 		hvarray[si++] = &pgcd[gc-1];
2843 		hvarray[si++] = GCD_Glue; hvarray[si++] = GCD_Glue;
2844 		y += 26;
2845 	      break;
2846 	      case pr_unicode:
2847 		/*sprintf(buf,"U+%04x", *((int *) pl->val));*/
2848 		{ char *pt; pt=buf; pt=utf8_idpb(pt,*((int *)pl->val),UTF8IDPB_NOZERO); *pt='\0'; }
2849 		plabel[gc].text = (unichar_t *) copy( buf );
2850 		pgcd[gc++].creator = GTextFieldCreate;
2851 		hvarray[si++] = &pgcd[gc-1];
2852 		hvarray[si++] = GCD_Glue; hvarray[si++] = GCD_Glue;
2853 		y += 26;
2854 	      break;
2855 	      case pr_real:
2856 		sprintf(buf,"%g", *((float *) pl->val));
2857 		plabel[gc].text = (unichar_t *) copy( buf );
2858 		pgcd[gc++].creator = GTextFieldCreate;
2859 		hvarray[si++] = &pgcd[gc-1];
2860 		hvarray[si++] = GCD_Glue; hvarray[si++] = GCD_Glue;
2861 		y += 26;
2862 	      break;
2863 	      case pr_encoding:
2864 		pgcd[gc].gd.u.list = GetEncodingTypes();
2865 		pgcd[gc].gd.label = EncodingTypesFindEnc(pgcd[gc].gd.u.list,
2866 			*(Encoding **) pl->val);
2867 		for ( ii=0; pgcd[gc].gd.u.list[ii].text!=NULL ||pgcd[gc].gd.u.list[ii].line; ++ii )
2868 		    if ( pgcd[gc].gd.u.list[ii].userdata!=NULL &&
2869 			    (strcmp(pgcd[gc].gd.u.list[ii].userdata,"Compacted")==0 ||
2870 			     strcmp(pgcd[gc].gd.u.list[ii].userdata,"Original")==0 ))
2871 			pgcd[gc].gd.u.list[ii].disabled = true;
2872 		pgcd[gc].creator = GListFieldCreate;
2873 		pgcd[gc].gd.pos.width = 160;
2874 		if ( pgcd[gc].gd.label==NULL ) pgcd[gc].gd.label = &encodingtypes[0];
2875 		++gc;
2876 		hvarray[si++] = &pgcd[gc-1];
2877 		hvarray[si++] = GCD_ColSpan; hvarray[si++] = GCD_ColSpan;
2878 		y += 28;
2879 	      break;
2880 	      case pr_namelist:
2881 	        { char **nlnames = AllNamelistNames();
2882 		int cnt;
2883 		GTextInfo *namelistnames;
2884 		for ( cnt=0; nlnames[cnt]!=NULL; ++cnt);
2885 		namelistnames = calloc(cnt+1,sizeof(GTextInfo));
2886 		for ( cnt=0; nlnames[cnt]!=NULL; ++cnt) {
2887 		    namelistnames[cnt].text = (unichar_t *) nlnames[cnt];
2888 		    namelistnames[cnt].text_is_1byte = true;
2889 		    if ( strcmp(_((*(NameList **) (pl->val))->title),nlnames[cnt])==0 ) {
2890 			namelistnames[cnt].selected = true;
2891 			pgcd[gc].gd.label = &namelistnames[cnt];
2892 		    }
2893 		}
2894 		pgcd[gc].gd.u.list = namelistnames;
2895 		pgcd[gc].creator = GListButtonCreate;
2896 		pgcd[gc].gd.pos.width = 160;
2897 		++gc;
2898 		hvarray[si++] = &pgcd[gc-1];
2899 		hvarray[si++] = GCD_ColSpan; hvarray[si++] = GCD_ColSpan;
2900 		y += 28;
2901 	      } break;
2902 	      case pr_string: case pr_file:
2903 		if ( pl->set==SetAutoTraceArgs || ((char **) pl->val)==&mf_args )
2904 		    pgcd[gc].gd.pos.width = 160;
2905 		if ( pl->val!=NULL )
2906 		    tempstr = *((char **) (pl->val));
2907 		else
2908 		    tempstr = (char *) ((pl->get)());
2909 		if ( tempstr!=NULL )
2910 		    plabel[gc].text = /* def2u_*/ uc_copy( tempstr );
2911 		else if ( ((char **) pl->val)==&BDFFoundry )
2912 		    plabel[gc].text = /* def2u_*/ uc_copy( "FontForge" );
2913 		else
2914 		    plabel[gc].text = /* def2u_*/ uc_copy( "" );
2915 		plabel[gc].text_is_1byte = false;
2916 		pgcd[gc++].creator = GTextFieldCreate;
2917 		hvarray[si++] = &pgcd[gc-1];
2918 		if ( pl->type==pr_file ) {
2919 		    pgcd[gc] = pgcd[gc-1];
2920 		    pgcd[gc-1].gd.pos.width = 140;
2921 		    hvarray[si++] = GCD_ColSpan;
2922 		    pgcd[gc].gd.pos.x += 145;
2923 		    pgcd[gc].gd.cid += CID_PrefsBrowseOffset;
2924 		    pgcd[gc].gd.label = &plabel[gc];
2925 		    plabel[gc].text = (unichar_t *) "...";
2926 		    plabel[gc].text_is_1byte = true;
2927 		    pgcd[gc].gd.handle_controlevent = Prefs_BrowseFile;
2928 		    pgcd[gc++].creator = GButtonCreate;
2929 		    hvarray[si++] = &pgcd[gc-1];
2930 		} else if ( pl->set==SetAutoTraceArgs || ((char **) pl->val)==&mf_args ) {
2931 		    hvarray[si++] = GCD_ColSpan;
2932 		    hvarray[si++] = GCD_Glue;
2933 		} else {
2934 		    hvarray[si++] = GCD_Glue;
2935 		    hvarray[si++] = GCD_Glue;
2936 		}
2937 		y += 26;
2938 		if ( pl->val==NULL )
2939 		    free(tempstr);
2940 	      break;
2941 	      case pr_angle:
2942 		sprintf(buf,"%g", *((float *) pl->val) * RAD2DEG);
2943 		plabel[gc].text = (unichar_t *) copy( buf );
2944 		pgcd[gc++].creator = GTextFieldCreate;
2945 		hvarray[si++] = &pgcd[gc-1];
2946 		plabel[gc].text = (unichar_t *) U_("°");
2947 		plabel[gc].text_is_1byte = true;
2948 		pgcd[gc].gd.label = &plabel[gc];
2949 		pgcd[gc].gd.pos.x = pgcd[gc-1].gd.pos.x+gcd[gc-1].gd.pos.width+2; pgcd[gc].gd.pos.y = pgcd[gc-1].gd.pos.y;
2950 		pgcd[gc].gd.flags = gg_enabled|gg_visible;
2951 		pgcd[gc++].creator = GLabelCreate;
2952 		hvarray[si++] = &pgcd[gc-1];
2953 		hvarray[si++] = GCD_Glue;
2954 		y += 26;
2955 	      break;
2956 	    }
2957 	    ++line;
2958 	    hvarray[si++] = NULL;
2959 
2960     }
2961 
2962     harray[4] = 0;
2963     harray[5] = 0;
2964     harray[6] = 0;
2965     harray[7] = 0;
2966 
2967     gcd[gc].gd.pos.x = 30-3;
2968     gcd[gc].gd.pos.y = y+5-3;
2969     gcd[gc].gd.pos.width = -1;
2970     gcd[gc].gd.pos.height = 0;
2971     gcd[gc].gd.flags = gg_visible | gg_enabled | gg_but_default;
2972     label[gc].text = (unichar_t *) _("_OK");
2973     label[gc].text_is_1byte = true;
2974     label[gc].text_in_resource = true;
2975     gcd[gc].gd.mnemonic = 'O';
2976     gcd[gc].gd.label = &label[gc];
2977     gcd[gc].gd.handle_controlevent = PrefsSubSet_Ok;
2978     gcd[gc++].creator = GButtonCreate;
2979     harray[0] = GCD_Glue; harray[1] = &gcd[gc-1]; harray[2] = GCD_Glue; harray[3] = GCD_Glue;
2980 
2981 
2982     memset(mboxes,0,sizeof(mboxes));
2983     memset(mboxes2,0,sizeof(mboxes2));
2984 
2985     mboxes[2].gd.pos.x = 2;
2986     mboxes[2].gd.pos.y = 20;
2987     mboxes[2].gd.flags = gg_enabled|gg_visible;
2988     mboxes[2].gd.u.boxelements = harray;
2989     mboxes[2].creator = GHBoxCreate;
2990 
2991     mboxes[0].gd.pos.x = mboxes[0].gd.pos.y = 2;
2992     mboxes[0].gd.flags = gg_enabled|gg_visible;
2993     mboxes[0].gd.u.boxelements = hvarray;
2994     mboxes[0].creator = GHVGroupCreate;
2995 
2996     varray[0] = &mboxes[0];
2997     varray[1] = &mboxes[2];
2998     varray[2] = 0;
2999     varray[3] = 0;
3000     varray[4] = 0;
3001 
3002     /* varray[0] = &mboxes[2]; */
3003     /* varray[1] = 0;//&mboxes[2]; */
3004     /* varray[2] = 0; */
3005     /* varray[3] = 0; */
3006     /* varray[4] = 0; */
3007 
3008     mboxes2[0].gd.pos.x = 4;
3009     mboxes2[0].gd.pos.y = 4;
3010     mboxes2[0].gd.flags = gg_enabled|gg_visible;
3011     mboxes2[0].gd.u.boxelements = varray;
3012     mboxes2[0].creator = GVBoxCreate;
3013 
3014     GGadgetsCreate(gw,mboxes2);
3015 
3016 
3017     GDrawSetVisible(gw,true);
3018     while ( !p.done )
3019 	GDrawProcessOneEvent(NULL);
3020     GDrawDestroyWindow(gw);
3021 }
3022 
3023 
PointerDlg(CharView * cv)3024 void PointerDlg(CharView *cv) {
3025     PrefsSubSetDlg( cv, _("Arrow Options"), pointer_dialog_list );
3026 }
3027 
RulerDlg(CharView * cv)3028 void RulerDlg(CharView *cv) {
3029     PrefsSubSetDlg( cv, _("Ruler Options"), ruler_dialog_list );
3030 }
3031 
3032