1 /* Copyright (C) 2000-2012 by George Williams */
2 /*
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are met:
5
6 * Redistributions of source code must retain the above copyright notice, this
7 * list of conditions and the following disclaimer.
8
9 * Redistributions in binary form must reproduce the above copyright notice,
10 * this list of conditions and the following disclaimer in the documentation
11 * and/or other materials provided with the distribution.
12
13 * The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include <fontforge-config.h>
29
30 #include "autohint.h"
31 #include "autosave.h"
32 #include "autotrace.h"
33 #include "autowidth.h"
34 #include "charview_private.h"
35 #include "cvruler.h"
36 #include "cvundoes.h"
37 #include "dlist.h"
38 #include "dumppfa.h"
39 #include "encoding.h"
40 #include "ffglib.h"
41 #include "fontforgeui.h"
42 #include "fvcomposite.h"
43 #include "fvfonts.h"
44 #include "gkeysym.h"
45 #include "gresedit.h"
46 #include "gresource.h"
47 #include "hotkeys.h"
48 #include "lookups.h"
49 #include "mm.h"
50 #include "namelist.h"
51 #include "prefs.h"
52 #include "sfd.h"
53 #include "spiro.h"
54 #include "splinefill.h"
55 #include "splineorder2.h"
56 #include "splineoverlap.h"
57 #include "splinesaveafm.h"
58 #include "splineutil.h"
59 #include "splineutil2.h"
60 #include "unicodelibinfo.h"
61 #include "ustring.h"
62 #include "utype.h"
63 #include "wordlistparser.h"
64
65 #include <locale.h>
66 #include <math.h>
67
68 #ifdef HAVE_IEEEFP_H
69 # include <ieeefp.h> /* Solaris defines isnan in ieeefp rather than math.h */
70 #endif
71
72 /* Barry wants to be able to redefine menu bindings only in the charview (I think) */
73 /* the menu parser will first check for something like "CV*Open|Ctl+O", and */
74 /* if that fails will strip off "CV*" and check for "Open|Ctl+O" */
75 #undef H_
76 #define H_(str) ("CV*" str)
77
78 extern void UndoesFreeButRetainFirstN( Undoes** undopp, int retainAmount );
79 static void CVMoveInWordListByOffset( CharView* cv, int offset );
80 extern void CVDebugFree( DebugView *dv );
81
82 extern int _GScrollBar_Width;
83
84 int additionalCharsToShowLimit = 50;
85
86 int ItalicConstrained=true;
87 float arrowAmount=1;
88 float arrowAccelFactor=10.;
89 float snapdistance=3.5;
90 float snapdistancemeasuretool=3.5;
91 int updateflex = false;
92 extern int clear_tt_instructions_when_needed;
93 int use_freetype_with_aa_fill_cv = 1;
94 int interpCPsOnMotion=false;
95 int DrawOpenPathsWithHighlight = 1;
96 #define default_cv_width 540
97 #define default_cv_height 540
98 int cv_width = default_cv_width;
99 int cv_height = default_cv_height;
100 int cv_show_fill_with_space = 1;
101
102 #define prefs_cvEditHandleSize_default 5.0
103 float prefs_cvEditHandleSize = prefs_cvEditHandleSize_default;
104
105 int prefs_cvInactiveHandleAlpha = 255;
106
107 int prefs_cv_show_control_points_always_initially = 0;
108 int prefs_create_dragging_comparison_outline = 0;
109
110 extern struct lconv localeinfo;
111 extern char *coord_sep;
112 struct cvshows CVShows = {
113 1, /* show foreground */
114 1, /* show background */
115 1, /* show grid plane */
116 1, /* show horizontal hints */
117 1, /* show vertical hints */
118 1, /* show diagonal hints */
119 1, /* show points */
120 0, /* show filled */
121 1, /* show rulers */
122 1, /* show points which are to be rounded to the ttf grid and aren't on hints */
123 1, /* show x minimum distances */
124 1, /* show y minimum distances */
125 1, /* show horizontal metrics */
126 1, /* show vertical metrics */
127 0, /* mark extrema */
128 0, /* show points of inflection */
129 1, /* show blue values */
130 1, /* show family blues too */
131 1, /* show anchor points */
132 0, /* show control point info when moving them */
133 1, /* show tabs containing names of former glyphs */
134 1, /* show side bearings */
135 1, /* show the names of references */
136 1, /* snap outlines to pixel grid */
137 0, /* show lines which are almost, but not exactly horizontal or vertical */
138 0, /* show curves which are almost, but not exactly horizontal or vertical at the end-points */
139 3, /* number of em-units a coord difference must be less than to qualify for almost hv */
140 1, /* Check for self-intersections in the element view */
141 1 /* In tt debugging, mark changed rasters differently */
142 };
143 struct cvshows CVShowsPrevewToggleSavedState;
144
145 #define CID_Base 1001
146 #define CID_getValueFromUser CID_Base + 1
147
148
149 // Note that the default values supplied in CVColInit over-ride these values.
150 static Color pointcol = 0xff0000;
151 static Color subcol = 0xffffff;
152 static Color firstpointcol = 0x707000;
153 static Color selectedpointcol = 0xc8c800;
154 static int selectedpointwidth = 2;
155 static Color extremepointcol = 0xCAA80A;
156 static Color pointofinflectioncol = 0x008080;
157 static Color almosthvcol = 0x00ff80;
158 Color nextcpcol = 0x007090;
159 Color prevcpcol = 0xcc00cc;
160 static Color selectedcpcol = 0xffffff;
161 static Color coordcol = 0x808080;
162 Color widthcol = 0x000000;
163 static Color widthselcol = 0x00ff00;
164 static Color lbearingselcol = 0x00ff00;
165 static Color widthgridfitcol = 0x009800;
166 static Color lcaretcol = 0x909040;
167 static Color rastercol = 0xffa0a0a0; /* Translucent */
168 static Color rasternewcol = 0xff909090;
169 static Color rasteroldcol = 0xffc0c0c0;
170 static Color rastergridcol = 0xffb0b0ff;
171 static Color rasterdarkcol = 0xff606060;
172 static Color deltagridcol = 0xcc0000;
173 static Color italiccoordcol = 0x909090;
174 static Color metricslabelcol = 0x00000;
175 static Color hintlabelcol = 0x00cccc;
176 static Color bluevalstipplecol = 0x808080ff; /* Translucent */
177 static Color fambluestipplecol = 0x80ff7070; /* Translucent */
178 static Color mdhintcol = 0x80e04040; /* Translucent */
179 static Color dhintcol = 0x80d0a0a0; /* Translucent */
180 static Color hhintcol = 0x80a0d0a0; /* Translucent */
181 static Color vhintcol = 0x80c0c0ff; /* Translucent */
182 static Color hflexhintcol = 0x00ff00;
183 static Color vflexhintcol = 0x00ff00;
184 static Color conflicthintcol = 0x00ffff;
185 static Color hhintactivecol = 0x00a000;
186 static Color vhintactivecol = 0x0000ff;
187 static Color anchorcol = 0x0040ff;
188 static Color anchoredoutlinecol = 0x0040ff;
189 static Color templateoutlinecol = 0x009800;
190 static Color oldoutlinecol = 0x008000;
191 static Color transformorigincol = 0x000000;
192 static Color guideoutlinecol = 0x808080;
193 static Color gridfitoutlinecol = 0x009800;
194 static Color backoutlinecol = 0x009800;
195 static Color foreoutlinecol = 0x000000;
196 static Color clippathcol = 0x0000ff;
197 static Color openpathcol = 0x40660000;
198 static Color backimagecol = 0x707070;
199 static Color fillcol = 0x80707070; /* Translucent */
200 static Color tracecol = 0x008000;
201 static Color rulerbigtickcol = 0x008000;
202 static Color previewfillcol = 0x0f0f0f;
203 static Color DraggingComparisonOutlineColor = 0x8800BB00;
204 static Color DraggingComparisonAlphaChannelOverride = 0x88000000;
205 static Color foreoutthicklinecol = 0x20707070;
206 static Color backoutthicklinecol = 0x20707070;
207 int prefs_cv_outline_thickness = 1;
208 int cvbutton3d = 1;
209 Color cvbutton3dedgelightcol = 0xe0e0e0;
210 Color cvbutton3dedgedarkcol = 0x707070;
211
212 // Format is 0x AA RR GG BB.
213
214 static int CV_OnCharSelectorTextChanged( GGadget *g, GEvent *e );
215 static void CVHScrollSetPos( CharView *cv, int newpos );
216
217 static void CVClear(GWindow,GMenuItem *mi, GEvent *);
218 static void CVMouseMove(CharView *cv, GEvent *event );
219 static void CVMouseUp(CharView *cv, GEvent *event );
220 static void CVHScroll(CharView *cv,struct sbevent *sb);
221 static void CVVScroll(CharView *cv,struct sbevent *sb);
222 /*static void CVElide(GWindow gw,struct gmenuitem *mi,GEvent *e);*/
223 static void CVMenuSimplify(GWindow gw,struct gmenuitem *mi,GEvent *e);
224 static void CVMenuSimplifyMore(GWindow gw,struct gmenuitem *mi,GEvent *e);
225 static void CVPreviewModeSet(GWindow gw, int checked);
226 static void CVExposeRulers(CharView *cv, GWindow pixmap);
227
228 static int cvcolsinited = false;
229
230 // Note that the GResource names for these preferences are defined separately in CVColInit.
231 // It would be wise to match any changes to these data structures with changes to the values in CVColInit.
232
233 static struct resed charview_re[] = {
234 { N_("Point Color"), "PointColor", rt_color, &pointcol, N_("The color of an on-curve point"), NULL, { 0 }, 0, 0 },
235 { N_("First Point Color"), "FirstPointColor", rt_color, &firstpointcol, N_("The color of the point which is the start of a contour"), NULL, { 0 }, 0, 0 },
236 { N_("Selected Point Color"), "SelectedPointColor", rt_color, &selectedpointcol, N_("The color of a selected point"), NULL, { 0 }, 0, 0 },
237 { N_("Selected Point Width"), "SelectedPointWidth", rt_int, &selectedpointwidth, N_("The width of the line used to draw selected points"), NULL, { 0 }, 0, 0 },
238 { N_("Extrema Point Color"), "ExtremePointColor", rt_color, &extremepointcol, N_("The color used to draw points at extrema (if that mode is active)"), NULL, { 0 }, 0, 0 },
239 { N_("Point of Inflection Color"), "PointOfInflectionColor", rt_color, &pointofinflectioncol, N_("The color used to draw points of inflection (if that mode is active)"), NULL, { 0 }, 0, 0 },
240 { N_("Almost H/V Color"), "AlmostHVColor", rt_color, &almosthvcol, N_("The color used to draw markers for splines which are almost, but not quite horizontal or vertical at their end-points"), NULL, { 0 }, 0, 0 },
241 { N_("Next CP Color"), "NextCPColor", rt_color, &nextcpcol, N_("The color used to draw the \"next\" control point of an on-curve point"), NULL, { 0 }, 0, 0 },
242 { N_("Prev CP Color"), "PrevCPColor", rt_color, &prevcpcol, N_("The color used to draw the \"previous\" control point of an on-curve point"), NULL, { 0 }, 0, 0 },
243 { N_("Selected CP Color"), "SelectedCPColor", rt_color, &selectedcpcol, N_("The color used to draw a selected control point of an on-curve point"), NULL, { 0 }, 0, 0 },
244 { N_("Coordinate Line Color"), "CoordinateLineColor", rt_color, &coordcol, NULL, NULL, { 0 }, 0, 0 },
245 { N_("Italic Coord. Color"), "ItalicCoordColor", rt_color, &italiccoordcol, NULL, NULL, { 0 }, 0, 0 },
246 { N_("Metrics Label Color"), "MetricsLabelColor", rt_color, &metricslabelcol, NULL, NULL, { 0 }, 0, 0 },
247 { N_("Hint Label Color"), "HintLabelColor", rt_color, &hintlabelcol,NULL, NULL, { 0 }, 0, 0 },
248 { N_("Blue Values Color"), "BlueValuesStippledColor", rt_coloralpha, &bluevalstipplecol, N_("The color used to mark blue zones in the blue values entry of the private dictionary"), NULL, { 0 }, 0, 0 },
249 { N_("Family Blue Color"), "FamilyBlueStippledColor", rt_coloralpha, &fambluestipplecol, N_("The color used to mark blue zones in the family blues entry of the private dictionary"), NULL, { 0 }, 0, 0 },
250 { N_("Diagonal Hint Color"), "DHintColor", rt_coloralpha, &dhintcol, N_("The color used to draw diagonal hints"), NULL, { 0 }, 0, 0 },
251 { N_("Horiz. Hint Color"), "HHintColor", rt_coloralpha, &hhintcol, N_("The color used to draw horizontal hints"), NULL, { 0 }, 0, 0 },
252 { N_("Vert. Hint Color"), "VHintColor", rt_coloralpha, &vhintcol, N_("The color used to draw vertical hints"), NULL, { 0 }, 0, 0 },
253 { N_("HFlex Hint Color"), "HFlexHintColor", rt_color, &hflexhintcol, NULL, NULL, { 0 }, 0, 0 },
254 { N_("VFlex Hint Color"), "VFlexHintColor", rt_color, &vflexhintcol, NULL, NULL, { 0 }, 0, 0 },
255 { N_("Conflict Hint Color"), "ConflictHintColor", rt_color, &conflicthintcol, N_("The color used to draw a hint which conflicts with another"), NULL, { 0 }, 0, 0 },
256 { N_("HHint Active Color"), "HHintActiveColor", rt_color, &hhintactivecol, N_("The color used to draw the active horizontal hint which the Review Hints dialog is examining"), NULL, { 0 }, 0, 0 },
257 { N_("VHint Active Color"), "VHintActiveColor", rt_color, &vhintactivecol, N_("The color used to draw the active vertical hint which the Review Hints dialog is examining"), NULL, { 0 }, 0, 0 },
258 { N_("Dragging Comparison Outline Color"), "DraggingComparisonOutlineColor", rt_coloralpha, &DraggingComparisonOutlineColor, N_("The color used to draw the outline of the old spline when you are interactively modifying a glyph"), NULL, { 0 }, 0, 0 },
259 { N_("Dragging Comparison Outline Color"), "DraggingComparisonAlphaChannelOverride", rt_coloralpha, &DraggingComparisonAlphaChannelOverride, N_("Only the alpha value is used and if non zero it will set the alpha channel for the control points, bezier information and other non spline indicators for the Dragging Comparison Outline spline"), NULL, { 0 }, 0, 0 },
260 RESED_EMPTY
261 };
262
263 static struct resed charview2_re[] = {
264 { N_("Width Color"), "WidthColor", rt_color, &widthcol, N_("The color of the line marking the advance width"), NULL, { 0 }, 0, 0 },
265 { N_("Selected Width Color"), "WidthSelColor", rt_color, &widthselcol, N_("The color of the line marking the advance width when it is selected"), NULL, { 0 }, 0, 0 },
266 { N_("Selected LBearing Color"), "LBearingSelColor", rt_color, &lbearingselcol, N_("The color of the line marking the left bearing when it is selected"), NULL, { 0 }, 0, 0 },
267 { N_("Grid Fit Width Color"), "GridFitWidthColor", rt_color, &widthgridfitcol, N_("The color of the line marking the grid-fit advance width"), NULL, { 0 }, 0, 0 },
268 { N_("Ligature Caret Color"), "LigatureCaretColor", rt_color, &lcaretcol, N_("The color of the line(s) marking ligature carets"), NULL, { 0 }, 0, 0 },
269 { N_("Anchor Color"), "AnchorColor", rt_color, &anchorcol, N_("The color of anchor stars"), NULL, { 0 }, 0, 0 },
270 { N_("Anchored Line Color"), "AnchoredOutlineColor", rt_color, &anchoredoutlinecol, N_("The color of another glyph drawn in the current view to show where it would be placed by an anchor lookup"), NULL, { 0 }, 0, 0 },
271 { N_("Template Color"), "TemplateOutlineColor", rt_color, &templateoutlinecol, NULL, NULL, { 0 }, 0, 0 },
272 { N_("Old Outline Color"), "OldOutlineColor", rt_color, &oldoutlinecol, NULL, NULL, { 0 }, 0, 0 },
273 { N_("Original Color"), "TransformOriginColor", rt_color, &transformorigincol, NULL, NULL, { 0 }, 0, 0 },
274 { N_("Guide Layer Color"), "GuideOutlineColor", rt_color, &guideoutlinecol, NULL, NULL, { 0 }, 0, 0 },
275 { N_("Grid Fit Color"), "GridFitOutlineColor", rt_color, &gridfitoutlinecol, N_("The color of grid-fit outlines"), NULL, { 0 }, 0, 0 },
276 { N_("Inactive Layer Color"), "BackgroundOutlineColor", rt_color, &backoutlinecol, N_("The color of outlines in inactive layers"), NULL, { 0 }, 0, 0 },
277 { N_("Active Layer Color"), "ForegroundOutlineColor", rt_color, &foreoutlinecol, N_("The color of outlines in the active layer"), NULL, { 0 }, 0, 0 },
278 { N_("Inactive Thick Layer Color"), "BackgroundThickOutlineColor", rt_coloralpha, &backoutthicklinecol, N_("The color of thick outlines in inactive layers"), NULL, { 0 }, 0, 0 },
279 { N_("Active Thick Layer Color"), "ForegroundThickOutlineColor", rt_coloralpha, &foreoutthicklinecol, N_("The color of thick outlines in the active layer"), NULL, { 0 }, 0, 0 },
280 { N_("Clip Path Color"), "ClipPathColor", rt_color, &clippathcol, N_("The color of the clip path"), NULL, { 0 }, 0, 0 },
281 { N_("Open Path Color"), "OpenPathColor", rt_coloralpha, &openpathcol, N_("The color of the open path"), NULL, { 0 }, 0, 0 },
282 { N_("Background Image Color"), "BackgroundImageColor", rt_coloralpha, &backimagecol, N_("The color used to draw bitmap (single bit) images which do not specify a clut"), NULL, { 0 }, 0, 0 },
283 { N_("Fill Color"), "FillColor", rt_coloralpha, &fillcol, N_("The color used to fill the outline if that mode is active"), NULL, { 0 }, 0, 0 },
284 { N_("Preview Fill Color"), "PreviewFillColor", rt_coloralpha, &previewfillcol, N_("The color used to fill the outline when in preview mode"), NULL, { 0 }, 0, 0 },
285 { N_("Trace Color"), "TraceColor", rt_color, &tracecol, NULL, NULL, { 0 }, 0, 0 },
286 { N_("Raster Color"), "RasterColor", rt_coloralpha, &rastercol, N_("The color of grid-fit (and other) raster blocks"), NULL, { 0 }, 0, 0 },
287 { N_("Raster New Color"), "RasterNewColor", rt_coloralpha, &rasternewcol, N_("The color of raster blocks which have just been turned on (in the debugger when an instruction moves a point)"), NULL, { 0 }, 0, 0 },
288 { N_("Raster Old Color"), "RasterOldColor", rt_coloralpha, &rasteroldcol, N_("The color of raster blocks which have just been turned off (in the debugger when an instruction moves a point)"), NULL, { 0 }, 0, 0 },
289 { N_("Raster Grid Color"), "RasterGridColor", rt_coloralpha, &rastergridcol, NULL, NULL, { 0 }, 0, 0 },
290 { N_("Raster Dark Color"), "RasterDarkColor", rt_coloralpha, &rasterdarkcol, N_("When debugging in grey-scale this is the color of a raster block which is fully covered."), NULL, { 0 }, 0, 0 },
291 { N_("Delta Grid Color"), "DeltaGridColor", rt_color, &deltagridcol, N_("Indicates a notable grid pixel when suggesting deltas."), NULL, { 0 }, 0, 0 },
292 { N_("Ruler Big Tick Color"), "RulerBigTickColor", rt_color, &rulerbigtickcol, N_("The color used to draw the large tick marks in rulers."), NULL, { 0 }, 0, 0 },
293 { N_("Measure Tool Line Color"), "MeasureToolLineColor", rt_color, &measuretoollinecol, N_("The color used to draw the measure tool line."), NULL, { 0 }, 0, 0 },
294 { N_("Measure Tool Point Color"), "MeasureToolPointColor", rt_color, &measuretoolpointcol, N_("The color used to draw the measure tool points."), NULL, { 0 }, 0, 0 },
295 { N_("Measure Tool Point Snapped Color"), "MeasureToolPointSnappedColor", rt_color, &measuretoolpointsnappedcol, N_("The color used to draw the measure tool points when snapped."), NULL, { 0 }, 0, 0 },
296 { N_("Measure Tool Canvas Number Color"), "MeasureToolCanvasNumbersColor", rt_color, &measuretoolcanvasnumberscol, N_("The color used to draw the measure tool numbers on the canvas."), NULL, { 0 }, 0, 0 },
297 { N_("Measure Tool Canvas Number Snapped Color"), "MeasureToolCanvasNumbersSnappedColor", rt_color, &measuretoolcanvasnumberssnappedcol, N_("The color used to draw the measure tool numbers on the canvas when snapped."), NULL, { 0 }, 0, 0 },
298 { N_("Measure Tool Windows Foreground Color"), "MeasureToolWindowForeground", rt_color, &measuretoolwindowforegroundcol, N_("The measure tool window foreground color."), NULL, { 0 }, 0, 0 },
299 { N_("Measure Tool Windows Background Color"), "MeasureToolWindowBackground", rt_color, &measuretoolwindowbackgroundcol, N_("The measure tool window background color."), NULL, { 0 }, 0, 0 },
300 RESED_EMPTY
301 };
302
303 /* return 1 if anything changed */
update_spacebar_hand_tool(CharView * cv)304 static void update_spacebar_hand_tool(CharView *cv) {
305 if ( GDrawKeyState(cv->v, ' ') ) {
306 if ( !cv->spacebar_hold && !cv_auto_goto ) {
307 cv->spacebar_hold = 1;
308 cv->b1_tool_old = cv->b1_tool;
309 cv->b1_tool = cvt_hand;
310 cv->active_tool = cvt_hand;
311 CVMouseDownHand(cv);
312 CVPreviewModeSet(cv->gw, cv_show_fill_with_space);
313 }
314 } else {
315 if ( cv->spacebar_hold ) {
316 cv->spacebar_hold = 0;
317 cv->b1_tool = cv->b1_tool_old;
318 cv->active_tool = cvt_none;
319 cv->b1_tool_old = cvt_none;
320 CVPreviewModeSet(cv->gw, false);
321 }
322 }
323 }
324
325
CVInSpiro(CharView * cv)326 int CVInSpiro( CharView *cv )
327 {
328 int inspiro = 0;
329 int canspiro = hasspiro();
330 if( cv )
331 inspiro = canspiro && cv->b.sc->inspiro;
332 return inspiro;
333 }
334
335 /**
336 * Returns the number of points which are currently selected in this
337 * charview. Handy for menus and the like which might like to grey out
338 * if there are <2, or <3 points actively selected.
339 */
CVCountSelectedPoints(CharView * cv)340 int CVCountSelectedPoints(CharView *cv) {
341 SplinePointList *spl;
342 Spline *spline, *first;
343 int ret = 0;
344
345 for ( spl = cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL; spl = spl->next ) {
346 first = NULL;
347 for ( spline = spl->first->next; spline!=NULL && spline!=first; spline=spline->to->next ) {
348 if( spline == spl->first->next ) {
349 if ( spline->from->selected ) {
350 ret++;
351 }
352 }
353 if ( spline->to->selected ) {
354 if( spline->to != spl->first->next->from )
355 ret++;
356 }
357 if ( first==NULL ) {
358 first = spline;
359 }
360 }
361 }
362 return ret;
363 }
364
365
366
367 /* floor(pt) would _not_ be more correct, as we want
368 * shapes not to cross axes multiple times while scaling.
369 */
rpt(CharView * cv,double pt)370 static double rpt(CharView *cv, double pt) {
371 return cv->snapoutlines ? rint(pt) : pt;
372 }
373
shouldShowFilledUsingCairo(CharView * cv)374 static int shouldShowFilledUsingCairo(CharView *cv) {
375 if ( cv->showfilled && GDrawHasCairo(cv->v) & gc_buildpath ) {
376 return 1;
377 }
378 return 0;
379 }
380
CVColInit(void)381 void CVColInit( void ) {
382 if ( cvcolsinited )
383 return;
384 GResEditFind( charview_re, "CharView.");
385 GResEditFind( charview2_re, "CharView.");
386 cvcolsinited = true;
387
388 // These value over-ride the static initializers.
389 // Note that the base resource names are copied from charview_re and charview2_re.
390 pointcol = GResourceFindColor("CharView.PointColor",0xff0000);
391 firstpointcol = GResourceFindColor("CharView.FirstPointColor",0x707000);
392 selectedpointcol = GResourceFindColor("CharView.SelectedPointColor",0xc8c800);
393 selectedpointwidth = GResourceFindInt("CharView.SelectedPointWidth",2);
394 extremepointcol = GResourceFindColor("CharView.ExtremePointColor",0xc00080);
395 pointofinflectioncol = GResourceFindColor("CharView.PointOfInflectionColor",0x008080);
396 almosthvcol = GResourceFindColor("CharView.AlmostHVColor",0x00ff80);
397 nextcpcol = GResourceFindColor("CharView.NextCPColor",0x007090);
398 prevcpcol = GResourceFindColor("CharView.PointColor",0xcc00cc);
399 selectedcpcol = GResourceFindColor("CharView.SelectedCPColor",0xffffff);
400 coordcol = GResourceFindColor("CharView.CoordinateColor",0x808080);
401 widthcol = GResourceFindColor("CharView.WidthColor",0x000000);
402 widthselcol = GResourceFindColor("CharView.WidthSelColor",0x00ff00);
403 lbearingselcol = GResourceFindColor("CharView.LBearingSelColor",0x00ff00);
404 widthgridfitcol = GResourceFindColor("CharView.GridFitWidthColor",0x009800);
405 lcaretcol = GResourceFindColor("CharView.LigatureCaretColor",0x909040);
406 rastercol = GResourceFindColor("CharView.RasterColor",0xffa0a0a0); /* Translucent */
407 rasternewcol = GResourceFindColor("CharView.RasterNewColor",0xff909090);
408 rasteroldcol = GResourceFindColor("CharView.RasterOldColor",0xffc0c0c0);
409 rastergridcol = GResourceFindColor("CharView.RasterGridColor",0xffb0b0ff);
410 rasterdarkcol = GResourceFindColor("CharView.RasterDarkColor",0xff606060);
411 deltagridcol = GResourceFindColor("CharView.DeltaGridColor",0xcc0000);
412 italiccoordcol = GResourceFindColor("CharView.ItalicCoordColor",0x909090);
413 metricslabelcol = GResourceFindColor("CharView.MetricsLabelColor",0x00000);
414 hintlabelcol = GResourceFindColor("CharView.HintLabelColor",0x00cccc);
415 bluevalstipplecol = GResourceFindColor("CharView.BlueValuesStippledColor",0x808080ff); /* Translucent */
416 fambluestipplecol = GResourceFindColor("CharView.FamilyBlueStippledColor",0x80ff7070); /* Translucent */
417 mdhintcol = GResourceFindColor("CharView.xxxxxx",0x80e04040); /* Translucent */
418 dhintcol = GResourceFindColor("CharView.DHintColor",0x80d0a0a0); /* Translucent */
419 hhintcol = GResourceFindColor("CharView.HHintColor",0x80a0d0a0); /* Translucent */
420 vhintcol = GResourceFindColor("CharView.VHintColor",0x80c0c0ff); /* Translucent */
421 hflexhintcol = GResourceFindColor("CharView.HFlexHintColor",0x00ff00);
422 vflexhintcol = GResourceFindColor("CharView.VFlexHintColor",0x00ff00);
423 conflicthintcol = GResourceFindColor("CharView.ConflictHintColor",0x00ffff);
424 hhintactivecol = GResourceFindColor("CharView.HHintActiveColor",0x00a000);
425 vhintactivecol = GResourceFindColor("CharView.VHintActiveColor",0x0000ff);
426 anchorcol = GResourceFindColor("CharView.AnchorColor",0x0040ff);
427 anchoredoutlinecol = GResourceFindColor("CharView.AnchoredOutlineColor",0x0040ff);
428 templateoutlinecol = GResourceFindColor("CharView.TemplateOutlineColor",0x009800);
429 oldoutlinecol = GResourceFindColor("CharView.OldOutlineColor",0x008000);
430 transformorigincol = GResourceFindColor("CharView.TransformOriginColor",0x000000);
431 guideoutlinecol = GResourceFindColor("CharView.GuideOutlineColor",0x808080);
432 gridfitoutlinecol = GResourceFindColor("CharView.GridFitOutlineColor",0x009800);
433 backoutlinecol = GResourceFindColor("CharView.BackgroundOutlineColor",0x009800);
434 foreoutlinecol = GResourceFindColor("CharView.ForegroundOutlineColor",0x000000);
435 clippathcol = GResourceFindColor("CharView.ClipPathColor",0x0000ff);
436 openpathcol = GResourceFindColor("CharView.OpenPathColor",0x40660000);
437 backimagecol = GResourceFindColor("CharView.BackgroundImageColor",0x707070);
438 fillcol = GResourceFindColor("CharView.FillColor",0x80707070); /* Translucent */
439 tracecol = GResourceFindColor("CharView.TraceColor",0x008000);
440 rulerbigtickcol = GResourceFindColor("CharView.RulerBigTickColor",0x008000);
441 // previewfillcol = GResourceFindColor(,0x0f0f0f);
442 // The code below defaults differently from the static initializer (from which we copied this value).
443 if( GResourceFindColor("CharView.PreviewFillColor", COLOR_UNKNOWN) == COLOR_UNKNOWN ) {
444 // no explicit previewfillcolor
445 previewfillcol = fillcol;
446 if( GResourceFindColor("CharView.FillColor", COLOR_UNKNOWN) == COLOR_UNKNOWN ) {
447 // no explicit fill color either
448 previewfillcol = 0x000000;
449 }
450 }
451 DraggingComparisonOutlineColor = GResourceFindColor("CharView.DraggingComparisonOutlineColor",0x8800BB00);
452 DraggingComparisonAlphaChannelOverride = GResourceFindColor("CharView.DraggingComparisonAlphaChannelOverride",0x88000000);
453 foreoutthicklinecol = GResourceFindColor("CharView.ForegroundThickOutlineColor",0x20707070);
454 backoutthicklinecol = GResourceFindColor("CharView.BackgroundThickOutlineColor",0x20707070);
455 cvbutton3d = GResourceFindInt("CharView.Button3D", 1);
456 cvbutton3dedgelightcol = GResourceFindColor("CharView.Button3DEdgeLightColor", 0xe0e0e0);
457 cvbutton3dedgedarkcol = GResourceFindColor("CharView.Button3DEdgeDarkColor", 0x707070);
458 }
459
460
461 GDevEventMask input_em[] = {
462 /* Event masks for wacom devices */
463 /* negative utility in opening Mouse1 */
464 /* No point in distinguishing cursor from core mouse */
465 { (1<<et_mousemove)|(1<<et_mousedown)|(1<<et_mouseup)|(1<<et_char), "stylus" },
466 { (1<<et_mousemove)|(1<<et_mousedown)|(1<<et_mouseup), "eraser" },
467 { 0, NULL }
468 };
469 const int input_em_cnt = sizeof(input_em)/sizeof(input_em[0])-1;
470
471 /* Positions on the info line */
472 #define RPT_BASE 5 /* Place to draw the pointer icon */
473 #define RPT_DATA 13 /* x,y text after above */
474 #define SPT_BASE 83 /* Place to draw selected pt icon */
475 #define SPT_DATA 97 /* Any text for it */
476 #define SOF_BASE 157 /* Place to draw selection to pointer icon */
477 #define SOF_DATA 179 /* Any text for it */
478 #define SDS_BASE 259 /* Place to draw distance icon */
479 #define SDS_DATA 281 /* Any text for it */
480 #define SAN_BASE 331 /* Place to draw angle icon */
481 #define SAN_DATA 353 /* Any text for it */
482 #define MAG_BASE 383 /* Place to draw magnification icon */
483 #define MAG_DATA 394 /* Any text for it */
484 #define LAYER_DATA 454 /* Text to show the current layer */
485 #define CODERANGE_DATA 574 /* Text to show the current code range (if the debugger be active) */
486 #define FLAGS_DATA 724 /* Text to show the current drawmode flags */
487
CVGetActiveTab(CharView * cv)488 CharViewTab* CVGetActiveTab(CharView *cv) {
489 if (cv->tabs == NULL) {
490 // This happens when used by the bitmap view, which doesn't support tabs
491 return &cv->cvtabs[0];
492 }
493 int tab = GTabSetGetSel(cv->tabs);
494 return &cv->cvtabs[tab];
495 }
496
CVDrawRubberRect(GWindow pixmap,CharView * cv)497 void CVDrawRubberRect(GWindow pixmap, CharView *cv) {
498 GRect r;
499 CharViewTab *tab = CVGetActiveTab(cv);
500 if ( !cv->p.rubberbanding )
501 return;
502 r.x = tab->xoff + rint(cv->p.cx*tab->scale);
503 r.y = -tab->yoff + cv->height - rint(cv->p.cy*tab->scale);
504 r.width = rint( (cv->p.ex-cv->p.cx)*tab->scale);
505 r.height = -rint( (cv->p.ey-cv->p.cy)*tab->scale);
506 if ( r.width<0 ) {
507 r.x += r.width;
508 r.width = -r.width;
509 }
510 if ( r.height<0 ) {
511 r.y += r.height;
512 r.height = -r.height;
513 }
514 GDrawSetDashedLine(pixmap,2,2,0);
515 GDrawSetLineWidth(pixmap,0);
516 GDrawDrawRect(pixmap,&r,oldoutlinecol);
517 GDrawSetDashedLine(pixmap,0,0,0);
518 }
519
CVDrawRubberLine(GWindow pixmap,CharView * cv)520 static void CVDrawRubberLine(GWindow pixmap, CharView *cv) {
521 int x,y, xend,yend;
522 CharViewTab* tab = CVGetActiveTab(cv);
523 Color col = cv->active_tool==cvt_ruler ? measuretoollinecol : oldoutlinecol;
524 if ( !cv->p.rubberlining )
525 return;
526 x = tab->xoff + rint(cv->p.cx*tab->scale);
527 y = -tab->yoff + cv->height - rint(cv->p.cy*tab->scale);
528 xend = tab->xoff + rint(cv->info.x*tab->scale);
529 yend = -tab->yoff + cv->height - rint(cv->info.y*tab->scale);
530 GDrawSetLineWidth(pixmap,0);
531 GDrawDrawLine(pixmap,x,y,xend,yend,col);
532 }
533
CVDrawBB(CharView * cv,GWindow pixmap,DBounds * bb)534 static void CVDrawBB(CharView *cv, GWindow pixmap, DBounds *bb) {
535 GRect r;
536 CharViewTab* tab = CVGetActiveTab(cv);
537 int off = tab->xoff+cv->height-tab->yoff;
538
539 r.x = tab->xoff + rint(bb->minx*tab->scale);
540 r.y = -tab->yoff + cv->height - rint(bb->maxy*tab->scale);
541 r.width = rint((bb->maxx-bb->minx)*tab->scale);
542 r.height = rint((bb->maxy-bb->miny)*tab->scale);
543 GDrawSetDashedLine(pixmap,1,1,off);
544 GDrawDrawRect(pixmap,&r,GDrawGetDefaultForeground(NULL));
545 GDrawSetDashedLine(pixmap,0,0,0);
546 }
547
548 /* Sigh. I have to do my own clipping because at large magnifications */
549 /* things can easily exceed 16 bits */
CVSplineOutside(CharView * cv,Spline * spline)550 static int CVSplineOutside(CharView *cv, Spline *spline) {
551 CharViewTab* tab = CVGetActiveTab(cv);
552 int x[4], y[4];
553
554 x[0] = tab->xoff + rint(spline->from->me.x*tab->scale);
555 y[0] = -tab->yoff + cv->height - rint(spline->from->me.y*tab->scale);
556
557 x[1] = tab->xoff + rint(spline->to->me.x*tab->scale);
558 y[1] = -tab->yoff + cv->height - rint(spline->to->me.y*tab->scale);
559
560 if ( spline->from->nonextcp && spline->to->noprevcp ) {
561 if ( (x[0]<0 && x[1]<0) || (x[0]>=cv->width && x[1]>=cv->width) ||
562 (y[0]<0 && y[1]<0) || (y[0]>=cv->height && y[1]>=cv->height) )
563 return( true );
564 } else {
565 x[2] = tab->xoff + rint(spline->from->nextcp.x*tab->scale);
566 y[2] = -tab->yoff + cv->height - rint(spline->from->nextcp.y*tab->scale);
567 x[3] = tab->xoff + rint(spline->to->prevcp.x*tab->scale);
568 y[3] = -tab->yoff + cv->height - rint(spline->to->prevcp.y*tab->scale);
569 if ( (x[0]<0 && x[1]<0 && x[2]<0 && x[3]<0) ||
570 (x[0]>=cv->width && x[1]>=cv->width && x[2]>=cv->width && x[3]>=cv->width ) ||
571 (y[0]<0 && y[1]<0 && y[2]<0 && y[3]<0 ) ||
572 (y[0]>=cv->height && y[1]>=cv->height && y[2]>=cv->height && y[3]>=cv->height) )
573 return( true );
574 }
575
576 return( false );
577 }
578
CVLinesIntersectScreen(CharView * cv,LinearApprox * lap)579 static int CVLinesIntersectScreen(CharView *cv, LinearApprox *lap) {
580 CharViewTab* tab = CVGetActiveTab(cv);
581 LineList *l;
582 int any = false;
583 int x,y;
584 int bothout;
585
586 for ( l=lap->lines; l!=NULL; l=l->next ) {
587 l->asend.x = l->asstart.x = tab->xoff + l->here.x;
588 l->asend.y = l->asstart.y = -tab->yoff + cv->height-l->here.y;
589 l->flags = 0;
590 if ( l->asend.x<0 || l->asend.x>=cv->width || l->asend.y<0 || l->asend.y>=cv->height ) {
591 l->flags = cvli_clipped;
592 any = true;
593 }
594 }
595 if ( !any ) {
596 for ( l=lap->lines; l!=NULL; l=l->next )
597 l->flags = cvli_onscreen;
598 lap->any = true;
599 return( true );
600 }
601
602 any = false;
603 for ( l=lap->lines; l->next!=NULL; l=l->next ) {
604 if ( !(l->flags&cvli_clipped) && !(l->next->flags&cvli_clipped) )
605 l->flags = cvli_onscreen;
606 else {
607 bothout = (l->flags&cvli_clipped) && (l->next->flags&cvli_clipped);
608 if (( l->asstart.x<0 && l->next->asend.x>0 ) ||
609 ( l->asstart.x>0 && l->next->asend.x<0 )) {
610 y = -(l->next->asend.y-l->asstart.y)*(double)l->asstart.x/(l->next->asend.x-l->asstart.x) +
611 l->asstart.y;
612 if ( l->asstart.x<0 ) {
613 l->asstart.x = 0;
614 l->asstart.y = y;
615 } else {
616 l->next->asend.x = 0;
617 l->next->asend.y = y;
618 }
619 } else if ( l->asstart.x<0 && l->next->asend.x<0 )
620 continue;
621 if (( l->asstart.x<cv->width && l->next->asend.x>cv->width ) ||
622 ( l->asstart.x>cv->width && l->next->asend.x<cv->width )) {
623 y = (l->next->asend.y-l->asstart.y)*(double)(cv->width-l->asstart.x)/(l->next->asend.x-l->asstart.x) +
624 l->asstart.y;
625 if ( l->asstart.x>cv->width ) {
626 l->asstart.x = cv->width;
627 l->asstart.y = y;
628 } else {
629 l->next->asend.x = cv->width;
630 l->next->asend.y = y;
631 }
632 } else if ( l->asstart.x>cv->width && l->next->asend.x>cv->width )
633 continue;
634 if (( l->asstart.y<0 && l->next->asend.y>0 ) ||
635 ( l->asstart.y>0 && l->next->asend.y<0 )) {
636 x = -(l->next->asend.x-l->asstart.x)*(double)l->asstart.y/(l->next->asend.y-l->asstart.y) +
637 l->asstart.x;
638 if (( x<0 || x>=cv->width ) && bothout )
639 continue; /* Not on screen */;
640 if ( l->asstart.y<0 ) {
641 l->asstart.y = 0;
642 l->asstart.x = x;
643 } else {
644 l->next->asend.y = 0;
645 l->next->asend.x = x;
646 }
647 } else if ( l->asstart.y<0 && l->next->asend.y< 0 )
648 continue;
649 if (( l->asstart.y<cv->height && l->next->asend.y>cv->height ) ||
650 ( l->asstart.y>cv->height && l->next->asend.y<cv->height )) {
651 x = (l->next->asend.x-l->asstart.x)*(double)(cv->height-l->asstart.y)/(l->next->asend.y-l->asstart.y) +
652 l->asstart.x;
653 if (( x<0 || x>=cv->width ) && bothout )
654 continue; /* Not on screen */;
655 if ( l->asstart.y>cv->height ) {
656 l->asstart.y = cv->height;
657 l->asstart.x = x;
658 } else {
659 l->next->asend.y = cv->height;
660 l->next->asend.x = x;
661 }
662 } else if ( l->asstart.y>cv->height && l->next->asend.y>cv->height )
663 continue;
664 l->flags |= cvli_onscreen;
665 any = true;
666 }
667 }
668 lap->any = any;
669 return( any );
670 }
671
672 typedef struct gpl { struct gpl *next; GPoint *gp; int cnt; } GPointList;
673
GPLFree(GPointList * gpl)674 static void GPLFree(GPointList *gpl) {
675 GPointList *next;
676
677 while ( gpl!=NULL ) {
678 next = gpl->next;
679 free( gpl->gp );
680 free( gpl );
681 gpl = next;
682 }
683 }
684
685 /* Before we did clipping this was a single polygon. Now it is a set of */
686 /* sets of line segments. If no clipping is done, then we end up with */
687 /* one set which is the original polygon, otherwise we get the segments */
688 /* which are inside the screen. Each set of segments is contiguous */
MakePoly(CharView * cv,SplinePointList * spl)689 static GPointList *MakePoly(CharView *cv, SplinePointList *spl) {
690 int i, len;
691 LinearApprox *lap;
692 LineList *line, *prev;
693 Spline *spline, *first;
694 GPointList *head=NULL, *last=NULL, *cur;
695 int closed;
696
697 for ( i=0; i<2; ++i ) {
698 len = 0; first = NULL;
699 closed = true;
700 cur = NULL;
701 for ( spline = spl->first->next; spline!=NULL && spline!=first; spline=spline->to->next ) {
702 if ( !CVSplineOutside(cv,spline) && !isnan(spline->splines[0].a) && !isnan(spline->splines[1].a)) {
703 CharViewTab* tab = CVGetActiveTab(cv);
704 lap = SplineApproximate(spline,tab->scale);
705 if ( i==0 )
706 CVLinesIntersectScreen(cv,lap);
707 if ( lap->any ) {
708 for ( prev = lap->lines, line=prev->next; line!=NULL; prev=line, line=line->next ) {
709 if ( !(prev->flags&cvli_onscreen) ) {
710 closed = true;
711 continue;
712 }
713 if ( closed || (prev->flags&cvli_clipped) ) {
714 if ( i==0 ) {
715 cur = calloc(1,sizeof(GPointList));
716 if ( head==NULL )
717 head = cur;
718 else {
719 last->cnt = len;
720 last->next = cur;
721 }
722 last = cur;
723 } else {
724 if ( cur==NULL )
725 cur = head;
726 else
727 cur = cur->next;
728 cur->gp = malloc(cur->cnt*sizeof(GPoint));
729 cur->gp[0].x = prev->asstart.x;
730 cur->gp[0].y = prev->asstart.y;
731 }
732 len=1;
733 closed = false;
734 }
735 if ( i!=0 ) {
736 if ( len>=cur->cnt )
737 fprintf( stderr, "Clipping is screwed up, about to die %d (should be less than %d)\n", len, cur->cnt );
738 cur->gp[len].x = line->asend.x;
739 cur->gp[len].y = line->asend.y;
740 }
741 ++len;
742 if ( line->flags&cvli_clipped )
743 closed = true;
744 }
745 } else
746 closed = true;
747 } else
748 closed = true;
749 if ( first==NULL ) first = spline;
750 }
751 if ( i==0 && cur!=NULL )
752 cur->cnt = len;
753 }
754 return( head );
755 }
756
DrawTangentPoint(GWindow pixmap,int x,int y,BasePoint * unit,int outline,Color col)757 static void DrawTangentPoint( GWindow pixmap, int x, int y,
758 BasePoint *unit, int outline, Color col )
759 {
760 int dir;
761 const int gp_sz = 4;
762 GPoint gp[5];
763
764 dir = 0;
765 if ( unit->x!=0 || unit->y!=0 ) {
766 float dx = unit->x, dy = unit->y;
767 if ( dx<0 ) dx= -dx;
768 if ( dy<0 ) dy= -dy;
769 if ( dx>2*dy ) {
770 if ( unit->x>0 ) dir = 0 /* right */;
771 else dir = 1 /* left */;
772 } else if ( dy>2*dx ) {
773 if ( unit->y>0 ) dir = 2 /* up */;
774 else dir = 3 /* down */;
775 } else {
776 if ( unit->y>0 && unit->x>0 ) dir=4;
777 else if ( unit->x>0 ) dir=5;
778 else if ( unit->y>0 ) dir=7;
779 else dir = 6;
780 }
781 }
782
783 float sizedelta = 4;
784 if( prefs_cvEditHandleSize > prefs_cvEditHandleSize_default )
785 sizedelta *= prefs_cvEditHandleSize / prefs_cvEditHandleSize_default;
786
787 if ( dir==1 /* left */ || dir==0 /* right */) {
788 gp[0].y = y; gp[0].x = (dir==0)?x+sizedelta:x-sizedelta;
789 gp[1].y = y-sizedelta; gp[1].x = x;
790 gp[2].y = y+sizedelta; gp[2].x = x;
791 } else if ( dir==2 /* up */ || dir==3 /* down */ ) {
792 gp[0].x = x; gp[0].y = dir==2?y-sizedelta:y+sizedelta; /* remember screen coordinates are backwards in y from character coords */
793 gp[1].x = x-sizedelta; gp[1].y = y;
794 gp[2].x = x+sizedelta; gp[2].y = y;
795 } else {
796 /* at a 45 angle, a value of 4 looks too small. I probably want 4*1.414 */
797 sizedelta = 5;
798 if( prefs_cvEditHandleSize > prefs_cvEditHandleSize_default )
799 sizedelta *= prefs_cvEditHandleSize / prefs_cvEditHandleSize_default;
800 int xdiff = unit->x > 0 ? sizedelta : -1*sizedelta;
801 int ydiff = unit->y > 0 ? -1*sizedelta : sizedelta;
802
803 gp[0].x = x+xdiff/2; gp[0].y = y+ydiff/2;
804 gp[1].x = gp[0].x-xdiff; gp[1].y = gp[0].y;
805 gp[2].x = gp[0].x; gp[2].y = gp[0].y-ydiff;
806 }
807 gp[3] = gp[0];
808 if ( outline )
809 GDrawDrawPoly(pixmap,gp,gp_sz,col);
810 else
811 GDrawFillPoly(pixmap,gp,4,col);
812 }
813
DrawPoint_SetupRectForSize(GRect * r,int cx,int cy,float sz)814 static GRect* DrawPoint_SetupRectForSize( GRect* r, int cx, int cy, float sz )
815 {
816 float sizedelta = sz;
817 if( prefs_cvEditHandleSize > prefs_cvEditHandleSize_default )
818 sizedelta *= prefs_cvEditHandleSize / prefs_cvEditHandleSize_default;
819
820 r->x = cx - sizedelta;
821 r->y = cy - sizedelta;
822 r->width = 1 + sizedelta * 2;
823 r->height = 1 + sizedelta * 2;
824 return r;
825 }
826
827
MaybeMaskColorToAlphaChannelOverride(Color c,Color AlphaChannelOverride)828 static Color MaybeMaskColorToAlphaChannelOverride( Color c, Color AlphaChannelOverride )
829 {
830 if( AlphaChannelOverride )
831 {
832 c &= 0x00FFFFFF;
833 c |= (AlphaChannelOverride & 0xFF000000);
834 }
835 return c;
836 }
837
838 /*
839 * Format the given real value to .001 precision, discarding trailing
840 * zeroes, and the decimal point if not needed.
841 */
FmtReal(char * buf,int buflen,real r)842 static int FmtReal(char *buf, int buflen, real r)
843 {
844 if (buf && buflen > 0) {
845 int ct;
846
847 if ((ct = snprintf(buf, buflen, "%.3f", r)) >= buflen)
848 ct = buflen-1;
849
850 if (strchr(buf, '.')) {
851 while (buf[ct-1] == '0') {
852 --ct;
853 }
854 if (buf[ct-1] == '.') {
855 --ct;
856 }
857 buf[ct] = '\0';
858 }
859 return ct;
860 }
861 return -1;
862 }
863
864 /*
865 * Write the given spline point's coordinates in the form (xxx,yyy)
866 * into the buffer provided, rounding fractions to the nearest .001
867 * and discarding trailing zeroes.
868 */
SplinePointCoords(char * buf,int buflen,SplinePoint * sp)869 static int SplinePointCoords(char *buf, int buflen, SplinePoint *sp)
870 {
871 if (buf && buflen > 0) {
872 int ct = 0, clen;
873
874 /* 4 chars for parens, comma and trailing NUL, then divide what
875 remains between the two coords */
876 clen = (buflen - 4) / 2;
877 if (clen > 0) {
878 buf[ct++] = '(';
879 ct += FmtReal(buf+ct, clen, sp->me.x);
880 buf[ct++] = ',';
881 ct += FmtReal(buf+ct, clen, sp->me.y);
882 buf[ct++] = ')';
883 }
884 buf[ct] = '\0';
885
886 return ct;
887 }
888 return -1;
889 }
890
DrawPoint(CharView * cv,GWindow pixmap,SplinePoint * sp,SplineSet * spl,int onlynumber,int truetype_markup,Color AlphaChannelOverride)891 static void DrawPoint( CharView *cv, GWindow pixmap, SplinePoint *sp,
892 SplineSet *spl, int onlynumber, int truetype_markup,
893 Color AlphaChannelOverride )
894 {
895 GRect r;
896 int x, y, cx, cy;
897 CharViewTab* tab = CVGetActiveTab(cv);
898 Color col = sp==spl->first ? firstpointcol : pointcol;
899 int pnum;
900 char buf[16];
901 int isfake;
902
903 if ( cv->markextrema && SpIsExtremum(sp) && sp!=spl->first )
904 col = extremepointcol;
905 if ( sp->selected )
906 col = selectedpointcol;
907 else {
908 col = col&0x00ffffff;
909 col |= prefs_cvInactiveHandleAlpha << 24;
910 }
911
912 col = MaybeMaskColorToAlphaChannelOverride( col, AlphaChannelOverride );
913 Color subcolmasked = MaybeMaskColorToAlphaChannelOverride( subcol, AlphaChannelOverride );
914 Color nextcpcolmasked = MaybeMaskColorToAlphaChannelOverride( nextcpcol, AlphaChannelOverride );
915 Color prevcpcolmasked = MaybeMaskColorToAlphaChannelOverride( prevcpcol, AlphaChannelOverride );
916 Color selectedpointcolmasked = MaybeMaskColorToAlphaChannelOverride( selectedpointcol, AlphaChannelOverride );
917 Color selectedcpcolmasked = MaybeMaskColorToAlphaChannelOverride( selectedcpcol, AlphaChannelOverride );
918
919 x = tab->xoff + rint(sp->me.x*tab->scale);
920 y = -tab->yoff + cv->height - rint(sp->me.y*tab->scale);
921 if ( x<-4000 || y<-4000 || x>cv->width+4000 || y>=cv->height+4000 )
922 return;
923
924 /* draw the control points if it's selected */
925 if ( sp->selected
926 || cv->showpointnumbers
927 || cv->alwaysshowcontrolpoints
928 || cv->show_ft_results
929 || cv->dv )
930 {
931 if ( !sp->nonextcp ) {
932 cx = tab->xoff + rint(sp->nextcp.x*tab->scale);
933 cy = -tab->yoff + cv->height - rint(sp->nextcp.y*tab->scale);
934 if ( cx<-100 ) { /* Clip */
935 cy = cx==x ? x : (cy-y) * (double)(-100-x)/(cx-x) + y;
936 cx = -100;
937 } else if ( cx>cv->width+100 ) {
938 cy = cx==x ? x : (cy-y) * (double)(cv->width+100-x)/(cx-x) + y;
939 cx = cv->width+100;
940 }
941 if ( cy<-100 ) {
942 cx = cy==y ? y : (cx-x) * (double)(-100-y)/(cy-y) + x;
943 cy = -100;
944 } else if ( cy>cv->height+100 ) {
945 cx = cy==y ? y : (cx-x) * (double)(cv->height+100-y)/(cy-y) + x;
946 cy = cv->height+100;
947 }
948 subcolmasked = nextcpcolmasked;
949
950 //
951 // If the next BCP is selected we should decorate the
952 // drawing to let the user know that. The primary (last)
953 // selected BCP is drawn with a backing rectangle of size
954 // 3, the secondary BCP (2nd, 3rd, 4th last selected BCP)
955 // are drawn with slightly smaller highlights.
956 //
957 if( !onlynumber && SPIsNextCPSelected( sp, cv ))
958 {
959 float sz = 2;
960 if( SPIsNextCPSelectedSingle( sp, cv ))
961 sz *= 1.5;
962
963 DrawPoint_SetupRectForSize( &r, cx, cy, sz );
964 GDrawFillRect(pixmap,&r, nextcpcol);
965 subcolmasked = selectedcpcolmasked;
966 }
967 else if ( truetype_markup )
968 {
969 if ( sp->flexy ) {
970 /* cp is about to be moved (or changed in some other way) */
971 DrawPoint_SetupRectForSize( &r, cx, cy, 3 );
972 GDrawFillRect(pixmap,&r, selectedpointcol);
973 }
974 if ( sp->flexx ) {
975 /* cp is a reference point */
976 DrawPoint_SetupRectForSize( &r, cx, cy, 5 );
977 GDrawDrawElipse(pixmap,&r,selectedpointcol );
978 }
979 }
980 if ( !onlynumber )
981 {
982 float sizedelta = 3;
983 if( prefs_cvEditHandleSize > prefs_cvEditHandleSize_default )
984 sizedelta *= prefs_cvEditHandleSize / prefs_cvEditHandleSize_default;
985 GDrawDrawLine(pixmap,x,y,cx,cy, nextcpcolmasked );
986 GDrawDrawLine(pixmap,cx-sizedelta,cy-sizedelta,cx+sizedelta,cy+sizedelta,subcolmasked);
987 GDrawDrawLine(pixmap,cx+sizedelta,cy-sizedelta,cx-sizedelta,cy+sizedelta,subcolmasked);
988 }
989 if ( cv->showpointnumbers || cv->show_ft_results || cv->dv ) {
990 pnum = sp->nextcpindex;
991 if ( pnum!=0xffff && pnum!=0xfffe ) {
992 if (cv->showpointnumbers == 2)
993 SplinePointCoords( buf, sizeof(buf), sp);
994 else
995 sprintf( buf,"%d", pnum );
996 GDrawDrawText8(pixmap,cx,cy-6,buf,-1,nextcpcol);
997 }
998 }
999 }
1000 if ( !sp->noprevcp ) {
1001 cx = tab->xoff + rint(sp->prevcp.x*tab->scale);
1002 cy = -tab->yoff + cv->height - rint(sp->prevcp.y*tab->scale);
1003 if ( cx<-100 ) { /* Clip */
1004 cy = cx==x ? x : (cy-y) * (double)(-100-x)/(cx-x) + y;
1005 cx = -100;
1006 } else if ( cx>cv->width+100 ) {
1007 cy = cx==x ? x : (cy-y) * (double)(cv->width+100-x)/(cx-x) + y;
1008 cx = cv->width+100;
1009 }
1010 if ( cy<-100 ) {
1011 cx = cy==y ? y : (cx-x) * (double)(-100-y)/(cy-y) + x;
1012 cy = -100;
1013 } else if ( cy>cv->height+100 ) {
1014 cx = cy==y ? y : (cx-x) * (double)(cv->height+100-y)/(cy-y) + x;
1015 cy = cv->height+100;
1016 }
1017 subcolmasked = prevcpcolmasked;
1018 if( !onlynumber && SPIsPrevCPSelected( sp, cv ))
1019 {
1020 float sz = 2;
1021 if( SPIsPrevCPSelectedSingle( sp, cv ))
1022 sz *= 1.5;
1023 DrawPoint_SetupRectForSize( &r, cx, cy, sz );
1024 GDrawFillRect(pixmap,&r, prevcpcol);
1025 subcolmasked = selectedcpcolmasked;
1026 }
1027 if ( !onlynumber ) {
1028 float sizedelta = 3;
1029 if( prefs_cvEditHandleSize > prefs_cvEditHandleSize_default )
1030 sizedelta *= prefs_cvEditHandleSize / prefs_cvEditHandleSize_default;
1031 GDrawDrawLine(pixmap,x,y,cx,cy, prevcpcolmasked);
1032 GDrawDrawLine(pixmap,cx-sizedelta,cy-sizedelta,cx+sizedelta,cy+sizedelta,subcolmasked);
1033 GDrawDrawLine(pixmap,cx+sizedelta,cy-sizedelta,cx-sizedelta,cy+sizedelta,subcolmasked);
1034 }
1035 }
1036 }
1037
1038 if ( x<-4 || y<-4 || x>cv->width+4 || y>=cv->height+4 )
1039 return;
1040 r.x = x-2;
1041 r.y = y-2;
1042 r.width = r.height = 0;
1043 r.width += prefs_cvEditHandleSize;
1044 r.height += prefs_cvEditHandleSize;
1045 if ( sp->selected )
1046 GDrawSetLineWidth(pixmap,selectedpointwidth);
1047 isfake = false;
1048 if ( cv->b.layerheads[cv->b.drawmode]->order2 &&
1049 cv->b.layerheads[cv->b.drawmode]->refs==NULL )
1050 {
1051 int mightbe_fake = SPInterpolate(sp);
1052 if ( !mightbe_fake && sp->ttfindex==0xffff )
1053 sp->ttfindex = 0xfffe; /* if we have no instructions we won't call instrcheck and won't notice when a point stops being fake */
1054 else if ( mightbe_fake )
1055 sp->ttfindex = 0xffff;
1056 isfake = sp->ttfindex==0xffff;
1057 }
1058 if ( onlynumber )
1059 {
1060 /* Draw Nothing */;
1061 }
1062 else if ( sp->pointtype==pt_curve )
1063 {
1064 r.width +=2; r.height += 2;
1065 r.x = x - r.width / 2;
1066 r.y = y - r.height / 2;
1067 if ( sp->selected || isfake )
1068 GDrawDrawElipse(pixmap,&r,col);
1069 else
1070 GDrawFillElipse(pixmap,&r,col);
1071 }
1072 else if ( sp->pointtype==pt_corner )
1073 {
1074 r.x = x - r.width / 2;
1075 r.y = y - r.height / 2;
1076 if ( sp->selected || isfake )
1077 GDrawDrawRect(pixmap,&r,col);
1078 else
1079 GDrawFillRect(pixmap,&r,col);
1080 }
1081 else if ( sp->pointtype==pt_hvcurve )
1082 {
1083 const int gp_sz = 5;
1084 GPoint gp[5];
1085
1086 float sizedelta = 3;
1087 float offsetdelta = 0; // 4 * tab->scale;
1088 if( prefs_cvEditHandleSize > prefs_cvEditHandleSize_default )
1089 {
1090 sizedelta *= prefs_cvEditHandleSize / prefs_cvEditHandleSize_default;
1091 offsetdelta *= prefs_cvEditHandleSize / prefs_cvEditHandleSize_default;
1092 }
1093
1094 float basex = r.x + 3 + offsetdelta;
1095 float basey = r.y + 3 + offsetdelta;
1096 gp[0].x = basex - sizedelta; gp[0].y = basey + 0;
1097 gp[1].x = basex + 0; gp[1].y = basey + sizedelta;
1098 gp[2].x = basex + sizedelta; gp[2].y = basey + 0;
1099 gp[3].x = basex + 0; gp[3].y = basey - sizedelta;
1100 gp[4] = gp[0];
1101
1102 if ( sp->selected || isfake )
1103 GDrawDrawPoly(pixmap,gp,gp_sz,col);
1104 else
1105 GDrawFillPoly(pixmap,gp,gp_sz,col);
1106 }
1107 else
1108 {
1109 BasePoint *cp=NULL;
1110 BasePoint unit;
1111
1112 if ( !sp->nonextcp )
1113 cp = &sp->nextcp;
1114 else if ( !sp->noprevcp )
1115 cp = &sp->prevcp;
1116 memset(&unit,0,sizeof(unit));
1117 if ( cp!=NULL ) {
1118 unit.x = cp->x-sp->me.x; unit.y = cp->y-sp->me.y;
1119 }
1120 DrawTangentPoint(pixmap, x, y, &unit, sp->selected || isfake, col);
1121 }
1122 GDrawSetLineWidth(pixmap,0);
1123 if ( (cv->showpointnumbers || cv->show_ft_results || cv->dv )
1124 && sp->ttfindex!=0xffff )
1125 {
1126 if ( sp->ttfindex==0xfffe )
1127 strcpy(buf,"??");
1128 else if (cv->showpointnumbers == 2)
1129 SplinePointCoords(buf, sizeof(buf), sp);
1130 else
1131 sprintf( buf,"%d", sp->ttfindex );
1132 GDrawDrawText8(pixmap,x,y-6,buf,-1,col);
1133 }
1134 if ( truetype_markup && sp->roundx ) {
1135 r.x = x-5; r.y = y-5;
1136 r.width = r.height = 11;
1137 GDrawDrawElipse(pixmap,&r,selectedpointcolmasked);
1138 } else if ( !onlynumber && !truetype_markup ) {
1139 if ((( sp->roundx || sp->roundy ) &&
1140 (((cv->showrounds&1) && tab->scale>=.3) || (cv->showrounds&2))) ||
1141 (sp->watched && cv->dv!=NULL) ||
1142 sp->hintmask!=NULL ) {
1143 r.x = x-5; r.y = y-5;
1144 r.width = r.height = 11;
1145 GDrawDrawElipse(pixmap,&r,col);
1146 }
1147 if (( sp->flexx && cv->showhhints ) || (sp->flexy && cv->showvhints)) {
1148 r.x = x-5; r.y = y-5;
1149 r.width = r.height = 11;
1150 GDrawDrawElipse(pixmap,&r,
1151 MaybeMaskColorToAlphaChannelOverride( sp->flexx ? hflexhintcol : vflexhintcol,
1152 AlphaChannelOverride ));
1153 }
1154 }
1155 }
1156
DrawSpiroPoint(CharView * cv,GWindow pixmap,spiro_cp * cp,SplineSet * spl,int cp_i,Color AlphaChannelOverride)1157 static void DrawSpiroPoint( CharView *cv, GWindow pixmap, spiro_cp *cp,
1158 SplineSet *spl, int cp_i, Color AlphaChannelOverride )
1159 {
1160 CharViewTab* tab = CVGetActiveTab(cv);
1161 GRect r;
1162 int x, y;
1163 Color col = cp==&spl->spiros[0] ? firstpointcol : pointcol;
1164 char ty = cp->ty&0x7f;
1165 int selected = SPIRO_SELECTED(cp);
1166 GPoint gp[5];
1167
1168 if ( selected )
1169 col = selectedpointcol;
1170
1171 if( !selected )
1172 {
1173 col = col & 0x00ffffff;
1174 col |= prefs_cvInactiveHandleAlpha << 24;
1175 }
1176
1177 col = MaybeMaskColorToAlphaChannelOverride( col, AlphaChannelOverride );
1178
1179
1180 x = tab->xoff + rint(cp->x*tab->scale);
1181 y = -tab->yoff + cv->height - rint(cp->y*tab->scale);
1182 if ( x<-4 || y<-4 || x>cv->width+4 || y>=cv->height+4 )
1183 return;
1184
1185 DrawPoint_SetupRectForSize( &r, x, y, 2 );
1186 /* r.x = x-2; */
1187 /* r.y = y-2; */
1188 /* r.width = r.height = 5; */
1189 if ( selected )
1190 GDrawSetLineWidth(pixmap,selectedpointwidth);
1191
1192 float sizedelta = 3;
1193 if( prefs_cvEditHandleSize > prefs_cvEditHandleSize_default )
1194 sizedelta *= prefs_cvEditHandleSize / prefs_cvEditHandleSize_default;
1195
1196 if ( ty == SPIRO_RIGHT ) {
1197 GDrawSetLineWidth(pixmap,2);
1198 gp[0].x = x-sizedelta; gp[0].y = y-sizedelta;
1199 gp[1].x = x; gp[1].y = y-sizedelta;
1200 gp[2].x = x; gp[2].y = y+sizedelta;
1201 gp[3].x = x-sizedelta; gp[3].y = y+sizedelta;
1202 GDrawDrawPoly(pixmap,gp,4,col);
1203 } else if ( ty == SPIRO_LEFT ) {
1204 GDrawSetLineWidth(pixmap,2);
1205 gp[0].x = x+sizedelta; gp[0].y = y-sizedelta;
1206 gp[1].x = x; gp[1].y = y-sizedelta;
1207 gp[2].x = x; gp[2].y = y+sizedelta;
1208 gp[3].x = x+sizedelta; gp[3].y = y+sizedelta;
1209 GDrawDrawPoly(pixmap,gp,4,col);
1210 } else if ( ty == SPIRO_G2 ) {
1211 GPoint gp[5];
1212
1213 float sizedelta = 3;
1214 float offsetdelta = 1;
1215 if( prefs_cvEditHandleSize > prefs_cvEditHandleSize_default )
1216 {
1217 sizedelta *= prefs_cvEditHandleSize / prefs_cvEditHandleSize_default;
1218 offsetdelta *= prefs_cvEditHandleSize / prefs_cvEditHandleSize_default;
1219 }
1220
1221 float basex = r.x + 1 + offsetdelta;
1222 float basey = r.y + 1 + offsetdelta;
1223 gp[0].x = basex - sizedelta; gp[0].y = basey + 0;
1224 gp[1].x = basex + 0; gp[1].y = basey + sizedelta;
1225 gp[2].x = basex + sizedelta; gp[2].y = basey + 0;
1226 gp[3].x = basex + 0; gp[3].y = basey - sizedelta;
1227 gp[4] = gp[0];
1228 if ( selected )
1229 GDrawDrawPoly(pixmap,gp,5,col);
1230 else
1231 GDrawFillPoly(pixmap,gp,5,col);
1232 } else if ( ty==SPIRO_CORNER ) {
1233 if ( selected )
1234 GDrawDrawRect(pixmap,&r,col);
1235 else
1236 GDrawFillRect(pixmap,&r,col);
1237 } else {
1238 --r.x; --r.y; r.width +=2; r.height += 2;
1239 if ( selected )
1240 GDrawDrawElipse(pixmap,&r,col);
1241 else
1242 GDrawFillElipse(pixmap,&r,col);
1243 }
1244 GDrawSetLineWidth(pixmap,0);
1245 }
1246
DrawLine(CharView * cv,GWindow pixmap,real x1,real y1,real x2,real y2,Color fg)1247 static void DrawLine(CharView *cv, GWindow pixmap,
1248 real x1, real y1, real x2, real y2, Color fg) {
1249 CharViewTab* tab = CVGetActiveTab(cv);
1250 int ix1 = tab->xoff + rint(x1*tab->scale);
1251 int iy1 = -tab->yoff + cv->height - rint(y1*tab->scale);
1252 int ix2 = tab->xoff + rint(x2*tab->scale);
1253 int iy2 = -tab->yoff + cv->height - rint(y2*tab->scale);
1254 if ( iy1==iy2 ) {
1255 if ( iy1<0 || iy1>cv->height )
1256 return;
1257 if ( ix1<0 ) ix1 = 0;
1258 if ( ix2>cv->width ) ix2 = cv->width;
1259 } else if ( ix1==ix2 ) {
1260 if ( ix1<0 || ix1>cv->width )
1261 return;
1262 if ( iy1<0 ) iy1 = 0;
1263 if ( iy2<0 ) iy2 = 0;
1264 if ( iy1>cv->height ) iy1 = cv->height;
1265 if ( iy2>cv->height ) iy2 = cv->height;
1266 }
1267 GDrawDrawLine(pixmap, ix1,iy1, ix2,iy2, fg );
1268 }
1269
DrawDirection(CharView * cv,GWindow pixmap,SplinePoint * sp)1270 static void DrawDirection(CharView *cv,GWindow pixmap, SplinePoint *sp) {
1271 BasePoint dir, *other;
1272 double len;
1273 CharViewTab* tab = CVGetActiveTab(cv);
1274 int x,y,xe,ye;
1275 SplinePoint *test;
1276
1277 if ( sp->next==NULL )
1278 return;
1279
1280 x = tab->xoff + rint(sp->me.x*tab->scale);
1281 y = -tab->yoff + cv->height - rint(sp->me.y*tab->scale);
1282 if ( x<0 || y<0 || x>cv->width || y>cv->width )
1283 return;
1284
1285 /* Werner complained when the first point and the second point were at */
1286 /* the same location... */ /* Damn. They weren't at the same location */
1287 /* the were off by a rounding error. I'm not going to fix for that */
1288 for ( test=sp; ; ) {
1289 if ( test->me.x!=sp->me.x || test->me.y!=sp->me.y ) {
1290 other = &test->me;
1291 break;
1292 } else if ( !test->nonextcp ) {
1293 other = &test->nextcp;
1294 break;
1295 }
1296 if ( test->next==NULL )
1297 return;
1298 test = test->next->to;
1299 if ( test==sp )
1300 return;
1301 }
1302
1303 dir.x = other->x-sp->me.x;
1304 dir.y = sp->me.y-other->y; /* screen coordinates are the mirror of user coords */
1305 len = sqrt(dir.x*dir.x + dir.y*dir.y);
1306 dir.x /= len; dir.y /= len;
1307
1308 x += rint(5*dir.y);
1309 y -= rint(5*dir.x);
1310 xe = x + rint(7*dir.x);
1311 ye = y + rint(7*dir.y);
1312 GDrawDrawLine(pixmap,x,y,xe,ye,firstpointcol);
1313 GDrawDrawLine(pixmap,xe,ye,xe+rint(2*(dir.y-dir.x)),ye+rint(2*(-dir.y-dir.x)), firstpointcol);
1314 GDrawDrawLine(pixmap,xe,ye,xe+rint(2*(-dir.y-dir.x)),ye+rint(2*(dir.x-dir.y)), firstpointcol);
1315 }
1316
CVMarkInterestingLocations(CharView * cv,GWindow pixmap,SplinePointList * spl)1317 static void CVMarkInterestingLocations(CharView *cv, GWindow pixmap,
1318 SplinePointList *spl) {
1319 Spline *s, *first;
1320 extended interesting[6];
1321 CharViewTab* tab = CVGetActiveTab(cv);
1322 int i, ecnt, cnt;
1323 GRect r;
1324
1325 for ( s=spl->first->next, first=NULL; s!=NULL && s!=first; s=s->to->next ) {
1326 if ( first==NULL ) first = s;
1327 cnt = ecnt = 0;
1328 if ( cv->markextrema )
1329 ecnt = cnt = Spline2DFindExtrema(s,interesting);
1330
1331 if ( cv->markpoi ) {
1332 cnt += Spline2DFindPointsOfInflection(s,interesting+cnt);
1333 }
1334 r.width = r.height = 9;
1335 for ( i=0; i<cnt; ++i ) if ( interesting[i]>0 && interesting[i]<1.0 ) {
1336 Color col = i<ecnt ? extremepointcol : pointofinflectioncol;
1337 double x = ((s->splines[0].a*interesting[i]+s->splines[0].b)*interesting[i]+s->splines[0].c)*interesting[i]+s->splines[0].d;
1338 double y = ((s->splines[1].a*interesting[i]+s->splines[1].b)*interesting[i]+s->splines[1].c)*interesting[i]+s->splines[1].d;
1339 double sx = tab->xoff + rint(x*tab->scale);
1340 double sy = -tab->yoff + cv->height - rint(y*tab->scale);
1341 if ( sx<-5 || sy<-5 || sx>10000 || sy>10000 )
1342 continue;
1343 GDrawDrawLine(pixmap,sx-4,sy,sx+4,sy, col);
1344 GDrawDrawLine(pixmap,sx,sy-4,sx,sy+4, col);
1345 r.x = sx-4; r.y = sy-4;
1346 GDrawDrawElipse(pixmap,&r,col);
1347 }
1348 }
1349 }
1350
CVMarkAlmostHV(CharView * cv,GWindow pixmap,SplinePointList * spl)1351 static void CVMarkAlmostHV(CharView *cv, GWindow pixmap,
1352 SplinePointList *spl) {
1353 Spline *s, *first;
1354 double dx, dy;
1355 int x1,x2,y1,y2;
1356 CharViewTab* tab = CVGetActiveTab(cv);
1357
1358 for ( s=spl->first->next, first=NULL; s!=NULL && s!=first; s=s->to->next ) {
1359 if ( first==NULL ) first = s;
1360
1361 if ( s->islinear ) {
1362 if ( !cv->showalmosthvlines )
1363 continue;
1364 if ( (dx = s->from->me.x - s->to->me.x)<0 ) dx = -dx;
1365 if ( (dy = s->from->me.y - s->to->me.y)<0 ) dy = -dy;
1366 if ( dx<=cv->hvoffset && dy<=cv->hvoffset )
1367 continue;
1368 if ( dx==0 || dy==0 )
1369 continue;
1370 if ( dx<cv->hvoffset || dy<cv->hvoffset ) {
1371 x1 = tab->xoff + rint(s->from->me.x*tab->scale);
1372 y1 = -tab->yoff + cv->height - rint(s->from->me.y*tab->scale);
1373 x2 = tab->xoff + rint(s->to->me.x*tab->scale);
1374 y2 = -tab->yoff + cv->height - rint(s->to->me.y*tab->scale);
1375 GDrawDrawLine(pixmap,x1,y1,x2,y2,almosthvcol);
1376 }
1377 } else {
1378 if ( !cv->showalmosthvcurves )
1379 continue;
1380 if ( (dx = s->from->me.x - s->from->nextcp.x)<0 ) dx = -dx;
1381 if ( (dy = s->from->me.y - s->from->nextcp.y)<0 ) dy = -dy;
1382 if ( dx<=cv->hvoffset && dy<=cv->hvoffset )
1383 /* Ignore */;
1384 else if ( dx==0 || dy==0 )
1385 /* It's right */;
1386 else if ( dx<cv->hvoffset || dy<cv->hvoffset ) {
1387 x2 = x1 = tab->xoff + rint(s->from->me.x*tab->scale);
1388 y2 = y1 = -tab->yoff + cv->height - rint(s->from->me.y*tab->scale);
1389 if ( dx<cv->hvoffset ) {
1390 if ( s->from->me.y<s->from->nextcp.y )
1391 y2 += 15;
1392 else
1393 y2 -= 15;
1394 } else {
1395 if ( s->from->me.x<s->from->nextcp.x )
1396 x2 += 15;
1397 else
1398 x2 -= 15;
1399 }
1400 GDrawDrawLine(pixmap,x1,y1,x2,y2,almosthvcol);
1401 }
1402
1403 if ( (dx = s->to->me.x - s->to->prevcp.x)<0 ) dx = -dx;
1404 if ( (dy = s->to->me.y - s->to->prevcp.y)<0 ) dy = -dy;
1405 if ( dx<=cv->hvoffset && dy<=cv->hvoffset )
1406 /* Ignore */;
1407 else if ( dx==0 || dy==0 )
1408 /* It's right */;
1409 else if ( dx<cv->hvoffset || dy<cv->hvoffset ) {
1410 x2 = x1 = tab->xoff + rint(s->to->me.x*tab->scale);
1411 y2 = y1 = -tab->yoff + cv->height - rint(s->to->me.y*tab->scale);
1412 if ( dx<cv->hvoffset ) {
1413 if ( s->to->me.y<s->to->prevcp.y )
1414 y2 += 15;
1415 else
1416 y2 -= 15;
1417 } else {
1418 if ( s->to->me.x<s->to->prevcp.x )
1419 x2 += 15;
1420 else
1421 x2 -= 15;
1422 }
1423 GDrawDrawLine(pixmap,x1,y1,x2,y2,almosthvcol);
1424 }
1425 }
1426 }
1427 }
1428
CVDrawPointName(CharView * cv,GWindow pixmap,SplinePoint * sp,Color fg)1429 static void CVDrawPointName(CharView *cv, GWindow pixmap, SplinePoint *sp, Color fg)
1430 {
1431 CharViewTab* tab = CVGetActiveTab(cv);
1432 if (sp->name && *sp->name) {
1433 int32 theight;
1434
1435 GDrawSetFont(pixmap, cv->normal);
1436 theight = GDrawGetText8Height(pixmap, sp->name, -1);
1437 GDrawDrawText8(pixmap,
1438 tab->xoff + rint(sp->me.x*tab->scale),
1439 cv->height-tab->yoff - rint(sp->me.y*tab->scale) + theight + 3,
1440 sp->name,-1,fg);
1441 GDrawSetFont(pixmap,cv->small); /* For point numbers */
1442 }
1443 }
1444
CVDrawContourName(CharView * cv,GWindow pixmap,SplinePointList * ss,Color fg)1445 static void CVDrawContourName(CharView *cv, GWindow pixmap, SplinePointList *ss,
1446 Color fg ) {
1447 SplinePoint *sp, *topright;
1448 GPoint tr;
1449 CharViewTab* tab = CVGetActiveTab(cv);
1450
1451 /* Find the top right point of the contour. This is where we will put the */
1452 /* label */
1453 for ( sp = topright = ss->first; ; ) {
1454 if ( sp->me.y>topright->me.y || (sp->me.y==topright->me.y && sp->me.x>topright->me.x) )
1455 topright = sp;
1456 if ( sp->next==NULL )
1457 break;
1458 sp = sp->next->to;
1459 if ( sp==ss->first )
1460 break;
1461 }
1462 tr.x = tab->xoff + rint(topright->me.x*tab->scale);
1463 tr.y = cv->height-tab->yoff - rint(topright->me.y*tab->scale);
1464
1465 /* If the top edge of the contour is off the bottom of the screen */
1466 /* then the contour won't show */
1467 if ( tr.y>cv->height )
1468 return;
1469
1470 GDrawSetFont(pixmap,cv->normal);
1471
1472 if ( ss->first->prev==NULL && ss->first->next!=NULL &&
1473 ss->first->next->to->next==NULL && ss->first->next->knownlinear &&
1474 (tr.y < cv->nfh || tr.x>cv->width-cv->nfh) ) {
1475 /* It's a simple line */
1476 /* A special case because: It's common, and it's important to get it */
1477 /* right and label lines even if the point to which we'd normally */
1478 /* attach a label is offscreen */
1479 SplinePoint *sp1 = ss->first, *sp2 = ss->first->next->to;
1480 double dx, dy, slope, off, yinter, xinter;
1481
1482 if ( (dx = sp1->me.x-sp2->me.x)<0 ) dx = -dx;
1483 if ( (dy = sp1->me.y-sp2->me.y)<0 ) dy = -dy;
1484 if ( dx==0 ) {
1485 /* Vertical line */
1486 tr.y = cv->nfh;
1487 tr.x += 2;
1488 } else if ( dy==0 ) {
1489 /* Horizontal line */
1490 tr.x = cv->width - cv->nfh - GDrawGetText8Width(pixmap,ss->contour_name,-1);
1491 } else {
1492 /* y = slope*x + off; */
1493 slope = (sp1->me.y-sp2->me.y)/(sp1->me.x-sp2->me.x);
1494 off = sp1->me.y - slope*sp1->me.x;
1495 /* Now translate to screen coords */
1496 off = (cv->height-tab->yoff)+slope*tab->xoff - tab->scale*off;
1497 slope = -slope;
1498 xinter = (0-off)/slope;
1499 yinter = slope*cv->width + off;
1500 if ( xinter>0 && xinter<cv->width ) {
1501 tr.x = xinter+2;
1502 tr.y = cv->nfh;
1503 } else if ( yinter>0 && yinter<cv->height ) {
1504 tr.x = cv->width - cv->nfh - GDrawGetText8Width(pixmap,ss->contour_name,-1);
1505 tr.y = yinter;
1506 }
1507 }
1508 } else {
1509 tr.y -= cv->nfh/2;
1510 tr.x -= GDrawGetText8Width(pixmap,ss->contour_name,-1)/2;
1511 }
1512
1513 GDrawDrawText8(pixmap,tr.x,tr.y,ss->contour_name,-1,fg);
1514 GDrawSetFont(pixmap,cv->small); /* For point numbers */
1515 }
1516
CVDrawSplineSet(CharView * cv,GWindow pixmap,SplinePointList * set,Color fg,int dopoints,DRect * clip)1517 void CVDrawSplineSet(CharView *cv, GWindow pixmap, SplinePointList *set,
1518 Color fg, int dopoints, DRect *clip ) {
1519 CVDrawSplineSetSpecialized( cv, pixmap, set, fg, dopoints, clip,
1520 sfm_stroke, 0 );
1521 }
1522
1523
CVDrawSplineSetOutlineOnly(CharView * cv,GWindow pixmap,SplinePointList * set,Color fg,int dopoints,DRect * clip,enum outlinesfm_flags strokeFillMode)1524 void CVDrawSplineSetOutlineOnly(CharView *cv, GWindow pixmap, SplinePointList *set,
1525 Color fg, int dopoints, DRect *clip, enum outlinesfm_flags strokeFillMode ) {
1526 SplinePointList *spl;
1527 int currentSplineCounter = 0;
1528 int activelayer = CVLayer(&cv->b);
1529 CharViewTab* tab = CVGetActiveTab(cv);
1530
1531 if( strokeFillMode == sfm_fill ) {
1532 GDrawFillRuleSetWinding(pixmap);
1533 }
1534
1535 for ( spl = set; spl!=NULL; spl = spl->next ) {
1536
1537 Color fc = spl->is_clip_path ? clippathcol : fg;
1538 /**
1539 * Only make the outline red if this is not a grid layer
1540 * and we want to highlight open paths
1541 * and the activelayer is sane
1542 * and the activelayer contains the given splinepointlist
1543 * and the path is open
1544 */
1545 if ( cv->b.drawmode!=dm_grid
1546 && DrawOpenPathsWithHighlight
1547 && activelayer < cv->b.sc->layer_cnt
1548 && activelayer >= 0
1549 && SplinePointListContains( cv->b.sc->layers[activelayer].splines, spl )
1550 && spl->first
1551 && spl->first->prev==NULL )
1552 {
1553 if ( GDrawGetLineWidth( pixmap ) <= 1 )
1554 fc = openpathcol | 0xff000000;
1555 else
1556 fc = openpathcol;
1557 }
1558
1559 if ( GDrawHasCairo(pixmap)&gc_buildpath ) {
1560 Spline *first, *spline;
1561 double x,y, cx1, cy1, cx2, cy2, dx,dy;
1562 GDrawPathStartSubNew(pixmap);
1563 x = rpt(cv, tab->xoff + spl->first->me.x*tab->scale);
1564 y = rpt(cv, -tab->yoff + cv->height - spl->first->me.y*tab->scale);
1565 GDrawPathMoveTo(pixmap,x+.5,y+.5);
1566 currentSplineCounter++;
1567 for ( spline=spl->first->next, first=NULL; spline!=first && spline!=NULL; spline=spline->to->next ) {
1568 x = rpt(cv, tab->xoff + spline->to->me.x*tab->scale);
1569 y = rpt(cv, -tab->yoff + cv->height - spline->to->me.y*tab->scale);
1570 if ( spline->knownlinear )
1571 GDrawPathLineTo(pixmap,x+.5,y+.5);
1572 else if ( spline->order2 ) {
1573 dx = rint(spline->from->me.x*tab->scale) - spline->from->me.x*tab->scale;
1574 dy = rint(spline->from->me.y*tab->scale) - spline->from->me.y*tab->scale;
1575 cx1 = spline->from->me.x + spline->splines[0].c/3;
1576 cy1 = spline->from->me.y + spline->splines[1].c/3;
1577 cx2 = cx1 + (spline->splines[0].b+spline->splines[0].c)/3;
1578 cy2 = cy1 + (spline->splines[1].b+spline->splines[1].c)/3;
1579 cx1 = tab->xoff + cx1*tab->scale + dx;
1580 cy1 = -tab->yoff + cv->height - cy1*tab->scale - dy;
1581 dx = rint(spline->to->me.x*tab->scale) - spline->to->me.x*tab->scale;
1582 dy = rint(spline->to->me.y*tab->scale) - spline->to->me.y*tab->scale;
1583 cx2 = tab->xoff + cx2*tab->scale + dx;
1584 cy2 = -tab->yoff + cv->height - cy2*tab->scale - dy;
1585 GDrawPathCurveTo(pixmap,cx1+.5,cy1+.5,cx2+.5,cy2+.5,x+.5,y+.5);
1586 } else {
1587 dx = rint(spline->from->me.x*tab->scale) - spline->from->me.x*tab->scale;
1588 dy = rint(spline->from->me.y*tab->scale) - spline->from->me.y*tab->scale;
1589 cx1 = tab->xoff + spline->from->nextcp.x*tab->scale + dx;
1590 cy1 = -tab->yoff + cv->height - spline->from->nextcp.y*tab->scale - dy;
1591 dx = rint(spline->to->me.x*tab->scale) - spline->to->me.x*tab->scale;
1592 dy = rint(spline->to->me.y*tab->scale) - spline->to->me.y*tab->scale;
1593 cx2 = tab->xoff + spline->to->prevcp.x*tab->scale + dx;
1594 cy2 = -tab->yoff + cv->height - spline->to->prevcp.y*tab->scale - dy;
1595 GDrawPathCurveTo(pixmap,cx1+.5,cy1+.5,cx2+.5,cy2+.5,x+.5,y+.5);
1596 }
1597 if ( first==NULL )
1598 first = spline;
1599 }
1600 if ( spline!=NULL )
1601 GDrawPathClose(pixmap);
1602
1603 switch( strokeFillMode ) {
1604 case sfm_stroke_trans:
1605 GDrawPathStroke( pixmap, fc );
1606 break;
1607 case sfm_stroke:
1608 GDrawPathStroke( pixmap, fc | 0xff000000 );
1609 break;
1610 case sfm_clip:
1611 case sfm_fill:
1612 case sfm_nothing:
1613 break;
1614 }
1615 } else if (strokeFillMode != sfm_clip) {
1616 GPointList *gpl = MakePoly(cv,spl), *cur;
1617 for ( cur=gpl; cur!=NULL; cur=cur->next )
1618 GDrawDrawPoly(pixmap,cur->gp,cur->cnt,fc);
1619 GPLFree(gpl);
1620 }
1621 }
1622
1623 if (strokeFillMode == sfm_clip && (GDrawHasCairo(pixmap) & gc_buildpath)) {
1624 // Really only cairo_clip needs to be called
1625 // But then I'd have to change the GDraw interface, ew...
1626 GDrawClipPreserve( pixmap );
1627 GDrawPathStartNew( pixmap );
1628 } else if (strokeFillMode == sfm_fill) {
1629 if ( cv->inPreviewMode )
1630 GDrawPathFill(pixmap, previewfillcol|0xff000000);
1631 else
1632 GDrawPathFill(pixmap, fillcol);
1633 }
1634 }
1635
1636
1637
CVDrawSplineSetSpecialized(CharView * cv,GWindow pixmap,SplinePointList * set,Color fg,int dopoints,DRect * clip,enum outlinesfm_flags strokeFillMode,Color AlphaChannelOverride)1638 void CVDrawSplineSetSpecialized( CharView *cv, GWindow pixmap, SplinePointList *set,
1639 Color fg, int dopoints, DRect *clip,
1640 enum outlinesfm_flags strokeFillMode,
1641 Color AlphaChannelOverride )
1642 {
1643 Spline *spline, *first;
1644 SplinePointList *spl;
1645 int truetype_markup = set==cv->b.gridfit && cv->dv!=NULL;
1646 CharViewTab* tab = CVGetActiveTab(cv);
1647
1648 if ( cv->inactive )
1649 dopoints = false;
1650
1651 if( strokeFillMode == sfm_fill ) {
1652 CVDrawSplineSetOutlineOnly( cv, pixmap, set,
1653 fg, dopoints, clip, strokeFillMode );
1654 }
1655
1656 GDrawSetFont(pixmap,cv->small); /* For point numbers */
1657 for ( spl = set; spl!=NULL; spl = spl->next ) {
1658 if ( spl->contour_name!=NULL )
1659 CVDrawContourName(cv,pixmap,spl,fg);
1660 if ( dopoints>0 || (dopoints==-1 && cv->showpointnumbers) ) {
1661 first = NULL;
1662 if ( dopoints>0 )
1663 DrawDirection(cv,pixmap,spl->first);
1664 if ( cv->b.sc->inspiro && hasspiro()) {
1665 if ( dopoints>=0 ) {
1666 int i;
1667 if ( spl->spiros==NULL ) {
1668 spl->spiros = SplineSet2SpiroCP(spl,&spl->spiro_cnt);
1669 spl->spiro_max = spl->spiro_cnt;
1670 }
1671 for ( i=0; i<spl->spiro_cnt-1; ++i )
1672 DrawSpiroPoint(cv,pixmap,&spl->spiros[i],spl,i, AlphaChannelOverride );
1673 }
1674 } else {
1675 for ( spline = spl->first->next; spline!=NULL && spline!=first; spline=spline->to->next ) {
1676 DrawPoint(cv,pixmap,spline->from,spl,dopoints<0,truetype_markup, AlphaChannelOverride );
1677 CVDrawPointName(cv,pixmap,spline->from,fg);
1678 if ( first==NULL ) first = spline;
1679 }
1680 if ( spline==NULL ) {
1681 DrawPoint(cv,pixmap,spl->last,spl,dopoints<0,truetype_markup, AlphaChannelOverride );
1682 CVDrawPointName(cv,pixmap,spl->last,fg);
1683 }
1684 }
1685 }
1686 }
1687
1688 if( strokeFillMode != sfm_nothing ) {
1689 /*
1690 * If we were filling, we have to stroke the outline again to properly show
1691 * clip path splines which will possibly have a different stroke color
1692 */
1693 Color thinfgcolor = fg;
1694 enum outlinesfm_flags fgstrokeFillMode = sfm_stroke;
1695 if( strokeFillMode==sfm_stroke_trans )
1696 fgstrokeFillMode = sfm_stroke_trans;
1697 if( shouldShowFilledUsingCairo(cv) ) {
1698 if (cv->inPreviewMode)
1699 thinfgcolor = (thinfgcolor | 0x01000000) & 0x01ffffff;
1700 fgstrokeFillMode = sfm_stroke_trans;
1701 }
1702 CVDrawSplineSetOutlineOnly( cv, pixmap, set,
1703 thinfgcolor, dopoints, clip,
1704 fgstrokeFillMode );
1705
1706 if( prefs_cv_outline_thickness > 1 )
1707 {
1708 // we only draw the inner half, so we double the user's expected
1709 // thickness here.
1710 int strokeWidth = prefs_cv_outline_thickness * 2 * tab->scale;
1711 Color strokefg = foreoutthicklinecol;
1712
1713 if( shouldShowFilledUsingCairo(cv) && cv->inPreviewMode ) {
1714 strokefg = (strokefg | 0x01000000) & 0x01ffffff;
1715 }
1716
1717 int16 oldwidth = GDrawGetLineWidth( pixmap );
1718 GDrawSetLineWidth( pixmap, strokeWidth );
1719 GDrawPushClipOnly( pixmap );
1720
1721 CVDrawSplineSetOutlineOnly( cv, pixmap, set,
1722 strokefg, dopoints, clip,
1723 sfm_clip );
1724 CVDrawSplineSetOutlineOnly( cv, pixmap, set,
1725 strokefg, dopoints, clip,
1726 sfm_stroke_trans );
1727
1728 GDrawPopClip( pixmap, NULL );
1729 GDrawSetLineWidth( pixmap, oldwidth );
1730 }
1731 }
1732
1733 for ( spl = set; spl!=NULL; spl = spl->next ) {
1734 if (( cv->markextrema || cv->markpoi ) && dopoints && !cv->b.sc->inspiro )
1735 CVMarkInterestingLocations(cv,pixmap,spl);
1736 if ( (cv->showalmosthvlines || cv->showalmosthvcurves ) && dopoints )
1737 CVMarkAlmostHV(cv,pixmap,spl);
1738 }
1739 }
1740
CVDrawLayerSplineSet(CharView * cv,GWindow pixmap,Layer * layer,Color fg,int dopoints,DRect * clip,enum outlinesfm_flags strokeFillMode)1741 static void CVDrawLayerSplineSet(CharView *cv, GWindow pixmap, Layer *layer,
1742 Color fg, int dopoints, DRect *clip, enum outlinesfm_flags strokeFillMode ) {
1743 CharViewTab* tab = CVGetActiveTab(cv);
1744 int active = cv->b.layerheads[cv->b.drawmode]==layer;
1745 int ml = cv->b.sc->parent->multilayer;
1746
1747 if ( ml && layer->dostroke ) {
1748 if ( layer->stroke_pen.brush.col!=COLOR_INHERITED &&
1749 layer->stroke_pen.brush.col!=view_bgcol )
1750 fg = layer->stroke_pen.brush.col;
1751 }
1752 if ( ml && layer->dofill ) {
1753 if ( layer->fill_brush.col!=COLOR_INHERITED &&
1754 layer->fill_brush.col!=view_bgcol )
1755 fg = layer->fill_brush.col;
1756 }
1757
1758 if ( ml && !active && layer!=&cv->b.sc->layers[ly_back] )
1759 GDrawSetDashedLine(pixmap,5,5,tab->xoff+cv->height-tab->yoff);
1760
1761 CVDrawSplineSetSpecialized( cv, pixmap, layer->splines,
1762 fg, dopoints && active, clip,
1763 strokeFillMode, 0 );
1764
1765 if ( ml && !active && layer!=&cv->b.sc->layers[ly_back] )
1766 GDrawSetDashedLine(pixmap,0,0,0);
1767 }
1768
CVDrawTemplates(CharView * cv,GWindow pixmap,SplineChar * template,DRect * clip)1769 static void CVDrawTemplates(CharView *cv,GWindow pixmap,SplineChar *template,DRect *clip) {
1770 RefChar *r;
1771
1772 CVDrawSplineSet(cv,pixmap,template->layers[ly_fore].splines,templateoutlinecol,false,clip);
1773 for ( r=template->layers[ly_fore].refs; r!=NULL; r=r->next )
1774 CVDrawSplineSet(cv,pixmap,r->layers[0].splines,templateoutlinecol,false,clip);
1775 }
1776
CVShowDHintInstance(CharView * cv,GWindow pixmap,BasePoint * bp)1777 static void CVShowDHintInstance(CharView *cv, GWindow pixmap, BasePoint *bp) {
1778 IPoint ip[40], ip2[40];
1779 GPoint clipped[13];
1780 int i,j, tot,last;
1781 CharViewTab* tab = CVGetActiveTab(cv);
1782
1783 ip[0].x = tab->xoff + rint( bp[0].x*tab->scale );
1784 ip[0].y = -tab->yoff + cv->height - rint( bp[0].y*tab->scale );
1785 ip[1].x = tab->xoff + rint(bp[1].x*tab->scale);
1786 ip[1].y = -tab->yoff + cv->height - rint( bp[1].y*tab->scale );
1787 ip[2].x = tab->xoff + rint( bp[2].x*tab->scale );
1788 ip[2].y = -tab->yoff + cv->height - rint( bp[2].y*tab->scale );
1789 ip[3].x = tab->xoff + rint( bp[3].x*tab->scale );
1790 ip[3].y = -tab->yoff + cv->height - rint( bp[3].y*tab->scale );
1791
1792 if (( ip[0].x<0 && ip[1].x<0 && ip[2].x<0 && ip[3].x<0 ) ||
1793 ( ip[0].x>=cv->width && ip[1].x>=cv->width && ip[2].x>=cv->width && ip[3].x>=cv->width ) ||
1794 ( ip[0].y<0 && ip[1].y<0 && ip[2].y<0 && ip[3].y<0 ) ||
1795 ( ip[0].y>=cv->height && ip[1].y>=cv->height && ip[2].y>=cv->height && ip[3].y>=cv->height ))
1796 return; /* Offscreen */
1797
1798 /* clip to left edge */
1799 tot = 4;
1800 for ( i=j=0; i<tot; ++i ) {
1801 last = i==0?tot-1:i-1;
1802 if ( ip[i].x>=0 && ip[last].x>=0) {
1803 ip2[j++] = ip[i];
1804 } else if ( ip[i].x<0 && ip[last].x<0 ) {
1805 if ( j==0 || ip2[j-1].x!=0 || ip2[j-1].y!=ip[i].y ) {
1806 ip2[j].x = 0;
1807 ip2[j++].y = ip[i].y;
1808 }
1809 } else {
1810 ip2[j].x = 0;
1811 ip2[j++].y = ip[last].y - ip[last].x * ((real) (ip[i].y-ip[last].y))/(ip[i].x-ip[last].x);
1812 if ( ip[i].x>0 )
1813 ip2[j++] = ip[i];
1814 else {
1815 ip2[j].x = 0;
1816 ip2[j++].y = ip[i].y;
1817 }
1818 }
1819 }
1820 /* clip to right edge */
1821 tot = j;
1822 for ( i=j=0; i<tot; ++i ) {
1823 last = i==0?tot-1:i-1;
1824 if ( ip2[i].x<cv->width && ip2[last].x<cv->width ) {
1825 ip[j++] = ip2[i];
1826 } else if ( ip2[i].x>=cv->width && ip2[last].x>=cv->width ) {
1827 if ( j==0 || ip[j-1].x!=cv->width-1 || ip[j-1].y!=ip2[i].y ) {
1828 ip[j].x = cv->width-1;
1829 ip[j++].y = ip2[i].y;
1830 }
1831 } else {
1832 ip[j].x = cv->width-1;
1833 ip[j++].y = ip2[last].y + (cv->width-1- ip2[last].x) * ((real) (ip2[i].y-ip2[last].y))/(ip2[i].x-ip2[last].x);
1834 if ( ip2[i].x<cv->width )
1835 ip[j++] = ip2[i];
1836 else {
1837 ip[j].x = cv->width-1;
1838 ip[j++].y = ip2[i].y;
1839 }
1840 }
1841 }
1842 /* clip to bottom edge */
1843 tot = j;
1844 for ( i=j=0; i<tot; ++i ) {
1845 last = i==0?tot-1:i-1;
1846 if ( ip[i].y>=0 && ip[last].y>=0) {
1847 ip2[j++] = ip[i];
1848 } else if ( ip[i].y<0 && ip[last].y<0 ) {
1849 ip2[j].y = 0;
1850 ip2[j++].x = ip[i].x;
1851 } else {
1852 ip2[j].y = 0;
1853 ip2[j++].x = ip[last].x - ip[last].y * ((real) (ip[i].x-ip[last].x))/(ip[i].y-ip[last].y);
1854 if ( ip[i].y>0 )
1855 ip2[j++] = ip[i];
1856 else {
1857 ip2[j].y = 0;
1858 ip2[j++].x = ip[i].x;
1859 }
1860 }
1861 }
1862 /* clip to top edge */
1863 tot = j;
1864 for ( i=j=0; i<tot; ++i ) {
1865 last = i==0?tot-1:i-1;
1866 if ( ip2[i].y<cv->height && ip2[last].y<cv->height ) {
1867 ip[j++] = ip2[i];
1868 } else if ( ip2[i].y>=cv->height && ip2[last].y>=cv->height ) {
1869 ip[j].y = cv->height-1;
1870 ip[j++].x = ip2[i].x;
1871 } else {
1872 ip[j].y = cv->height-1;
1873 ip[j++].x = ip2[last].x + (cv->height-1- ip2[last].y) * ((real) (ip2[i].x-ip2[last].x))/(ip2[i].y-ip2[last].y);
1874 if ( ip2[i].y<cv->height )
1875 ip[j++] = ip2[i];
1876 else {
1877 ip[j].y = cv->height-1;
1878 ip[j++].x = ip2[i].x;
1879 }
1880 }
1881 }
1882
1883 tot=j;
1884 clipped[0].x = ip[0].x; clipped[0].y = ip[0].y;
1885 for ( i=j=1; i<tot; ++i ) {
1886 if ( ip[i].x!=ip[i-1].x || ip[i].y!=ip[i-1].y ) {
1887 clipped[j].x = ip[i].x; clipped[j++].y = ip[i].y;
1888 }
1889 }
1890 clipped[j++] = clipped[0];
1891 GDrawFillPoly(pixmap,clipped,j,dhintcol);
1892 }
1893
CVShowDHint(CharView * cv,GWindow pixmap,DStemInfo * dstem)1894 static void CVShowDHint ( CharView *cv, GWindow pixmap, DStemInfo *dstem ) {
1895 BasePoint bp[4];
1896 HintInstance *hi;
1897 double roff;
1898
1899 roff = ( dstem->right.x - dstem->left.x ) * dstem->unit.x +
1900 ( dstem->right.y - dstem->left.y ) * dstem->unit.y;
1901
1902 for ( hi=dstem->where; hi!=NULL; hi=hi->next ) {
1903 bp[0].x = dstem->left.x + dstem->unit.x * hi->begin;
1904 bp[0].y = dstem->left.y + dstem->unit.y * hi->begin;
1905 bp[1].x = dstem->right.x + dstem->unit.x * ( hi->begin - roff );
1906 bp[1].y = dstem->right.y + dstem->unit.y * ( hi->begin - roff );
1907 bp[2].x = dstem->right.x + dstem->unit.x * ( hi->end - roff );
1908 bp[2].y = dstem->right.y + dstem->unit.y * ( hi->end - roff );
1909 bp[3].x = dstem->left.x + dstem->unit.x * hi->end;
1910 bp[3].y = dstem->left.y + dstem->unit.y * hi->end;
1911 CVShowDHintInstance( cv, pixmap, bp );
1912 }
1913 }
1914
CVShowMinimumDistance(CharView * cv,GWindow pixmap,MinimumDistance * md)1915 static void CVShowMinimumDistance(CharView *cv, GWindow pixmap,MinimumDistance *md) {
1916 CharViewTab* tab = CVGetActiveTab(cv);
1917 int x1,y1, x2,y2;
1918 int xa, ya;
1919 int off = tab->xoff+cv->height-tab->yoff;
1920
1921 if (( md->x && !cv->showmdx ) || (!md->x && !cv->showmdy))
1922 return;
1923 if ( md->sp1==NULL && md->sp2==NULL )
1924 return;
1925 if ( md->sp1!=NULL ) {
1926 x1 = tab->xoff + rint( md->sp1->me.x*tab->scale );
1927 y1 = -tab->yoff + cv->height - rint(md->sp1->me.y*tab->scale);
1928 } else {
1929 x1 = tab->xoff + rint( cv->b.sc->width*tab->scale );
1930 y1 = 0x80000000;
1931 }
1932 if ( md->sp2!=NULL ) {
1933 x2 = tab->xoff + rint( md->sp2->me.x*tab->scale );
1934 y2 = -tab->yoff + cv->height - rint(md->sp2->me.y*tab->scale);
1935 } else {
1936 x2 = tab->xoff + rint( cv->b.sc->width*tab->scale );
1937 y2 = y1-8;
1938 }
1939 if ( y1==0x80000000 )
1940 y1 = y2-8;
1941 if ( md->x ) {
1942 ya = (y1+y2)/2;
1943 GDrawDrawArrow(pixmap, x1,ya, x2,ya, 2, mdhintcol);
1944 GDrawSetDashedLine(pixmap,5,5,off);
1945 GDrawDrawLine(pixmap, x1,ya, x1,y1, mdhintcol);
1946 GDrawDrawLine(pixmap, x2,ya, x2,y2, mdhintcol);
1947 } else {
1948 xa = (x1+x2)/2;
1949 GDrawDrawArrow(pixmap, xa,y1, xa,y2, 2, mdhintcol);
1950 GDrawSetDashedLine(pixmap,5,5,off);
1951 GDrawDrawLine(pixmap, xa,y1, x1,y1, mdhintcol);
1952 GDrawDrawLine(pixmap, xa,y2, x2,y2, mdhintcol);
1953 }
1954 GDrawSetDashedLine(pixmap,0,0,0);
1955 }
1956
dtos(char * buf,real val)1957 static void dtos(char *buf,real val) {
1958 char *pt;
1959
1960 sprintf( buf,"%.1f", (double) val);
1961 pt = buf+strlen(buf);
1962 if ( pt[-1]=='0' && pt[-2]=='.' ) pt[-2] = '\0';
1963 }
1964
CVDrawBlues(CharView * cv,GWindow pixmap,char * bluevals,char * others,Color col)1965 static void CVDrawBlues(CharView *cv,GWindow pixmap,char *bluevals,char *others,
1966 Color col) {
1967 double blues[24];
1968 char *pt, *end;
1969 int i=0, bcnt=0;
1970 GRect r;
1971 char buf[20];
1972 int len,len2;
1973 CharViewTab* tab = CVGetActiveTab(cv);
1974
1975 if ( bluevals!=NULL ) {
1976 for ( pt = bluevals; isspace( *pt ) || *pt=='['; ++pt);
1977 while ( i<14 && *pt!='\0' && *pt!=']' ) {
1978 blues[i] = g_ascii_strtod(pt,&end);
1979 if ( pt==end )
1980 break;
1981 ++i;
1982 pt = end;
1983 while ( isspace( *pt )) ++pt;
1984 }
1985 if ( i&1 ) --i;
1986 }
1987 if ( others!=NULL ) {
1988 for ( pt = others; isspace( *pt ) || *pt=='['; ++pt);
1989 while ( i<24 && *pt!='\0' && *pt!=']' ) {
1990 blues[i] = g_ascii_strtod(pt,&end);
1991 if ( pt==end )
1992 break;
1993 ++i;
1994 pt = end;
1995 while ( isspace( *pt )) ++pt;
1996 }
1997 if ( i&1 ) --i;
1998 }
1999 bcnt = i;
2000 if ( i==0 )
2001 return;
2002
2003 r.x = 0; r.width = cv->width;
2004 for ( i=0; i<bcnt; i += 2 ) {
2005 int first, other;
2006 first = -tab->yoff + cv->height - rint(blues[i]*tab->scale);
2007 other = -tab->yoff + cv->height - rint(blues[i+1]*tab->scale);
2008 r.y = first;
2009 if ( ( r.y<0 && other<0 ) || (r.y>cv->height && other>cv->height))
2010 continue;
2011 if ( r.y<0 ) r.y = 0;
2012 else if ( r.y>cv->height ) r.y = cv->height;
2013 if ( other<0 ) other = 0;
2014 else if ( other>cv->height ) other = cv->height;
2015 if ( other<r.y ) {
2016 r.height = r.y-other;
2017 r.y = other;
2018 } else
2019 r.height = other-r.y;
2020 if ( r.height==0 ) r.height = 1; /* show something */
2021 GDrawSetStippled(pixmap,2, 0,0);
2022 GDrawFillRect(pixmap,&r,col);
2023 GDrawSetStippled(pixmap,0, 0,0);
2024
2025 if ( first>-20 && first<cv->height+20 ) {
2026 dtos( buf, blues[i]);
2027 len = GDrawGetText8Width(pixmap,buf,-1);
2028 GDrawDrawText8(pixmap,cv->width-len-5,first-3,buf,-1,hintlabelcol);
2029 } else
2030 len = 0;
2031 if ( other>-20 && other<cv->height+20 ) {
2032 dtos( buf, blues[i+1]-blues[i]);
2033 len2 = GDrawGetText8Width(pixmap,buf,-1);
2034 GDrawDrawText8(pixmap,cv->width-len-5-len2-5,other+cv->sas-3,buf,-1,hintlabelcol);
2035 }
2036 }
2037 }
2038
CVShowHints(CharView * cv,GWindow pixmap)2039 static void CVShowHints(CharView *cv, GWindow pixmap) {
2040 StemInfo *hint;
2041 GRect r;
2042 HintInstance *hi;
2043 int end;
2044 Color col;
2045 DStemInfo *dstem;
2046 MinimumDistance *md;
2047 char *blues, *others;
2048 struct psdict *private = cv->b.sc->parent->private;
2049 char buf[20];
2050 int len, len2;
2051 SplinePoint *sp;
2052 SplineSet *spl;
2053 CharViewTab* tab = CVGetActiveTab(cv);
2054
2055 GDrawSetFont(pixmap,cv->small);
2056 blues = PSDictHasEntry(private,"BlueValues"); others = PSDictHasEntry(private,"OtherBlues");
2057 if ( cv->showblues && (blues!=NULL || others!=NULL))
2058 CVDrawBlues(cv,pixmap,blues,others,bluevalstipplecol);
2059 blues = PSDictHasEntry(private,"FamilyBlues"); others = PSDictHasEntry(private,"FamilyOtherBlues");
2060 if ( cv->showfamilyblues && (blues!=NULL || others!=NULL))
2061 CVDrawBlues(cv,pixmap,blues,others,fambluestipplecol);
2062
2063 if ( cv->showdhints ) for ( dstem = cv->b.sc->dstem; dstem!=NULL; dstem = dstem->next ) {
2064 CVShowDHint(cv,pixmap,dstem);
2065 }
2066
2067 if ( cv->showhhints && cv->b.sc->hstem!=NULL ) {
2068 GDrawSetDashedLine(pixmap,5,5,tab->xoff);
2069 for ( hint = cv->b.sc->hstem; hint!=NULL; hint = hint->next ) {
2070 if ( hint->width<0 ) {
2071 r.y = -tab->yoff + cv->height - rint(hint->start*tab->scale);
2072 r.height = rint(-hint->width*tab->scale)+1;
2073 } else {
2074 r.y = -tab->yoff + cv->height - rint((hint->start+hint->width)*tab->scale);
2075 r.height = rint(hint->width*tab->scale)+1;
2076 }
2077 col = hint->active ? hhintactivecol : hhintcol;
2078 /* XRectangles are shorts! */
2079 if ( r.y<32767 && r.y+r.height>-32768 ) {
2080 if ( r.y<-32768 ) {
2081 r.height -= (-32768-r.y);
2082 r.y = -32768;
2083 }
2084 if ( r.y+r.height>32767 )
2085 r.height = 32767-r.y;
2086 for ( hi=hint->where; hi!=NULL; hi=hi->next ) {
2087 r.x = tab->xoff + rint(hi->begin*tab->scale);
2088 end = tab->xoff + rint(hi->end*tab->scale);
2089 if ( end>=0 && r.x<=cv->width ) {
2090 r.width = end-r.x+1;
2091 GDrawFillRect(pixmap,&r,col);
2092 }
2093 }
2094 }
2095 col = (!hint->active && hint->hasconflicts) ? conflicthintcol : col;
2096 if ( r.y>=0 && r.y<=cv->height )
2097 GDrawDrawLine(pixmap,0,r.y,cv->width,r.y,col);
2098 if ( r.y+r.height>=0 && r.y+r.height<=cv->width )
2099 GDrawDrawLine(pixmap,0,r.y+r.height-1,cv->width,r.y+r.height-1,col);
2100
2101 r.y = -tab->yoff + cv->height - rint(hint->start*tab->scale);
2102 r.y += ( hint->width>0 ) ? -3 : cv->sas+3;
2103 if ( r.y>-20 && r.y<cv->height+20 ) {
2104 dtos( buf, hint->start);
2105 len = GDrawGetText8Width(pixmap,buf,-1);
2106 GDrawDrawText8(pixmap,cv->width-len-5,r.y,buf,-1,hintlabelcol);
2107 } else
2108 len = 0;
2109 r.y = -tab->yoff + cv->height - rint((hint->start+hint->width)*tab->scale);
2110 r.y += ( hint->width>0 ) ? cv->sas+3 : -3;
2111 if ( r.y>-20 && r.y<cv->height+20 ) {
2112 if ( hint->ghost ) {
2113 buf[0] = 'G';
2114 buf[1] = ' ';
2115 dtos(buf+2, hint->width);
2116 } else
2117 dtos( buf, hint->width);
2118 len2 = GDrawGetText8Width(pixmap,buf,-1);
2119 GDrawDrawText8(pixmap,cv->width-len-5-len2-5,r.y,buf,-1,hintlabelcol);
2120 }
2121 }
2122 }
2123 if ( cv->showvhints && cv->b.sc->vstem!=NULL ) {
2124 GDrawSetDashedLine(pixmap,5,5,cv->height-tab->yoff);
2125 for ( hint = cv->b.sc->vstem; hint!=NULL; hint = hint->next ) {
2126 if ( hint->width<0 ) {
2127 r.x = tab->xoff + rint( (hint->start+hint->width)*tab->scale );
2128 r.width = rint(-hint->width*tab->scale)+1;
2129 } else {
2130 r.x = tab->xoff + rint(hint->start*tab->scale);
2131 r.width = rint(hint->width*tab->scale)+1;
2132 }
2133 col = hint->active ? vhintactivecol : vhintcol;
2134 if ( r.x<32767 && r.x+r.width>-32768 ) {
2135 if ( r.x<-32768 ) {
2136 r.width -= (-32768-r.x);
2137 r.x = -32768;
2138 }
2139 if ( r.x+r.width>32767 )
2140 r.width = 32767-r.x;
2141 for ( hi=hint->where; hi!=NULL; hi=hi->next ) {
2142 r.y = -tab->yoff + cv->height - rint(hi->end*tab->scale);
2143 end = -tab->yoff + cv->height - rint(hi->begin*tab->scale);
2144 if ( end>=0 && r.y<=cv->height ) {
2145 r.height = end-r.y+1;
2146 GDrawFillRect(pixmap,&r,col);
2147 }
2148 }
2149 }
2150 col = (!hint->active && hint->hasconflicts) ? conflicthintcol : col;
2151 if ( r.x>=0 && r.x<=cv->width )
2152 GDrawDrawLine(pixmap,r.x,0,r.x,cv->height,col);
2153 if ( r.x+r.width>=0 && r.x+r.width<=cv->width )
2154 GDrawDrawLine(pixmap,r.x+r.width-1,0,r.x+r.width-1,cv->height,col);
2155
2156 r.x = tab->xoff + rint(hint->start*tab->scale);
2157 if ( r.x>-60 && r.x<cv->width+20 ) {
2158 dtos( buf, hint->start);
2159 len = GDrawGetText8Width(pixmap,buf,-1);
2160 r.x += ( hint->width>0 ) ? 3 : -len-3;
2161 GDrawDrawText8(pixmap,r.x,cv->sas+3,buf,-1,hintlabelcol);
2162 }
2163 r.x = tab->xoff + rint((hint->start+hint->width)*tab->scale);
2164 if ( r.x>-60 && r.x<cv->width+20 ) {
2165 if ( hint->ghost ) {
2166 buf[0] = 'G';
2167 buf[1] = ' ';
2168 dtos(buf+2, hint->width);
2169 } else
2170 dtos( buf, hint->width);
2171 len = GDrawGetText8Width(pixmap,buf,-1);
2172 r.x += ( hint->width>0 ) ? -len-3 : 3;
2173 GDrawDrawText8(pixmap,r.x,cv->sas+cv->sfh+3,buf,-1,hintlabelcol);
2174 }
2175 }
2176 }
2177 GDrawSetDashedLine(pixmap,0,0,0);
2178
2179 for ( md=cv->b.sc->md; md!=NULL; md=md->next )
2180 CVShowMinimumDistance(cv, pixmap,md);
2181
2182 if ( cv->showvhints || cv->showhhints ) {
2183 for ( spl=cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL; spl=spl->next ) {
2184 if ( spl->first->prev!=NULL ) for ( sp=spl->first ; ; ) {
2185 if ( cv->showhhints && sp->flexx ) {
2186 double x,y,end;
2187 x = tab->xoff + rint(sp->me.x*tab->scale);
2188 y = -tab->yoff + cv->height - rint(sp->me.y*tab->scale);
2189 end = tab->xoff + rint(sp->next->to->me.x*tab->scale);
2190 if ( x>-4096 && x<32767 && y>-4096 && y<32767 ) {
2191 GDrawDrawLine(pixmap,x,y,end,y,hflexhintcol);
2192 }
2193 }
2194 if ( cv->showvhints && sp->flexy ) {
2195 double x,y,end;
2196 x = tab->xoff + rint(sp->me.x*tab->scale);
2197 y = -tab->yoff + cv->height - rint(sp->me.y*tab->scale);
2198 end = -tab->yoff + cv->height - rint(sp->next->to->me.y*tab->scale);
2199 if ( x>-4096 && x<32767 && y>-4096 && y<32767 ) {
2200 GDrawDrawLine(pixmap,x,y,x,end,vflexhintcol);
2201 }
2202 }
2203 if ( sp->next==NULL ) /* This can happen if we get an internal error inside of RemoveOverlap when the pointlist is not in good shape */
2204 break;
2205 sp = sp->next->to;
2206 if ( sp==spl->first )
2207 break;
2208 }
2209 }
2210 }
2211 }
2212
CVDrawRefName(CharView * cv,GWindow pixmap,RefChar * ref,int fg)2213 static void CVDrawRefName(CharView *cv,GWindow pixmap,RefChar *ref,int fg) {
2214 CharViewTab* tab = CVGetActiveTab(cv);
2215 int x,y, len;
2216 GRect size;
2217
2218 x = tab->xoff + rint(ref->top.x*tab->scale);
2219 y = -tab->yoff + cv->height - rint(ref->top.y*tab->scale);
2220 y -= 5;
2221 if ( x<-400 || y<-40 || x>cv->width+400 || y>cv->height )
2222 return;
2223
2224 GDrawLayoutInit(pixmap,ref->sc->name,-1,cv->small);
2225 GDrawLayoutExtents(pixmap,&size);
2226 GDrawLayoutDraw(pixmap,x-size.width/2,y,fg);
2227 len = size.width;
2228 if ( ref->use_my_metrics )
2229 GDrawDrawImage(pixmap,&GIcon_lock,NULL,x+len+3,y-cv->sas);
2230 }
2231
DrawAnchorPoint(GWindow pixmap,int x,int y,int selected)2232 void DrawAnchorPoint(GWindow pixmap,int x, int y,int selected) {
2233 GPoint gp[9];
2234 Color col = anchorcol;
2235
2236 gp[0].x = x-1; gp[0].y = y-1;
2237 gp[1].x = x; gp[1].y = y-6;
2238 gp[2].x = x+1; gp[2].y = y-1;
2239 gp[3].x = x+6; gp[3].y = y;
2240 gp[4].x = x+1; gp[4].y = y+1;
2241 gp[5].x = x; gp[5].y = y+6;
2242 gp[6].x = x-1; gp[6].y = y+1;
2243 gp[7].x = x-6; gp[7].y = y;
2244 gp[8] = gp[0];
2245 if ( selected )
2246 GDrawDrawPoly(pixmap,gp,9,col);
2247 else
2248 GDrawFillPoly(pixmap,gp,9,col);
2249 }
2250
CVDrawAnchorPoints(CharView * cv,GWindow pixmap)2251 static void CVDrawAnchorPoints(CharView *cv,GWindow pixmap) {
2252 CharViewTab* tab = CVGetActiveTab(cv);
2253 int x,y, len, sel;
2254 Color col = anchorcol;
2255 AnchorPoint *ap;
2256 char *name, ubuf[50];
2257 GRect r;
2258
2259 if ( cv->b.drawmode!=dm_fore || cv->b.sc->anchor==NULL || !cv->showanchor )
2260 return;
2261 GDrawSetFont(pixmap,cv->normal);
2262
2263 for ( sel=0; sel<2; ++sel ) {
2264 for ( ap = cv->b.sc->anchor; ap!=NULL; ap=ap->next ) if ( ap->selected==sel ) {
2265 x = tab->xoff + rint(ap->me.x*tab->scale);
2266 y = -tab->yoff + cv->height - rint(ap->me.y*tab->scale);
2267 if ( x<-400 || y<-40 || x>cv->width+400 || y>cv->height )
2268 continue;
2269
2270 DrawAnchorPoint(pixmap,x,y,ap->selected);
2271 ubuf[30]=0;
2272 if ( ap->anchor->type==act_mkmk ) {
2273 cc_strncpy(ubuf,ap->anchor->name,30);
2274 strcat(ubuf," ");
2275 strcat(ubuf,ap->type==at_basemark ? _("Base") : _("Mark") );
2276 name = ubuf;
2277 } else if ( ap->type==at_basechar || ap->type==at_mark || ap->type==at_basemark ) {
2278 name = ap->anchor->name;
2279 } else if ( ap->type==at_centry || ap->type==at_cexit ) {
2280 cc_strncpy(ubuf,ap->anchor->name,30);
2281 strcat(ubuf,ap->type==at_centry ? _("Entry") : _("Exit") );
2282 name = ubuf;
2283 } else if ( ap->type==at_baselig ) {
2284 cc_strncpy(ubuf,ap->anchor->name,30);
2285 sprintf(ubuf+strlen(ubuf),"#%d", ap->lig_index);
2286 name = ubuf;
2287 } else
2288 name = NULL; /* Should never happen */
2289
2290 GRect size;
2291 GDrawLayoutInit(pixmap,name,-1,NULL);
2292 GDrawLayoutExtents(pixmap,&size);
2293 len = size.width;
2294
2295 r.x = x-len/2; r.width = len;
2296 r.y = y+7; r.height = cv->nfh;
2297 GDrawFillRect(pixmap,&r,view_bgcol );
2298 GDrawLayoutDraw(pixmap,x-len/2,y+7+cv->nas,col);
2299 }
2300 }
2301 }
2302
DrawImageList(CharView * cv,GWindow pixmap,ImageList * backimages)2303 static void DrawImageList(CharView *cv,GWindow pixmap,ImageList *backimages) {
2304 CharViewTab* tab = CVGetActiveTab(cv);
2305
2306 while ( backimages!=NULL ) {
2307 struct _GImage *base = backimages->image->list_len==0?
2308 backimages->image->u.image:backimages->image->u.images[0];
2309
2310 GDrawDrawImageMagnified(pixmap, backimages->image, NULL,
2311 (int) (tab->xoff + rint(backimages->xoff * tab->scale)),
2312 (int) (-tab->yoff + cv->height - rint(backimages->yoff*tab->scale)),
2313 (int) rint((base->width*backimages->xscale*tab->scale)),
2314 (int) rint((base->height*backimages->yscale*tab->scale)));
2315 backimages = backimages->next;
2316 }
2317 }
2318
DrawSelImageList(CharView * cv,GWindow pixmap,ImageList * images)2319 static void DrawSelImageList(CharView *cv,GWindow pixmap,ImageList *images) {
2320 while ( images!=NULL ) {
2321 if ( images->selected )
2322 CVDrawBB(cv,pixmap,&images->bb);
2323 images = images->next;
2324 }
2325 }
2326
DrawOldState(CharView * cv,GWindow pixmap,Undoes * undo,DRect * clip)2327 static void DrawOldState(CharView *cv, GWindow pixmap, Undoes *undo, DRect *clip) {
2328 RefChar *refs;
2329
2330 if ( undo==NULL )
2331 return;
2332
2333 CVDrawSplineSet(cv,pixmap,undo->u.state.splines,oldoutlinecol,false,clip);
2334 for ( refs=undo->u.state.refs; refs!=NULL; refs=refs->next )
2335 if ( refs->layers[0].splines!=NULL )
2336 CVDrawSplineSet(cv,pixmap,refs->layers[0].splines,oldoutlinecol,false,clip);
2337 /* Don't do images... */
2338 }
2339
DrawTransOrigin(CharView * cv,GWindow pixmap)2340 static void DrawTransOrigin(CharView *cv, GWindow pixmap) {
2341 CharViewTab* tab = CVGetActiveTab(cv);
2342 int x = rint(cv->p.cx*tab->scale) + tab->xoff, y = cv->height-tab->yoff-rint(cv->p.cy*tab->scale);
2343
2344 GDrawDrawLine(pixmap,x-4,y,x+4,y,transformorigincol);
2345 GDrawDrawLine(pixmap,x,y-4,x,y+4,transformorigincol);
2346 }
2347
DrawVLine(CharView * cv,GWindow pixmap,real pos,Color fg,int flags,GImage * lock,char * name)2348 static void DrawVLine(CharView *cv,GWindow pixmap,real pos,Color fg, int flags,
2349 GImage *lock, char *name) {
2350 CharViewTab* tab = CVGetActiveTab(cv);
2351 char buf[20];
2352 int x = tab->xoff + rint(pos*tab->scale);
2353 DrawLine(cv,pixmap,pos,-32768,pos,32767,fg);
2354 if ( x>-400 && x<cv->width+400 ) {
2355 if ( flags&1 ) {
2356 dtos( buf, pos);
2357 GDrawSetFont(pixmap,cv->small);
2358 GDrawDrawText8(pixmap,x+5,cv->sas+3,buf,-1,metricslabelcol);
2359 if ( lock!=NULL )
2360 GDrawDrawImage(pixmap,lock,NULL,x+5,3+cv->sfh);
2361 }
2362 if ( name!=NULL )
2363 GDrawDrawText8(pixmap,x+5,cv->sas+cv->sfh*(1+lock!=NULL)+3,name,-1,metricslabelcol);
2364 }
2365 if ( ItalicConstrained && cv->b.sc->parent->italicangle!=0 ) {
2366 double t = tan(-cv->b.sc->parent->italicangle*FF_PI/180.);
2367 int xoff = rint(8096*t);
2368 DrawLine(cv,pixmap,pos-xoff,-8096,pos+xoff,8096,italiccoordcol);
2369 }
2370 }
2371
DrawMMGhosts(CharView * cv,GWindow pixmap,DRect * clip)2372 static void DrawMMGhosts(CharView *cv,GWindow pixmap,DRect *clip) {
2373 /* In an MM font, draw any selected alternate versions of the current char */
2374 MMSet *mm = cv->b.sc->parent->mm;
2375 int j;
2376 SplineFont *sub;
2377 SplineChar *sc;
2378 RefChar *rf;
2379
2380 if ( mm==NULL )
2381 return;
2382 for ( j = 0; j<mm->instance_count+1; ++j ) {
2383 if ( j==0 )
2384 sub = mm->normal;
2385 else
2386 sub = mm->instances[j-1];
2387 sc = NULL;
2388 if ( cv->b.sc->parent!=sub && (cv->mmvisible & (1<<j)) &&
2389 cv->b.sc->orig_pos<sub->glyphcnt )
2390 sc = sub->glyphs[cv->b.sc->orig_pos];
2391 if ( sc!=NULL ) {
2392 for ( rf=sc->layers[ly_fore].refs; rf!=NULL; rf = rf->next )
2393 CVDrawSplineSet(cv,pixmap,rf->layers[0].splines,backoutlinecol,false,clip);
2394 CVDrawSplineSet(cv,pixmap,sc->layers[ly_fore].splines,backoutlinecol,false,clip);
2395 }
2396 }
2397 }
2398
CVDrawGridRaster(CharView * cv,GWindow pixmap,DRect * clip)2399 static void CVDrawGridRaster(CharView *cv, GWindow pixmap, DRect *clip ) {
2400 CharViewTab* tab = CVGetActiveTab(cv);
2401 if ( cv->showgrids ) {
2402 /* Draw ppem grid, and the raster for truetype debugging, grid fit */
2403 GRect pixel;
2404 real ygrid_spacing = (cv->b.sc->parent->ascent+cv->b.sc->parent->descent) / (real) cv->ft_ppemy;
2405 real xgrid_spacing = (cv->b.sc->parent->ascent+cv->b.sc->parent->descent) / (real) cv->ft_ppemx;
2406 int max,jmax,ii,i,jj,j;
2407 int minx, maxx, miny, maxy, r,or=0;
2408 Color clut[256];
2409
2410 pixel.width = xgrid_spacing*tab->scale+1;
2411 pixel.height = ygrid_spacing*tab->scale+1;
2412 if ( cv->raster!=NULL ) {
2413 if ( cv->raster->num_greys>2 ) {
2414 int rb, gb, bb, rd, gd, bd;
2415 clut[0] = view_bgcol ;
2416 rb = COLOR_RED(clut[0]); gb = COLOR_GREEN(clut[0]); bb = COLOR_BLUE(clut[0]);
2417 rd = COLOR_RED(rasterdarkcol)-rb;
2418 gd = COLOR_GREEN(rasterdarkcol)-gb;
2419 bd = COLOR_BLUE(rasterdarkcol)-bb;
2420 for ( i=1; i<256; ++i ) {
2421 clut[i] = ( (rb +rd*(i)/0xff)<<16 ) |
2422 ( (gb+gd*(i)/0xff)<<8 ) |
2423 ( (bb+bd*(i)/0xff) );
2424 }
2425 }
2426 minx = cv->raster->lb; maxx = minx+cv->raster->cols;
2427 maxy = cv->raster->as; miny = maxy-cv->raster->rows;
2428 if ( cv->oldraster!=NULL ) {
2429 if ( cv->oldraster->lb<minx ) minx = cv->oldraster->lb;
2430 if ( cv->oldraster->lb+cv->oldraster->cols>maxx ) maxx = cv->oldraster->lb+cv->oldraster->cols;
2431 if ( cv->oldraster->as>maxy ) maxy = cv->oldraster->as;
2432 if ( cv->oldraster->as-cv->oldraster->rows<miny ) miny = cv->oldraster->as-cv->oldraster->rows;
2433 }
2434 for ( ii=maxy; ii>miny; --ii ) {
2435 for ( jj=minx; jj<maxx; ++jj ) {
2436 i = cv->raster->as-ii; j = jj-cv->raster->lb;
2437 if ( i<0 || i>=cv->raster->rows || j<0 || j>=cv->raster->cols )
2438 r = 0;
2439 else if ( cv->raster->num_greys<=2 )
2440 r = cv->raster->bitmap[i*cv->raster->bytes_per_row+(j>>3)] & (1<<(7-(j&7)));
2441 else
2442 r = cv->raster->bitmap[i*cv->raster->bytes_per_row+j];
2443 if ( cv->oldraster==NULL || cv->oldraster->num_greys!=cv->raster->num_greys)
2444 or = r;
2445 else {
2446 i = cv->oldraster->as-ii; j = jj-cv->oldraster->lb;
2447 if ( i<0 || i>=cv->oldraster->rows || j<0 || j>=cv->oldraster->cols )
2448 or = 0;
2449 else if ( cv->oldraster->num_greys<=2 )
2450 or = cv->oldraster->bitmap[i*cv->oldraster->bytes_per_row+(j>>3)] & (1<<(7-(j&7)));
2451 else
2452 or = cv->oldraster->bitmap[i*cv->oldraster->bytes_per_row+j];
2453 }
2454 if ( r || ( or && cv->showdebugchanges)) {
2455 pixel.x = jj*xgrid_spacing*tab->scale + tab->xoff+1;
2456 pixel.y = cv->height-tab->yoff - rint(ii*ygrid_spacing*tab->scale);
2457 if ( cv->showdebugchanges ) {
2458 if ( cv->raster->num_greys<=2 )
2459 GDrawFillRect(pixmap,&pixel,(r && or) ? rastercol : r ? rasternewcol : rasteroldcol );
2460 else
2461 GDrawFillRect(pixmap,&pixel,(r-or>-16 && r-or<16) ? clut[r] : (clut[r]&0x00ff00) );
2462 } else {
2463 if ( cv->raster->num_greys<=2 )
2464 GDrawFillRect(pixmap,&pixel, rastercol );
2465 else
2466 GDrawFillRect(pixmap,&pixel, clut[r] );
2467 }
2468 }
2469 }
2470 }
2471 }
2472
2473 for ( i = floor( clip->x/xgrid_spacing ), max = ceil((clip->x+clip->width)/xgrid_spacing);
2474 i<=max; ++i )
2475 DrawLine(cv,pixmap,i*xgrid_spacing,-32768,i*xgrid_spacing,32767,i==0?coordcol:rastergridcol);
2476 for ( i = floor( clip->y/ygrid_spacing ), max = ceil((clip->y+clip->height)/ygrid_spacing);
2477 i<=max; ++i )
2478 DrawLine(cv,pixmap,-32768,i*ygrid_spacing,32767,i*ygrid_spacing,i==0?coordcol:rastergridcol);
2479 if ( xgrid_spacing*tab->scale>=7 && ygrid_spacing*tab->scale>=7) {
2480 for ( i = floor( clip->x/xgrid_spacing ), max = ceil((clip->x+clip->width)/xgrid_spacing);
2481 i<=max; ++i )
2482 for ( j = floor( clip->y/ygrid_spacing ), jmax = ceil((clip->y+clip->height)/ygrid_spacing);
2483 j<=jmax; ++j ) {
2484 int x = (i+.5)*xgrid_spacing*tab->scale + tab->xoff;
2485 int y = cv->height-tab->yoff - rint((j+.5)*ygrid_spacing*tab->scale);
2486 GDrawDrawLine(pixmap,x-2,y,x+2,y,rastergridcol);
2487 GDrawDrawLine(pixmap,x,y-2,x,y+2,rastergridcol);
2488 }
2489 }
2490 if ( cv->qg!=NULL ) {
2491 pixel.x = cv->note_x*xgrid_spacing*tab->scale + tab->xoff;
2492 pixel.y = cv->height-tab->yoff - rint(cv->note_y*ygrid_spacing*tab->scale)
2493 - pixel.height;
2494 if ( pixel.height>=20 )
2495 GDrawSetLineWidth(pixmap,3);
2496 else if ( pixel.height>10 )
2497 GDrawSetLineWidth(pixmap,2);
2498 GDrawDrawRect(pixmap,&pixel,deltagridcol);
2499 GDrawSetLineWidth(pixmap,0);
2500 {
2501 int x = (cv->note_x+.5)*xgrid_spacing*tab->scale + tab->xoff;
2502 int y = cv->height-tab->yoff - rint((cv->note_y+.5)*ygrid_spacing*tab->scale);
2503 GDrawDrawLine(pixmap,x-2,y,x+2,y,deltagridcol);
2504 GDrawDrawLine(pixmap,x,y-2,x,y+2,deltagridcol);
2505 }
2506 }
2507 }
2508 if ( cv->showback[0]&1 ) {
2509 CVDrawSplineSet(cv,pixmap,cv->b.gridfit,gridfitoutlinecol,
2510 cv->showpoints,clip);
2511 }
2512 }
2513
APinSC(AnchorPoint * ap,SplineChar * sc)2514 static int APinSC(AnchorPoint *ap,SplineChar *sc) {
2515 /* Anchor points can be deleted ... */
2516 AnchorPoint *test;
2517
2518 for ( test=sc->anchor; test!=NULL && test!=ap; test = test->next );
2519 return( test==ap );
2520 }
2521
DrawAPMatch(CharView * cv,GWindow pixmap,DRect * clip)2522 static void DrawAPMatch(CharView *cv,GWindow pixmap,DRect *clip) {
2523 SplineChar *sc = cv->b.sc, *apsc = cv->apsc;
2524 SplineFont *sf = sc->parent;
2525 real trans[6];
2526 SplineSet *head, *tail, *temp;
2527 RefChar *ref;
2528 int layer = CVLayer((CharViewBase *) cv);
2529
2530 if ( cv->b.drawmode==dm_grid )
2531 return;
2532
2533 /* The other glyph might have been removed from the font */
2534 /* Either anchor might have been deleted. Be prepared for that to happen */
2535 if ( (apsc->orig_pos>=sf->glyphcnt || apsc->orig_pos<0) ||
2536 sf->glyphs[apsc->orig_pos]!=apsc ||
2537 !APinSC(cv->apmine,sc) || !APinSC(cv->apmatch,apsc)) {
2538 cv->apmine = cv->apmatch = NULL;
2539 cv->apsc =NULL;
2540 return;
2541 }
2542
2543 /* Ok this isn't very accurate, but we are going to use the current glyph's*/
2544 /* coordinate system (because we're showing the current glyph), we should */
2545 /* always use the base character's coordinates, but that would screw up */
2546 /* editing of the current glyph if it happened to be the mark */
2547 trans[0] = trans[3] = 1;
2548 trans[1] = trans[2] = 0;
2549 trans[4] = cv->apmine->me.x - cv->apmatch->me.x;
2550 trans[5] = cv->apmine->me.y - cv->apmatch->me.y;
2551
2552 head = tail = SplinePointListCopy(apsc->layers[layer].splines);
2553 for ( ref = apsc->layers[layer].refs; ref!=NULL; ref = ref->next ) {
2554 temp = SplinePointListCopy(ref->layers[0].splines);
2555 if ( head!=NULL ) {
2556 for ( ; tail->next!=NULL; tail = tail->next );
2557 tail->next = temp;
2558 } else
2559 head = tail = temp;
2560 }
2561 head = SplinePointListTransform(head,trans,tpt_AllPoints);
2562 CVDrawSplineSet(cv,pixmap,head,anchoredoutlinecol,
2563 false,clip);
2564 SplinePointListsFree(head);
2565 if ( cv->apmine->type==at_mark || cv->apmine->type==at_centry ) {
2566 DrawVLine(cv,pixmap,trans[4],anchoredoutlinecol,false,NULL,NULL);
2567 DrawLine(cv,pixmap,-8096,trans[5],8096,trans[5],anchoredoutlinecol);
2568 }
2569 }
2570
DrawPLine(CharView * cv,GWindow pixmap,int x1,int y1,int x2,int y2,Color col)2571 static void DrawPLine(CharView *cv,GWindow pixmap,int x1, int y1, int x2, int y2,Color col) {
2572
2573 if ( x1==x2 || y1==y2 ) {
2574 if ( x1<0 ) x1=0;
2575 else if ( x1>cv->width ) x1 = cv->width;
2576 if ( x2<0 ) x2=0;
2577 else if ( x2>cv->width ) x2 = cv->width;
2578 if ( y1<0 ) y1=0;
2579 else if ( y1>cv->height ) y1 = cv->height;
2580 if ( y2<0 ) y2=0;
2581 else if ( y2>cv->height ) y2 = cv->height;
2582 } else if ( y1<-1000 || y2<-1000 || x1<-1000 || x2<-1000 ||
2583 y1>cv->height+1000 || y2>cv->height+1000 ||
2584 x1>cv->width+1000 || x2>cv->width+1000 )
2585 return;
2586 GDrawDrawLine(pixmap,x1,y1,x2,y2,col);
2587 }
2588
FindQuickBounds(SplineSet * ss,BasePoint ** bounds)2589 static void FindQuickBounds(SplineSet *ss,BasePoint **bounds) {
2590 SplinePoint *sp;
2591
2592 for ( ; ss!=NULL; ss=ss->next ) {
2593 sp = ss->first;
2594 if ( sp->next==NULL || sp->next->to==sp ) /* Ignore contours with one point. Often tt points for moving references or anchors */
2595 continue;
2596 for (;;) {
2597 if ( bounds[0]==NULL )
2598 bounds[0] = bounds[1] = bounds[2] = bounds[3] = &sp->me;
2599 else {
2600 if ( sp->me.x<bounds[0]->x ) bounds[0] = &sp->me;
2601 if ( sp->me.x>bounds[1]->x ) bounds[1] = &sp->me;
2602 if ( sp->me.y<bounds[2]->y ) bounds[2] = &sp->me;
2603 if ( sp->me.y>bounds[3]->y ) bounds[3] = &sp->me;
2604 }
2605 if ( sp->next==NULL )
2606 break;
2607 sp = sp->next->to;
2608 if ( sp==ss->first )
2609 break;
2610 }
2611 }
2612 }
2613
SSFindItalicBounds(SplineSet * ss,double t,SplinePoint ** left,SplinePoint ** right)2614 static void SSFindItalicBounds(SplineSet *ss,double t,SplinePoint **left, SplinePoint **right) {
2615 SplinePoint *sp;
2616
2617 if ( t==0 )
2618 return;
2619
2620 for ( ; ss!=NULL; ss=ss->next ) {
2621 sp = ss->first;
2622 if ( sp->next==NULL || sp->next->to==sp ) /* Ignore contours with one point. Often tt points for moving references or anchors */
2623 continue;
2624 for (;;) {
2625 if ( *left==NULL )
2626 *left = *right = sp;
2627 else {
2628 double xoff = sp->me.y*t;
2629 if ( sp->me.x-xoff < (*left)->me.x - (*left)->me.y*t ) *left = sp;
2630 if ( sp->me.x-xoff > (*right)->me.x - (*right)->me.y*t ) *right = sp;
2631 }
2632 if ( sp->next==NULL )
2633 break;
2634 sp = sp->next->to;
2635 if ( sp==ss->first )
2636 break;
2637 }
2638 }
2639 }
2640
CVSideBearings(GWindow pixmap,CharView * cv)2641 static void CVSideBearings(GWindow pixmap, CharView *cv) {
2642 CharViewTab* tab = CVGetActiveTab(cv);
2643 SplineChar *sc = cv->b.sc;
2644 RefChar *ref;
2645 BasePoint *bounds[4];
2646 int layer,last, first,l;
2647 int x,y, x2, y2;
2648 char buf[20];
2649
2650 memset(bounds,0,sizeof(bounds));
2651 if ( sc->parent->multilayer ) {
2652 last = sc->layer_cnt-1;
2653 first = ly_fore;
2654 } else {
2655 first = last = CVLayer( (CharViewBase *) cv);
2656 if ( first==ly_grid )
2657 first = last = ly_fore;
2658 }
2659 for ( layer = first ; layer<=last; ++layer ) {
2660 FindQuickBounds(sc->layers[layer].splines,bounds);
2661 for ( ref=sc->layers[layer].refs; ref!=NULL; ref=ref->next )
2662 for ( l=0; l<ref->layer_cnt; ++l )
2663 FindQuickBounds(ref->layers[l].splines,bounds);
2664 }
2665
2666 if ( bounds[0]==NULL )
2667 return; /* no points. no side bearings */
2668
2669 GDrawSetFont(pixmap,cv->small);
2670 if ( cv->showhmetrics ) {
2671 if ( bounds[0]->x!=0 ) {
2672 x = rint(bounds[0]->x*tab->scale) + tab->xoff;
2673 y = cv->height-tab->yoff-rint(bounds[0]->y*tab->scale);
2674 DrawPLine(cv,pixmap,tab->xoff,y,x,y,metricslabelcol);
2675 /* arrow heads */
2676 DrawPLine(cv,pixmap,tab->xoff,y,tab->xoff+4,y+4,metricslabelcol);
2677 DrawPLine(cv,pixmap,tab->xoff,y,tab->xoff+4,y-4,metricslabelcol);
2678 DrawPLine(cv,pixmap,x,y,x-4,y-4,metricslabelcol);
2679 DrawPLine(cv,pixmap,x,y,x-4,y+4,metricslabelcol);
2680 dtos( buf, bounds[0]->x);
2681 x = tab->xoff + (x-tab->xoff-GDrawGetText8Width(pixmap,buf,-1))/2;
2682 GDrawDrawText8(pixmap,x,y-4,buf,-1,metricslabelcol);
2683 }
2684
2685 if ( sc->width != bounds[1]->x ) {
2686 x = rint(bounds[1]->x*tab->scale) + tab->xoff;
2687 y = cv->height-tab->yoff-rint(bounds[1]->y*tab->scale);
2688 x2 = rint(sc->width*tab->scale) + tab->xoff;
2689 DrawPLine(cv,pixmap,x,y,x2,y,metricslabelcol);
2690 /* arrow heads */
2691 DrawPLine(cv,pixmap,x,y,x+4,y+4,metricslabelcol);
2692 DrawPLine(cv,pixmap,x,y,x+4,y-4,metricslabelcol);
2693 DrawPLine(cv,pixmap,x2,y,x2-4,y-4,metricslabelcol);
2694 DrawPLine(cv,pixmap,x2,y,x2-4,y+4,metricslabelcol);
2695 dtos( buf, sc->width-bounds[1]->x);
2696 x = x + (x2-x-GDrawGetText8Width(pixmap,buf,-1))/2;
2697 GDrawDrawText8(pixmap,x,y-4,buf,-1,metricslabelcol);
2698 }
2699 if ( ItalicConstrained && cv->b.sc->parent->italicangle!=0 ) {
2700 double t = tan(-cv->b.sc->parent->italicangle*FF_PI/180.);
2701 if ( t!=0 ) {
2702 SplinePoint *leftmost=NULL, *rightmost=NULL;
2703 for ( layer=first; layer<=last; ++layer ) {
2704 SSFindItalicBounds(sc->layers[layer].splines,t,&leftmost,&rightmost);
2705 for ( ref=sc->layers[layer].refs; ref!=NULL; ref=ref->next )
2706 for ( l=0; l<ref->layer_cnt; ++l )
2707 SSFindItalicBounds(ref->layers[l].splines,t,&leftmost,&rightmost);
2708 }
2709 if ( leftmost!=NULL ) {
2710 x = rint(leftmost->me.y*t*tab->scale) + tab->xoff;
2711 x2 = rint(leftmost->me.x*tab->scale) + tab->xoff;
2712 y = cv->height-tab->yoff-rint(leftmost->me.y*tab->scale);
2713 DrawPLine(cv,pixmap,x,y,x2,y,italiccoordcol);
2714 /* arrow heads */
2715 DrawPLine(cv,pixmap,x,y,x+4,y+4,italiccoordcol);
2716 DrawPLine(cv,pixmap,x,y,x+4,y-4,italiccoordcol);
2717 DrawPLine(cv,pixmap,x2,y,x2-4,y-4,italiccoordcol);
2718 DrawPLine(cv,pixmap,x2,y,x2-4,y+4,italiccoordcol);
2719 dtos( buf, leftmost->me.x-leftmost->me.y*t);
2720 x = x + (x2-x-GDrawGetText8Width(pixmap,buf,-1))/2;
2721 GDrawDrawText8(pixmap,x,y+12,buf,-1,italiccoordcol);
2722 }
2723 if ( rightmost!=NULL ) {
2724 x = rint(rightmost->me.x*tab->scale) + tab->xoff;
2725 y = cv->height-tab->yoff-rint(rightmost->me.y*tab->scale);
2726 x2 = rint((sc->width + rightmost->me.y*t)*tab->scale) + tab->xoff;
2727 DrawPLine(cv,pixmap,x,y,x2,y,italiccoordcol);
2728 /* arrow heads */
2729 DrawPLine(cv,pixmap,x,y,x+4,y+4,italiccoordcol);
2730 DrawPLine(cv,pixmap,x,y,x+4,y-4,italiccoordcol);
2731 DrawPLine(cv,pixmap,x2,y,x2-4,y-4,italiccoordcol);
2732 DrawPLine(cv,pixmap,x2,y,x2-4,y+4,italiccoordcol);
2733 dtos( buf, sc->width+rightmost->me.y*t-rightmost->me.x);
2734 x = x + (x2-x-GDrawGetText8Width(pixmap,buf,-1))/2;
2735 GDrawDrawText8(pixmap,x,y+12,buf,-1,italiccoordcol);
2736 }
2737 }
2738 }
2739 }
2740
2741 if ( cv->showvmetrics ) {
2742 x = rint(bounds[2]->x*tab->scale) + tab->xoff;
2743 y = cv->height-tab->yoff-rint(bounds[2]->y*tab->scale);
2744 y2 = cv->height-tab->yoff-rint(-sc->parent->descent*tab->scale);
2745 DrawPLine(cv,pixmap,x,y,x,y2,metricslabelcol);
2746 /* arrow heads */
2747 DrawPLine(cv,pixmap,x,y,x-4,y+4,metricslabelcol);
2748 DrawPLine(cv,pixmap,x,y,x+4,y+4,metricslabelcol);
2749 DrawPLine(cv,pixmap,x,y2,x+4,y2-4,metricslabelcol);
2750 DrawPLine(cv,pixmap,x,y2,x-4,y2-4,metricslabelcol);
2751 dtos( buf, bounds[2]->y+sc->parent->descent);
2752 y = y - (y-y2-cv->sfh)/2;
2753 GDrawDrawText8(pixmap,x+4,y,buf,-1,metricslabelcol);
2754
2755 x = rint(bounds[3]->x*tab->scale) + tab->xoff;
2756 y = cv->height-tab->yoff-rint(bounds[3]->y*tab->scale);
2757 y2 = cv->height-tab->yoff-rint(sc->parent->ascent*tab->scale);
2758 DrawPLine(cv,pixmap,x,y,x,y2,metricslabelcol);
2759 /* arrow heads */
2760 DrawPLine(cv,pixmap,x,y,x-4,y-4,metricslabelcol);
2761 DrawPLine(cv,pixmap,x,y,x+4,y-4,metricslabelcol);
2762 DrawPLine(cv,pixmap,x,y2,x+4,y2+4,metricslabelcol);
2763 DrawPLine(cv,pixmap,x,y2,x-4,y2+4,metricslabelcol);
2764 dtos( buf, sc->parent->ascent-bounds[3]->y);
2765 x = x + (x2-x-GDrawGetText8Width(pixmap,buf,-1))/2;
2766 GDrawDrawText8(pixmap,x,y-4,buf,-1,metricslabelcol);
2767 }
2768 }
2769
CVExposeGlyphFill(CharView * cv,GWindow pixmap,GEvent * event,DRect * clip)2770 static int CVExposeGlyphFill(CharView *cv, GWindow pixmap, GEvent *event, DRect* clip ) {
2771 CharViewTab* tab = CVGetActiveTab(cv);
2772 int layer, cvlayer = CVLayer((CharViewBase *) cv);
2773 int filled = 0;
2774
2775 if( shouldShowFilledUsingCairo(cv) ) {
2776 layer = cvlayer;
2777 if ( layer>=0 ) {
2778 CVDrawLayerSplineSet(cv,pixmap,&cv->b.sc->layers[layer],foreoutlinecol,
2779 cv->showpoints, clip, sfm_fill );
2780 filled = 1;
2781 }
2782 } else {
2783 if (( cv->showfore || cv->b.drawmode==dm_fore ) && cv->showfilled &&
2784 cv->filled!=NULL ) {
2785 GDrawDrawImage(pixmap, &cv->gi, NULL,
2786 tab->xoff + cv->filled->xmin,
2787 -tab->yoff + cv->height-cv->filled->ymax);
2788 filled = 1;
2789 }
2790 }
2791 return(filled);
2792 }
2793
CVExposeReferences(CharView * cv,GWindow pixmap,SplineChar * sc,int layer,DRect * clip)2794 static void CVExposeReferences( CharView *cv, GWindow pixmap, SplineChar* sc, int layer, DRect* clip )
2795 {
2796 RefChar *rf = 0;
2797 int rlayer = 0;
2798
2799 for ( rf = sc->layers[layer].refs; rf!=NULL; rf = rf->next )
2800 {
2801 if ( cv->showrefnames )
2802 CVDrawRefName(cv,pixmap,rf,0);
2803 enum outlinesfm_flags refsfm = sfm_stroke;
2804 if( shouldShowFilledUsingCairo(cv) ) {
2805 refsfm = sfm_fill;
2806 }
2807
2808 for ( rlayer=0; rlayer<rf->layer_cnt; ++rlayer )
2809 CVDrawSplineSetSpecialized(cv,pixmap,rf->layers[rlayer].splines,foreoutlinecol,-1,clip, refsfm, 0);
2810 if ( rf->selected && cv->b.layerheads[cv->b.drawmode]==&sc->layers[layer])
2811 CVDrawBB(cv,pixmap,&rf->bb);
2812 }
2813 }
2814
2815
CVExpose(CharView * cv,GWindow pixmap,GEvent * event)2816 static void CVExpose(CharView *cv, GWindow pixmap, GEvent *event ) {
2817 CharViewTab* tab = CVGetActiveTab(cv);
2818 SplineFont *sf = cv->b.sc->parent;
2819 RefChar *rf;
2820 GRect old;
2821 DRect clip;
2822 char buf[20];
2823 PST *pst;
2824 int i, layer, rlayer, cvlayer = CVLayer((CharViewBase *) cv);
2825 enum outlinesfm_flags strokeFillMode = sfm_stroke;
2826 int GlyphHasBeenFilled = 0;
2827
2828 GDrawPushClip(pixmap,&event->u.expose.rect,&old);
2829
2830 if( shouldShowFilledUsingCairo(cv) ) {
2831 strokeFillMode = sfm_fill;
2832 }
2833
2834 clip.width = event->u.expose.rect.width/tab->scale;
2835 clip.height = event->u.expose.rect.height/tab->scale;
2836 clip.x = (event->u.expose.rect.x-tab->xoff)/tab->scale;
2837 clip.y = (cv->height-event->u.expose.rect.y-event->u.expose.rect.height-tab->yoff)/tab->scale;
2838
2839 GDrawSetFont(pixmap,cv->small);
2840 GDrawSetLineWidth(pixmap,0);
2841
2842 if ( !cv->show_ft_results && cv->dv==NULL ) {
2843
2844 if ( cv->backimgs==NULL && !(GDrawHasCairo(cv->v)&gc_buildpath))
2845 cv->backimgs = GDrawCreatePixmap(GDrawGetDisplayOfWindow(cv->v),cv->v,cv->width,cv->height);
2846 if ( GDrawHasCairo(cv->v)&gc_buildpath ) {
2847 for ( layer = ly_back; layer<cv->b.sc->layer_cnt; ++layer ) if ( cv->b.sc->layers[layer].images!=NULL ) {
2848 if (( sf->multilayer && ((( cv->showback[0]&1 || cvlayer==layer) && layer==ly_back ) ||
2849 ((cv->showfore || cvlayer==layer) && layer>ly_back)) ) ||
2850 ( !sf->multilayer && (((cv->showfore && cvlayer==layer) && layer==ly_fore) ||
2851 (((cv->showback[layer>>5]&(1<<(layer&31))) || cvlayer==layer) && layer!=ly_fore))) ) {
2852 /* This really should be after the grids, but then it would completely*/
2853 /* hide them. */
2854 DrawImageList(cv,pixmap,cv->b.sc->layers[layer].images);
2855 }
2856 }
2857 cv->back_img_out_of_date = false;
2858 if ( cv->showhhints || cv->showvhints || cv->showdhints || cv->showblues || cv->showfamilyblues)
2859 CVShowHints(cv,pixmap);
2860 } else if ( cv->back_img_out_of_date ) {
2861 GDrawFillRect(cv->backimgs,NULL,view_bgcol);
2862 if ( cv->showhhints || cv->showvhints || cv->showdhints || cv->showblues || cv->showfamilyblues)
2863 CVShowHints(cv,cv->backimgs);
2864 for ( layer = ly_back; layer<cv->b.sc->layer_cnt; ++layer ) if ( cv->b.sc->layers[layer].images!=NULL ) {
2865 if (( sf->multilayer && ((( cv->showback[0]&1 || cvlayer==layer) && layer==ly_back ) ||
2866 ((cv->showfore || cvlayer==layer) && layer>ly_back)) ) ||
2867 ( !sf->multilayer && (((cv->showfore && cvlayer==layer) && layer==ly_fore) ||
2868 (((cv->showback[layer>>5]&(1<<(layer&31))) || cvlayer==layer) && layer!=ly_fore))) ) {
2869 /* This really should be after the grids, but then it would completely*/
2870 /* hide them. */
2871 if ( cv->back_img_out_of_date )
2872 DrawImageList(cv,cv->backimgs,cv->b.sc->layers[layer].images);
2873 }
2874 }
2875 cv->back_img_out_of_date = false;
2876 }
2877 if ( cv->backimgs!=NULL ) {
2878 GRect r;
2879 r.x = r.y = 0; r.width = cv->width; r.height = cv->height;
2880 GDrawDrawPixmap(pixmap,cv->backimgs,&r,0,0);
2881 } else if ( !(GDrawHasCairo(cv->v)&gc_buildpath) &&
2882 ( cv->showhhints || cv->showvhints || cv->showdhints || cv->showblues || cv->showfamilyblues)) {
2883 /* if we've got bg images (and we're showing them) then the hints live in */
2884 /* the bg image pixmap (else they get overwritten by the pixmap) */
2885 CVShowHints(cv,pixmap);
2886 }
2887 if ( cv->showgrids || cv->b.drawmode==dm_grid ) {
2888 CVDrawSplineSet(cv,pixmap,cv->b.fv->sf->grid.splines,guideoutlinecol,
2889 cv->showpoints && cv->b.drawmode==dm_grid,&clip);
2890 }
2891 if ( cv->showhmetrics ) {
2892 Color lbcolor = (!cv->inactive && cv->lbearingsel) ? lbearingselcol : coordcol;
2893 DrawVLine(cv,pixmap,0,lbcolor,false,NULL,NULL);
2894 DrawLine(cv,pixmap,-8096,0,8096,0,coordcol);
2895 DrawLine(cv,pixmap,-8096,sf->ascent,8096,sf->ascent,coordcol);
2896 DrawLine(cv,pixmap,-8096,-sf->descent,8096,-sf->descent,coordcol);
2897 }
2898 if ( cv->showvmetrics ) {
2899 /*DrawLine(cv,pixmap,(sf->ascent+sf->descent)/2,-8096,(sf->ascent+sf->descent)/2,8096,coordcol);
2900 DrawLine(cv,pixmap,-8096,sf->vertical_origin,8096,sf->vertical_origin,coordcol);*/
2901 }
2902
2903 DrawSelImageList(cv,pixmap,cv->b.layerheads[cv->b.drawmode]->images);
2904
2905 /* Wrong order, I know. But it is useful to have the background */
2906 /* visible on top of the fill... */
2907 GlyphHasBeenFilled = CVExposeGlyphFill(cv, pixmap, event, &clip );
2908 } else {
2909 /* Draw FreeType Results */
2910 CVDrawGridRaster(cv,pixmap,&clip);
2911 }
2912
2913 if ( cv->b.layerheads[cv->b.drawmode]->undoes!=NULL &&
2914 cv->b.layerheads[cv->b.drawmode]->undoes->undotype==ut_tstate )
2915 DrawOldState(cv,pixmap,cv->b.layerheads[cv->b.drawmode]->undoes, &clip);
2916
2917 if ( cv->showfore )
2918 cv->showback[0] |= (1<<ly_fore);
2919 else
2920 cv->showback[0] &= ~(1<<ly_fore);
2921
2922 for ( layer=ly_back; layer<cv->b.sc->layer_cnt; ++layer ) if ( layer!=cvlayer ) {
2923 if ( cv->showback[layer>>5]&(1<<(layer&31)) ) {
2924 /* Used to draw the image list here, but that's too slow. Optimization*/
2925 /* is to draw to pixmap, dump pixmap a bit earlier */
2926 /* Then when we moved the fill image around, we had to deal with the */
2927 /* images before the fill... */
2928 int activelayer = CVLayer(&cv->b);
2929
2930 enum outlinesfm_flags strokeFillMode = sfm_stroke;
2931 if( cv->inPreviewMode )
2932 strokeFillMode = sfm_nothing;
2933 if( layer == activelayer && layer >= ly_back )
2934 strokeFillMode = sfm_fill;
2935
2936 CVDrawLayerSplineSet(cv,pixmap,&cv->b.sc->layers[layer],
2937 !sf->multilayer || layer==ly_back ? backoutlinecol : foreoutlinecol,
2938 false,&clip,strokeFillMode);
2939 for ( rf=cv->b.sc->layers[layer].refs; rf!=NULL; rf = rf->next ) {
2940 if ( /* cv->b.drawmode==dm_back &&*/ cv->showrefnames )
2941 CVDrawRefName(cv,pixmap,rf,0);
2942 for ( rlayer=0; rlayer<rf->layer_cnt; ++rlayer )
2943 CVDrawSplineSet(cv,pixmap,rf->layers[rlayer].splines, backoutlinecol,false,&clip);
2944 if ( rf->selected && cv->b.layerheads[cv->b.drawmode]==&cv->b.sc->layers[layer])
2945 CVDrawBB(cv,pixmap,&rf->bb);
2946 }
2947 }
2948 }
2949 if ( cv->mmvisible!=0 )
2950 DrawMMGhosts(cv,pixmap,&clip);
2951 if ( cv->template1!=NULL )
2952 CVDrawTemplates(cv,pixmap,cv->template1,&clip);
2953 if ( cv->template2!=NULL )
2954 CVDrawTemplates(cv,pixmap,cv->template2,&clip);
2955
2956 /* Draw the active layer last so its splines are on top. */
2957 /* Note that we don't check whether the layer is visible or not, we always*/
2958 /* draw the current layer -- unless they've turned on grid fit. Then they*/
2959 /* might want to hide the active layer. */
2960 layer = cvlayer;
2961
2962
2963 /*
2964 * If we have a pretransform_spl and the user wants to see it then show it to them
2965 */
2966 if(cv->p.pretransform_spl) {
2967 CVDrawSplineSetSpecialized(cv, pixmap, cv->p.pretransform_spl,
2968 DraggingComparisonOutlineColor, 1, &clip, sfm_stroke_trans,
2969 DraggingComparisonAlphaChannelOverride);
2970 }
2971
2972 /* The call to CVExposeGlyphFill() above will have rendered a filled glyph already. */
2973 /* We draw the outline only at this stage so as to have it layered */
2974 /* over the control points if they are currently visible. */
2975 /* CVDrawLayerSplineSet() will draw both the control points, and the font outline over those */
2976 /* NB:
2977 * Drawing the stroked outline may also use the color
2978 * clippathcol for some splines, so we can't really avoid a
2979 * restroke unless we are sure
2980 * FOR-ALL(splines):spl->is_clip_path==0 */
2981 if( shouldShowFilledUsingCairo(cv) ) {
2982 strokeFillMode = sfm_stroke;
2983 }
2984 if( GlyphHasBeenFilled ) {
2985 strokeFillMode = sfm_stroke_trans;
2986 }
2987
2988 if ( layer<0 ) /* Guide lines are special */
2989 CVDrawLayerSplineSet( cv,pixmap,cv->b.layerheads[cv->b.drawmode],foreoutlinecol,
2990 cv->showpoints ,&clip, strokeFillMode );
2991 else if ( (cv->showback[layer>>5]&(1<<(layer&31))) ||
2992 (!cv->show_ft_results && cv->dv==NULL ))
2993 {
2994 CVExposeReferences( cv, pixmap, cv->b.sc, layer, &clip );
2995 }
2996 if ( layer>=0 )
2997 {
2998 if( cv->dv && !(cv->showback[layer>>5]&(1<<(layer&31))))
2999 {
3000 // MIQ 2013 feb: issue/168
3001 // turn off the glyph outline if we are in debug mode and
3002 // the layer is not visible
3003 }
3004 else
3005 {
3006 CVDrawLayerSplineSet( cv,pixmap,&cv->b.sc->layers[layer],foreoutlinecol,
3007 cv->showpoints ,&clip, strokeFillMode );
3008
3009
3010 int showpoints = 0;
3011 enum outlinesfm_flags sm = sfm_stroke;
3012 if( cv->inPreviewMode ) {
3013 sm = sfm_fill;
3014 }
3015
3016 int ridx = cv->additionalCharsToShowActiveIndex+1;
3017 // TRACE("expose(b) additionalCharsToShowActiveIndex:%d\n", cv->additionalCharsToShowActiveIndex );
3018 if( cv->additionalCharsToShow[ ridx ] )
3019 {
3020 int i = 1;
3021 int originalxoff = tab->xoff;
3022 int offset = tab->scale * cv->b.sc->width;
3023 for( i=ridx; i < additionalCharsToShowLimit; i++ )
3024 {
3025 // TRACE("expose(right) loop:%d\n", i );
3026 SplineChar* xc = cv->additionalCharsToShow[i];
3027 if( !xc )
3028 break;
3029
3030 tab->xoff += offset;
3031 CVExposeReferences( cv, pixmap, xc, layer, &clip );
3032 CVDrawLayerSplineSet( cv, pixmap, &xc->layers[layer], foreoutlinecol,
3033 showpoints ,&clip, sm );
3034 offset = tab->scale * xc->width;
3035 }
3036 tab->xoff = originalxoff;
3037 }
3038
3039
3040
3041 if( cv->additionalCharsToShowActiveIndex > 0 )
3042 {
3043 int i = 1;
3044 int originalxoff = tab->xoff;
3045 int offset = 0;
3046
3047 for( i=cv->additionalCharsToShowActiveIndex-1; i >= 0; i-- )
3048 {
3049 // TRACE("expose(left) loop:%d\n", i );
3050 SplineChar* xc = cv->additionalCharsToShow[i];
3051 if( !xc )
3052 break;
3053
3054 offset = tab->scale * xc->width;
3055 tab->xoff -= offset;
3056 CVExposeReferences( cv, pixmap, xc, layer, &clip );
3057 CVDrawLayerSplineSet( cv, pixmap, &xc->layers[layer], foreoutlinecol,
3058 showpoints ,&clip, sm );
3059 }
3060 tab->xoff = originalxoff;
3061 }
3062
3063 // TRACE("expose(e) ridx:%d\n", ridx );
3064
3065 }
3066 }
3067
3068
3069 if ( cv->freehand.current_trace )
3070 CVDrawSplineSet( cv,pixmap,cv->freehand.current_trace,tracecol,
3071 false,&clip);
3072
3073 if ( cv->showhmetrics && (cv->b.container==NULL || cv->b.container->funcs->type==cvc_mathkern) ) {
3074 RefChar *lock = HasUseMyMetrics(cv->b.sc,cvlayer);
3075 if ( lock!=NULL ) cv->b.sc->width = lock->sc->width;
3076 DrawVLine(cv,pixmap,cv->b.sc->width,(!cv->inactive && cv->widthsel)?widthselcol:widthcol,true,
3077 lock!=NULL ? &GIcon_lock : NULL, NULL);
3078 if ( cv->b.sc->italic_correction!=TEX_UNDEF && cv->b.sc->italic_correction!=0 ) {
3079 GDrawSetDashedLine(pixmap,2,2,0);
3080 DrawVLine(cv,pixmap,cv->b.sc->width+cv->b.sc->italic_correction,(!cv->inactive && cv->icsel)?widthselcol:widthcol,
3081 /* GT: Italic Correction */
3082 false, NULL,_("ItalicCor."));
3083 GDrawSetDashedLine(pixmap,0,0,0);
3084 }
3085 }
3086 if ( cv->showhmetrics && cv->b.container==NULL ) {
3087 for ( pst=cv->b.sc->possub; pst!=NULL && pst->type!=pst_lcaret; pst=pst->next );
3088 if ( pst!=NULL ) {
3089 for ( i=0; i<pst->u.lcaret.cnt; ++i )
3090 DrawVLine(cv,pixmap,pst->u.lcaret.carets[i],lcaretcol,true,NULL,_("Lig.Caret"));
3091 }
3092 if ( cv->show_ft_results || cv->dv!=NULL )
3093 DrawVLine(cv,pixmap,cv->b.ft_gridfitwidth,widthgridfitcol,true,NULL,NULL);
3094 if ( cv->b.sc->top_accent_horiz!=TEX_UNDEF )
3095 DrawVLine(cv,pixmap,cv->b.sc->top_accent_horiz,(!cv->inactive && cv->tah_sel)?widthselcol:anchorcol,true,
3096 NULL,_("TopAccent"));
3097 }
3098 if ( cv->showvmetrics ) {
3099 int vertical_height = -cv->b.sc->vwidth + cv->b.sc->parent->ascent;
3100 int len, y = -tab->yoff + cv->height - rint(vertical_height*tab->scale);
3101 DrawLine(cv,pixmap,-32768,vertical_height,32767,vertical_height,
3102 (!cv->inactive && cv->vwidthsel)?widthselcol:widthcol);
3103 if ( y>-40 && y<cv->height+40 ) {
3104 dtos( buf, cv->b.sc->vwidth);
3105 GDrawSetFont(pixmap,cv->small);
3106 len = GDrawGetText8Width(pixmap,buf,-1);
3107 GDrawDrawText8(pixmap,cv->width-len-5,y,buf,-1,metricslabelcol);
3108 }
3109 }
3110 if ( cv->showsidebearings && cv->showfore &&
3111 (cv->showvmetrics || cv->showhmetrics))
3112 CVSideBearings(pixmap,cv);
3113
3114 if ((( cv->active_tool >= cvt_scale && cv->active_tool <= cvt_perspective ) ||
3115 cv->active_shape!=NULL ) &&
3116 cv->p.pressed )
3117 DrawTransOrigin(cv,pixmap);
3118 if ( cv->dv==NULL || (cv->showback[ly_fore>>5]&(1<<(ly_fore&31))) )
3119 CVDrawAnchorPoints(cv,pixmap);
3120 if ( cv->apmine!=NULL )
3121 DrawAPMatch(cv,pixmap,&clip);
3122
3123 if ( cv->p.rubberbanding || cv->p.rubberlining ) {
3124 if ( cv->p.rubberbanding )
3125 CVDrawRubberRect(pixmap,cv);
3126 if ( cv->p.rubberlining )
3127 CVDrawRubberLine(pixmap,cv);
3128 }
3129 CVRulerExpose(pixmap,cv);
3130
3131 GDrawPopClip(pixmap,&old);
3132 }
3133
SC_UpdateAll(SplineChar * sc)3134 static void SC_UpdateAll(SplineChar *sc) {
3135 CharView *cv;
3136 struct splinecharlist *dlist;
3137 MetricsView *mv;
3138 FontView *fv;
3139
3140 for ( cv=(CharView *) (sc->views); cv!=NULL; cv=(CharView *) (cv->b.next) )
3141 GDrawRequestExpose(cv->v,NULL,false);
3142 for ( dlist=sc->dependents; dlist!=NULL; dlist=dlist->next )
3143 SCUpdateAll(dlist->sc);
3144 if ( sc->parent!=NULL ) {
3145 for ( fv = (FontView *) (sc->parent->fv); fv!=NULL; fv=(FontView *) (fv->b.nextsame) )
3146 FVRegenChar(fv,sc);
3147 for ( mv = sc->parent->metrics; mv!=NULL; mv=mv->next )
3148 MVRegenChar(mv,sc);
3149 }
3150 }
3151
SC_OutOfDateBackground(SplineChar * sc)3152 static void SC_OutOfDateBackground(SplineChar *sc) {
3153 CharView *cv;
3154
3155 for ( cv=(CharView *) (sc->views); cv!=NULL; cv=(CharView *) (cv->b.next) )
3156 cv->back_img_out_of_date = true;
3157 }
3158
3159 /* CVRegenFill() regenerates data used to show or not show paths as filled */
3160 /* This is not static so that it can be called from the layers palette */
CVRegenFill(CharView * cv)3161 void CVRegenFill(CharView *cv) {
3162 CharViewTab* tab = CVGetActiveTab(cv);
3163 BDFCharFree(cv->filled);
3164 cv->filled = NULL;
3165 if ( cv->showfilled && !shouldShowFilledUsingCairo(cv) ) {
3166 extern int use_freetype_to_rasterize_fv;
3167 int layer = CVLayer((CharViewBase *) cv);
3168 int size = tab->scale*(cv->b.fv->sf->ascent+cv->b.fv->sf->descent);
3169 int clut_len= 2;
3170
3171 if ( layer==ly_grid ) layer=ly_fore; /* otherwise crashes when using guides layer! */
3172
3173 /* Generally I don't think there's much point in doing an anti-aliased*/
3174 /* fill. But on the "M" (and "W") glyph of extravigant caps, ft won't*/
3175 /* do a mono fill */
3176 if ( use_freetype_to_rasterize_fv && hasFreeType()) {
3177 int depth = 1;
3178 if( use_freetype_with_aa_fill_cv ) {
3179 depth = 4;
3180 clut_len = 16;
3181 }
3182 cv->filled = SplineCharFreeTypeRasterizeNoHints(cv->b.sc,layer,
3183 size,72, depth);
3184 if ( cv->filled==NULL && size<2000 ) {
3185 /* There are some glyphs which freetype won't rasterize in */
3186 /* mono mode, but will in grey scale. Don't ask me why */
3187 cv->filled = SplineCharFreeTypeRasterizeNoHints(cv->b.sc,
3188 layer, size, 72, 4);
3189 clut_len = 16;
3190 }
3191 }
3192 if ( cv->filled==NULL )
3193 cv->filled = SplineCharRasterize(cv->b.sc,layer,size+.1);
3194 if ( cv->filled==NULL )
3195 return;
3196 cv->gi.u.image->image_type = clut_len==2 ? it_mono : it_index;
3197 cv->gi.u.image->data = cv->filled->bitmap;
3198 cv->gi.u.image->bytes_per_line = cv->filled->bytes_per_line;
3199 cv->gi.u.image->width = cv->filled->xmax-cv->filled->xmin+1;
3200 cv->gi.u.image->height = cv->filled->ymax-cv->filled->ymin+1;
3201 if ( clut_len!=cv->gi.u.image->clut->clut_len ) {
3202 GClut *clut = cv->gi.u.image->clut;
3203 int i;
3204 Color bg = view_bgcol;
3205 for ( i=0; i<clut_len; ++i ) {
3206 int r,g,b;
3207 r = ((bg>>16)&0xff)*(clut_len-1-i) + ((fillcol>>16)&0xff)*i;
3208 g = ((bg>>8 )&0xff)*(clut_len-1-i) + ((fillcol>>8 )&0xff)*i;
3209 b = ((bg )&0xff)*(clut_len-1-i) + ((fillcol )&0xff)*i;
3210 clut->clut[i] = COLOR_CREATE(r/(clut_len-1),g/(clut_len-1),b/(clut_len-1));
3211 }
3212 clut->clut_len = clut_len;
3213 }
3214 GDrawRequestExpose(cv->v,NULL,false);
3215 }
3216 }
3217
3218
FVRedrawAllCharViewsSF(SplineFont * sf)3219 static void FVRedrawAllCharViewsSF(SplineFont *sf)
3220 {
3221 int i;
3222 CharView *cv;
3223
3224 for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL )
3225 for ( cv = (CharView *) (sf->glyphs[i]->views); cv!=NULL; cv=(CharView *) (cv->b.next) )
3226 GDrawRequestExpose(cv->v,NULL,false);
3227 }
3228
FVRedrawAllCharViews(FontView * fv)3229 void FVRedrawAllCharViews(FontView *fv)
3230 {
3231 FVRedrawAllCharViewsSF( fv->b.sf );
3232 }
3233
SCRegenFills(SplineChar * sc)3234 static void SCRegenFills(SplineChar *sc) {
3235 struct splinecharlist *dlist;
3236 CharView *cv;
3237
3238 for ( cv = (CharView *) (sc->views); cv!=NULL; cv=(CharView *) (cv->b.next) )
3239 CVRegenFill(cv);
3240 for ( dlist=sc->dependents; dlist!=NULL; dlist=dlist->next )
3241 SCRegenFills(dlist->sc);
3242 }
3243
SCRegenDependents(SplineChar * sc,int layer)3244 static void SCRegenDependents(SplineChar *sc, int layer) {
3245 struct splinecharlist *dlist;
3246 FontView *fv;
3247 int first, last;
3248
3249 first = last = layer;
3250 if ( layer==ly_all ) {
3251 first = 0; last = sc->layer_cnt-1;
3252 }
3253 for ( layer = first; layer<=last; ++layer ) {
3254 for ( fv = (FontView *) (sc->parent->fv); fv!=NULL; fv=(FontView *) (fv->b.nextsame) ) {
3255 if ( fv->sv!=NULL && layer<=ly_fore ) {
3256 SCReinstanciateRef(&fv->sv->sd.sc_srch,sc,layer);
3257 SCReinstanciateRef(&fv->sv->sd.sc_rpl,sc,layer);
3258 }
3259 }
3260
3261 for ( dlist=sc->dependents; dlist!=NULL; dlist=dlist->next ) {
3262 SCReinstanciateRef(dlist->sc,sc,layer);
3263 SCRegenDependents(dlist->sc,layer);
3264 }
3265 }
3266 }
3267
CVUpdateInfo(CharView * cv,GEvent * event)3268 static void CVUpdateInfo(CharView *cv, GEvent *event) {
3269 CharViewTab* tab = CVGetActiveTab(cv);
3270
3271 cv->info_within = true;
3272 cv->e.x = event->u.mouse.x; cv->e.y = event->u.mouse.y;
3273 cv->info.x = (event->u.mouse.x-tab->xoff)/tab->scale;
3274 cv->info.y = (cv->height-event->u.mouse.y-tab->yoff)/tab->scale;
3275 CVInfoDraw(cv,cv->gw);
3276 }
3277
CVNewScale(CharView * cv)3278 static void CVNewScale(CharView *cv) {
3279 CharViewTab* tab = CVGetActiveTab(cv);
3280 GEvent e;
3281
3282 CVRegenFill(cv);
3283 cv->back_img_out_of_date = true;
3284
3285 GScrollBarSetBounds(cv->vsb,-20000*tab->scale,8000*tab->scale,cv->height);
3286 GScrollBarSetBounds(cv->hsb,-8000*tab->scale,32000*tab->scale,cv->width);
3287 GScrollBarSetPos(cv->vsb,tab->yoff-cv->height);
3288 GScrollBarSetPos(cv->hsb,-tab->xoff);
3289
3290 GDrawRequestExpose(cv->v,NULL,false);
3291 if ( cv->showrulers )
3292 GDrawRequestExpose(cv->gw,NULL,false);
3293 GDrawGetPointerPosition(cv->v,&e);
3294 CVUpdateInfo(cv,&e);
3295 }
3296
_CVFit(CharView * cv,DBounds * b,int integral)3297 static void _CVFit(CharView *cv,DBounds *b, int integral) {
3298 CharViewTab* tab = CVGetActiveTab(cv);
3299 real left, right, top, bottom, hsc, wsc;
3300 extern int palettes_docked;
3301 int offset = palettes_docked ? 90 : 0;
3302 int em = cv->b.sc->parent->ascent + cv->b.sc->parent->descent;
3303 int hsmall = true;
3304
3305 if ( offset>cv->width ) offset = 0;
3306
3307 bottom = b->miny;
3308 top = b->maxy;
3309 left = b->minx;
3310 right = b->maxx;
3311
3312 if ( top<bottom ) IError("Bottom bigger than top!");
3313 if ( right<left ) IError("Left bigger than right!");
3314 top -= bottom;
3315 right -= left;
3316 if ( top==0 ) top = em;
3317 if ( right==0 ) right = em;
3318 wsc = (cv->width-offset) / right;
3319 hsc = cv->height / top;
3320 if ( wsc<hsc ) { hsc = wsc; hsmall = false ; }
3321
3322 tab->scale = hsc;
3323 if ( integral ) {
3324 if ( tab->scale > 1.0 ) {
3325 tab->scale = floor(tab->scale);
3326 } else {
3327 tab->scale = 1/ceil(1/tab->scale);
3328 }
3329 } else {
3330 if ( tab->scale > 1.0 ) {
3331 tab->scale = floor(2*tab->scale)/2;
3332 } else {
3333 tab->scale = 2/ceil(2/tab->scale);
3334 }
3335 }
3336
3337 /* Center glyph horizontally */
3338 tab->xoff = ( (cv->width-offset) - (right*tab->scale) )/2 + offset - b->minx*tab->scale;
3339 if ( hsmall )
3340 tab->yoff = -bottom*tab->scale;
3341 else
3342 tab->yoff = -(bottom+top/2)*tab->scale + cv->height/2;
3343
3344 CVNewScale(cv);
3345 }
3346
CVFit(CharView * cv)3347 static void CVFit(CharView *cv) {
3348 DBounds b;
3349 double center;
3350
3351 SplineCharFindBounds(cv->b.sc,&b);
3352 if ( b.miny==0 && b.maxy==0 ) {
3353 b.maxy =cv->b.sc->parent->ascent;
3354 b.miny = -cv->b.sc->parent->descent;
3355 }
3356 /* FF used to normalize bounding boxes making maxx positive. But this */
3357 /* may result into an incorrect positioning for combining marks, which */
3358 /* usually have both bearings negative. So keep negative values as they are. */
3359 /* As for the Y axis, we only ensure the minimum value doesn't exceed zero, */
3360 /* so that the baseline is always visible. */
3361
3362 if ( b.miny>0 ) b.miny = 0;
3363
3364 /* Now give some extra space around the interesting stuff */
3365 center = (b.maxx+b.minx)/2;
3366 b.minx = center - (center - b.minx)*1.2;
3367 b.maxx = center + (b.maxx - center)*1.2;
3368 center = (b.maxy+b.miny)/2;
3369 b.miny = center - (center - b.miny)*1.2;
3370 b.maxy = center + (b.maxy - center)*1.2;
3371
3372 _CVFit(cv,&b,true);
3373 }
3374
CVUnlinkView(CharView * cv)3375 void CVUnlinkView(CharView *cv ) {
3376 CharView *test;
3377
3378 if ( cv->b.sc->views == (CharViewBase *) cv ) {
3379 cv->b.sc->views = cv->b.next;
3380 } else {
3381 for ( test=(CharView *) (cv->b.sc->views);
3382 test->b.next!=(CharViewBase *) cv && test->b.next!=NULL;
3383 test=(CharView *) (test->b.next) );
3384 if ( test->b.next==(CharViewBase *) cv )
3385 test->b.next = cv->b.next;
3386 }
3387 }
3388
CharIcon(CharView * cv,FontView * fv)3389 static GWindow CharIcon(CharView *cv, FontView *fv) {
3390 SplineChar *sc = cv->b.sc;
3391 BDFFont *bdf, *bdf2;
3392 BDFChar *bdfc;
3393 GWindow icon = cv->icon;
3394 GRect r;
3395
3396 r.x = r.y = 0; r.width = r.height = fv->cbw-1;
3397 if ( icon == NULL )
3398 cv->icon = icon = GDrawCreatePixmap(NULL,NULL,r.width,r.width);
3399 GDrawFillRect(icon,&r,0x0); /* for some reason icons seem to be color reversed by my defn */
3400
3401 bdf = NULL; bdfc = NULL;
3402 if ( sc->layers[ly_fore].refs!=NULL || sc->layers[ly_fore].splines!=NULL ) {
3403 bdf = fv->show;
3404 if ( sc->orig_pos>=bdf->glyphcnt || bdf->glyphs[sc->orig_pos]==NULL )
3405 bdf = fv->filled;
3406 if ( sc->orig_pos>=bdf->glyphcnt || bdf->glyphs[sc->orig_pos]==NULL ) {
3407 bdf2 = NULL; bdfc = NULL;
3408 for ( bdf=fv->b.sf->bitmaps; bdf!=NULL && bdf->pixelsize<24 ; bdf=bdf->next )
3409 bdf2 = bdf;
3410 if ( bdf2!=NULL && bdf!=NULL ) {
3411 if ( 24-bdf2->pixelsize < bdf->pixelsize-24 )
3412 bdf = bdf2;
3413 } else if ( bdf==NULL )
3414 bdf = bdf2;
3415 }
3416 if ( bdf!=NULL && sc->orig_pos<bdf->glyphcnt )
3417 bdfc = bdf->glyphs[sc->orig_pos];
3418 }
3419
3420 if ( bdfc!=NULL ) {
3421 GClut clut;
3422 struct _GImage base;
3423 GImage gi;
3424 /* if not empty, use the font's own shape, otherwise use a standard */
3425 /* font */
3426 memset(&gi,'\0',sizeof(gi));
3427 memset(&base,'\0',sizeof(base));
3428 memset(&clut,'\0',sizeof(clut));
3429 gi.u.image = &base;
3430 base.trans = -1;
3431 base.clut = &clut;
3432 if ( bdfc->byte_data ) { int i;
3433 base.image_type = it_index;
3434 clut.clut_len = bdf->clut->clut_len;
3435 for ( i=0; i<clut.clut_len; ++i ) {
3436 int v = 255-i*255/(clut.clut_len-1);
3437 clut.clut[i] = COLOR_CREATE(v,v,v);
3438 }
3439 clut.trans_index = -1;
3440 } else {
3441 base.image_type = it_mono;
3442 clut.clut_len = 2;
3443 clut.clut[1] = 0xffffff;
3444 }
3445 base.data = bdfc->bitmap;
3446 base.bytes_per_line = bdfc->bytes_per_line;
3447 base.width = bdfc->xmax-bdfc->xmin+1;
3448 base.height = bdfc->ymax-bdfc->ymin+1;
3449 GDrawDrawImage(icon,&gi,NULL,(r.width-base.width)/2,(r.height-base.height)/2);
3450 } else if ( sc->unicodeenc!=-1 ) {
3451 FontRequest rq;
3452 GFont *font;
3453 unichar_t text[2];
3454 int as, ds, ld, width;
3455
3456 memset(&rq,0,sizeof(rq));
3457 rq.utf8_family_name = SERIF_UI_FAMILIES;
3458 rq.point_size = 24;
3459 rq.weight = 400;
3460 font = GDrawInstanciateFont(NULL,&rq);
3461 GDrawSetFont(icon,font);
3462 text[0] = sc->unicodeenc; text[1] = 0;
3463 GDrawWindowFontMetrics(icon,font,&as,&ds,&ld);
3464 width = GDrawGetTextWidth(icon,text,1);
3465 GDrawDrawText(icon,(r.width-width)/2,(r.height-as-ds)/2+as,text,1,0xffffff);
3466 }
3467 return( icon );
3468 }
3469
CVCurEnc(CharView * cv)3470 static int CVCurEnc(CharView *cv)
3471 {
3472 if ( cv->map_of_enc == ((FontView *) (cv->b.fv))->b.map && cv->enc!=-1 )
3473 return( cv->enc );
3474
3475 return( ((FontView *) (cv->b.fv))->b.map->backmap[cv->b.sc->orig_pos] );
3476 }
3477
CVMakeTitles(CharView * cv,char * buf,size_t len)3478 static char *CVMakeTitles(CharView *cv,char *buf,size_t len) {
3479 char *title;
3480 SplineChar *sc = cv->b.sc;
3481 SplineFont *sf = sc->parent;
3482 char *uniname;
3483 size_t used;
3484
3485 /* GT: This is the title for a window showing an outline character */
3486 /* GT: It will look something like: */
3487 /* GT: exclam at 33 from Arial */
3488 /* GT: $1 is the name of the glyph */
3489 /* GT: $2 is the glyph's encoding */
3490 /* GT: $3 is the font name */
3491 /* GT: $4 is the changed flag ('*' for the changed items)*/
3492 used = snprintf(buf,len,_("%1$.80s at %2$d from %3$.90s%4$s"),
3493 sc->name, CVCurEnc(cv), sf->fontname,
3494 sc->changed ? "*" : "");
3495 title = copy(buf);
3496
3497 if (used < len) {
3498 /* Enhance 'buf' description with Nameslist.txt unicode name definition */
3499 if ( (uniname=unicode_name(sc->unicodeenc))!=NULL ) {
3500 used += snprintf(buf+used, len-used, " %s", uniname);
3501 free(uniname);
3502 }
3503 }
3504
3505 if (used < len && ( cv->show_ft_results || cv->dv )) {
3506 snprintf(buf+used, len-used, " (%gpt, %ddpi)", (double) cv->ft_pointsizey, cv->ft_dpi );
3507 }
3508
3509 return( title );
3510 }
3511
SC_RefreshTitles(SplineChar * sc)3512 static void SC_RefreshTitles(SplineChar *sc) {
3513 /* Called if the user changes the unicode encoding or the character name */
3514 CharView *cv;
3515 char buf[300], *title;
3516
3517 if ( (CharView *) (sc->views)==NULL )
3518 return;
3519 for ( cv = (CharView *) (sc->views); cv!=NULL; cv=(CharView *) (cv->b.next) ) {
3520 title = CVMakeTitles(cv,buf,sizeof(buf));
3521 /* Could be different if one window is debugging and one is not */
3522 GDrawSetWindowTitles8(cv->gw,buf,title);
3523 free(title);
3524 }
3525 }
3526
CVChangeTabsVisibility(CharView * cv,int makevisible)3527 static void CVChangeTabsVisibility(CharView *cv,int makevisible) {
3528 GRect gsize, pos, sbsize;
3529
3530 if ( cv->tabs==NULL || GGadgetIsVisible(cv->tabs)==makevisible )
3531 return;
3532 GGadgetGetSize(cv->tabs,&gsize);
3533 GGadgetGetSize(cv->vsb,&sbsize);
3534 if ( makevisible ) {
3535 cv->mbh += gsize.height;
3536 cv->height -= gsize.height;
3537 GGadgetMove(cv->vsb,sbsize.x,sbsize.y+gsize.height);
3538 GGadgetResize(cv->vsb,sbsize.width,sbsize.height-gsize.height);
3539 GGadgetMoveAddToY( cv->charselector, gsize.height );
3540 GGadgetMoveAddToY( cv->charselectorNext, gsize.height );
3541 GGadgetMoveAddToY( cv->charselectorPrev, gsize.height );
3542 } else {
3543 cv->mbh -= gsize.height;
3544 cv->height += gsize.height;
3545 GGadgetMove(cv->vsb,sbsize.x,sbsize.y-gsize.height);
3546 GGadgetResize(cv->vsb,sbsize.width,sbsize.height+gsize.height);
3547 GGadgetMoveAddToY( cv->charselector, -1*gsize.height );
3548 GGadgetMoveAddToY( cv->charselectorNext, -1*gsize.height );
3549 GGadgetMoveAddToY( cv->charselectorPrev, -1*gsize.height );
3550 }
3551 GGadgetSetVisible(cv->tabs,makevisible);
3552 cv->back_img_out_of_date = true;
3553 pos.x = 0; pos.y = cv->mbh+cv->charselectorh+cv->infoh;
3554 pos.width = cv->width; pos.height = cv->height;
3555 if ( cv->showrulers ) {
3556 pos.x += cv->rulerh;
3557 pos.y += cv->rulerh;
3558 }
3559 GDrawMoveResize(cv->v,pos.x,pos.y,pos.width,pos.height);
3560 GDrawSync(NULL);
3561 GDrawRequestExpose(cv->v,NULL,false);
3562 GDrawRequestExpose(cv->gw,NULL,false);
3563 }
3564
CVCheckPoints(CharView * cv)3565 static void CVCheckPoints(CharView *cv) {
3566 if ( !SCPointsNumberedProperly(cv->b.sc,CVLayer((CharViewBase *) cv)) && cv->b.sc->ttf_instrs_len!=0 ) {
3567 char *buts[3];
3568 int answer;
3569 buts[0] = _("_Yes");
3570 buts[1] = _("_No");
3571 buts[2] = NULL;
3572 answer = ff_ask(_("Bad Point Numbering"),(const char **) buts,0,1,_("The points in %s are not numbered properly. This means that any instructions will probably move the wrong points and do the wrong thing.\nWould you like me to remove the instructions?"),cv->b.sc->name);
3573 if ( answer==0 ) {
3574 free(cv->b.sc->ttf_instrs); cv->b.sc->ttf_instrs = NULL;
3575 cv->b.sc->ttf_instrs_len = 0;
3576 }
3577 }
3578 }
3579
CVChangeSC_storeTab(CharView * cv,int tabnumber)3580 static void CVChangeSC_storeTab( CharView *cv, int tabnumber )
3581 {
3582 TRACE("CVChangeSC_storeTab() %d\n", tabnumber );
3583 if( tabnumber < charview_cvtabssz )
3584 {
3585 CharViewTab* t = &cv->cvtabs[tabnumber];
3586 strncpy( t->charselected,
3587 GGadgetGetTitle8(cv->charselector),
3588 charviewtab_charselectedsz );
3589 }
3590 }
3591
CVChangeSC_fetchTab(CharView * cv,int tabnumber)3592 static void CVChangeSC_fetchTab( CharView *cv, int tabnumber )
3593 {
3594 if( tabnumber < charview_cvtabssz )
3595 {
3596 CharViewTab* t = &cv->cvtabs[tabnumber];
3597 GGadgetSetTitle8(cv->charselector, t->charselected );
3598 }
3599 }
3600
CVSetCharSelectorValueFromSC(CharView * cv,SplineChar * sc)3601 static void CVSetCharSelectorValueFromSC( CharView *cv, SplineChar *sc )
3602 {
3603 const char* title = Wordlist_getSCName( sc );
3604 GGadgetSetTitle8(cv->charselector, title);
3605 }
3606
3607 // See comment in gtabset.c (fn GTabSetRemoveTabByPos)
3608 static void CVMenuCloseTab(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e));
CVTabSetRemoveSync(GWindow gw,int pos)3609 static void CVTabSetRemoveSync(GWindow gw, int pos) {
3610 CharView* cv = (CharView*) GDrawGetUserData(gw);
3611 // There's no other good way to pass an "argument" to this function as its definition
3612 // is required to be a certain way. The user_data of the GWindow is already our CharView
3613 // so we can't use that.
3614 cv->ctpos = pos;
3615 CVMenuCloseTab(gw, NULL, NULL);
3616 }
3617
CVTabSetSwapSync(GWindow gw,int pos_a,int pos_b)3618 static void CVTabSetSwapSync(GWindow gw, int pos_a, int pos_b) {
3619 CharView* cv = (CharView*) GDrawGetUserData(gw);
3620 CharViewTab tempt = cv->cvtabs[pos_a];
3621 char* fnt = cv->former_names[pos_a];
3622
3623 cv->cvtabs[pos_a] = cv->cvtabs[pos_b];
3624 cv->former_names[pos_a] = cv->former_names[pos_b];
3625 cv->cvtabs[pos_b] = tempt;
3626 cv->former_names[pos_b] = fnt;
3627
3628 int sel = GTabSetGetSel(cv->tabs);
3629 if (pos_a == sel)
3630 cv->oldtabnum = pos_b;
3631 if (pos_b == sel)
3632 cv->oldtabnum = pos_a;
3633 }
3634
CVChangeSC(CharView * cv,SplineChar * sc)3635 void CVChangeSC( CharView *cv, SplineChar *sc )
3636 {
3637 char *title;
3638 char buf[300];
3639 extern int updateflex;
3640 int i;
3641 int old_layer = CVLayer((CharViewBase *) cv), blayer;
3642 int was_fitted = cv->dv==NULL && cv->b.gridfit!=NULL;
3643
3644 if ( old_layer>=sc->layer_cnt )
3645 old_layer = ly_fore; /* Can happen in type3 fonts where each glyph has a different layer cnt */
3646
3647 memset( cv->additionalCharsToShow, 0, sizeof(SplineChar*) * additionalCharsToShowLimit );
3648 cv->additionalCharsToShowActiveIndex = 0;
3649 cv->additionalCharsToShow[0] = sc;
3650
3651 CVDebugFree(cv->dv);
3652
3653 if ( cv->expandedge != ee_none ) {
3654 GDrawSetCursor(cv->v,ct_mypointer);
3655 cv->expandedge = ee_none;
3656 }
3657
3658 SplinePointListsFree(cv->b.gridfit); cv->b.gridfit = NULL;
3659 FreeType_FreeRaster(cv->oldraster); cv->oldraster = NULL;
3660 FreeType_FreeRaster(cv->raster); cv->raster = NULL;
3661
3662 SCLigCaretCheck(sc,false);
3663
3664 CVUnlinkView(cv);
3665 cv->p.nextcp = cv->p.prevcp = cv->widthsel = cv->vwidthsel = false;
3666 if ( (CharView *) (sc->views)==NULL && updateflex )
3667 SplineCharIsFlexible(sc,old_layer!=ly_grid ? old_layer : ly_fore );
3668 cv->b.sc = sc;
3669 cv->b.next = sc->views;
3670 sc->views = &cv->b;
3671 cv->enc = ( ((FontView *) (cv->b.fv))->b.map->backmap[cv->b.sc->orig_pos] );
3672 cv->b.layerheads[dm_fore] = &sc->layers[ly_fore];
3673 blayer = old_layer;
3674 if ( old_layer==ly_grid || old_layer==ly_fore ||
3675 sc->parent->multilayer || old_layer>=sc->layer_cnt )
3676 blayer = ly_back;
3677 cv->b.layerheads[dm_back] = &sc->layers[blayer];
3678 cv->b.layerheads[dm_grid] = &sc->parent->grid;
3679 cv->p.sp = cv->lastselpt = NULL;
3680 cv->p.spiro = cv->lastselcp = NULL;
3681 cv->apmine = cv->apmatch = NULL; cv->apsc = NULL;
3682 cv->template1 = cv->template2 = NULL;
3683 #if HANYANG
3684 if ( cv->b.sc->parent->rules!=NULL && cv->b.sc->compositionunit )
3685 Disp_DefaultTemplate(cv);
3686 #endif
3687 if ( cv->b.layerheads[cv->b.drawmode]->order2 )
3688 CVCheckPoints(cv);
3689 if ( cv->showpointnumbers || cv->show_ft_results )
3690 SCNumberPoints(sc,old_layer);
3691 if ( cv->show_ft_results )
3692 CVGridFitChar(cv);
3693
3694 CVNewScale(cv);
3695
3696 CharIcon(cv,(FontView *) (cv->b.fv));
3697 title = CVMakeTitles(cv,buf,sizeof(buf));
3698 GDrawSetWindowTitles8(cv->gw,buf,title);
3699 CVInfoDraw(cv,cv->gw);
3700 free(title);
3701 _CVPaletteActivate(cv,true,false);
3702
3703 if ( cv->tabs!=NULL ) {
3704 for ( i=0; i<cv->former_cnt; ++i )
3705 if ( strcmp(cv->former_names[i],sc->name)==0 )
3706 break;
3707 if ( i!=cv->former_cnt && cv->showtabs )
3708 {
3709 CVChangeSC_storeTab( cv, cv->oldtabnum );
3710 CVChangeSC_fetchTab( cv, i );
3711 cv->oldtabnum = i;
3712 GTabSetSetSel(cv->tabs,i);
3713 }
3714 else
3715 {
3716 // Only need to store here, as we are about to make a new tab.
3717 CVChangeSC_storeTab( cv, cv->oldtabnum );
3718 cv->oldtabnum = 0;
3719 // have to shuffle the cvtabs along to be in sync with cv->tabs
3720 {
3721 int i = 0;
3722 for( i=charview_cvtabssz-1; i > 0; i-- )
3723 {
3724 cv->cvtabs[i] = cv->cvtabs[i-1];
3725 }
3726 }
3727 CVSetCharSelectorValueFromSC( cv, sc );
3728
3729 if ( cv->former_cnt==CV_TABMAX )
3730 free(cv->former_names[CV_TABMAX-1]);
3731 for ( i=cv->former_cnt<CV_TABMAX?cv->former_cnt-1:CV_TABMAX-2; i>=0; --i )
3732 cv->former_names[i+1] = cv->former_names[i];
3733 cv->former_names[0] = copy(sc->name);
3734 if ( cv->former_cnt<CV_TABMAX )
3735 ++cv->former_cnt;
3736 for ( i=0; i<cv->former_cnt; ++i )
3737 {
3738 if( i < charview_cvtabssz )
3739 {
3740 CharViewTab* t = &cv->cvtabs[i];
3741 GTabSetChangeTabName(cv->tabs, t->charselected, i);
3742 }
3743 }
3744
3745 GTabSetRemetric(cv->tabs);
3746 GTabSetSetSel(cv->tabs,0); /* This does a redraw */
3747 if ( !GGadgetIsVisible(cv->tabs) && cv->showtabs )
3748 CVChangeTabsVisibility(cv,true);
3749 }
3750 }
3751 if( !strcmp(GGadgetGetTitle8(cv->charselector),""))
3752 CVSetCharSelectorValueFromSC( cv, sc );
3753
3754 if ( sc->inspiro && !hasspiro() && !sc->parent->complained_about_spiros ) {
3755 sc->parent->complained_about_spiros = true;
3756 #ifdef _NO_LIBSPIRO
3757 ff_post_error(_("You may not use spiros"),_("This glyph should display spiro points, but unfortunately this version of fontforge was not linked with the spiro library, so only normal bezier points will be displayed."));
3758 #else
3759 ff_post_error(_("You may not use spiros"),_("This glyph should display spiro points, but unfortunately FontForge was unable to load libspiro, spiros are not available for use, and normal bezier points will be displayed instead."));
3760 #endif
3761 }
3762
3763 if ( was_fitted )
3764 CVGridFitChar(cv);
3765
3766 // Force any extra chars to be setup and drawn
3767 GEvent e;
3768 e.type=et_controlevent;
3769 e.u.control.subtype = et_textchanged;
3770 e.u.control.u.tf_changed.from_pulldown = 0;
3771 CV_OnCharSelectorTextChanged( cv->charselector, &e );
3772 }
3773
CVChangeChar(CharView * cv,int i)3774 static void CVChangeChar(CharView *cv, int i )
3775 {
3776 SplineChar *sc;
3777 SplineFont *sf = cv->b.sc->parent;
3778 EncMap *map = ((FontView *) (cv->b.fv))->b.map;
3779 int gid = i<0 || i>= map->enccount ? -2 : map->map[i];
3780
3781 if ( sf->cidmaster!=NULL && !map->enc->is_compact ) {
3782 SplineFont *cidmaster = sf->cidmaster;
3783 int k;
3784 for ( k=0; k<cidmaster->subfontcnt; ++k ) {
3785 SplineFont *sf = cidmaster->subfonts[k];
3786 if ( i<sf->glyphcnt && sf->glyphs[i]!=NULL )
3787 break;
3788 }
3789 if ( k!=cidmaster->subfontcnt ) {
3790 if ( cidmaster->subfonts[k] != sf ) {
3791 sf = cidmaster->subfonts[k];
3792 gid = ( i>=sf->glyphcnt ) ? -2 : i;
3793 /* can't create a new glyph this way */
3794 }
3795 }
3796 }
3797 if ( gid == -2 )
3798 return;
3799 if ( gid==-1 || (sc = sf->glyphs[gid])==NULL ) {
3800 sc = SFMakeChar(sf,map,i);
3801 sc->inspiro = cv->b.sc->inspiro && hasspiro();
3802 }
3803
3804 if ( sc==NULL || (cv->b.sc == sc && cv->enc==i ))
3805 return;
3806 cv->map_of_enc = map;
3807 cv->enc = i;
3808 CVChangeSC(cv,sc);
3809 }
3810
3811 /*
3812 * Unused
3813 static void CVSwitchToTab(CharView *cv,int tnum ) {
3814 if( tnum >= cv->former_cnt )
3815 return;
3816
3817 SplineFont *sf = cv->b.fv->sf;
3818 char* n = cv->former_names[tnum];
3819 int unienc = UniFromName(n,sf->uni_interp,cv->b.fv->map->enc);
3820 CVChangeChar(cv,unienc);
3821 }
3822
3823 static void CVMenuShowTab(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
3824 CharView *cv = (CharView *) GDrawGetUserData(gw);
3825 CVSwitchToTab(cv,mi->mid);
3826 }
3827 */
3828
CVChangeToFormer(GGadget * g,GEvent * e)3829 static int CVChangeToFormer( GGadget *g, GEvent *e) {
3830 if ( e->type==et_controlevent && e->u.control.subtype == et_radiochanged ) {
3831 CharView *cv = GDrawGetUserData(GGadgetGetWindow(g));
3832 int new_aspect = GTabSetGetSel(g);
3833 SplineFont *sf = cv->b.sc->parent;
3834 int gid;
3835
3836 for ( gid=sf->glyphcnt-1; gid>=0; --gid )
3837 if ( sf->glyphs[gid]!=NULL &&
3838 strcmp(sf->glyphs[gid]->name,cv->former_names[new_aspect])==0 )
3839 break;
3840 if ( gid<0 ) {
3841 /* They changed the name? See if we can get a unicode value from it */
3842 int unienc = UniFromName(cv->former_names[new_aspect],sf->uni_interp,cv->b.fv->map->enc);
3843 if ( unienc>=0 ) {
3844 gid = SFFindGID(sf,unienc,cv->former_names[new_aspect]);
3845 if ( gid>=0 ) {
3846 free(cv->former_names[new_aspect]);
3847 cv->former_names[new_aspect] = copy(sf->glyphs[gid]->name);
3848 }
3849 }
3850 }
3851 if ( gid<0 )
3852 return( true );
3853 CVChangeSC(cv,sf->glyphs[gid]);
3854 TRACE("CVChangeToFormer: Changed SC to %s (GID %d)\n", sf->glyphs[gid]->name, gid);
3855 cv->enc = ((FontView *) (cv->b.fv))->b.map->backmap[cv->b.sc->orig_pos];
3856 }
3857 return( true );
3858 }
3859
CVFakeMove(CharView * cv,GEvent * event)3860 static void CVFakeMove(CharView *cv, GEvent *event) {
3861 GEvent e;
3862
3863 memset(&e,0,sizeof(e));
3864 e.type = et_mousemove;
3865 e.w = cv->v;
3866 if ( event->w!=cv->v ) {
3867 GPoint p;
3868 p.x = event->u.chr.x; p.y = event->u.chr.y;
3869 GDrawTranslateCoordinates(event->w,cv->v,&p);
3870 event->u.chr.x = p.x; event->u.chr.y = p.y;
3871 }
3872 e.u.mouse.state = TrueCharState(event);
3873 e.u.mouse.x = event->u.chr.x;
3874 e.u.mouse.y = event->u.chr.y;
3875 e.u.mouse.device = NULL;
3876 CVMouseMove(cv,&e);
3877 }
3878
CVDoFindInFontView(CharView * cv)3879 static void CVDoFindInFontView(CharView *cv) {
3880 FVChangeChar((FontView *) (cv->b.fv),CVCurEnc(cv));
3881 GDrawSetVisible(((FontView *) (cv->b.fv))->gw,true);
3882 GDrawRaise(((FontView *) (cv->b.fv))->gw);
3883 }
3884
3885 static uint16 HaveModifiers = 0;
3886 static uint16 PressingTilde = 0;
3887 static uint16 PrevCharEventWasCharUpOnControl = 0;
3888
3889
CVCharUp(CharView * cv,GEvent * event)3890 static void CVCharUp(CharView *cv, GEvent *event ) {
3891
3892 if ( !event->u.chr.autorepeat && !HaveModifiers && event->u.chr.keysym==' ' ) {
3893 update_spacebar_hand_tool(cv);
3894 }
3895
3896 int oldactiveModifierControl = cv->activeModifierControl;
3897 int oldactiveModifierAlt = cv->activeModifierAlt;
3898 cv->activeModifierControl &= ~( event->u.chr.keysym == GK_Control_L || event->u.chr.keysym == GK_Control_R
3899 || event->u.chr.keysym == GK_Meta_L || event->u.chr.keysym == GK_Meta_R );
3900 cv->activeModifierAlt &= ~( event->u.chr.keysym == GK_Alt_L || event->u.chr.keysym == GK_Alt_R
3901 || event->u.chr.keysym == GK_Mode_switch );
3902 // helps with keys on the mac
3903 if( (event->u.chr.state&ksm_meta) )
3904 cv->activeModifierAlt = 0;
3905 if( oldactiveModifierControl != cv->activeModifierControl
3906 || oldactiveModifierAlt != cv->activeModifierAlt )
3907 {
3908 CVInfoDraw(cv,cv->gw);
3909 }
3910
3911
3912
3913 // TRACE("CVCharUp() ag:%d key:%d\n", cv_auto_goto, event->u.chr.keysym );
3914 if( !cv_auto_goto )
3915 {
3916 bool isImmediateKeyTogglePreview = isImmediateKey( cv->gw, "TogglePreview", event ) != NULL;
3917 if( isImmediateKeyTogglePreview ) {
3918 PressingTilde = 1;
3919 }
3920
3921 if( PrevCharEventWasCharUpOnControl && isImmediateKeyTogglePreview )
3922 {
3923 HaveModifiers = 0;
3924 PrevCharEventWasCharUpOnControl = 0;
3925 return;
3926 }
3927 PrevCharEventWasCharUpOnControl = 0;
3928
3929 if( !event->u.chr.autorepeat
3930 && (event->u.chr.keysym == GK_Control_L
3931 || event->u.chr.keysym == GK_Control_R ))
3932 {
3933 PrevCharEventWasCharUpOnControl = 1;
3934 if( !PressingTilde ) {
3935 HaveModifiers = 0;
3936 }
3937 }
3938
3939 if ( !event->u.chr.autorepeat && !HaveModifiers && isImmediateKeyTogglePreview ) {
3940 PressingTilde = 0;
3941 CVPreviewModeSet( cv->gw, false );
3942 return;
3943 }
3944
3945 if ( !event->u.chr.autorepeat && isImmediateKeyTogglePreview ) {
3946 PressingTilde = 0;
3947 }
3948 if ( event->u.chr.autorepeat && HaveModifiers && isImmediateKeyTogglePreview ) {
3949 return;
3950 }
3951 }
3952
3953
3954 if( event->u.chr.keysym == GK_Escape )
3955 {
3956 TRACE("escape char.......!\n");
3957 GGadget *active = GWindowGetFocusGadgetOfWindow(cv->gw);
3958 if( active == cv->charselector )
3959 {
3960 TRACE("was on charselector\n");
3961 GWidgetIndicateFocusGadget( cv->hsb );
3962 }
3963 else if ( cv->charselector != NULL )
3964 {
3965 TRACE("was on NOT charselector\n");
3966 GWidgetIndicateFocusGadget( cv->charselector );
3967 }
3968 }
3969
3970
3971 #if _ModKeysAutoRepeat
3972 /* Under cygwin these keys auto repeat, they don't under normal X */
3973 if ( event->u.chr.keysym == GK_Shift_L || event->u.chr.keysym == GK_Shift_R ||
3974 event->u.chr.keysym == GK_Control_L || event->u.chr.keysym == GK_Control_R ||
3975 event->u.chr.keysym == GK_Meta_L || event->u.chr.keysym == GK_Meta_R ||
3976 event->u.chr.keysym == GK_Alt_L || event->u.chr.keysym == GK_Alt_R ||
3977 event->u.chr.keysym == GK_Super_L || event->u.chr.keysym == GK_Super_R ||
3978 event->u.chr.keysym == GK_Hyper_L || event->u.chr.keysym == GK_Hyper_R ) {
3979 if ( cv->autorpt!=NULL ) {
3980 GDrawCancelTimer(cv->autorpt);
3981 CVToolsSetCursor(cv,cv->oldstate,NULL);
3982 }
3983 cv->keysym = event->u.chr.keysym;
3984 cv->oldkeyx = event->u.chr.x;
3985 cv->oldkeyy = event->u.chr.y;
3986 cv->oldkeyw = event->w;
3987 cv->oldstate = TrueCharState(event);
3988 cv->autorpt = GDrawRequestTimer(cv->v,100,0,NULL);
3989 } else {
3990 if ( cv->autorpt!=NULL ) {
3991 GDrawCancelTimer(cv->autorpt); cv->autorpt=NULL;
3992 CVToolsSetCursor(cv,cv->oldstate,NULL);
3993 }
3994 CVToolsSetCursor(cv,TrueCharState(event),NULL);
3995 }
3996 #else
3997 CVToolsSetCursor(cv,TrueCharState(event),NULL);
3998 if ( event->u.chr.keysym == GK_Shift_L || event->u.chr.keysym == GK_Shift_R ||
3999 event->u.chr.keysym == GK_Alt_L || event->u.chr.keysym == GK_Alt_R ||
4000 event->u.chr.keysym == GK_Meta_L || event->u.chr.keysym == GK_Meta_R )
4001 CVFakeMove(cv, event);
4002 #endif
4003 }
4004
CVInfoDrawText(CharView * cv,GWindow pixmap)4005 void CVInfoDrawText(CharView *cv, GWindow pixmap ) {
4006 CharViewTab* tab = CVGetActiveTab(cv);
4007 GRect r;
4008 Color bg = GDrawGetDefaultBackground(GDrawGetDisplayOfWindow(pixmap));
4009 Color fg = GDrawGetDefaultForeground(GDrawGetDisplayOfWindow(pixmap));
4010 const int buffersz = 150;
4011 char buffer[buffersz+1];
4012 int ybase = cv->mbh+cv->charselectorh+(cv->infoh-cv->sfh)/2+cv->sas;
4013 real xdiff, ydiff;
4014 SplinePoint *sp, dummy;
4015 spiro_cp *cp;
4016
4017 GDrawSetFont(pixmap,cv->small);
4018 r.x = RPT_DATA; r.width = SPT_BASE-RPT_DATA;
4019 r.y = cv->mbh+cv->charselectorh; r.height = cv->infoh-1;
4020 GDrawFillRect(pixmap,&r,bg);
4021 r.x = SPT_DATA; r.width = SOF_BASE-SPT_DATA;
4022 GDrawFillRect(pixmap,&r,bg);
4023 r.x = SOF_DATA; r.width = SDS_BASE-SOF_DATA;
4024 GDrawFillRect(pixmap,&r,bg);
4025 r.x = SDS_DATA; r.width = SAN_BASE-SDS_DATA;
4026 GDrawFillRect(pixmap,&r,bg);
4027 r.x = SAN_DATA; r.width = MAG_BASE-SAN_DATA;
4028 GDrawFillRect(pixmap,&r,bg);
4029 r.x = MAG_DATA; r.width = LAYER_DATA-MAG_DATA;
4030 GDrawFillRect(pixmap,&r,bg);
4031 r.x = LAYER_DATA; r.width = CODERANGE_DATA-LAYER_DATA;
4032 GDrawFillRect(pixmap,&r,bg);
4033 r.x = CODERANGE_DATA; r.width = FLAGS_DATA-CODERANGE_DATA;
4034 GDrawFillRect(pixmap,&r,bg);
4035 r.x = FLAGS_DATA; r.width = 200;
4036 GDrawFillRect(pixmap,&r,bg);
4037
4038 if ( cv->info_within ) {
4039 if ( cv->info.x>=1000 || cv->info.x<=-1000 || cv->info.y>=1000 || cv->info.y<=-1000 )
4040 sprintf(buffer,"%d%s%d", (int) cv->info.x, coord_sep, (int) cv->info.y );
4041 else
4042 sprintf(buffer,"%.4g%s%.4g", (double) cv->info.x, coord_sep, (double) cv->info.y );
4043 buffer[11] = '\0';
4044 GDrawDrawText8(pixmap,RPT_DATA,ybase,buffer,-1,fg);
4045 }
4046 if ( tab->scale>=.25 )
4047 sprintf( buffer, "%d%%", (int) (100*tab->scale));
4048 else
4049 sprintf( buffer, "%.3g%%", (double) (100*tab->scale));
4050 GDrawDrawText8(pixmap,MAG_DATA,ybase,buffer,-1,fg);
4051
4052 const int layernamesz = 100;
4053 char layername[layernamesz+1];
4054 strncpy(layername,_("Guide"),layernamesz);
4055 if(cv->b.drawmode!=dm_grid) {
4056 int idx = CVLayer((CharViewBase *) cv);
4057 if(idx >= 0 && idx < cv->b.sc->parent->layer_cnt) {
4058 strncpy(layername,cv->b.sc->parent->layers[idx].name,layernamesz);
4059 }
4060 }
4061 snprintf( buffer, buffersz, _("Active Layer: %s (%s)"),
4062 layername,
4063 /* GT: Guide layer, make it short */
4064 ( cv->b.drawmode==dm_grid ? _("Guide") :
4065 /* GT: Background, make it short */
4066 cv->b.layerheads[cv->b.drawmode]->background ? _("Back") :
4067 /* GT: Foreground, make it short */
4068 _("Fore") )
4069 );
4070 GDrawDrawText8(pixmap,LAYER_DATA,ybase,buffer,-1,fg);
4071 GDrawDrawText8(pixmap,LAYER_DATA,ybase,buffer,-1,fg);
4072
4073 if ( cv->coderange==cr_none )
4074 {
4075 snprintf( buffer, buffersz, _("Modes: "));
4076 if( CVShouldInterpolateCPsOnMotion(cv) )
4077 strcat( buffer, "Interpolate" );
4078 GDrawDrawText8(pixmap,FLAGS_DATA,ybase,buffer,-1,fg);
4079 }
4080
4081
4082 if ( cv->coderange!=cr_none ) {
4083 GDrawDrawText8(pixmap,CODERANGE_DATA,ybase,
4084 cv->coderange==cr_fpgm ? _("'fpgm'") :
4085 cv->coderange==cr_prep ? _("'prep'") : _("Glyph"),
4086 -1,fg);
4087 GDrawDrawText8(pixmap,CODERANGE_DATA+40,ybase,
4088 FreeTypeStringVersion(), -1,fg);
4089 }
4090 sp = NULL; cp = NULL;
4091 if ( cv->b.sc->inspiro && hasspiro())
4092 cp = cv->p.spiro!=NULL ? cv->p.spiro : cv->lastselcp;
4093 else
4094 sp = cv->p.sp!=NULL ? cv->p.sp : cv->lastselpt;
4095 if ( sp==NULL && cp==NULL )
4096 if ( cv->active_tool==cvt_rect || cv->active_tool==cvt_elipse ||
4097 cv->active_tool==cvt_poly || cv->active_tool==cvt_star ||
4098 cv->active_tool==cvt_scale || cv->active_tool==cvt_skew ||
4099 cv->active_tool==cvt_rotate || cv->active_tool==cvt_flip ) {
4100 dummy.me.x = cv->p.cx; dummy.me.y = cv->p.cy;
4101 sp = &dummy;
4102 }
4103 if ( sp || cp ) {
4104 real selx, sely;
4105 if ( sp ) {
4106 if ( cv->pressed && sp==cv->p.sp ) {
4107 selx = cv->p.constrain.x;
4108 sely = cv->p.constrain.y;
4109 } else {
4110 selx = sp->me.x;
4111 sely = sp->me.y;
4112 }
4113 } else {
4114 selx = cp->x;
4115 sely = cp->y;
4116 }
4117 xdiff=cv->info.x-selx;
4118 ydiff = cv->info.y-sely;
4119
4120 if ( selx>=1000 || selx<=-1000 || sely>=1000 || sely<=-1000 )
4121 sprintf(buffer,"%d%s%d", (int) selx, coord_sep, (int) sely );
4122 else
4123 sprintf(buffer,"%.4g%s%.4g", (double) selx, coord_sep, (double) sely );
4124 buffer[11] = '\0';
4125 GDrawDrawText8(pixmap,SPT_DATA,ybase,buffer,-1,fg);
4126 } else if ( cv->widthsel && cv->info_within ) {
4127 xdiff = cv->info.x-cv->p.cx;
4128 ydiff = 0;
4129 } else if ( cv->p.rubberbanding && cv->info_within ) {
4130 xdiff=cv->info.x-cv->p.cx;
4131 ydiff = cv->info.y-cv->p.cy;
4132 } else
4133 return;
4134 if ( !cv->info_within )
4135 return;
4136
4137 if ( cv->active_tool==cvt_scale ) {
4138 xdiff = 100.0 + (cv->info.x-cv->p.cx)/(4*tab->scale);
4139 ydiff = 100.0 + (cv->info.y-cv->p.cy)/(4*tab->scale);
4140 if ( xdiff>=100 || xdiff<=-100 || ydiff>=100 || ydiff<=-100 )
4141 sprintf(buffer,"%d%%%s%d%%", (int) xdiff, coord_sep, (int) ydiff );
4142 else
4143 sprintf(buffer,"%.3g%%%s%.3g%%", (double) xdiff, coord_sep, (double) ydiff );
4144 } else if ( xdiff>=1000 || xdiff<=-1000 || ydiff>=1000 || ydiff<=-1000 )
4145 sprintf(buffer,"%d%s%d", (int) xdiff, coord_sep, (int) ydiff );
4146 else
4147 sprintf(buffer,"%.4g%s%.4g", (double) xdiff, coord_sep, (double) ydiff );
4148 buffer[11] = '\0';
4149 GDrawDrawText8(pixmap,SOF_DATA,ybase,buffer,-1,fg);
4150
4151 sprintf( buffer, "%.1f", sqrt(xdiff*xdiff+ydiff*ydiff));
4152 GDrawDrawText8(pixmap,SDS_DATA,ybase,buffer,-1,fg);
4153
4154 /* Utf-8 for degree sign */
4155 sprintf( buffer, "%d\302\260", (int) rint(180*atan2(ydiff,xdiff)/FF_PI));
4156 GDrawDrawText8(pixmap,SAN_DATA,ybase,buffer,-1,fg);
4157 }
4158
CVInfoDrawRulers(CharView * cv,GWindow pixmap)4159 static void CVInfoDrawRulers(CharView *cv, GWindow pixmap ) {
4160 // Check if we have any rulers to draw over
4161 if (cv->hruler == NULL || cv->vruler == NULL) {
4162 return;
4163 }
4164
4165 int rstart = cv->mbh+cv->charselectorh+cv->infoh;
4166 GRect rh, rv, oldrh, oldrv;
4167 rh.y = rstart; rh.height = cv->rulerh; rh.x = cv->rulerh; rh.width = cv->width;
4168 rv.x = 0; rv.width = cv->rulerh; rv.y = rstart + cv->rulerh; rv.height = cv->height;
4169
4170 GDrawSetLineWidth(pixmap,0);
4171 // Draw the new rulers
4172 GDrawPushClip(pixmap, &rh, &oldrh);
4173 rh.x = cv->olde.x; rh.y = 0; rh.width = 1;
4174 GDrawDrawPixmap(pixmap, cv->hruler, &rh, cv->rulerh + cv->olde.x, rstart);
4175 GDrawDrawLine(pixmap,cv->e.x+cv->rulerh,rstart,cv->e.x+cv->rulerh,rstart+cv->rulerh,0xff0000);
4176 GDrawPopClip(pixmap, &oldrh);
4177
4178 GDrawPushClip(pixmap, &rv, &oldrv);
4179 rv.x = 0; rv.y = cv->olde.y; rv.height = 1;
4180 GDrawDrawPixmap(pixmap, cv->vruler, &rv, 0, cv->rulerh + rstart + cv->olde.y);
4181 GDrawDrawLine(pixmap,0,cv->e.y+rstart+cv->rulerh,cv->rulerh,cv->e.y+rstart+cv->rulerh,0xff0000);
4182 GDrawPopClip(pixmap, &oldrv);
4183
4184 cv->olde = cv->e;
4185 }
4186
CVInfoDraw(CharView * cv,GWindow pixmap)4187 void CVInfoDraw(CharView *cv, GWindow pixmap ) {
4188 CVInfoDrawText(cv,pixmap);
4189 if ( cv->showrulers )
4190 CVInfoDrawRulers(cv,pixmap);
4191 }
4192
CVCrossing(CharView * cv,GEvent * event)4193 static void CVCrossing(CharView *cv, GEvent *event ) {
4194 CharViewTab* tab = CVGetActiveTab(cv);
4195 CVToolsSetCursor(cv,event->u.mouse.state,event->u.mouse.device);
4196 cv->info_within = event->u.crossing.entered;
4197 cv->info.x = (event->u.crossing.x-tab->xoff)/tab->scale;
4198 cv->info.y = (cv->height-event->u.crossing.y-tab->yoff)/tab->scale;
4199 CVInfoDraw(cv,cv->gw);
4200 CPEndInfo(cv);
4201 }
4202
CheckSpiroPoint(FindSel * fs,spiro_cp * cp,SplineSet * spl,int index)4203 static int CheckSpiroPoint(FindSel *fs, spiro_cp *cp, SplineSet *spl,int index) {
4204
4205 if ( fs->xl<=cp->x && fs->xh>=cp->x &&
4206 fs->yl<=cp->y && fs->yh >= cp->y ) {
4207 fs->p->spiro = cp;
4208 fs->p->spline = NULL;
4209 fs->p->anysel = true;
4210 fs->p->spl = spl;
4211 fs->p->spiro_index = index;
4212 return( true );
4213 }
4214 return( false );
4215 }
4216
CheckPoint(FindSel * fs,SplinePoint * sp,SplineSet * spl)4217 static int CheckPoint(FindSel *fs, SplinePoint *sp, SplineSet *spl) {
4218
4219 if ( fs->xl<=sp->me.x && fs->xh>=sp->me.x &&
4220 fs->yl<=sp->me.y && fs->yh >= sp->me.y ) {
4221 fs->p->sp = sp;
4222 fs->p->spline = NULL;
4223 fs->p->anysel = true;
4224 fs->p->spl = spl;
4225 if ( !fs->seek_controls )
4226 return( true );
4227 }
4228 if ( (sp->selected && fs->select_controls)
4229 || fs->all_controls
4230 || fs->alwaysshowcontrolpoints )
4231 {
4232 int seln=false, selp=false;
4233 if ( fs->c_xl<=sp->nextcp.x && fs->c_xh>=sp->nextcp.x &&
4234 fs->c_yl<=sp->nextcp.y && fs->c_yh >= sp->nextcp.y )
4235 seln = true;
4236 if ( fs->c_xl<=sp->prevcp.x && fs->c_xh>=sp->prevcp.x &&
4237 fs->c_yl<=sp->prevcp.y && fs->c_yh >= sp->prevcp.y )
4238 selp = true;
4239 if ( seln && selp ) {
4240 /* Select the one with a spline attached. */
4241 if ( sp->prev!=NULL && sp->next==NULL )
4242 seln = false;
4243 }
4244 if ( seln ) {
4245 fs->p->sp = sp;
4246 fs->p->spline = NULL;
4247 fs->p->spl = spl;
4248 fs->p->nextcp = true;
4249 fs->p->anysel = true;
4250 fs->p->cp = sp->nextcp;
4251 if ( sp->nonextcp && (sp->pointtype==pt_curve || sp->pointtype==pt_hvcurve)) {
4252 fs->p->cp.x = sp->me.x + (sp->me.x-sp->prevcp.x);
4253 fs->p->cp.y = sp->me.y + (sp->me.y-sp->prevcp.y);
4254 }
4255 sp->selected = true;
4256 sp->nextcpselected = true;
4257 return( true );
4258 } else if ( selp ) {
4259 fs->p->sp = sp;
4260 fs->p->spline = NULL;
4261 fs->p->spl = spl;
4262 fs->p->prevcp = true;
4263 fs->p->anysel = true;
4264 fs->p->cp = sp->prevcp;
4265 if ( sp->noprevcp && (sp->pointtype==pt_curve || sp->pointtype==pt_hvcurve)) {
4266 fs->p->cp.x = sp->me.x + (sp->me.x-sp->nextcp.x);
4267 fs->p->cp.y = sp->me.y + (sp->me.y-sp->nextcp.y);
4268 }
4269 sp->selected = true;
4270 sp->prevcpselected = true;
4271 return( true );
4272 }
4273 }
4274 return( false );
4275 }
4276
CheckSpline(FindSel * fs,Spline * spline,SplineSet * spl)4277 static int CheckSpline(FindSel *fs, Spline *spline, SplineSet *spl) {
4278
4279 /* Anything else is better than a spline */
4280 if ( fs->p->anysel )
4281 return( false );
4282
4283 if ( NearSpline(fs,spline)) {
4284 fs->p->spline = spline;
4285 fs->p->spl = spl;
4286 fs->p->anysel = true;
4287 fs->p->spiro_index = SplineT2SpiroIndex(spline,fs->p->t,spl);
4288 return( false /*true*/ ); /* Check if there's a point where we are first */
4289 /* if there is use it, if not (because anysel is true) we'll fall back */
4290 /* here */
4291 }
4292
4293 return( false );
4294 }
4295
InImage(FindSel * fs,ImageList * img)4296 static int InImage( FindSel *fs, ImageList *img) {
4297 int x,y;
4298
4299 x = floor((fs->p->cx-img->xoff)/img->xscale);
4300 y = floor((img->yoff-fs->p->cy)/img->yscale);
4301 if ( x<0 || y<0 || x>=GImageGetWidth(img->image) || y>=GImageGetHeight(img->image))
4302 return ( false );
4303 if ( GImageGetPixelRGBA(img->image,x,y)<0x80000000 ) /* Transparent(ish) */
4304 return( false );
4305
4306 return( true );
4307 }
4308
InSplineSet(FindSel * fs,SplinePointList * set,int inspiro)4309 static int InSplineSet( FindSel *fs, SplinePointList *set,int inspiro) {
4310 SplinePointList *spl;
4311 Spline *spline, *first;
4312 int i;
4313
4314 for ( spl = set; spl!=NULL; spl = spl->next ) {
4315 if ( inspiro ) {
4316 for ( i=0; i<spl->spiro_cnt-1; ++i )
4317 if ( CheckSpiroPoint(fs,&spl->spiros[i],spl,i))
4318 return( true );
4319 first = NULL;
4320 for ( spline = spl->first->next; spline!=NULL && spline!=first; spline=spline->to->next ) {
4321 if ( CheckSpline(fs,spline,spl), fs->p->anysel )
4322 return( true );
4323 if ( first==NULL ) first = spline;
4324 }
4325 } else {
4326 if ( CheckPoint(fs,spl->first,spl) && ( !fs->seek_controls || fs->p->nextcp || fs->p->prevcp )) {
4327 return( true );
4328 }
4329 first = NULL;
4330 for ( spline = spl->first->next; spline!=NULL && spline!=first; spline=spline->to->next ) {
4331 if ( (CheckPoint(fs,spline->to,spl) && ( !fs->seek_controls || fs->p->nextcp || fs->p->prevcp )) ||
4332 ( CheckSpline(fs,spline,spl) && !fs->seek_controls )) {
4333 return( true );
4334 }
4335 if ( first==NULL ) first = spline;
4336 }
4337 }
4338 }
4339 return( fs->p->anysel );
4340 }
4341
NearSplineSetPoints(FindSel * fs,SplinePointList * set,int inspiro)4342 static int NearSplineSetPoints( FindSel *fs, SplinePointList *set,int inspiro) {
4343 SplinePointList *spl;
4344 Spline *spline, *first;
4345 int i;
4346
4347 for ( spl = set; spl!=NULL; spl = spl->next ) {
4348 if ( inspiro ) {
4349 for ( i=0; i<spl->spiro_cnt; ++i )
4350 if ( CheckSpiroPoint(fs,&spl->spiros[i],spl,i))
4351 return( true );
4352 } else {
4353 if ( CheckPoint(fs,spl->first,spl)) {
4354 return( true );
4355 }
4356 first = NULL;
4357 for ( spline = spl->first->next; spline!=NULL && spline!=first; spline=spline->to->next ) {
4358 if ( CheckPoint(fs,spline->to,spl) ) {
4359 return( true );
4360 }
4361 if ( first==NULL ) first = spline;
4362 }
4363 }
4364 }
4365 return( fs->p->anysel );
4366 }
4367
MouseToCX(CharView * cv,int16 mx)4368 static int16 MouseToCX( CharView *cv, int16 mx )
4369 {
4370 CharViewTab* tab = CVGetActiveTab(cv);
4371 return( mx - tab->xoff ) / tab->scale;
4372 }
4373
4374
SetFS(FindSel * fs,PressedOn * p,CharView * cv,GEvent * event)4375 static void SetFS( FindSel *fs, PressedOn *p, CharView *cv, GEvent *event) {
4376 CharViewTab* tab = CVGetActiveTab(cv);
4377 extern int snaptoint;
4378
4379 memset(p,'\0',sizeof(PressedOn));
4380 p->pressed = true;
4381
4382 memset(fs,'\0',sizeof(*fs));
4383 fs->p = p;
4384 fs->e = event;
4385 p->x = event->u.mouse.x;
4386 p->y = event->u.mouse.y;
4387 p->cx = (event->u.mouse.x-tab->xoff)/tab->scale;
4388 p->cy = (cv->height-event->u.mouse.y-tab->yoff)/tab->scale;
4389
4390 fs->fudge = (cv->active_tool==cvt_ruler ? snapdistancemeasuretool : snapdistance)/tab->scale;
4391
4392 /* If they have really large control points then expand
4393 * the selection range to allow them to still click on the
4394 * very edge of the control point to select it.
4395 */
4396 if( prefs_cvEditHandleSize > prefs_cvEditHandleSize_default )
4397 {
4398 float delta = (prefs_cvEditHandleSize - prefs_cvEditHandleSize_default) / tab->scale;
4399 delta *= 1.5;
4400 fs->fudge += delta;
4401 }
4402
4403 fs->c_xl = fs->xl = p->cx - fs->fudge;
4404 fs->c_xh = fs->xh = p->cx + fs->fudge;
4405 fs->c_yl = fs->yl = p->cy - fs->fudge;
4406 fs->c_yh = fs->yh = p->cy + fs->fudge;
4407 if ( snaptoint ) {
4408 p->cx = rint(p->cx);
4409 p->cy = rint(p->cy);
4410 if ( fs->xl>p->cx - fs->fudge )
4411 fs->xl = p->cx - fs->fudge;
4412 if ( fs->xh < p->cx + fs->fudge )
4413 fs->xh = p->cx + fs->fudge;
4414 if ( fs->yl>p->cy - fs->fudge )
4415 fs->yl = p->cy - fs->fudge;
4416 if ( fs->yh < p->cy + fs->fudge )
4417 fs->yh = p->cy + fs->fudge;
4418 }
4419 }
4420
CVMouseAtSpline(CharView * cv,GEvent * event)4421 int CVMouseAtSpline(CharView *cv,GEvent *event) {
4422 FindSel fs;
4423 int pressed = cv->p.pressed;
4424
4425 SetFS(&fs,&cv->p,cv,event);
4426 cv->p.pressed = pressed;
4427 return( InSplineSet(&fs,cv->b.layerheads[cv->b.drawmode]->splines,cv->b.sc->inspiro && hasspiro()));
4428 }
4429
CVConstrainedMouseDown(CharView * cv,GEvent * event,GEvent * fake)4430 static GEvent *CVConstrainedMouseDown(CharView *cv,GEvent *event, GEvent *fake) {
4431 CharViewTab* tab = CVGetActiveTab(cv);
4432 SplinePoint *base;
4433 spiro_cp *basecp;
4434 int basex, basey, dx, dy;
4435 double basetruex, basetruey;
4436 int sign;
4437
4438 if ( !CVAnySelPoint(cv,&base,&basecp))
4439 return( event );
4440
4441 if ( base!=NULL ) {
4442 basetruex = base->me.x;
4443 basetruey = base->me.y;
4444 } else {
4445 basetruex = basecp->x;
4446 basetruey = basecp->y;
4447 }
4448 basex = tab->xoff + rint(basetruex*tab->scale);
4449 basey = -tab->yoff + cv->height - rint(basetruey*tab->scale);
4450
4451 dx= event->u.mouse.x-basex, dy = event->u.mouse.y-basey;
4452 sign = dx*dy<0?-1:1;
4453
4454 fake->u.mouse = event->u.mouse;
4455 if ( dx<0 ) dx = -dx; if ( dy<0 ) dy = -dy;
4456 if ( dy >= 2*dx ) {
4457 cv->p.x = fake->u.mouse.x = basex;
4458 cv->p.cx = basetruex ;
4459 if ( !(event->u.mouse.state&ksm_meta) &&
4460 ItalicConstrained && cv->b.sc->parent->italicangle!=0 ) {
4461 double off = tan(cv->b.sc->parent->italicangle*FF_PI/180)*
4462 (cv->p.cy-basetruey);
4463 double aoff = off<0 ? -off : off;
4464 if ( dx>=aoff*tab->scale/2 && (event->u.mouse.x-basex<0)!=(off<0) ) {
4465 cv->p.cx -= off;
4466 cv->p.x = fake->u.mouse.x = tab->xoff + rint(cv->p.cx*tab->scale);
4467 }
4468 }
4469 } else if ( dx >= 2*dy ) {
4470 fake->u.mouse.y = basey;
4471 cv->p.cy = basetruey;
4472 } else if ( dx > dy ) {
4473 fake->u.mouse.x = basex + sign * (event->u.mouse.y-cv->p.y);
4474 cv->p.cx = basetruex - sign * (cv->p.cy-basetruey);
4475 } else {
4476 fake->u.mouse.y = basey + sign * (event->u.mouse.x-cv->p.x);
4477 cv->p.cy = basetruey - sign * (cv->p.cx-basetruex);
4478 }
4479
4480 return( fake );
4481 }
4482
CVSetConstrainPoint(CharView * cv,GEvent * event)4483 static void CVSetConstrainPoint(CharView *cv, GEvent *event) {
4484 SplineSet *sel;
4485
4486 if ( (sel = CVAnySelPointList(cv))!=NULL ) {
4487 if ( sel->first->selected ) cv->p.constrain = sel->first->me;
4488 else cv->p.constrain = sel->last->me;
4489 } else if ( cv->p.sp!=NULL ) {
4490 cv->p.constrain = cv->p.sp->me;
4491 } else {
4492 cv->p.constrain.x = cv->info.x;
4493 cv->p.constrain.y = cv->info.y;
4494 }
4495 }
4496
CVDoSnaps(CharView * cv,FindSel * fs)4497 static void CVDoSnaps(CharView *cv, FindSel *fs) {
4498 PressedOn *p = fs->p;
4499
4500 if ( cv->b.drawmode!=dm_grid && cv->b.layerheads[dm_grid]->splines!=NULL ) {
4501 PressedOn temp;
4502 int oldseek = fs->seek_controls;
4503 temp = *p;
4504 fs->p = &temp;
4505 fs->seek_controls = false;
4506 if ( InSplineSet( fs, cv->b.layerheads[dm_grid]->splines,cv->b.sc->inspiro && hasspiro())) {
4507 if ( temp.spline!=NULL ) {
4508 p->cx = ((temp.spline->splines[0].a*temp.t+
4509 temp.spline->splines[0].b)*temp.t+
4510 temp.spline->splines[0].c)*temp.t+
4511 temp.spline->splines[0].d;
4512 p->cy = ((temp.spline->splines[1].a*temp.t+
4513 temp.spline->splines[1].b)*temp.t+
4514 temp.spline->splines[1].c)*temp.t+
4515 temp.spline->splines[1].d;
4516 } else if ( temp.sp!=NULL ) {
4517 p->cx = temp.sp->me.x;
4518 p->cy = temp.sp->me.y;
4519 }
4520 }
4521 fs->p = p;
4522 fs->seek_controls = oldseek;
4523 }
4524 if ( p->cx>-fs->fudge && p->cx<fs->fudge )
4525 p->cx = 0;
4526 else if ( p->cx>cv->b.sc->width-fs->fudge && p->cx<cv->b.sc->width+fs->fudge &&
4527 !cv->widthsel)
4528 p->cx = cv->b.sc->width;
4529 else if ( cv->widthsel && p!=&cv->p &&
4530 p->cx>cv->oldwidth-fs->fudge && p->cx<cv->oldwidth+fs->fudge )
4531 p->cx = cv->oldwidth;
4532 if ( p->cy>-fs->fudge && p->cy<fs->fudge )
4533 p->cy = 0;
4534 }
4535
_CVTestSelectFromEvent(CharView * cv,FindSel * fs)4536 static int _CVTestSelectFromEvent(CharView *cv,FindSel *fs) {
4537 PressedOn temp;
4538 ImageList *img;
4539 int found;
4540
4541 found = InSplineSet(fs,cv->b.layerheads[cv->b.drawmode]->splines,cv->b.sc->inspiro && hasspiro());
4542
4543 if ( !found ) {
4544 RefChar *rf;
4545 temp = cv->p;
4546 fs->p = &temp;
4547 fs->seek_controls = false;
4548 for ( rf=cv->b.layerheads[cv->b.drawmode]->refs; rf!=NULL; rf = rf->next ) {
4549 if ( InSplineSet(fs,rf->layers[0].splines,cv->b.sc->inspiro && hasspiro())) {
4550 cv->p.ref = rf;
4551 cv->p.anysel = true;
4552 break;
4553 }
4554 }
4555 if ( cv->b.drawmode==dm_fore && ( cv->showanchor && !cv->p.anysel )) {
4556 AnchorPoint *ap, *found=NULL;
4557 /* I do this pecular search because: */
4558 /* 1) I expect there to be lots of times we get multiple */
4559 /* anchors at the same location */
4560 /* 2) The anchor points are drawn so that the bottommost */
4561 /* is displayed */
4562 for ( ap=cv->b.sc->anchor; ap!=NULL; ap=ap->next )
4563 if ( fs->xl<=ap->me.x && fs->xh>=ap->me.x &&
4564 fs->yl<=ap->me.y && fs->yh >= ap->me.y )
4565 found = ap;
4566 if ( found!=NULL ) {
4567 cv->p.ap = found;
4568 cv->p.anysel = true;
4569 }
4570 }
4571 for ( img = cv->b.layerheads[cv->b.drawmode]->images; img!=NULL; img=img->next ) {
4572 if ( InImage(fs,img)) {
4573 cv->p.img = img;
4574 cv->p.anysel = true;
4575 break;
4576 }
4577 }
4578 }
4579 return( cv->p.anysel );
4580 }
4581
CVTestSelectFromEvent(CharView * cv,GEvent * event)4582 int CVTestSelectFromEvent(CharView *cv,GEvent *event) {
4583 FindSel fs;
4584
4585 SetFS(&fs,&cv->p,cv,event);
4586 return( _CVTestSelectFromEvent(cv,&fs));
4587 }
4588
4589 /**
4590 * A cache for the selected spline point or spiro control point
4591 */
4592 typedef struct lastselectedpoint
4593 {
4594 SplinePoint *lastselpt;
4595 spiro_cp *lastselcp;
4596 } lastSelectedPoint;
4597
CVMaybeCreateDraggingComparisonOutline(CharView * cv)4598 static void CVMaybeCreateDraggingComparisonOutline( CharView* cv )
4599 {
4600 if (!prefs_create_dragging_comparison_outline)
4601 return;
4602 if (!cv)
4603 return;
4604 if (cv->p.pretransform_spl) {
4605 SplinePointListFree(cv->p.pretransform_spl);
4606 cv->p.pretransform_spl = NULL;
4607 }
4608
4609 Layer* l = cv->b.layerheads[cv->b.drawmode];
4610 if (!l || !l->splines)
4611 return;
4612
4613 if (cv->p.anysel) {
4614 SplinePointList *cur = NULL;
4615 for (SplinePointList *spl = l->splines; spl; spl = spl->next) {
4616 if (SplinePointListCheckSelected1(spl, cv->b.sc->inspiro && hasspiro(), NULL, false)) {
4617 if (cur == NULL) {
4618 cv->p.pretransform_spl = cur = SplinePointListCopy1(spl);
4619 } else {
4620 cur->next = SplinePointListCopy1(spl);
4621 cur = cur->next;
4622 }
4623 }
4624 }
4625 }
4626 }
4627
CVSwitchActiveSC(CharView * cv,SplineChar * sc,int idx)4628 static void CVSwitchActiveSC( CharView *cv, SplineChar* sc, int idx )
4629 {
4630 CharViewTab* tab = CVGetActiveTab(cv);
4631 int i=0;
4632 FontViewBase *fv = cv->b.fv;
4633 char buf[300];
4634
4635 TRACE("CVSwitchActiveSC() idx:%d active:%d\n", idx, cv->additionalCharsToShowActiveIndex );
4636 if( !sc )
4637 {
4638 sc = cv->additionalCharsToShow[i];
4639 if( !sc )
4640 return;
4641 }
4642 else
4643 {
4644 // test for setting something twice
4645 if( !idx && cv->additionalCharsToShowActiveIndex == idx )
4646 {
4647 if( cv->additionalCharsToShow[i] == sc )
4648 return;
4649 }
4650 }
4651
4652 cv->changedActiveGlyph = 1;
4653 TRACE("CVSwitchActiveSC(b) activeidx:%d newidx:%d\n", cv->additionalCharsToShowActiveIndex, idx );
4654 for( i=0; i < additionalCharsToShowLimit; i++ )
4655 if( cv->additionalCharsToShow[i] )
4656 TRACE("CVSwitchActiveSC(b) toshow.. i:%d char:%s\n", i, cv->additionalCharsToShow[i]
4657 ? cv->additionalCharsToShow[i]->name : "N/A" );
4658
4659
4660 //
4661 // Work out how far we should scroll the panel to keep
4662 // the display from jumping around. First look right then
4663 // check left.
4664 int scroll_offset = 0;
4665 if( idx > cv->additionalCharsToShowActiveIndex )
4666 {
4667 SplineChar* xc = 0;
4668 int i = 0;
4669 scroll_offset = cv->b.sc->width;
4670 int ridx = cv->additionalCharsToShowActiveIndex+1;
4671 for( i=ridx; i < idx; i++ )
4672 {
4673 if((xc = cv->additionalCharsToShow[i]))
4674 scroll_offset += xc->width;
4675 }
4676 }
4677 if( idx < cv->additionalCharsToShowActiveIndex )
4678 {
4679 SplineChar* xc = 0;
4680 int i = 0;
4681 scroll_offset = 0;
4682 int ridx = cv->additionalCharsToShowActiveIndex-1;
4683 for( i=ridx; i >= idx; i-- )
4684 {
4685 if((xc = cv->additionalCharsToShow[i]))
4686 scroll_offset -= xc->width;
4687 }
4688 }
4689
4690
4691
4692
4693
4694 CVUnlinkView( cv );
4695 cv->b.sc = sc;
4696 cv->b.next = sc->views;
4697 cv->b.layerheads[dm_fore] = &sc->layers[ly_fore];
4698 cv->b.layerheads[dm_back] = &sc->layers[ly_back];
4699 cv->b.layerheads[dm_grid] = &fv->sf->grid;
4700 if ( !sc->parent->multilayer && fv->active_layer!=ly_fore ) {
4701 cv->b.layerheads[dm_back] = &sc->layers[fv->active_layer];
4702 cv->b.drawmode = dm_back;
4703 }
4704 CharIcon(cv,(FontView *) (cv->b.fv));
4705 char* title = CVMakeTitles(cv,buf,sizeof(buf));
4706 GDrawSetWindowTitles8(cv->gw,buf,title);
4707 CVInfoDraw(cv,cv->gw);
4708 free(title);
4709 _CVPaletteActivate(cv,true,false);
4710
4711 TRACE("CVSwitchActiveSC() idx:%d\n", idx );
4712
4713 cv->additionalCharsToShowActiveIndex = idx;
4714
4715 // update the select[i]on in the input text to reflect
4716 // the users currently selected char.
4717 {
4718 SplineFont* sf = cv->b.sc->parent;
4719 EncMap *map = ((FontView *) (cv->b.fv))->b.map;
4720 unichar_t *srctxt = GGadgetGetTitle( cv->charselector );
4721 int endsWithSlash = u_endswith( srctxt, c_to_u("/"));
4722
4723 unichar_t* p = 0;
4724 p = Wordlist_selectionClear( sf, map, srctxt );
4725 p = Wordlist_selectionAdd( sf, map, p, idx );
4726 if( endsWithSlash )
4727 uc_strcat( p, "/" );
4728
4729 // only update when the selection has changed.
4730 // updating this string is a non reversable operation if the
4731 // user is part way through typing some text.
4732 if( !Wordlist_selectionsEqual( srctxt, p ))
4733 {
4734 GGadgetSetTitle( cv->charselector, p );
4735 }
4736 }
4737
4738
4739 cv->b.next = sc->views;
4740 sc->views = &cv->b;
4741
4742 // Move the scrollbar so that it appears the selection
4743 // box has moved rather than all the characters.
4744 if( scroll_offset )
4745 CVHScrollSetPos( cv, tab->xoff + scroll_offset * tab->scale );
4746
4747 // if ( CVClearSel(cv))
4748 // SCUpdateAll(cv->b.sc);
4749
4750 }
4751
CVMouseDown(CharView * cv,GEvent * event)4752 static void CVMouseDown(CharView *cv, GEvent *event ) {
4753 FindSel fs;
4754 GEvent fake;
4755 lastSelectedPoint lastSel;
4756 memset( &lastSel, 0, sizeof(lastSelectedPoint));
4757
4758 if ( event->u.mouse.button==2 && event->u.mouse.device!=NULL &&
4759 strcmp(event->u.mouse.device,"stylus")==0 )
4760 return; /* I treat this more like a modifier key change than a button press */
4761
4762 if ( cv->expandedge != ee_none )
4763 GDrawSetCursor(cv->v,ct_mypointer);
4764 if ( event->u.mouse.button==3 )
4765 {
4766 /* context menu */
4767 CVToolsPopup(cv,event);
4768 return;
4769 }
4770
4771 TRACE("tool:%d pointer:%d ctl:%d alt:%d\n",
4772 cv->showing_tool,
4773 (cv->showing_tool == cvt_pointer),
4774 cv->activeModifierControl, cv->activeModifierAlt );
4775
4776 int8 override_showing_tool = cvt_none;
4777 int8 old_showing_tool = cv->showing_tool;
4778 if( cv->showing_tool == cvt_pointer
4779 && cv->activeModifierControl
4780 && cv->activeModifierAlt )
4781 {
4782 FindSel fs;
4783 SetFS(&fs,&cv->p,cv,event);
4784 int found = InSplineSet( &fs, cv->b.layerheads[cv->b.drawmode]->splines,
4785 cv->b.sc->inspiro && hasspiro());
4786 TRACE("in spline set:%d cv->p.sp:%p\n", found, cv->p.sp );
4787
4788 //
4789 // Only overwrite to create a point if the user has clicked a spline.
4790 //
4791 if( found && !cv->p.sp )
4792 override_showing_tool = cvt_curve;
4793 }
4794
4795 if( cv->charselector && cv->charselector == GWindowGetFocusGadgetOfWindow(cv->gw))
4796 GWindowClearFocusGadgetOfWindow(cv->gw);
4797
4798 update_spacebar_hand_tool(cv);
4799
4800 CVToolsSetCursor(cv,event->u.mouse.state|(1<<(7+event->u.mouse.button)), event->u.mouse.device );
4801 if( override_showing_tool != cvt_none )
4802 cv->showing_tool = override_showing_tool;
4803 cv->active_tool = cv->showing_tool;
4804 cv->needsrasterize = false;
4805 cv->recentchange = false;
4806
4807
4808 SetFS(&fs,&cv->p,cv,event);
4809 if ( event->u.mouse.state&ksm_shift )
4810 event = CVConstrainedMouseDown(cv,event,&fake);
4811
4812 if ( cv->active_tool == cvt_pointer ) {
4813 fs.select_controls = true;
4814 if ( event->u.mouse.state&ksm_meta ) {
4815 fs.seek_controls = true;
4816 /* Allow more slop looking for control points if they asked for them */
4817 fs.c_xl -= fs.fudge; fs.c_xh += fs.fudge;
4818 fs.c_yl -= fs.fudge; fs.c_yh += fs.fudge;
4819 }
4820 if ( cv->showpointnumbers && cv->b.layerheads[cv->b.drawmode]->order2 )
4821 fs.all_controls = true;
4822 fs.alwaysshowcontrolpoints = cv->alwaysshowcontrolpoints;
4823 lastSel.lastselpt = cv->lastselpt;
4824 lastSel.lastselcp = cv->lastselcp;
4825 cv->lastselpt = NULL;
4826 cv->lastselcp = NULL;
4827 _CVTestSelectFromEvent(cv,&fs);
4828 fs.p = &cv->p;
4829
4830 // TRACE("cvmousedown tab->xoff:%d\n", tab->xoff );
4831 // TRACE("cvmousedown x:%d y:%d\n", event->u.mouse.x, event->u.mouse.y );
4832
4833 if( !cv->p.anysel && cv->b.drawmode != dm_grid )
4834 {
4835 // If we are in left-right arrow cursor mode to move
4836 // those bearings then don't even think about changing
4837 // the char right now.
4838 if( !CVNearRBearingLine( cv, cv->p.cx, fs.fudge )
4839 && !CVNearLBearingLine( cv, cv->p.cx, fs.fudge ))
4840 {
4841 int i=0;
4842 FindSel fsadjusted = fs;
4843 fsadjusted.c_xl -= 2*fsadjusted.fudge;
4844 fsadjusted.c_xh += 2*fsadjusted.fudge;
4845 fsadjusted.xl -= 2*fsadjusted.fudge;
4846 fsadjusted.xh += 2*fsadjusted.fudge;
4847 SplineChar* xc = 0;
4848 int xcidx = -1;
4849 int borderFudge = 20;
4850
4851 {
4852 int offset = cv->b.sc->width;
4853 int cumulativeLeftSideBearing = 0;
4854 // TRACE("first offset:%d original cx:%f \n", offset, fsadjusted.p->cx );
4855 int ridx = cv->additionalCharsToShowActiveIndex+1;
4856 for( i=ridx; i < additionalCharsToShowLimit; i++ )
4857 {
4858 if( i == cv->additionalCharsToShowActiveIndex )
4859 continue;
4860 xc = cv->additionalCharsToShow[i];
4861 if( !xc )
4862 break;
4863 int OffsetForDoingCharNextToActive = 0;
4864 if( i == ridx )
4865 {
4866 OffsetForDoingCharNextToActive = borderFudge;
4867 }
4868
4869
4870 cumulativeLeftSideBearing += offset;
4871 /* TRACE("1 adj. x:%f %f\n",fsadjusted.xl,fsadjusted.xh); */
4872 /* TRACE("1 adj.cx:%f %f\n",fsadjusted.c_xl,fsadjusted.c_xh); */
4873 /* TRACE("1 p. cx:%f %f\n",fsadjusted.p->cx,fsadjusted.p->cy ); */
4874 /* fsadjusted.c_xl -= offset; */
4875 /* fsadjusted.c_xh -= offset; */
4876 /* fsadjusted.xl -= offset; */
4877 /* fsadjusted.xh -= offset; */
4878 /* TRACE("2 adj. x:%f %f\n",fsadjusted.xl,fsadjusted.xh); */
4879 /* TRACE("2 adj.cx:%f %f\n",fsadjusted.c_xl,fsadjusted.c_xh); */
4880 /* TRACE("2 p. cx:%f %f\n",fsadjusted.p->cx,fsadjusted.p->cy ); */
4881 /* int found = InSplineSet( &fsadjusted, */
4882 /* xc->layers[cv->b.drawmode-1].splines, */
4883 /* xc->inspiro && hasspiro()); */
4884 TRACE("A:%d\n", cumulativeLeftSideBearing );
4885 TRACE("B:%f\n", fsadjusted.p->cx );
4886 TRACE("C:%d\n", cumulativeLeftSideBearing+xc->width );
4887 int found = IS_IN_ORDER3(
4888 cumulativeLeftSideBearing + OffsetForDoingCharNextToActive,
4889 fsadjusted.p->cx,
4890 cumulativeLeftSideBearing+xc->width );
4891 TRACE("CVMOUSEDOWN i:%d found:%d\n", i, found );
4892 if( found )
4893 {
4894 TRACE("FOUND FOUND FOUND FOUND FOUND FOUND FOUND \n");
4895
4896 xcidx = i;
4897 // CVChangeSC(cv,xc);
4898 break;
4899 }
4900
4901 offset = xc->width;
4902 }
4903 }
4904
4905 fsadjusted = fs;
4906 fsadjusted.c_xl -= 2*fsadjusted.fudge;
4907 fsadjusted.c_xh += 2*fsadjusted.fudge;
4908 fsadjusted.xl -= 2*fsadjusted.fudge;
4909 fsadjusted.xh += 2*fsadjusted.fudge;
4910
4911 if( !xc && cv->additionalCharsToShowActiveIndex > 0 )
4912 {
4913 xc = cv->additionalCharsToShow[cv->additionalCharsToShowActiveIndex-1];
4914 int offset = xc->width;
4915 int cumulativeLeftSideBearing = 0;
4916 // TRACE("first offset:%d original cx:%f \n", offset, fsadjusted.p->cx );
4917 int lidx = cv->additionalCharsToShowActiveIndex-1;
4918 for( i=lidx; i>=0; i-- )
4919 {
4920 if( i == cv->additionalCharsToShowActiveIndex )
4921 continue;
4922 xc = cv->additionalCharsToShow[i];
4923 if( !xc )
4924 break;
4925 cumulativeLeftSideBearing -= xc->width;
4926 int OffsetForDoingCharNextToActive = 0;
4927 if( i == lidx )
4928 {
4929 OffsetForDoingCharNextToActive = borderFudge;
4930 }
4931
4932 /* TRACE("1 adj. x:%f %f\n",fsadjusted.xl,fsadjusted.xh); */
4933 /* TRACE("1 adj.cx:%f %f\n",fsadjusted.c_xl,fsadjusted.c_xh); */
4934 /* TRACE("1 p. cx:%f %f\n",fsadjusted.p->cx,fsadjusted.p->cy ); */
4935 /* fsadjusted.c_xl += offset; */
4936 /* fsadjusted.c_xh += offset; */
4937 /* fsadjusted.xl += offset; */
4938 /* fsadjusted.xh += offset; */
4939 /* TRACE("2 adj. x:%f %f\n",fsadjusted.xl,fsadjusted.xh); */
4940 /* TRACE("2 adj.cx:%f %f\n",fsadjusted.c_xl,fsadjusted.c_xh); */
4941 /* TRACE("2 p. cx:%f %f\n",fsadjusted.p->cx,fsadjusted.p->cy ); */
4942 /* int found = InSplineSet( &fsadjusted, */
4943 /* xc->layers[cv->b.drawmode-1].splines, */
4944 /* xc->inspiro && hasspiro()); */
4945 TRACE("A:%d\n", cumulativeLeftSideBearing );
4946 TRACE("B:%f\n", fsadjusted.p->cx );
4947 TRACE("C:%d\n", cumulativeLeftSideBearing+xc->width );
4948 int found = IS_IN_ORDER3(
4949 cumulativeLeftSideBearing,
4950 fsadjusted.p->cx,
4951 cumulativeLeftSideBearing + xc->width - OffsetForDoingCharNextToActive );
4952
4953 TRACE("cvmousedown i:%d found:%d\n", i, found );
4954 if( found )
4955 {
4956 TRACE("FOUND FOUND FOUND FOUND FOUND FOUND FOUND i:%d\n", i);
4957 xcidx = i;
4958 break;
4959 }
4960
4961 offset = xc->width;
4962 }
4963 }
4964
4965 TRACE("have xc:%p xcidx:%d\n", xc, xcidx );
4966 TRACE(" idx:%d active:%d\n", xcidx, cv->additionalCharsToShowActiveIndex );
4967 if( xc && xcidx >= 0 )
4968 {
4969 CVSwitchActiveSC( cv, xc, xcidx );
4970 GDrawRequestExpose(cv->v,NULL,false);
4971 return;
4972 }
4973 }
4974 }
4975
4976
4977
4978 } else if ( cv->active_tool == cvt_curve || cv->active_tool == cvt_corner ||
4979 cv->active_tool == cvt_tangent || cv->active_tool == cvt_hvcurve ||
4980 cv->active_tool == cvt_pen || cv->active_tool == cvt_ruler )
4981 {
4982 /* Snap to points and splines */
4983 InSplineSet(&fs,cv->b.layerheads[cv->b.drawmode]->splines,cv->b.sc->inspiro && hasspiro());
4984 if ( fs.p->sp==NULL && fs.p->spline==NULL )
4985 CVDoSnaps(cv,&fs);
4986 } else {
4987 /* Just snap to points */
4988 NearSplineSetPoints(&fs,cv->b.layerheads[cv->b.drawmode]->splines,cv->b.sc->inspiro && hasspiro());
4989 if ( fs.p->sp==NULL && fs.p->spline==NULL )
4990 CVDoSnaps(cv,&fs);
4991 }
4992
4993 cv->e.x = event->u.mouse.x; cv->e.y = event->u.mouse.y;
4994 if ( cv->p.sp!=NULL ) {
4995 BasePoint *p;
4996 if ( cv->p.nextcp )
4997 p = &cv->p.sp->nextcp;
4998 else if ( cv->p.prevcp )
4999 p = &cv->p.sp->prevcp;
5000 else
5001 p = &cv->p.sp->me;
5002 cv->info.x = p->x;
5003 cv->info.y = p->y;
5004 cv->p.cx = p->x; cv->p.cy = p->y;
5005 } else if ( cv->p.spiro!=NULL ) {
5006 cv->info.x = cv->p.spiro->x;
5007 cv->info.y = cv->p.spiro->y;
5008 cv->p.cx = cv->p.spiro->x; cv->p.cy = cv->p.spiro->y;
5009 } else {
5010 cv->info.x = cv->p.cx;
5011 cv->info.y = cv->p.cy;
5012 }
5013 cv->info_within = true;
5014 CVInfoDraw(cv,cv->gw);
5015 CVSetConstrainPoint(cv,event);
5016
5017 switch ( cv->active_tool ) {
5018 case cvt_pointer:
5019 CVMouseDownPointer(cv, &fs, event);
5020 CVMaybeCreateDraggingComparisonOutline( cv );
5021 cv->lastselpt = fs.p->sp;
5022 cv->lastselcp = fs.p->spiro;
5023 break;
5024 case cvt_magnify: case cvt_minify:
5025 //When scroll zooming, the old showing tool is the normal pointer.
5026 old_showing_tool = cv->active_tool;
5027 break;
5028 case cvt_hand:
5029 CVMouseDownHand(cv);
5030 break;
5031 case cvt_freehand:
5032 CVMouseDownFreeHand(cv,event);
5033 break;
5034 case cvt_curve: case cvt_corner: case cvt_tangent: case cvt_pen:
5035 case cvt_hvcurve:
5036 CVMouseDownPoint(cv,event);
5037 break;
5038 case cvt_ruler:
5039 CVMouseDownRuler(cv,event);
5040 break;
5041 case cvt_rotate: case cvt_flip: case cvt_scale: case cvt_skew:
5042 case cvt_3d_rotate: case cvt_perspective:
5043 CVMouseDownTransform(cv);
5044 break;
5045 case cvt_knife:
5046 CVMouseDownKnife(cv);
5047 break;
5048 case cvt_rect: case cvt_elipse: case cvt_poly: case cvt_star:
5049 CVMouseDownShape(cv,event);
5050 break;
5051 }
5052 cv->showing_tool = old_showing_tool;
5053 }
5054
_SCHintsChanged(SplineChar * sc)5055 static void _SCHintsChanged(SplineChar *sc) {
5056 struct splinecharlist *dlist;
5057
5058 if ( !sc->changedsincelasthinted ) {
5059 sc->changedsincelasthinted = true;
5060 FVMarkHintsOutOfDate(sc);
5061 }
5062
5063 for ( dlist=sc->dependents; dlist!=NULL; dlist=dlist->next )
5064 _SCHintsChanged(dlist->sc);
5065 }
5066
SC_HintsChanged(SplineChar * sc)5067 static void SC_HintsChanged(SplineChar *sc) {
5068 struct splinecharlist *dlist;
5069 int was = sc->changedsincelasthinted;
5070
5071 if ( sc->parent->onlybitmaps || sc->parent->multilayer || sc->parent->strokedfont )
5072 return;
5073 sc->changedsincelasthinted = false; /* We just applied a hinting change */
5074 if ( !sc->changed ) {
5075 sc->changed = true;
5076 FVToggleCharChanged(sc);
5077 SCRefreshTitles(sc);
5078 if ( !sc->parent->changed ) {
5079 sc->parent->changed = true;
5080 FVSetTitles(sc->parent);
5081 }
5082 }
5083 for ( dlist=sc->dependents; dlist!=NULL; dlist=dlist->next )
5084 _SCHintsChanged(dlist->sc);
5085 if ( was ) {
5086 FontView *fvs;
5087 for ( fvs = (FontView *) (sc->parent->fv); fvs!=NULL; fvs=(FontView *) (fvs->b.nextsame) )
5088 GDrawRequestExpose(fvs->v,NULL,false);
5089 }
5090 }
5091
CVSetCharChanged(CharView * cv,int changed)5092 void CVSetCharChanged(CharView *cv,int changed) {
5093 SplineFont *sf = cv->b.fv->sf;
5094 SplineChar *sc = cv->b.sc;
5095 int oldchanged = sf->changed;
5096 /* A changed argument of 2 means the outline didn't change, but something */
5097 /* else (width, anchorpoint) did */
5098 int cvlayer = CVLayer((CharViewBase *) cv);
5099
5100 if ( changed )
5101 SFSetModTime(sf);
5102 if ( cv->b.drawmode==dm_grid ) {
5103 if ( changed ) {
5104 sf->changed = true;
5105 if ( sf->cidmaster!=NULL )
5106 sf->cidmaster->changed = true;
5107 }
5108 } else {
5109 if ( cv->b.drawmode==dm_fore && changed==1 ) {
5110 sf->onlybitmaps = false;
5111 }
5112 SCTickValidationState(cv->b.sc,cvlayer);
5113 if ( (sc->changed==0) != (changed==0) ) {
5114 sc->changed = (changed!=0);
5115 FVToggleCharChanged(sc);
5116 SCRefreshTitles(sc);
5117 if ( changed ) {
5118 sf->changed = true;
5119 if ( sf->cidmaster!=NULL )
5120 sf->cidmaster->changed = true;
5121 }
5122 }
5123 if ( changed==1 ) {
5124 instrcheck(sc,cvlayer);
5125 /*SCDeGridFit(sc);*/
5126 if ( sc->parent->onlybitmaps )
5127 /* Do nothing */;
5128 else if ( sc->parent->multilayer || sc->parent->strokedfont || sc->layers[cvlayer].order2 )
5129 sc->changed_since_search = true;
5130 else if ( cv->b.drawmode==dm_fore ) {
5131 sc->changed_since_search = true;
5132 _SCHintsChanged(cv->b.sc);
5133 }
5134 sc->changed_since_autosave = true;
5135 sf->changed_since_autosave = true;
5136 sf->changed_since_xuidchanged = true;
5137 if ( sf->cidmaster!=NULL ) {
5138 sf->cidmaster->changed_since_autosave = true;
5139 sf->cidmaster->changed_since_xuidchanged = true;
5140 }
5141 }
5142 if ( cv->b.drawmode!=dm_grid ) {
5143 cv->needsrasterize = true;
5144 }
5145 }
5146 cv->recentchange = true;
5147 if ( !oldchanged )
5148 FVSetTitles(sf);
5149 }
5150
SCClearSelPt(SplineChar * sc)5151 void SCClearSelPt(SplineChar *sc) {
5152 CharView *cv;
5153
5154 for ( cv=(CharView *) (sc->views); cv!=NULL; cv=(CharView *) (cv->b.next) ) {
5155 cv->lastselpt = cv->p.sp = NULL;
5156 cv->p.spiro = cv->lastselcp = NULL;
5157 }
5158 }
5159
_SC_CharChangedUpdate(SplineChar * sc,int layer,int changed)5160 static void _SC_CharChangedUpdate(SplineChar *sc,int layer,int changed) {
5161 SplineFont *sf = sc->parent;
5162 extern int updateflex;
5163 /* layer might be ly_none or ly_all */
5164
5165 if ( layer>=sc->layer_cnt ) {
5166 IError( "Bad layer in _SC_CharChangedUpdate");
5167 layer = ly_fore;
5168 }
5169 if ( layer>=0 && !sc->layers[layer].background )
5170 TTFPointMatches(sc,layer,true);
5171 if ( changed != -1 ) {
5172 sc->changed_since_autosave = true;
5173 SFSetModTime(sf);
5174 if ( (sc->changed==0) != (changed==0) ) {
5175 sc->changed = (changed!=0);
5176 if ( changed && layer>=ly_fore && (sc->layers[layer].splines!=NULL || sc->layers[layer].refs!=NULL))
5177 sc->parent->onlybitmaps = false;
5178 FVToggleCharChanged(sc);
5179 SCRefreshTitles(sc);
5180 }
5181 if ( !sf->changed ) {
5182 sf->changed = true;
5183 if ( sf->cidmaster )
5184 sf->cidmaster->changed = true;
5185 FVSetTitles(sf);
5186 }
5187 if ( changed && layer>=0 && !sc->layers[layer].background && sc->layers[layer].order2 ) {
5188 instrcheck(sc,layer);
5189 SCReGridFit(sc,layer);
5190 }
5191 if ( !sc->parent->onlybitmaps && !sc->parent->multilayer &&
5192 changed==1 && !sc->parent->strokedfont &&
5193 layer>=0 &&
5194 !sc->layers[layer].background && !sc->layers[layer].order2 )
5195 _SCHintsChanged(sc);
5196 sc->changed_since_search = true;
5197 sf->changed = true;
5198 sf->changed_since_autosave = true;
5199 sf->changed_since_xuidchanged = true;
5200 if ( layer>=0 )
5201 SCTickValidationState(sc,layer);
5202 }
5203 if ( sf->cidmaster!=NULL )
5204 sf->cidmaster->changed = sf->cidmaster->changed_since_autosave =
5205 sf->cidmaster->changed_since_xuidchanged = true;
5206 SCRegenDependents(sc,ly_all); /* All chars linked to this one need to get the new splines */
5207 if ( updateflex && (CharView *) (sc->views)!=NULL && layer>=ly_fore )
5208 SplineCharIsFlexible(sc,layer);
5209 SCUpdateAll(sc);
5210 SCLayersChange(sc);
5211 SCRegenFills(sc);
5212 }
5213
SC_CharChangedUpdate(SplineChar * sc,int layer)5214 static void SC_CharChangedUpdate(SplineChar *sc,int layer) {
5215 _SC_CharChangedUpdate(sc,layer,true);
5216 }
5217
_CV_CharChangedUpdate(CharView * cv,int changed)5218 static void _CV_CharChangedUpdate(CharView *cv,int changed) {
5219 extern int updateflex;
5220 FontView *fv;
5221 int cvlayer = CVLayer((CharViewBase *) cv);
5222
5223 CVSetCharChanged(cv,changed);
5224 CVLayerChange(cv);
5225 if ( cv->needsrasterize ) {
5226 TTFPointMatches(cv->b.sc,cvlayer,true); /* Must precede regen dependents, as this can change references */
5227 SCRegenDependents(cv->b.sc,cvlayer); /* All chars linked to this one need to get the new splines */
5228 if ( cv->b.layerheads[cv->b.drawmode]->order2 )
5229 SCReGridFit(cv->b.sc,cvlayer);
5230 if ( updateflex && cvlayer!=ly_grid && !cv->b.layerheads[cv->b.drawmode]->background )
5231 SplineCharIsFlexible(cv->b.sc,cvlayer);
5232 SCUpdateAll(cv->b.sc);
5233 SCRegenFills(cv->b.sc);
5234 for ( fv = (FontView *) (cv->b.sc->parent->fv); fv!=NULL; fv=(FontView *) (fv->b.nextsame) )
5235 FVRegenChar(fv,cv->b.sc);
5236 cv->needsrasterize = false;
5237 } else if ( cv->b.drawmode!=dm_grid ) {
5238 /* If we changed the background then only views of this character */
5239 /* need to know about it. No dependents needed, but why write */
5240 /* another routine for a rare case... */
5241 SCUpdateAll(cv->b.sc);
5242 } else /* if ( cv->b.drawmode==dm_grid )*/ {
5243 /* If we changed the grid then any character needs to know it */
5244 FVRedrawAllCharViewsSF(cv->b.sc->parent);
5245 }
5246 if ( cv->showpointnumbers || cv->show_ft_results )
5247 SCNumberPoints(cv->b.sc, cvlayer);
5248 cv->recentchange = false;
5249 cv->p.sp = NULL; /* Might have been deleted */
5250 }
5251
CV_CharChangedUpdate(CharView * cv)5252 static void CV_CharChangedUpdate(CharView *cv) {
5253 _CV_CharChangedUpdate(cv,true);
5254 }
5255
CVMouseMove(CharView * cv,GEvent * event)5256 static void CVMouseMove(CharView *cv, GEvent *event ) {
5257 CharViewTab* tab = CVGetActiveTab(cv);
5258 real cx, cy;
5259 PressedOn p;
5260 FindSel fs;
5261 GEvent fake;
5262 int stop_motion = false;
5263 int has_spiro = hasspiro();
5264
5265 /* Debug wacom !!!! */
5266 /* TRACE( "dev=%s (%d,%d) 0x%x\n", event->u.mouse.device!=NULL?event->u.mouse.device:"<None>", */
5267 /* event->u.mouse.x, event->u.mouse.y, event->u.mouse.state); */
5268
5269 if ( event->u.mouse.device!=NULL )
5270 CVToolsSetCursor(cv,event->u.mouse.state,event->u.mouse.device);
5271
5272 if ( !cv->p.pressed ) {
5273 CVUpdateInfo(cv, event);
5274 if ( cv->showing_tool==cvt_pointer ) {
5275 CVCheckResizeCursors(cv);
5276 if ( cv->dv!=NULL )
5277 CVDebugPointPopup(cv);
5278 } else if ( cv->showing_tool == cvt_ruler )
5279 CVMouseMoveRuler(cv,event);
5280 return;
5281 }
5282
5283 //GDrawRequestExpose(cv->v,NULL,false); /* TBD, hack to clear ruler */
5284
5285 SetFS(&fs,&p,cv,event);
5286 if ( cv->active_tool == cvt_freehand )
5287 /* freehand does it's own kind of constraining */;
5288 else if ( (event->u.mouse.state&ksm_shift) && !cv->p.rubberbanding ) {
5289 /* Constrained */
5290
5291 fake.u.mouse = event->u.mouse;
5292 if ( ((event->u.mouse.state&ksm_meta) ||
5293 (!cv->cntrldown && (event->u.mouse.state&ksm_control))) &&
5294 (cv->p.nextcp || cv->p.prevcp)) {
5295 real dot = (cv->p.cp.x-cv->p.constrain.x)*(p.cx-cv->p.constrain.x) +
5296 (cv->p.cp.y-cv->p.constrain.y)*(p.cy-cv->p.constrain.y);
5297 real len = (cv->p.cp.x-cv->p.constrain.x)*(cv->p.cp.x-cv->p.constrain.x)+
5298 (cv->p.cp.y-cv->p.constrain.y)*(cv->p.cp.y-cv->p.constrain.y);
5299 if ( len!=0 ) {
5300 dot /= len;
5301 /* constrain control point to same angle with respect to base point*/
5302 if ( dot<0 ) dot = 0;
5303 p.cx = cv->p.constrain.x + dot*(cv->p.cp.x-cv->p.constrain.x);
5304 p.cy = cv->p.constrain.y + dot*(cv->p.cp.y-cv->p.constrain.y);
5305 p.x = fake.u.mouse.x = tab->xoff + rint(p.cx*tab->scale);
5306 p.y = fake.u.mouse.y = -tab->yoff + cv->height - rint(p.cy*tab->scale);
5307 }
5308 } else {
5309 /* Constrain mouse to hor/vert/45 from base point */
5310 int basex = cv->active_tool!=cvt_hand ? tab->xoff + rint(cv->p.constrain.x*tab->scale) : cv->p.x;
5311 int basey = cv->active_tool!=cvt_hand ?-tab->yoff + cv->height - rint(cv->p.constrain.y*tab->scale) : cv->p.y;
5312 int dx= event->u.mouse.x-basex, dy = event->u.mouse.y-basey;
5313 int sign = dx*dy<0?-1:1;
5314 double aspect = 1.0;
5315
5316 if ( dx<0 ) dx = -dx; if ( dy<0 ) dy = -dy;
5317 if ( cv->p.img!=NULL && cv->p.img->bb.minx!=cv->p.img->bb.maxx )
5318 aspect = (cv->p.img->bb.maxy - cv->p.img->bb.miny) / (cv->p.img->bb.maxx - cv->p.img->bb.minx);
5319 else if ( cv->p.ref!=NULL && cv->p.ref->bb.minx!=cv->p.ref->bb.maxx )
5320 aspect = (cv->p.ref->bb.maxy - cv->p.ref->bb.miny) / (cv->p.ref->bb.maxx - cv->p.ref->bb.minx);
5321 if ( dy >= 2*dx ) {
5322 p.x = fake.u.mouse.x = basex;
5323 p.cx = cv->p.constrain.x;
5324 if ( ItalicConstrained && cv->b.sc->parent->italicangle!=0 ) {
5325 double off = tan(cv->b.sc->parent->italicangle*FF_PI/180)*
5326 (p.cy-cv->p.constrain.y);
5327 double aoff = off<0 ? -off : off;
5328 if ( dx>=aoff*tab->scale/2 && (event->u.mouse.x-basex<0)!=(off<0) ) {
5329 p.cx -= off;
5330 p.x = fake.u.mouse.x = tab->xoff + rint(p.cx*tab->scale);
5331 }
5332 }
5333 } else if ( dx >= 2*dy ) {
5334 p.y = fake.u.mouse.y = basey;
5335 p.cy = cv->p.constrain.y;
5336 } else if ( dx > dy ) {
5337 p.x = fake.u.mouse.x = basex + sign * (event->u.mouse.y-basey)/aspect;
5338 p.cx = cv->p.constrain.x - sign * (p.cy-cv->p.constrain.y)/aspect;
5339 } else {
5340 p.y = fake.u.mouse.y = basey + sign * (event->u.mouse.x-basex)*aspect;
5341 p.cy = cv->p.constrain.y - sign * (p.cx-cv->p.constrain.x)*aspect;
5342 }
5343 }
5344 event = &fake;
5345 }
5346
5347 /* If we've changed the character (recentchange is true) we want to */
5348 /* snap to the original location, otherwise we'll keep snapping to the */
5349 /* current point as it moves across the screen (jerkily) */
5350 if ( cv->active_tool == cvt_hand || cv->active_tool == cvt_freehand )
5351 /* Don't snap to points */;
5352 else if ( !cv->joinvalid ||
5353 ((!cv->b.sc->inspiro || has_spiro) && !CheckPoint(&fs,&cv->joinpos,NULL)) ||
5354 ( cv->b.sc->inspiro && has_spiro && !CheckSpiroPoint(&fs,&cv->joincp,NULL,0))) {
5355 SplinePointList *spl;
5356 spl = cv->b.layerheads[cv->b.drawmode]->splines;
5357 if ( cv->recentchange && cv->active_tool==cvt_pointer &&
5358 cv->b.layerheads[cv->b.drawmode]->undoes!=NULL &&
5359 (cv->b.layerheads[cv->b.drawmode]->undoes->undotype==ut_state ||
5360 cv->b.layerheads[cv->b.drawmode]->undoes->undotype==ut_tstate ))
5361 spl = cv->b.layerheads[cv->b.drawmode]->undoes->u.state.splines;
5362 if ( cv->active_tool != cvt_knife && cv->active_tool != cvt_ruler ) {
5363 if ( cv->active_tool == cvt_pointer && ( cv->p.nextcp || cv->p.prevcp ))
5364 fs.select_controls = true;
5365 NearSplineSetPoints(&fs,spl,cv->b.sc->inspiro && has_spiro);
5366 } else
5367 InSplineSet(&fs,spl,cv->b.sc->inspiro && has_spiro);
5368 }
5369 /* p.sp and cv->p.sp may correspond to different undo states, thus being */
5370 /* different objects even while describing essentially the same point. */
5371 /* So compare point coordinates rather than the points themselves */
5372 if ( (cv->p.nextcp || cv->p.prevcp) && p.nextcp &&
5373 p.sp!=NULL && cv->p.sp != NULL &&
5374 p.sp->me.x == cv->p.sp->me.x && p.sp->me.y == cv->p.sp->me.y ) {
5375 /* If either control point selected, then snap to it or its brother */
5376 /* when close */
5377 p.cx = p.sp->nextcp.x;
5378 p.cy = p.sp->nextcp.y;
5379 } else if (( cv->p.nextcp || cv->p.prevcp) && p.prevcp &&
5380 p.sp!=NULL && cv->p.sp != NULL &&
5381 p.sp->me.x == cv->p.sp->me.x && p.sp->me.y == cv->p.sp->me.y ) {
5382 p.cx = p.sp->prevcp.x;
5383 p.cy = p.sp->prevcp.y;
5384 } else if ( p.sp!=NULL && p.sp!=cv->active_sp ) { /* Snap to points */
5385 p.cx = p.sp->me.x;
5386 p.cy = p.sp->me.y;
5387 } else if ( p.spiro!=NULL && p.spiro!=cv->active_cp ) {
5388 p.cx = p.spiro->x;
5389 p.cy = p.spiro->y;
5390 } else {
5391 CVDoSnaps(cv,&fs);
5392 }
5393 cx = (p.cx -cv->p.cx) / tab->scale;
5394 cy = (p.cy - cv->p.cy) / tab->scale;
5395 if ( cx<0 ) cx = -cx;
5396 if ( cy<0 ) cy = -cy;
5397
5398 /* If they haven't moved far from the start point, then snap to it */
5399 if ( cx+cy < 4 ) {
5400 p.x = cv->p.x; p.y = cv->p.y;
5401 }
5402
5403 cv->info.x = p.cx; cv->info.y = p.cy;
5404 cv->info_sp = p.sp;
5405 cv->info_spline = p.spline;
5406 cv->info_t = p.t;
5407 cv->e.x = event->u.mouse.x; cv->e.y = event->u.mouse.y;
5408 CVInfoDraw(cv,cv->gw);
5409
5410 switch ( cv->active_tool ) {
5411 case cvt_pointer:
5412 stop_motion = CVMouseMovePointer(cv,event);
5413 break;
5414 case cvt_magnify: case cvt_minify:
5415 if ( !cv->p.rubberbanding ) {
5416 cv->p.ex = cv->p.cx;
5417 cv->p.ey = cv->p.cy;
5418 }
5419 cv->p.ex = cv->info.x;
5420 cv->p.ey = cv->info.y;
5421 cv->p.rubberbanding = true;
5422 GDrawRequestExpose(cv->v, NULL, false);
5423 break;
5424 case cvt_hand:
5425 CVMouseMoveHand(cv,event);
5426 break;
5427 case cvt_freehand:
5428 CVMouseMoveFreeHand(cv,event);
5429 break;
5430 case cvt_curve: case cvt_corner: case cvt_tangent: case cvt_hvcurve:
5431 CVMouseMovePoint(cv,&p);
5432 break;
5433 case cvt_pen:
5434 CVMouseMovePen(cv,&p,event);
5435 break;
5436 case cvt_ruler:
5437 CVMouseMoveRuler(cv,event);
5438 break;
5439 case cvt_rotate: case cvt_flip: case cvt_scale: case cvt_skew:
5440 case cvt_3d_rotate: case cvt_perspective:
5441 CVMouseMoveTransform(cv);
5442 break;
5443 case cvt_knife:
5444 CVMouseMoveKnife(cv,&p);
5445 break;
5446 case cvt_rect: case cvt_elipse: case cvt_poly: case cvt_star:
5447 CVMouseMoveShape(cv);
5448 break;
5449 }
5450 if ( stop_motion ) {
5451 event->type = et_mouseup;
5452 CVMouseUp(cv,event);
5453 }
5454 }
5455
CVMagnify(CharView * cv,real midx,real midy,int bigger,int LockPosition)5456 static void CVMagnify(CharView *cv, real midx, real midy, int bigger, int LockPosition) {
5457 CharViewTab* tab = CVGetActiveTab(cv);
5458 static float scales[] = { 1, 2, 3, 4, 6, 8, 11, 16, 23, 32, 45, 64, 90, 128, 181, 256, 512, 1024, 0 };
5459 float oldscale;
5460 int i, j;
5461
5462 oldscale = tab->scale;
5463
5464 if ( bigger!=0 ) {
5465 if ( tab->scale>=1 ) {
5466 for ( i=0; scales[i]!=0 && tab->scale>scales[i]; ++i );
5467 if ( scales[i]==0 ) i=j= i-1;
5468 else if ( RealNear(scales[i],tab->scale) ) j=i;
5469 else if ( i!=0 && RealNear(scales[i-1],tab->scale) ) j= --i; /* Round errors! */
5470 else j = i-1;
5471 } else { real sinv = 1/tab->scale; int t;
5472 for ( i=0; scales[i]!=0 && sinv>scales[i]; ++i );
5473 if ( scales[i]==0 ) i=j= i-1;
5474 else if ( RealNear(scales[i],sinv) ) j=i;
5475 else if ( i!=0 && RealNear(scales[i-1],sinv) ) j= --i; /* Round errors! */
5476 else j = i-1;
5477 t = j;
5478 j = -i; i = -t;
5479 }
5480 if ( bigger==1 ) {
5481 if ( i==j ) ++i;
5482 if ( i>0 && scales[i]==0 ) --i;
5483 if ( i>=0 )
5484 tab->scale = scales[i];
5485 else
5486 tab->scale = 1/scales[-i];
5487 } else {
5488 if ( i==j ) --j;
5489 if ( j<0 && scales[-j]==0 ) ++j;
5490 if ( j>=0 )
5491 tab->scale = scales[j];
5492 else
5493 tab->scale = 1/scales[-j];
5494 }
5495 }
5496
5497 if (LockPosition) {
5498 float mousex = rint(midx * oldscale + tab->xoff);
5499 float mousey = rint(midy * oldscale + tab->yoff - cv->height);
5500 tab->xoff = mousex - midx*tab->scale;
5501 tab->yoff = mousey - midy*tab->scale + cv->height;
5502 }
5503 else {
5504 tab->xoff = -(rint(midx*tab->scale) - cv->width/2);
5505 tab->yoff = -(rint(midy*tab->scale) - cv->height/2);
5506 }
5507
5508 CVNewScale(cv);
5509 }
5510
CVMouseUp(CharView * cv,GEvent * event)5511 static void CVMouseUp(CharView *cv, GEvent *event ) {
5512 CharViewTab* tab = CVGetActiveTab(cv);
5513
5514 CVMouseMove(cv,event);
5515 if ( cv->pressed!=NULL ) {
5516 GDrawCancelTimer(cv->pressed);
5517 cv->pressed = NULL;
5518 }
5519 cv->p.pressed = false;
5520 SplinePointListFree(cv->p.pretransform_spl);
5521 cv->p.pretransform_spl = NULL;
5522 update_spacebar_hand_tool(cv);
5523
5524 if ( cv->p.rubberbanding ) {
5525 cv->p.rubberbanding = false;
5526 } else if ( cv->p.rubberlining ) {
5527 cv->p.rubberlining = false;
5528 }
5529
5530 // This is needed to allow characters to the left of the
5531 // active one to be picked with the mouse,
5532 // but outright it does mess with keyboard input changing BCP
5533 // so we only do it for mouse up to the left of the left side
5534 // bearing, because that click can not currently activate any BCP
5535 if ( cv->active_tool == cvt_pointer &&
5536 MouseToCX( cv, event->u.mouse.x ) < -2 )
5537 {
5538 // Since we allow clicking anywhere now, instead of having
5539 // to check if you clicked on a spline of a prev char,
5540 // then we don't need this. It also causes an issue with the arrow
5541 // keys moving a BCP on a spline left of the lbearing line.
5542 // (comment included just in case this click on spline feature is desired in the future)
5543 /* FindSel fs; */
5544 /* SetFS(&fs,&cv->p,cv,event); */
5545 /* _CVTestSelectFromEvent(cv,&fs); */
5546 /* fs.p = &cv->p; */
5547 }
5548
5549
5550 switch ( cv->active_tool ) {
5551 case cvt_pointer:
5552 CVMouseUpPointer(cv);
5553 break;
5554 case cvt_ruler:
5555 CVMouseUpRuler(cv,event);
5556 break;
5557 case cvt_hand:
5558 CVMouseUpHand(cv);
5559 break;
5560 case cvt_freehand:
5561 CVMouseUpFreeHand(cv,event);
5562 break;
5563 case cvt_curve: case cvt_corner: case cvt_tangent: case cvt_hvcurve:
5564 case cvt_pen:
5565 CVMouseUpPoint(cv,event);
5566 CVGridHandlePossibleFitChar( cv );
5567 break;
5568 case cvt_magnify: case cvt_minify:
5569 if ( cv->p.x>=event->u.mouse.x-6 && cv->p.x<=event->u.mouse.x+6 &&
5570 cv->p.y>=event->u.mouse.y-6 && cv->p.y<=event->u.mouse.y+6 ) {
5571 real cx, cy;
5572 cx = (event->u.mouse.x-tab->xoff)/tab->scale;
5573 cy = (cv->height-event->u.mouse.y-tab->yoff)/tab->scale ;
5574 CVMagnify(cv,cx,cy,cv->active_tool==cvt_minify?-1:1,event->u.mouse.button>3);
5575 } else {
5576 DBounds b;
5577 double oldscale = tab->scale;
5578 if ( cv->p.cx>cv->info.x ) {
5579 b.minx = cv->info.x;
5580 b.maxx = cv->p.cx;
5581 } else {
5582 b.minx = cv->p.cx;
5583 b.maxx = cv->info.x;
5584 }
5585 if ( cv->p.cy>cv->info.y ) {
5586 b.miny = cv->info.y;
5587 b.maxy = cv->p.cy;
5588 } else {
5589 b.miny = cv->p.cy;
5590 b.maxy = cv->info.y;
5591 }
5592 _CVFit(cv,&b,false);
5593 if ( oldscale==tab->scale ) {
5594 tab->scale += .5;
5595 CVNewScale(cv);
5596 }
5597 }
5598 break;
5599 case cvt_rotate: case cvt_flip: case cvt_scale: case cvt_skew:
5600 case cvt_3d_rotate: case cvt_perspective:
5601 CVMouseUpTransform(cv);
5602 break;
5603 case cvt_knife:
5604 CVMouseUpKnife(cv,event);
5605 break;
5606 case cvt_rect: case cvt_elipse: case cvt_poly: case cvt_star:
5607 CVMouseUpShape(cv);
5608 CVGridHandlePossibleFitChar( cv );
5609 break;
5610 }
5611 cv->active_tool = cvt_none;
5612 CVToolsSetCursor(cv,event->u.mouse.state&~(1<<(7+event->u.mouse.button)),event->u.mouse.device); /* X still has the buttons set in the state, even though we just released them. I don't want em */
5613 /* CharChangedUpdate is a rather blunt tool. When moving anchor points with */
5614 /* the mouse we need finer control than it provides */
5615 /* If recentchange is set then change should also be set, don't think we */
5616 /* need the full form of this call */
5617 if ( cv->needsrasterize || cv->recentchange )
5618 _CV_CharChangedUpdate(cv,2);
5619
5620 dlist_foreach( &cv->pointInfoDialogs, (dlist_foreach_func_type)PIChangePoint );
5621 }
5622
CVTimer(CharView * cv,GEvent * event)5623 static void CVTimer(CharView *cv,GEvent *event) {
5624 CharViewTab* tab = CVGetActiveTab(cv);
5625
5626 if ( event->u.timer.timer==cv->pressed ) {
5627 GEvent e;
5628 GDrawGetPointerPosition(cv->v,&e);
5629 if ( e.u.mouse.x<0 || e.u.mouse.y<0 ||
5630 e.u.mouse.x>=cv->width || e.u.mouse.y >= cv->height ) {
5631 real dx = 0, dy = 0;
5632 if ( e.u.mouse.x<0 )
5633 dx = cv->width/8;
5634 else if ( e.u.mouse.x>=cv->width )
5635 dx = -cv->width/8;
5636 if ( e.u.mouse.y<0 )
5637 dy = -cv->height/8;
5638 else if ( e.u.mouse.y>=cv->height )
5639 dy = cv->height/8;
5640 tab->xoff += dx; tab->yoff += dy;
5641 cv->back_img_out_of_date = true;
5642 if ( dy!=0 )
5643 GScrollBarSetPos(cv->vsb,tab->yoff-cv->height);
5644 if ( dx!=0 )
5645 GScrollBarSetPos(cv->hsb,-tab->xoff);
5646 GDrawRequestExpose(cv->v,NULL,false);
5647 }
5648 #if _ModKeysAutoRepeat
5649 /* Under cygwin the modifier keys auto repeat, they don't under normal X */
5650 } else if ( cv->autorpt==event->u.timer.timer ) {
5651 cv->autorpt = NULL;
5652 CVToolsSetCursor(cv,cv->oldstate,NULL);
5653 if ( cv->keysym == GK_Shift_L || cv->keysym == GK_Shift_R ||
5654 cv->keysym == GK_Alt_L || cv->keysym == GK_Alt_R ||
5655 cv->keysym == GK_Meta_L || cv->keysym == GK_Meta_R ) {
5656 GEvent e;
5657 e.w = cv->oldkeyw;
5658 e.u.chr.keysym = cv->keysym;
5659 e.u.chr.x = cv->oldkeyx;
5660 e.u.chr.y = cv->oldkeyy;
5661 CVFakeMove(cv,&e);
5662 }
5663 #endif
5664 }
5665 }
5666
CVDrop(CharView * cv,GEvent * event)5667 static void CVDrop(CharView *cv,GEvent *event) {
5668 /* We should get a list of character names. Add each as a RefChar */
5669 int32 len;
5670 int ch, first = true;
5671 char *start, *pt, *cnames;
5672 SplineChar *rsc;
5673 RefChar *new;
5674 int layer = CVLayer((CharViewBase *) cv);
5675
5676 if ( cv->b.drawmode==dm_grid ) {
5677 ff_post_error(_("Not Guides"),_("References may not be dragged into the guidelines layer"));
5678 return;
5679 }
5680 if ( !GDrawSelectionHasType(cv->gw,sn_drag_and_drop,"STRING"))
5681 return;
5682 cnames = GDrawRequestSelection(cv->gw,sn_drag_and_drop,"STRING",&len);
5683 if ( cnames==NULL )
5684 return;
5685
5686 start = cnames;
5687 while ( *start ) {
5688 while ( *start==' ' ) ++start;
5689 if ( *start=='\0' )
5690 break;
5691 for ( pt=start; *pt && *pt!=' '; ++pt );
5692 ch = *pt; *pt = '\0';
5693 if ( (rsc=SFGetChar(cv->b.sc->parent,-1,start))!=NULL && rsc!=cv->b.sc ) {
5694 if ( first ) {
5695 CVPreserveState(&cv->b);
5696 first =false;
5697 }
5698 new = RefCharCreate();
5699 new->transform[0] = new->transform[3] = 1.0;
5700 new->layers[0].splines = NULL;
5701 new->sc = rsc;
5702 new->next = cv->b.sc->layers[layer].refs;
5703 cv->b.sc->layers[layer].refs = new;
5704 SCReinstanciateRefChar(cv->b.sc,new,layer);
5705 SCMakeDependent(cv->b.sc,rsc);
5706 }
5707 *pt = ch;
5708 start = pt;
5709 }
5710
5711 free(cnames);
5712 CVCharChangedUpdate(&cv->b);
5713 }
5714
v_e_h(GWindow gw,GEvent * event)5715 static int v_e_h(GWindow gw, GEvent *event) {
5716 CharView *cv = (CharView *) GDrawGetUserData(gw);
5717
5718 GGadgetPopupExternalEvent(event);
5719 if (( event->type==et_mouseup || event->type==et_mousedown ) &&
5720 (event->u.mouse.button>=4 && event->u.mouse.button<=7 ) ) {
5721 if ( !(event->u.mouse.state&(ksm_control)) ) /* bind control to magnify/minify */
5722 {
5723 int ish = event->u.mouse.button>5;
5724 if ( event->u.mouse.state&ksm_shift ) ish = !ish;
5725 if ( ish ) /* bind shift to vertical scrolling */
5726 return( GGadgetDispatchEvent(cv->hsb,event));
5727 else
5728 return( GGadgetDispatchEvent(cv->vsb,event));
5729 }
5730 }
5731
5732 switch ( event->type ) {
5733 case et_expose:
5734 GDrawSetLineWidth(gw,0);
5735 CVExpose(cv,gw,event);
5736 break;
5737 case et_crossing:
5738 CVCrossing(cv,event);
5739 break;
5740 case et_mousedown:
5741 CVPaletteActivate(cv);
5742 if ( cv->gic!=NULL )
5743 GDrawSetGIC(gw,cv->gic,0,20);
5744 if ( cv->inactive )
5745 (cv->b.container->funcs->activateMe)(cv->b.container,&cv->b);
5746 CVMouseDown(cv,event);
5747 break;
5748 case et_mousemove:
5749 if ( cv->p.pressed || cv->spacebar_hold)
5750 GDrawSkipMouseMoveEvents(cv->v,event);
5751 CVMouseMove(cv,event);
5752 break;
5753 case et_mouseup:
5754 CVMouseUp(cv,event);
5755 break;
5756 case et_char:
5757 if ( cv->b.container!=NULL )
5758 (cv->b.container->funcs->charEvent)(cv->b.container,event);
5759 else
5760 CVChar(cv,event);
5761 break;
5762 case et_charup:
5763 CVCharUp(cv,event);
5764 break;
5765 case et_timer:
5766 CVTimer(cv,event);
5767 break;
5768 case et_drop:
5769 CVDrop(cv,event);
5770 break;
5771 case et_focus:
5772 if ( event->u.focus.gained_focus ) {
5773 if ( cv->gic!=NULL )
5774 GDrawSetGIC(gw,cv->gic,0,20);
5775 }
5776 break;
5777 }
5778 return( true );
5779 }
5780
CVDrawNum(CharView * UNUSED (cv),GWindow pixmap,int x,int y,char * format,real val,int align)5781 static void CVDrawNum(CharView *UNUSED(cv),GWindow pixmap,int x, int y, char *format,real val, int align) {
5782 char buffer[40];
5783 int len;
5784
5785 if ( val==0 ) val=0; /* avoid -0 */
5786 sprintf(buffer,format,(double)val); /* formats are given as for doubles */
5787 if ( align!=0 ) {
5788 len = GDrawGetText8Width(pixmap,buffer,-1);
5789 if ( align==1 )
5790 x-=len/2;
5791 else
5792 x-=len;
5793 }
5794 GDrawDrawText8(pixmap,x,y,buffer,-1,GDrawGetDefaultForeground(NULL));
5795 }
5796
CVDrawVNum(CharView * cv,GWindow pixmap,int x,int y,char * format,real val,int align)5797 static void CVDrawVNum(CharView *cv,GWindow pixmap,int x, int y, char *format,real val, int align) {
5798 char buffer[40], *pt;
5799 int len;
5800
5801 if ( val==0 ) val=0; /* avoid -0 */
5802 sprintf(buffer,format,(double)val); /* formats are given as for doubles */
5803 if ( align!=0 ) {
5804 len = strlen(buffer)*cv->sfh;
5805 if ( align==1 )
5806 y-=len/2;
5807 else
5808 y-=len;
5809 }
5810 for ( pt=buffer; *pt; ++pt ) {
5811 GDrawDrawText8(pixmap,x,y,pt,1,GDrawGetDefaultForeground(NULL));
5812 y += cv->sdh;
5813 }
5814 }
5815
5816
CVExposeRulers(CharView * cv,GWindow pixmap)5817 static void CVExposeRulers(CharView *cv, GWindow pixmap ) {
5818 CharViewTab* tab = CVGetActiveTab(cv);
5819 real xmin, xmax, ymin, ymax;
5820 real onehundred, pos;
5821 real units, littleunits;
5822 int ybase = cv->mbh+cv->charselectorh+cv->infoh;
5823 int x,y;
5824 GRect rect;
5825 Color def_fg = GDrawGetDefaultForeground(NULL);
5826
5827 xmin = -tab->xoff/tab->scale;
5828 xmax = (cv->width-tab->xoff)/tab->scale;
5829 ymin = -tab->yoff/tab->scale;
5830 ymax = (cv->height-tab->yoff)/tab->scale;
5831 onehundred = 100/tab->scale;
5832
5833 if ( onehundred<5 ) {
5834 units = 1; littleunits=0;
5835 } else if ( onehundred<10 ) {
5836 units = 5; littleunits=1;
5837 } else if ( onehundred<50 ) {
5838 units = 10; littleunits=2;
5839 } else if ( onehundred<100 ) {
5840 units = 25; littleunits=5;
5841 } else if ( onehundred<500/2 ) {
5842 units = 100; littleunits=20;
5843 } else if ( onehundred<1000/2 ) {
5844 // The next numbers (1000 and up) take more space to display, so Frank has adjusted the thresholds.
5845 units = 250; littleunits=50;
5846 } else if ( onehundred<5000/2 ) {
5847 units = 1000; littleunits=200;
5848 } else if ( onehundred<10000/2 ) {
5849 units = 2500; littleunits=500;
5850 } else if ( onehundred<50000/2 ) {
5851 units = 10000; littleunits=2000;
5852 } else {
5853 for ( units=1 ; units<onehundred*2; units *= 10 );
5854 units/=10; littleunits = units/5;
5855 }
5856
5857 // Create the pixmaps
5858 if (cv->hruler != NULL) {
5859 GDrawGetSize(cv->hruler, &rect);
5860 if (rect.width != cv->width || rect.height != cv->rulerh) {
5861 GDrawDestroyWindow(cv->hruler);
5862 cv->hruler = NULL;
5863 }
5864 }
5865 if (cv->vruler != NULL) {
5866 GDrawGetSize(cv->vruler, &rect);
5867 if (rect.height != cv->height || rect.width != cv->rulerh) {
5868 GDrawDestroyWindow(cv->vruler);
5869 cv->vruler = NULL;
5870 }
5871 }
5872 if (cv->hruler == NULL) {
5873 cv->hruler = GDrawCreatePixmap(GDrawGetDisplayOfWindow(cv->v), cv->v, cv->width, cv->rulerh);
5874 }
5875 if (cv->vruler == NULL) {
5876 cv->vruler = GDrawCreatePixmap(GDrawGetDisplayOfWindow(cv->v), cv->v, cv->rulerh, cv->height);
5877 }
5878
5879 // Set background
5880 rect.x = 0; rect.width = cv->width; rect.y = 0; rect.height = cv->rulerh;
5881 GDrawFillRect(cv->hruler, &rect, GDrawGetDefaultBackground(NULL));
5882 rect.width = cv->rulerh; rect.height = cv->height;
5883 GDrawFillRect(cv->vruler, &rect, GDrawGetDefaultBackground(NULL));
5884
5885 // Draw bottom line of rulers
5886 GDrawSetLineWidth(cv->hruler, 0);
5887 GDrawSetLineWidth(cv->vruler, 0);
5888 GDrawDrawLine(cv->hruler, 0, cv->rulerh - 1, cv->width, cv->rulerh - 1, def_fg);
5889 GDrawDrawLine(cv->vruler, cv->rulerh - 1, 0, cv->rulerh - 1, cv->height, def_fg);
5890
5891 // Draw the ticks
5892 GDrawSetFont(cv->hruler, cv->small);
5893 GDrawSetFont(cv->vruler, cv->small);
5894 if ( xmax-xmin<1 && cv->width>100 ) {
5895 CVDrawNum(cv,cv->hruler,0,cv->sas,"%.3f",xmin,0);
5896 CVDrawNum(cv,cv->hruler,cv->width,cv->sas,"%.3f",xmax,2);
5897 }
5898
5899 if ( ymax-ymin<1 && cv->height>100 ) {
5900 CVDrawVNum(cv,cv->vruler,1,cv->height+cv->sas,"%.3f",ymin,0);
5901 CVDrawVNum(cv,cv->vruler,1,cv->sas,"%.3f",ymax,2);
5902 }
5903 if ( fabs(xmin/units) < 1e5 && fabs(ymin/units)<1e5 && fabs(xmax/units)<1e5 && fabs(ymax/units)<1e5 ) {
5904 if ( littleunits!=0 ) {
5905 for ( pos=littleunits*ceil(xmin/littleunits); pos<xmax; pos += littleunits ) {
5906 x = tab->xoff + rint(pos*tab->scale);
5907 GDrawDrawLine(cv->hruler,x,cv->rulerh-4,x,cv->rulerh, def_fg);
5908 }
5909 for ( pos=littleunits*ceil(ymin/littleunits); pos<ymax; pos += littleunits ) {
5910 y = -tab->yoff + cv->height - rint(pos*tab->scale);
5911 GDrawDrawLine(cv->vruler,cv->rulerh-4,y,cv->rulerh,y, def_fg);
5912 }
5913 }
5914 for ( pos=units*ceil(xmin/units); pos<xmax; pos += units ) {
5915 x = tab->xoff + rint(pos*tab->scale);
5916 GDrawDrawLine(cv->hruler,x,0,x,cv->rulerh, rulerbigtickcol);
5917 CVDrawNum(cv,cv->hruler,x+15,cv->sas,"%g",pos,1);
5918 }
5919 for ( pos=units*ceil(ymin/units); pos<ymax; pos += units ) {
5920 y = -tab->yoff + cv->height - rint(pos*tab->scale);
5921 GDrawDrawLine(cv->vruler,0,y,cv->rulerh,y, rulerbigtickcol);
5922 CVDrawVNum(cv,cv->vruler,1,y+cv->sas+20,"%g",pos,1);
5923 }
5924 }
5925
5926 // Draw the pixmaps to screen
5927 GDrawDrawPixmap(pixmap, cv->vruler, &rect, 0, cv->rulerh + ybase);
5928 rect.width = cv->width; rect.height = cv->rulerh;
5929 GDrawDrawPixmap(pixmap, cv->hruler, &rect, cv->rulerh, ybase);
5930 }
5931
InfoExpose(CharView * cv,GWindow pixmap,GEvent * expose)5932 static void InfoExpose(CharView *cv, GWindow pixmap, GEvent *expose) {
5933 GRect old1, old2;
5934 Color def_fg = GDrawGetDefaultForeground(NULL);
5935
5936 if ( expose->u.expose.rect.y + expose->u.expose.rect.height < cv->mbh ||
5937 (!cv->showrulers && expose->u.expose.rect.y >= cv->mbh+cv->charselectorh+cv->infoh ))
5938 return;
5939
5940 GDrawPushClip(pixmap,&expose->u.expose.rect,&old1);
5941 GDrawSetLineWidth(pixmap,0);
5942 if ( expose->u.expose.rect.y< cv->mbh+cv->charselectorh+cv->infoh ) {
5943 GDrawPushClip(pixmap,&expose->u.expose.rect,&old2);
5944
5945 GDrawDrawLine(pixmap,0,cv->mbh+cv->charselectorh+cv->infoh-1,8096,cv->mbh+cv->charselectorh+cv->infoh-1,def_fg);
5946 GDrawDrawImage(pixmap,&GIcon_rightpointer,NULL,RPT_BASE,cv->mbh+cv->charselectorh+2);
5947 GDrawDrawImage(pixmap,&GIcon_selectedpoint,NULL,SPT_BASE,cv->mbh+cv->charselectorh+2);
5948 GDrawDrawImage(pixmap,&GIcon_sel2ptr,NULL,SOF_BASE,cv->mbh+cv->charselectorh+2);
5949 GDrawDrawImage(pixmap,&GIcon_distance,NULL,SDS_BASE,cv->mbh+cv->charselectorh+2);
5950 GDrawDrawImage(pixmap,&GIcon_angle,NULL,SAN_BASE,cv->mbh+cv->charselectorh+2);
5951 GDrawDrawImage(pixmap,&GIcon_mag,NULL,MAG_BASE,cv->mbh+cv->charselectorh+2);
5952 CVInfoDrawText(cv,pixmap);
5953 GDrawPopClip(pixmap,&old2);
5954 }
5955 if ( cv->showrulers ) {
5956 CVExposeRulers(cv,pixmap);
5957 cv->olde.x = -1;
5958 CVInfoDrawRulers(cv,pixmap);
5959 }
5960 GDrawPopClip(pixmap,&old1);
5961 }
5962
CVResize(CharView * cv)5963 void CVResize(CharView *cv ) {
5964 int sbsize = GDrawPointsToPixels(cv->gw,_GScrollBar_Width);
5965 GRect size;
5966 GDrawGetSize(cv->gw,&size);
5967 {
5968 int newwidth = size.width-sbsize,
5969 newheight = size.height-sbsize - cv->mbh-cv->charselectorh-cv->infoh;
5970 int sbwidth = newwidth, sbheight = newheight;
5971
5972 if ( cv->dv!=NULL ) {
5973 newwidth -= cv->dv->dwidth;
5974 sbwidth -= cv->dv->dwidth;
5975 }
5976 if ( newwidth<30 || newheight<50 ) {
5977 if ( newwidth<30 )
5978 newwidth = 30+sbsize+(cv->dv!=NULL ? cv->dv->dwidth : 0);
5979 if ( newheight<50 )
5980 newheight = 50+sbsize+cv->mbh+cv->charselectorh+cv->infoh;
5981 GDrawResize(cv->gw,newwidth,newheight);
5982 return;
5983 }
5984
5985 if ( cv->dv!=NULL ) {
5986 int dvheight = size.height-(cv->mbh+cv->charselectorh+cv->infoh);
5987 GDrawMove(cv->dv->dv,size.width-cv->dv->dwidth,cv->mbh+cv->charselectorh+cv->infoh);
5988 GDrawResize(cv->dv->dv,cv->dv->dwidth,dvheight);
5989 GDrawResize(cv->dv->ii.v,cv->dv->dwidth-sbsize,dvheight-cv->dv->toph);
5990 GGadgetResize(cv->dv->ii.vsb,sbsize,dvheight-cv->dv->toph);
5991 cv->dv->ii.vheight = dvheight-cv->dv->toph;
5992 GDrawRequestExpose(cv->dv->dv,NULL,false);
5993 GDrawRequestExpose(cv->dv->ii.v,NULL,false);
5994 GScrollBarSetBounds(cv->dv->ii.vsb,0,cv->dv->ii.lheight+1,
5995 cv->dv->ii.vheight/cv->dv->ii.fh);
5996 }
5997
5998 if (cv->charselector != NULL && cv->charselectorPrev != NULL && cv->charselectorNext != NULL) {
5999 GRect charselector_size;
6000 GRect charselectorNext_size;
6001 GRect charselectorPrev_size;
6002 GGadgetGetSize(cv->charselector, &charselector_size);
6003 GGadgetGetSize(cv->charselectorPrev, &charselectorPrev_size);
6004 GGadgetGetSize(cv->charselectorNext, &charselectorNext_size);
6005 int new_charselector_width = newwidth + sbsize - ( 4 * charselector_size.x ) - charselectorNext_size.width - charselectorPrev_size.width;
6006 int new_charselectorPrev_x = newwidth + sbsize - ( 2 * charselector_size.x ) - charselectorNext_size.width - charselectorPrev_size.width;
6007 int new_charselectorNext_x = newwidth + sbsize - ( 1 * charselector_size.x ) - charselectorNext_size.width;
6008 GGadgetResize(cv->charselector, new_charselector_width, charselector_size.height);
6009 GGadgetMove(cv->charselectorPrev, new_charselectorPrev_x, charselectorPrev_size.y);
6010 GGadgetMove(cv->charselectorNext, new_charselectorNext_x, charselectorNext_size.y);
6011 charselector_size.x = 0; charselector_size.y = cv->mbh; charselector_size.width = newwidth + sbsize; charselector_size.height = cv->charselectorh;
6012 GDrawRequestExpose(cv->gw, &charselector_size, false);
6013 }
6014
6015 if ( cv->showrulers ) {
6016 newheight -= cv->rulerh;
6017 newwidth -= cv->rulerh;
6018 }
6019
6020 if ( newwidth == cv->width && newheight == cv->height )
6021 return;
6022 if ( cv->backimgs!=NULL )
6023 GDrawDestroyWindow(cv->backimgs);
6024 cv->backimgs = NULL;
6025
6026 /* MenuBar takes care of itself */
6027 GDrawResize(cv->v,newwidth,newheight);
6028 GGadgetMove(cv->vsb,sbwidth, cv->mbh+cv->charselectorh+cv->infoh);
6029 GGadgetResize(cv->vsb,sbsize,sbheight);
6030 GGadgetMove(cv->hsb,0,size.height-sbsize);
6031 GGadgetResize(cv->hsb,sbwidth,sbsize);
6032 cv->width = newwidth; cv->height = newheight;
6033 /*CVFit(cv);*/ CVNewScale(cv);
6034 CVPalettesRaise(cv);
6035 if ( cv->b.container == NULL && ( cv_width!=size.width || cv_height!=size.height )) {
6036 cv_width = size.width;
6037 cv_height = size.height;
6038 SavePrefs(true);
6039 }
6040 }
6041 }
6042
CVHScrollSetPos(CharView * cv,int newpos)6043 static void CVHScrollSetPos( CharView *cv, int newpos )
6044 {
6045 CharViewTab* tab = CVGetActiveTab(cv);
6046 TRACE("CVHScrollSetPos(1) cvxoff:%f newpos:%d\n", tab->xoff, newpos );
6047 if ( newpos<-(32000*tab->scale-cv->width) )
6048 newpos = -(32000*tab->scale-cv->width);
6049 if ( newpos>8000*tab->scale ) newpos = 8000*tab->scale;
6050 TRACE("CVHScrollSetPos(2) cvxoff:%f newpos:%d\n", tab->xoff, newpos );
6051 if ( newpos!=tab->xoff ) {
6052 int diff = newpos-tab->xoff;
6053 tab->xoff = newpos;
6054 cv->back_img_out_of_date = true;
6055 GScrollBarSetPos(cv->hsb,-newpos);
6056 GDrawScroll(cv->v,NULL,diff,0);
6057 if (( cv->showhhints && cv->b.sc->hstem!=NULL ) || cv->showblues || cv->showvmetrics ) {
6058 GRect r;
6059 r.y = 0; r.height = cv->height;
6060 r.width = 6*cv->sfh+10;
6061 if ( diff>0 )
6062 r.x = cv->width-r.width;
6063 else
6064 r.x = cv->width+diff-r.width;
6065 GDrawRequestExpose(cv->v,&r,false);
6066 }
6067 if ( cv->showrulers ) {
6068 GRect r;
6069 r.y = cv->infoh+cv->mbh+cv->charselectorh; r.height = cv->rulerh; r.x = 0; r.width = cv->rulerh+cv->width;
6070 GDrawRequestExpose(cv->gw,&r,false);
6071 }
6072 }
6073 }
6074
CVHScroll(CharView * cv,struct sbevent * sb)6075 static void CVHScroll(CharView *cv, struct sbevent *sb) {
6076 CharViewTab* tab = CVGetActiveTab(cv);
6077 int newpos = tab->xoff;
6078
6079 switch( sb->type ) {
6080 case et_sb_top:
6081 newpos = 0;
6082 break;
6083 case et_sb_uppage:
6084 newpos += 9*cv->width/10;
6085 break;
6086 case et_sb_up:
6087 newpos += cv->width/15;
6088 break;
6089 case et_sb_down:
6090 newpos -= cv->width/15;
6091 break;
6092 case et_sb_downpage:
6093 newpos -= 9*cv->width/10;
6094 break;
6095 case et_sb_bottom:
6096 newpos = 0;
6097 break;
6098 case et_sb_thumb:
6099 case et_sb_thumbrelease:
6100 newpos = -sb->pos;
6101 break;
6102 case et_sb_halfup:
6103 newpos += cv->width/30;
6104 break;
6105 case et_sb_halfdown:
6106 newpos -= cv->width/30;
6107 break;
6108 }
6109
6110 CVHScrollSetPos( cv, newpos );
6111 }
6112
CVVScroll(CharView * cv,struct sbevent * sb)6113 static void CVVScroll(CharView *cv, struct sbevent *sb) {
6114 CharViewTab* tab = CVGetActiveTab(cv);
6115 int newpos = tab->yoff;
6116
6117 switch( sb->type ) {
6118 case et_sb_top:
6119 newpos = 0;
6120 break;
6121 case et_sb_uppage:
6122 newpos -= 9*cv->height/10;
6123 break;
6124 case et_sb_up:
6125 newpos -= cv->height/15;
6126 break;
6127 case et_sb_down:
6128 newpos += cv->height/15;
6129 break;
6130 case et_sb_downpage:
6131 newpos += 9*cv->height/10;
6132 break;
6133 case et_sb_bottom:
6134 newpos = 0;
6135 break;
6136 case et_sb_thumb:
6137 case et_sb_thumbrelease:
6138 newpos = sb->pos+cv->height;
6139 break;
6140 case et_sb_halfup:
6141 newpos -= cv->height/30;
6142 break;
6143 case et_sb_halfdown:
6144 newpos += cv->height/30;
6145 break;
6146 }
6147 if ( newpos<-(20000*tab->scale-cv->height) )
6148 newpos = -(20000*tab->scale-cv->height);
6149 if ( newpos>8000*tab->scale ) newpos = 8000*tab->scale;
6150 if ( newpos!=tab->yoff ) {
6151 int diff = newpos-tab->yoff;
6152 tab->yoff = newpos;
6153 cv->back_img_out_of_date = true;
6154 GScrollBarSetPos(cv->vsb,newpos-cv->height);
6155 GDrawScroll(cv->v,NULL,0,diff);
6156 if (( cv->showvhints && cv->b.sc->vstem!=NULL) || cv->showhmetrics ) {
6157 GRect r;
6158 RefChar *lock = HasUseMyMetrics(cv->b.sc,CVLayer((CharViewBase *) cv));
6159 r.x = 0; r.width = cv->width;
6160 r.height = 2*cv->sfh+6;
6161 if ( lock!=NULL )
6162 r.height = cv->sfh+3+GImageGetHeight(&GIcon_lock);
6163 if ( diff>0 )
6164 r.y = 0;
6165 else
6166 r.y = -diff;
6167 GDrawRequestExpose(cv->v,&r,false);
6168 }
6169 if ( cv->showrulers ) {
6170 GRect r;
6171 r.x = 0; r.width = cv->rulerh; r.y = cv->infoh+cv->charselectorh+cv->mbh; r.height = cv->rulerh+cv->height;
6172 GDrawRequestExpose(cv->gw,&r,false);
6173 }
6174 }
6175 }
6176
LogoExpose(GWindow pixmap,GEvent * event,GRect * r,enum drawmode dm)6177 void LogoExpose(GWindow pixmap,GEvent *event, GRect *r,enum drawmode dm) {
6178 int sbsize = GDrawPointsToPixels(pixmap,_GScrollBar_Width);
6179 GRect old;
6180
6181 r->width = r->height = sbsize;
6182 if ( event->u.expose.rect.x+event->u.expose.rect.width >= r->x &&
6183 event->u.expose.rect.y+event->u.expose.rect.height >= r->y ) {
6184 /* Put something into the little box where the two scroll bars meet */
6185 int xoff, yoff;
6186 GImage *which = (dm==dm_fore) ? &GIcon_FontForgeLogo :
6187 (dm==dm_back) ? &GIcon_FontForgeBack :
6188 &GIcon_FontForgeGuide;
6189 struct _GImage *base = which->u.image;
6190 xoff = (sbsize-base->width);
6191 yoff = (sbsize-base->height);
6192 GDrawPushClip(pixmap,r,&old);
6193 GDrawDrawImage(pixmap,which,NULL,
6194 r->x+(xoff-xoff/2),r->y+(yoff-yoff/2));
6195 GDrawPopClip(pixmap,&old);
6196 /*GDrawDrawLine(pixmap,r->x+sbsize-1,r->y,r->x+sbsize-1,r->y+sbsize,0x000000);*/
6197 }
6198 }
6199
CVLogoExpose(CharView * cv,GWindow pixmap,GEvent * event)6200 static void CVLogoExpose(CharView *cv,GWindow pixmap,GEvent *event) {
6201 int rh = cv->showrulers ? cv->rulerh : 0;
6202 GRect r;
6203
6204 r.x = cv->width+rh;
6205 r.y = cv->height+cv->mbh+cv->charselectorh+cv->infoh+rh;
6206 LogoExpose(pixmap,event,&r,cv->b.drawmode==dm_grid? dm_grid :
6207 cv->b.layerheads[cv->b.drawmode]->background ? dm_back : dm_fore );
6208 }
6209
CVDrawGuideLine(CharView * cv,int old_guide_pos,int guide_pos)6210 static void CVDrawGuideLine(CharView *cv, int old_guide_pos, int guide_pos) {
6211 GWindow pixmap = cv->v;
6212
6213 if ( guide_pos<0 )
6214 return;
6215 GDrawSetDashedLine(pixmap,2,2,0);
6216 GDrawSetLineWidth(pixmap,0);
6217
6218 if ( cv->ruler_pressedv ) {
6219 if (old_guide_pos >= 0) {
6220 GRect r = {.x = old_guide_pos, .y = 0, .width = 1, .height = cv->height};
6221 GDrawRequestExpose(pixmap,&r,false);
6222 }
6223 GDrawDrawLine(pixmap,guide_pos,0,guide_pos,cv->height,0x000000);
6224 } else {
6225 if (old_guide_pos >= 0) {
6226 GRect r = {.x = 0, .y = old_guide_pos, .width = cv->width, .height = 1};
6227 GDrawRequestExpose(pixmap,&r,false);
6228 }
6229 GDrawDrawLine(pixmap,0,guide_pos,cv->width,guide_pos,0x000000);
6230 }
6231 GDrawSetDashedLine(pixmap,0,0,0);
6232 }
6233
CVAddGuide(CharView * cv,int is_v,int guide_pos)6234 static void CVAddGuide(CharView *cv,int is_v,int guide_pos) {
6235 CharViewTab* tab = CVGetActiveTab(cv);
6236 SplinePoint *sp1, *sp2;
6237 SplineSet *ss;
6238 SplineFont *sf = cv->b.sc->parent;
6239 int emsize = sf->ascent+sf->descent;
6240
6241 if ( is_v ) {
6242 /* Create a vertical guide line */
6243 double x = (guide_pos-tab->xoff)/tab->scale;
6244 sp1 = SplinePointCreate(x,sf->ascent+emsize/2);
6245 sp2 = SplinePointCreate(x,-sf->descent-emsize/2);
6246 } else {
6247 double y = (cv->height-guide_pos-tab->yoff)/tab->scale;
6248 sp1 = SplinePointCreate(-emsize,y);
6249 sp2 = SplinePointCreate(2*emsize,y);
6250 }
6251 SplineMake(sp1,sp2,sf->grid.order2);
6252 ss = chunkalloc(sizeof(SplineSet));
6253 ss->first = sp1; ss->last = sp2;
6254 ss->next = sf->grid.splines;
6255 sf->grid.splines = ss;
6256 ss->contour_name = gwwv_ask_string(_("Name this contour"),NULL,
6257 _("Name this guideline or cancel to create it without a name"));
6258 if ( ss->contour_name!=NULL && *ss->contour_name=='\0' ) {
6259 free(ss->contour_name);
6260 ss->contour_name = NULL;
6261 }
6262
6263 FVRedrawAllCharViewsSF(sf);
6264 if ( !sf->changed ) {
6265 sf->changed = true;
6266 FVSetTitles(sf);
6267 }
6268 }
6269
cv_e_h(GWindow gw,GEvent * event)6270 static int cv_e_h(GWindow gw, GEvent *event) {
6271 CharView *cv = (CharView *) GDrawGetUserData(gw);
6272
6273 if (( event->type==et_mouseup || event->type==et_mousedown ) &&
6274 (event->u.mouse.button>=4 && event->u.mouse.button<=7) ) {
6275 int ish = event->u.mouse.button>5;
6276 if ( event->u.mouse.state&ksm_shift ) ish = !ish;
6277 if ( ish ) /* bind shift to vertical scrolling */
6278 return( GGadgetDispatchEvent(cv->hsb,event));
6279 else
6280 return( GGadgetDispatchEvent(cv->vsb,event));
6281 }
6282
6283 switch ( event->type ) {
6284 case et_selclear:
6285 ClipboardClear();
6286 break;
6287 case et_expose:
6288 GDrawSetLineWidth(gw,0);
6289 InfoExpose(cv,gw,event);
6290 CVLogoExpose(cv,gw,event);
6291 break;
6292 case et_char:
6293 if ( cv->b.container!=NULL )
6294 (cv->b.container->funcs->charEvent)(cv->b.container,event);
6295 else
6296 CVChar(cv,event);
6297 break;
6298 case et_charup:
6299 CVCharUp(cv,event);
6300 break;
6301 case et_resize:
6302 if ( event->u.resize.sized )
6303 CVResize(cv);
6304 break;
6305 case et_controlevent:
6306 switch ( event->u.control.subtype ) {
6307 case et_scrollbarchange:
6308 if ( event->u.control.g == cv->hsb )
6309 CVHScroll(cv,&event->u.control.u.sb);
6310 else
6311 CVVScroll(cv,&event->u.control.u.sb);
6312 break;
6313 }
6314 break;
6315 case et_map:
6316 if ( event->u.map.is_visible )
6317 CVPaletteActivate(cv);
6318 else
6319 CVPalettesHideIfMine(cv);
6320 break;
6321 case et_destroy:
6322 CVUnlinkView(cv);
6323 CVPalettesHideIfMine(cv);
6324 if ( cv->backimgs!=NULL ) {
6325 GDrawDestroyWindow(cv->backimgs);
6326 cv->backimgs = NULL;
6327 }
6328 if ( cv->icon!=NULL ) {
6329 GDrawDestroyWindow(cv->icon);
6330 cv->icon = NULL;
6331 }
6332 if (cv->hruler != NULL) {
6333 GDrawDestroyWindow(cv->hruler);
6334 cv->hruler = NULL;
6335 }
6336 if (cv->vruler != NULL) {
6337 GDrawDestroyWindow(cv->vruler);
6338 cv->vruler = NULL;
6339 }
6340 CharViewFree(cv);
6341 break;
6342 case et_close:
6343 dlist_foreach( &cv->pointInfoDialogs, PI_Destroy );
6344 GDrawDestroyWindow(gw);
6345 break;
6346 case et_mouseup: case et_mousedown:
6347 GGadgetEndPopup();
6348 CVPaletteActivate(cv);
6349 if ( cv->inactive )
6350 (cv->b.container->funcs->activateMe)(cv->b.container,&cv->b);
6351 if ( cv->showrulers ) {
6352 int is_h = event->u.mouse.y>cv->mbh+cv->charselectorh+cv->infoh && event->u.mouse.y<cv->mbh+cv->charselectorh+cv->infoh+cv->rulerh;
6353 int is_v = event->u.mouse.x<cv->rulerh;
6354 if ( cv->gwgic!=NULL && event->type==et_mousedown)
6355 GDrawSetGIC(gw,cv->gwgic,0,20);
6356 if ( event->type == et_mousedown ) {
6357 if ( is_h && is_v )
6358 /* Ambiguous, ignore */;
6359 else if ( is_h ) {
6360 cv->ruler_pressed = true;
6361 cv->ruler_pressedv = false;
6362 GDrawSetCursor(cv->v,ct_updown);
6363 GDrawSetCursor(cv->gw,ct_updown);
6364 } else if ( is_v ) {
6365 cv->ruler_pressed = true;
6366 cv->ruler_pressedv = true;
6367 GDrawSetCursor(cv->v,ct_leftright);
6368 GDrawSetCursor(cv->gw,ct_leftright);
6369 }
6370 cv->guide_pos = -1;
6371 } else if ( event->type==et_mouseup && cv->ruler_pressed ) {
6372 CVDrawGuideLine(cv,-1,cv->guide_pos);
6373 cv->guide_pos = -1;
6374 cv->showing_tool = cvt_none;
6375 CVToolsSetCursor(cv,event->u.mouse.state&~(1<<(7+event->u.mouse.button)),event->u.mouse.device); /* X still has the buttons set in the state, even though we just released them. I don't want em */
6376 GDrawSetCursor(cv->gw,ct_mypointer);
6377 cv->ruler_pressed = false;
6378 if ( is_h || is_v )
6379 /* Do Nothing */;
6380 else if ( cv->ruler_pressedv )
6381 CVAddGuide(cv,true,event->u.mouse.x-cv->rulerh);
6382 else
6383 CVAddGuide(cv,false,event->u.mouse.y-(cv->mbh+cv->charselectorh+cv->infoh+cv->rulerh));
6384 }
6385 }
6386 break;
6387 case et_mousemove:
6388 if ( cv->ruler_pressed ) {
6389 int old_pos = cv->guide_pos;
6390 CharViewTab* tab = CVGetActiveTab(cv);
6391 cv->e.x = event->u.mouse.x - cv->rulerh;
6392 cv->e.y = event->u.mouse.y-(cv->mbh+cv->charselectorh+cv->infoh+cv->rulerh);
6393 cv->info.x = (cv->e.x-tab->xoff)/tab->scale;
6394 cv->info.y = (cv->height-cv->e.y-tab->yoff)/tab->scale;
6395 if ( cv->ruler_pressedv )
6396 cv->guide_pos = cv->e.x;
6397 else
6398 cv->guide_pos = cv->e.y;
6399 CVDrawGuideLine(cv,old_pos,cv->guide_pos);
6400 CVInfoDraw(cv,cv->gw);
6401 }
6402 else if ( event->u.mouse.y > cv->mbh )
6403 {
6404 if( GGadgetContainsEventLocation( cv->charselectorPrev, event ))
6405 {
6406 GGadgetPreparePopup(cv->gw,c_to_u("Show the previous word in the current word list\n"
6407 "Select the menu File / Load Word List... to load a wordlist."));
6408 }
6409 else if( GGadgetContainsEventLocation( cv->charselectorNext, event ))
6410 {
6411 GGadgetPreparePopup(cv->gw,c_to_u("Show the next word in the current word list\n"
6412 "Select the menu File / Load Word List... to load a wordlist."));
6413 }
6414 else if( GGadgetContainsEventLocation( cv->charselector, event ))
6415 {
6416 GGadgetPreparePopup(cv->gw,c_to_u("This is a word list that you can step through to quickly see your glyphs in context\n"
6417 "Select the menu File / Load Word List... to load a wordlist."));
6418 }
6419 else
6420 {
6421 int enc = CVCurEnc(cv);
6422 SCPreparePopup(cv->gw,cv->b.sc,cv->b.fv->map->remap,enc,
6423 UniFromEnc(enc,cv->b.fv->map->enc));
6424 }
6425 }
6426 break;
6427 case et_drop:
6428 CVDrop(cv,event);
6429 break;
6430 case et_focus:
6431 if ( event->u.focus.gained_focus ) {
6432 if ( cv->gic!=NULL )
6433 GDrawSetGIC(gw,cv->gic,0,20);
6434
6435 // X11 on Windows is broken, non-active windows
6436 // receive this event on mouseover
6437 #if !defined(_WIN32) || defined(FONTFORGE_CAN_USE_GDK)
6438 CVPaletteActivate(cv);
6439 #endif
6440 }
6441 break;
6442 }
6443 return( true );
6444 }
6445
6446 #define MID_Fit 2001
6447 #define MID_ZoomIn 2002
6448 #define MID_ZoomOut 2003
6449 #define MID_HidePoints 2004
6450 #define MID_HideControlPoints 2005
6451 #define MID_Fill 2006
6452 #define MID_Next 2007
6453 #define MID_Prev 2008
6454 #define MID_HideRulers 2009
6455 #define MID_Preview 2010
6456 #define MID_DraggingComparisonOutline 2011
6457 #define MID_NextDef 2012
6458 #define MID_PrevDef 2013
6459 #define MID_DisplayCompositions 2014
6460 #define MID_MarkExtrema 2015
6461 #define MID_Goto 2016
6462 #define MID_FindInFontView 2017
6463 #define MID_KernPairs 2018
6464 #define MID_AnchorPairs 2019
6465 #define MID_ShowGridFit 2020
6466 #define MID_PtsNone 2021
6467 #define MID_PtsTrue 2022
6468 #define MID_PtsPost 2023
6469 #define MID_PtsSVG 2024
6470 #define MID_Ligatures 2025
6471 #define MID_Former 2026
6472 #define MID_MarkPointsOfInflection 2027
6473 #define MID_ShowCPInfo 2028
6474 #define MID_ShowTabs 2029
6475 #define MID_AnchorGlyph 2030
6476 #define MID_AnchorControl 2031
6477 #define MID_ShowSideBearings 2032
6478 #define MID_Bigger 2033
6479 #define MID_Smaller 2034
6480 #define MID_GridFitAA 2035
6481 #define MID_GridFitOff 2036
6482 #define MID_ShowHHints 2037
6483 #define MID_ShowVHints 2038
6484 #define MID_ShowDHints 2039
6485 #define MID_ShowBlueValues 2040
6486 #define MID_ShowFamilyBlues 2041
6487 #define MID_ShowAnchors 2042
6488 #define MID_ShowHMetrics 2043
6489 #define MID_ShowVMetrics 2044
6490 #define MID_ShowRefNames 2045
6491 #define MID_ShowAlmostHV 2046
6492 #define MID_ShowAlmostHVCurves 2047
6493 #define MID_DefineAlmost 2048
6494 #define MID_SnapOutlines 2049
6495 #define MID_ShowDebugChanges 2050
6496 #define MID_Cut 2101
6497 #define MID_Copy 2102
6498 #define MID_Paste 2103
6499 #define MID_Clear 2104
6500 #define MID_Merge 2105
6501 #define MID_SelAll 2106
6502 #define MID_CopyRef 2107
6503 #define MID_UnlinkRef 2108
6504 #define MID_Undo 2109
6505 #define MID_Redo 2110
6506 #define MID_CopyWidth 2111
6507 #define MID_RemoveUndoes 2112
6508 #define MID_CopyFgToBg 2115
6509 #define MID_NextPt 2116
6510 #define MID_PrevPt 2117
6511 #define MID_FirstPt 2118
6512 #define MID_NextCP 2119
6513 #define MID_PrevCP 2120
6514 #define MID_SelNone 2121
6515 #define MID_SelectWidth 2122
6516 #define MID_SelectVWidth 2123
6517 #define MID_CopyLBearing 2124
6518 #define MID_CopyRBearing 2125
6519 #define MID_CopyVWidth 2126
6520 #define MID_Join 2127
6521 #define MID_CopyGridFit 2128
6522 /*#define MID_Elide 2129*/
6523 #define MID_SelectAllPoints 2130
6524 #define MID_SelectAnchors 2131
6525 #define MID_FirstPtNextCont 2132
6526 #define MID_Contours 2133
6527 #define MID_SelectHM 2134
6528 #define MID_SelInvert 2136
6529 #define MID_CopyBgToFg 2137
6530 #define MID_SelPointAt 2138
6531 #define MID_CopyLookupData 2139
6532 #define MID_SelectOpenContours 2140
6533 #define MID_MergeToLine 2141
6534 #define MID_Clockwise 2201
6535 #define MID_Counter 2202
6536 #define MID_GetInfo 2203
6537 #define MID_Correct 2204
6538 #define MID_AvailBitmaps 2210
6539 #define MID_RegenBitmaps 2211
6540 #define MID_Stroke 2205
6541 #define MID_RmOverlap 2206
6542 #define MID_Simplify 2207
6543 #define MID_BuildAccent 2208
6544 #define MID_Autotrace 2212
6545 #define MID_Round 2213
6546 #define MID_Embolden 2217
6547 #define MID_Condense 2218
6548 #define MID_Average 2219
6549 #define MID_SpacePts 2220
6550 #define MID_SpaceRegion 2221
6551 #define MID_MakeParallel 2222
6552 #define MID_ShowDependentRefs 2223
6553 #define MID_AddExtrema 2224
6554 #define MID_CleanupGlyph 2225
6555 #define MID_TilePath 2226
6556 #define MID_BuildComposite 2227
6557 #define MID_Exclude 2228
6558 #define MID_Intersection 2229
6559 #define MID_FindInter 2230
6560 #define MID_Styles 2231
6561 #define MID_SimplifyMore 2232
6562 #define MID_First 2233
6563 #define MID_Earlier 2234
6564 #define MID_Later 2235
6565 #define MID_Last 2236
6566 #define MID_CharInfo 2240
6567 #define MID_ShowDependentSubs 2241
6568 #define MID_CanonicalStart 2242
6569 #define MID_CanonicalContours 2243
6570 #define MID_RemoveBitmaps 2244
6571 #define MID_RoundToCluster 2245
6572 #define MID_Align 2246
6573 #define MID_FontInfo 2247
6574 #define MID_FindProblems 2248
6575 #define MID_InsertText 2249
6576 #define MID_Italic 2250
6577 #define MID_ChangeXHeight 2251
6578 #define MID_ChangeGlyph 2252
6579 #define MID_CheckSelf 2253
6580 #define MID_GlyphSelfIntersects 2254
6581 #define MID_ReverseDir 2255
6582 #define MID_Corner 2301
6583 #define MID_Tangent 2302
6584 #define MID_Curve 2303
6585 #define MID_MakeFirst 2304
6586 #define MID_MakeLine 2305
6587 #define MID_CenterCP 2306
6588 #define MID_ImplicitPt 2307
6589 #define MID_NoImplicitPt 2308
6590 #define MID_InsertPtOnSplineAt 2309
6591 #define MID_AddAnchor 2310
6592 #define MID_HVCurve 2311
6593 #define MID_SpiroG4 2312
6594 #define MID_SpiroG2 2313
6595 #define MID_SpiroCorner 2314
6596 #define MID_SpiroLeft 2315
6597 #define MID_SpiroRight 2316
6598 #define MID_SpiroMakeFirst 2317
6599 #define MID_NamePoint 2318
6600 #define MID_NameContour 2319
6601 #define MID_AcceptableExtrema 2320
6602 #define MID_MakeArc 2321
6603 #define MID_ClipPath 2322
6604
6605 #define MID_AutoHint 2400
6606 #define MID_ClearHStem 2401
6607 #define MID_ClearVStem 2402
6608 #define MID_ClearDStem 2403
6609 #define MID_AddHHint 2404
6610 #define MID_AddVHint 2405
6611 #define MID_AddDHint 2406
6612 #define MID_ReviewHints 2407
6613 #define MID_CreateHHint 2408
6614 #define MID_CreateVHint 2409
6615 #define MID_MinimumDistance 2410
6616 #define MID_AutoInstr 2411
6617 #define MID_ClearInstr 2412
6618 #define MID_EditInstructions 2413
6619 #define MID_Debug 2414
6620 #define MID_HintSubsPt 2415
6621 #define MID_AutoCounter 2416
6622 #define MID_DontAutoHint 2417
6623 #define MID_Deltas 2418
6624 #define MID_Tools 2501
6625 #define MID_Layers 2502
6626 #define MID_DockPalettes 2503
6627 #define MID_Center 2600
6628 #define MID_SetWidth 2601
6629 #define MID_SetLBearing 2602
6630 #define MID_SetRBearing 2603
6631 #define MID_Thirds 2604
6632 #define MID_RemoveKerns 2605
6633 #define MID_SetVWidth 2606
6634 #define MID_RemoveVKerns 2607
6635 #define MID_KPCloseup 2608
6636 #define MID_AnchorsAway 2609
6637 #define MID_SetBearings 2610
6638 #define MID_OpenBitmap 2700
6639 #define MID_Revert 2702
6640 #define MID_Recent 2703
6641 #define MID_RevertGlyph 2707
6642 #define MID_Open 2708
6643 #define MID_New 2709
6644 #define MID_Close 2710
6645 #define MID_Quit 2711
6646 #define MID_CloseTab 2712
6647 #define MID_GenerateTTC 2713
6648 #define MID_VKernClass 2715
6649 #define MID_VKernFromHKern 2716
6650
6651 #define MID_ShowGridFitLiveUpdate 2720
6652
6653 #define MID_MMReblend 2800
6654 #define MID_MMAll 2821
6655 #define MID_MMNone 2822
6656
6657 #define MID_PtsPos 2823
6658
6659 #define MID_Warnings 3000
6660
CVMenuClose(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))6661 static void CVMenuClose(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6662 CharView *cv = (CharView *) GDrawGetUserData(gw);
6663 if ( cv->b.container )
6664 (cv->b.container->funcs->doClose)(cv->b.container);
6665 else
6666 GDrawDestroyWindow(gw);
6667 }
6668
6669 // This can be triggered two ways: by the "X" buttons on tabs, and regularly in the menu.
CVMenuCloseTab(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))6670 static void CVMenuCloseTab(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6671 CharView *cv = (CharView *) GDrawGetUserData(gw);
6672 int pos, i;
6673
6674 if ( cv->b.container || cv->tabs==NULL || cv->former_cnt<=1 )
6675 return;
6676 pos = cv->ctpos == -1 ? GTabSetGetSel(cv->tabs) : cv->ctpos;
6677 free(cv->former_names[pos]);
6678 for ( i=pos+1; i<cv->former_cnt; ++i ) {
6679 cv->former_names[i-1] = cv->former_names[i];
6680 cv->cvtabs[i-1] = cv->cvtabs[i];
6681 }
6682 --cv->former_cnt;
6683 if (cv->ctpos==-1){
6684 GTabSetRemoveTabByPos(cv->tabs,pos); /* This should send an event that the selection has changed */
6685 }
6686 GTabSetRemetric(cv->tabs);
6687 if (GTabSetGetSel(cv->tabs) >= pos) {
6688 CVChangeSC_fetchTab(cv, pos);
6689 // Otherwise subsequent calls to CVChangeSC_storeTab which use this value will be off by one
6690 cv->oldtabnum = pos;
6691 }
6692 if (GTabSetGetTabCount(cv->tabs)<=1) CVChangeTabsVisibility(cv,false);
6693 // Reset this argument so in case it's called by the menu the right tab will be removed.
6694 cv->ctpos = -1;
6695 }
6696
CVMenuOpen(GWindow gw,struct gmenuitem * mi,GEvent * g)6697 static void CVMenuOpen(GWindow gw, struct gmenuitem *mi, GEvent *g) {
6698 CharView *d = (CharView*)GDrawGetUserData(gw);
6699 FontView *fv = NULL;
6700 if (d) {
6701 fv = (FontView*)d->b.fv;
6702 }
6703 _FVMenuOpen(fv);
6704 }
6705
CVMenuOpenBitmap(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))6706 static void CVMenuOpenBitmap(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6707 CharView *cv = (CharView *) GDrawGetUserData(gw);
6708 if ( cv->b.fv->sf->bitmaps==NULL )
6709 return;
6710 BitmapViewCreatePick(CVCurEnc(cv),(FontView *) (cv->b.fv));
6711 }
6712
CVMenuOpenMetrics(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))6713 static void CVMenuOpenMetrics(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6714 CharView *cv = (CharView *) GDrawGetUserData(gw);
6715 MetricsViewCreate((FontView *) (cv->b.fv),cv->b.sc,NULL);
6716 }
6717
CVMenuSave(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))6718 static void CVMenuSave(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6719 CharView *cv = (CharView *) GDrawGetUserData(gw);
6720 _FVMenuSave((FontView *) (cv->b.fv));
6721 }
6722
CVMenuSaveAs(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))6723 static void CVMenuSaveAs(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6724 CharView *cv = (CharView *) GDrawGetUserData(gw);
6725 _FVMenuSaveAs((FontView *) (cv->b.fv));
6726 }
6727
CVMenuGenerate(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))6728 static void CVMenuGenerate(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6729 CharView *cv = (CharView *) GDrawGetUserData(gw);
6730 FontViewBase *fv = cv->b.fv;
6731 SFGenerateFont(cv->b.sc->parent,CVLayer((CharViewBase *) cv),false,fv->normal==NULL?fv->map:fv->normal);
6732 }
6733
CVMenuGenerateFamily(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))6734 static void CVMenuGenerateFamily(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6735 CharView *cv = (CharView *) GDrawGetUserData(gw);
6736 _FVMenuGenerate((FontView *) (cv->b.fv),gf_macfamily);
6737 }
6738
CVMenuGenerateTTC(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))6739 static void CVMenuGenerateTTC(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6740 CharView *cv = (CharView *) GDrawGetUserData(gw);
6741 _FVMenuGenerate((FontView *) (cv->b.fv),gf_ttc);
6742 }
6743
CVMenuExport(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))6744 static void CVMenuExport(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6745 CharView *cv = (CharView *) GDrawGetUserData(gw);
6746 CVExport(cv);
6747 }
6748
CVInkscapeAdjust(CharView * cv)6749 static void CVInkscapeAdjust(CharView *cv) {
6750 CharViewTab* tab = CVGetActiveTab(cv);
6751 /* Inkscape considers different coordinates useful. That is to say, */
6752 /* Inkscape views the world as a blank sheet of paper and often */
6753 /* put things outside the [0,1000] range (especially in Y) that */
6754 /* FF uses. So after doing a Paste, or Import or something similar */
6755 /* check and see if the image is completely out of view, and if so */
6756 /* then adjust the view field */
6757 DBounds b;
6758 int layer = CVLayer((CharViewBase *) cv);
6759
6760 if (layer != ly_grid) SplineCharLayerQuickBounds(cv->b.sc,layer,&b);
6761 else {
6762 b.minx = b.miny = 1e10;
6763 b.maxx = b.maxy = -1e10;
6764 SplineSetQuickBounds(cv->b.sc->parent->grid.splines,&b);
6765 }
6766
6767 b.minx *= tab->scale; b.maxx *= tab->scale;
6768 b.miny *= tab->scale; b.maxy *= tab->scale;
6769
6770 if ( b.minx + tab->xoff < 0 || b.miny + tab->yoff < 0 ||
6771 b.maxx + tab->xoff > cv->width || b.maxy + tab->yoff > cv->height )
6772 CVFit(cv);
6773 }
6774
CVMenuImport(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))6775 static void CVMenuImport(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6776 CharView *cv = (CharView *) GDrawGetUserData(gw);
6777 CVImport(cv);
6778 CVInkscapeAdjust(cv);
6779 }
6780
CVMenuRevert(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))6781 static void CVMenuRevert(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6782 CharView *cv = (CharView *) GDrawGetUserData(gw);
6783 FVDelay((FontView *) (cv->b.fv),(void (*)(FontView *)) FVRevert);
6784 /* The revert command can potentially */
6785 /* destroy our window (if the char weren't in the */
6786 /* old font). If that happens before the menu finishes */
6787 /* we get a crash. So delay till after the menu completes */
6788 }
6789
CVMenuRevertGlyph(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))6790 static void CVMenuRevertGlyph(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6791 CharView *cv = (CharView *) GDrawGetUserData(gw);
6792 SplineChar *sc, temp;
6793 Undoes **undoes;
6794 int layer, lc;
6795 CharView *cvs;
6796 int mylayer = CVLayer((CharViewBase *) cv);
6797
6798 if ( cv->b.sc->parent->filename==NULL || cv->b.sc->namechanged || cv->b.sc->parent->mm!=NULL )
6799 return;
6800 if ( cv->b.sc->parent->sfd_version<2 )
6801 ff_post_error(_("Old sfd file"),_("This font comes from an old format sfd file. Not all aspects of it can be reverted successfully."));
6802
6803 sc = SFDReadOneChar(cv->b.sc->parent,cv->b.sc->name);
6804 if ( sc==NULL ) {
6805 ff_post_error(_("Can't Find Glyph"),_("The glyph, %.80s, can't be found in the sfd file"),cv->b.sc->name);
6806 cv->b.sc->namechanged = true;
6807 } else {
6808 SCPreserveState(cv->b.sc,true);
6809 SCPreserveBackground(cv->b.sc);
6810 temp = *cv->b.sc;
6811 cv->b.sc->dependents = NULL;
6812 lc = cv->b.sc->layer_cnt;
6813 undoes = malloc(lc*sizeof(Undoes *));
6814 for ( layer=0; layer<lc; ++layer ) {
6815 undoes[layer] = cv->b.sc->layers[layer].undoes;
6816 cv->b.sc->layers[layer].undoes = NULL;
6817 }
6818 SplineCharFreeContents(cv->b.sc);
6819 *cv->b.sc = *sc;
6820 chunkfree(sc,sizeof(SplineChar));
6821 cv->b.sc->parent = temp.parent;
6822 cv->b.sc->dependents = temp.dependents;
6823 for ( layer = 0; layer<lc && layer<cv->b.sc->layer_cnt; ++layer )
6824 cv->b.sc->layers[layer].undoes = undoes[layer];
6825 for ( ; layer<lc; ++layer )
6826 UndoesFree(undoes[layer]);
6827 free(undoes);
6828 cv->b.sc->views = temp.views;
6829 /* cv->b.sc->changed = temp.changed; */
6830 for ( cvs=(CharView *) (cv->b.sc->views); cvs!=NULL; cvs=(CharView *) (cvs->b.next) ) {
6831 cvs->b.layerheads[dm_back] = &cv->b.sc->layers[ly_back];
6832 cvs->b.layerheads[dm_fore] = &cv->b.sc->layers[ly_fore];
6833 if ( cv->b.sc->parent->multilayer ) {
6834 if ( mylayer!=ly_back )
6835 cvs->b.layerheads[dm_fore] = &cv->b.sc->layers[mylayer];
6836 } else {
6837 if ( mylayer!=ly_fore )
6838 cvs->b.layerheads[dm_back] = &cv->b.sc->layers[mylayer];
6839 }
6840 }
6841 RevertedGlyphReferenceFixup(cv->b.sc, temp.parent);
6842 _CV_CharChangedUpdate(cv,false);
6843 }
6844 }
6845
CVAddWordList(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))6846 static void CVAddWordList(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e))
6847 {
6848 CharView *cv = (CharView *) GDrawGetUserData(gw);
6849 WordlistLoadToGTextInfo( cv->charselector, &cv->charselectoridx );
6850 }
6851
CVMenuPrint(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))6852 static void CVMenuPrint(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6853 CharView *cv = (CharView *) GDrawGetUserData(gw);
6854
6855 PrintFFDlg(NULL,cv->b.sc,NULL);
6856 }
6857
6858 #if !defined(_NO_PYTHON)
CVMenuExecute(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))6859 static void CVMenuExecute(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6860 CharView *cv = (CharView *) GDrawGetUserData(gw);
6861 ScriptDlg((FontView *) (cv->b.fv),cv);
6862 }
6863 #endif /* !_NO_PYTHON */
6864
fllistcheck(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))6865 static void fllistcheck(GWindow gw, struct gmenuitem *mi,GEvent *UNUSED(e)) {
6866 CharView *cv = (CharView *) GDrawGetUserData(gw);
6867 FontView *fvs;
6868
6869 for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
6870 switch ( mi->mid ) {
6871 case MID_Open: case MID_New:
6872 mi->ti.disabled = cv->b.container!=NULL && !(cv->b.container->funcs->canOpen)(cv->b.container);
6873 break;
6874 case MID_GenerateTTC:
6875 for ( fvs=fv_list; fvs!=NULL; fvs=(FontView *) (fvs->b.next) ) {
6876 if ( fvs!=(FontView *) cv->b.fv )
6877 break;
6878 }
6879 mi->ti.disabled = fvs==NULL || cv->b.container!=NULL;
6880 break;
6881 case MID_Revert:
6882 mi->ti.disabled = cv->b.fv->sf->origname==NULL || cv->b.fv->sf->new || cv->b.container;
6883 break;
6884 case MID_RevertGlyph:
6885 mi->ti.disabled = cv->b.fv->sf->filename==NULL ||
6886 cv->b.fv->sf->sfd_version<2 ||
6887 cv->b.sc->namechanged ||
6888 cv->b.fv->sf->mm!=NULL ||
6889 cv->b.container;
6890 break;
6891 case MID_Recent:
6892 mi->ti.disabled = !RecentFilesAny() ||
6893 (cv->b.container!=NULL && !(cv->b.container->funcs->canOpen)(cv->b.container));
6894 break;
6895 case MID_Close: case MID_Quit:
6896 mi->ti.disabled = false;
6897 break;
6898 case MID_CloseTab:
6899 mi->ti.disabled = cv->tabs==NULL || cv->former_cnt<=1;
6900 break;
6901 default:
6902 mi->ti.disabled = cv->b.container!=NULL;
6903 break;
6904 }
6905 }
6906 }
6907
CVMenuFontInfo(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))6908 static void CVMenuFontInfo(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6909 CharView *cv = (CharView *) GDrawGetUserData(gw);
6910 FontInfo(cv->b.sc->parent,CVLayer((CharViewBase *) cv),-1,false);
6911 }
6912
CVMenuFindProblems(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))6913 static void CVMenuFindProblems(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6914 CharView *cv = (CharView *) GDrawGetUserData(gw);
6915 FindProblems(NULL,cv,NULL);
6916 }
6917
CVMenuEmbolden(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))6918 static void CVMenuEmbolden(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6919 CharView *cv = (CharView *) GDrawGetUserData(gw);
6920 EmboldenDlg(NULL,cv);
6921 }
6922
CVMenuItalic(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))6923 static void CVMenuItalic(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6924 CharView *cv = (CharView *) GDrawGetUserData(gw);
6925 ItalicDlg(NULL,cv);
6926 }
6927
CVMenuOblique(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))6928 static void CVMenuOblique(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6929 CharView *cv = (CharView *) GDrawGetUserData(gw);
6930 ObliqueDlg(NULL,cv);
6931 }
6932
CVMenuCondense(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))6933 static void CVMenuCondense(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6934 CharView *cv = (CharView *) GDrawGetUserData(gw);
6935 CondenseExtendDlg(NULL,cv);
6936 }
6937
CVMenuChangeXHeight(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))6938 static void CVMenuChangeXHeight(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6939 CharView *cv = (CharView *) GDrawGetUserData(gw);
6940 ChangeXHeightDlg(NULL,cv);
6941 }
6942
CVMenuChangeGlyph(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))6943 static void CVMenuChangeGlyph(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6944 CharView *cv = (CharView *) GDrawGetUserData(gw);
6945 GlyphChangeDlg(NULL,cv,gc_generic);
6946 }
6947
CVMenuInline(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))6948 static void CVMenuInline(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6949 CharView *cv = (CharView *) GDrawGetUserData(gw);
6950 OutlineDlg(NULL,cv,NULL,true);
6951 }
6952
CVMenuOutline(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))6953 static void CVMenuOutline(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6954 CharView *cv = (CharView *) GDrawGetUserData(gw);
6955 OutlineDlg(NULL,cv,NULL,false);
6956 }
6957
CVMenuShadow(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))6958 static void CVMenuShadow(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6959 CharView *cv = (CharView *) GDrawGetUserData(gw);
6960 ShadowDlg(NULL,cv,NULL,false);
6961 }
6962
CVMenuWireframe(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))6963 static void CVMenuWireframe(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6964 CharView *cv = (CharView *) GDrawGetUserData(gw);
6965 ShadowDlg(NULL,cv,NULL,true);
6966 }
6967
_CVMenuScale(CharView * cv,int mid)6968 static void _CVMenuScale(CharView *cv, int mid) {
6969 CharViewTab* tab = CVGetActiveTab(cv);
6970 if ( mid == MID_Fit ) {
6971 CVFit(cv);
6972 } else {
6973 BasePoint c;
6974 c.x = (cv->width/2-tab->xoff)/tab->scale;
6975 c.y = (cv->height/2-tab->yoff)/tab->scale;
6976 if ( CVAnySel(cv,NULL,NULL,NULL,NULL))
6977 CVFindCenter(cv,&c,false);
6978 CVMagnify(cv,c.x,c.y, mid==MID_ZoomOut?-1:1,0);
6979 }
6980 }
6981
CVMenuScale(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))6982 static void CVMenuScale(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
6983 CharView *cv = (CharView *) GDrawGetUserData(gw);
6984 _CVMenuScale(cv,mi->mid);
6985 }
6986
CVMenuShowHide(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))6987 static void CVMenuShowHide(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6988 CharView *cv = (CharView *) GDrawGetUserData(gw);
6989 CVShows.showpoints = cv->showpoints = !cv->showpoints;
6990 GDrawRequestExpose(cv->v,NULL,false);
6991 }
6992
CVMenuShowHideControlPoints(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))6993 static void CVMenuShowHideControlPoints(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6994 CharView *cv = (CharView *) GDrawGetUserData(gw);
6995 CVShows.alwaysshowcontrolpoints = cv->alwaysshowcontrolpoints = !cv->alwaysshowcontrolpoints;
6996 GDrawRequestExpose(cv->v,NULL,false);
6997 }
6998
CVMenuNumberPoints(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))6999 static void CVMenuNumberPoints(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
7000 CharView *cv = (CharView *) GDrawGetUserData(gw);
7001
7002 switch ( mi->mid ) {
7003 case MID_PtsNone:
7004 cv->showpointnumbers = 0;
7005 break;
7006 case MID_PtsTrue:
7007 cv->showpointnumbers = 1;
7008 CVCheckPoints(cv);
7009 break;
7010 case MID_PtsPost:
7011 cv->showpointnumbers = 1;
7012 cv->b.sc->numberpointsbackards = true;
7013 break;
7014 case MID_PtsSVG:
7015 cv->showpointnumbers = 1;
7016 cv->b.sc->numberpointsbackards = false;
7017 break;
7018 case MID_PtsPos:
7019 cv->showpointnumbers = 2;
7020 break;
7021 }
7022 SCNumberPoints(cv->b.sc,CVLayer((CharViewBase *) cv));
7023 SCUpdateAll(cv->b.sc);
7024 }
7025
CVMenuMarkExtrema(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))7026 static void CVMenuMarkExtrema(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
7027 CharView *cv = (CharView *) GDrawGetUserData(gw);
7028
7029 CVShows.markextrema = cv->markextrema = !cv->markextrema;
7030 SavePrefs(true);
7031 GDrawRequestExpose(cv->v,NULL,false);
7032 }
7033
CVMenuMarkPointsOfInflection(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))7034 static void CVMenuMarkPointsOfInflection(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
7035 CharView *cv = (CharView *) GDrawGetUserData(gw);
7036
7037 CVShows.markpoi = cv->markpoi = !cv->markpoi;
7038 SavePrefs(true);
7039 GDrawRequestExpose(cv->v,NULL,false);
7040 }
7041
CVMenuShowAlmostHV(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))7042 static void CVMenuShowAlmostHV(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
7043 CharView *cv = (CharView *) GDrawGetUserData(gw);
7044
7045 CVShows.showalmosthvlines = cv->showalmosthvlines = !cv->showalmosthvlines;
7046 SavePrefs(true);
7047 GDrawRequestExpose(cv->v,NULL,false);
7048 }
7049
CVMenuShowAlmostHVCurves(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))7050 static void CVMenuShowAlmostHVCurves(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
7051 CharView *cv = (CharView *) GDrawGetUserData(gw);
7052
7053 CVShows.showalmosthvcurves = cv->showalmosthvcurves = !cv->showalmosthvcurves;
7054 SavePrefs(true);
7055 GDrawRequestExpose(cv->v,NULL,false);
7056 }
7057
CVMenuDefineAlmost(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))7058 static void CVMenuDefineAlmost(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
7059 CharView *cv = (CharView *) GDrawGetUserData(gw);
7060 char buf[20], *end;
7061 int val;
7062 char *ret;
7063
7064 sprintf(buf,"%d",cv->hvoffset );
7065
7066 ret = gwwv_ask_string(_("Define \"Almost Horizontal\""),buf,
7067 _("A line is \"almost\" horizontal (or vertical)\nif the coordinates are within this many em-units"));
7068 if ( ret==NULL )
7069 return;
7070 val = strtol(ret,&end,10);
7071 if ( val>100 || val<=0 || *end!='\0' ) {
7072 free(ret);
7073 ff_post_error(_("Bad number"),_("Bad number"));
7074 } else {
7075 free(ret);
7076 CVShows.hvoffset = cv->hvoffset = val;
7077 SavePrefs(true);
7078 GDrawRequestExpose(cv->v,NULL,false);
7079 }
7080 }
7081
CVMenuShowCPInfo(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))7082 static void CVMenuShowCPInfo(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
7083 CharView *cv = (CharView *) GDrawGetUserData(gw);
7084
7085 CVShows.showcpinfo = cv->showcpinfo = !cv->showcpinfo;
7086 SavePrefs(true);
7087 /* Nothing to update, only show this stuff in the user is moving a cp */
7088 /* which s/he is currently not, s/he is manipulating the menu */
7089 }
7090
CVMenuShowTabs(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))7091 static void CVMenuShowTabs(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
7092 CharView *cv = (CharView *) GDrawGetUserData(gw);
7093
7094 CVShows.showtabs = cv->showtabs = !cv->showtabs;
7095 CVChangeTabsVisibility(cv,cv->showtabs);
7096 SavePrefs(true);
7097 }
7098
CVMenuShowSideBearings(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))7099 static void CVMenuShowSideBearings(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
7100 CharView *cv = (CharView *) GDrawGetUserData(gw);
7101
7102 CVShows.showsidebearings = cv->showsidebearings = !cv->showsidebearings;
7103 SavePrefs(true);
7104 GDrawRequestExpose(cv->v,NULL,false);
7105 }
7106
CVMenuShowRefNames(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))7107 static void CVMenuShowRefNames(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
7108 CharView *cv = (CharView *) GDrawGetUserData(gw);
7109
7110 CVShows.showrefnames = cv->showrefnames = !cv->showrefnames;
7111 SavePrefs(true);
7112 GDrawRequestExpose(cv->v,NULL,false);
7113 }
7114
CVMenuSnapOutlines(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))7115 static void CVMenuSnapOutlines(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
7116 CharView *cv = (CharView *) GDrawGetUserData(gw);
7117
7118 CVShows.snapoutlines = cv->snapoutlines = !cv->snapoutlines;
7119 SavePrefs(true);
7120 GDrawRequestExpose(cv->v,NULL,false);
7121 }
7122
CVMenuShowHints(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))7123 static void CVMenuShowHints(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
7124 CharView *cv = (CharView *) GDrawGetUserData(gw);
7125
7126 switch ( mi->mid ) {
7127 case MID_ShowHHints:
7128 CVShows.showhhints = cv->showhhints = !cv->showhhints;
7129 cv->back_img_out_of_date = true; /* only this cv */
7130 break;
7131 case MID_ShowVHints:
7132 CVShows.showvhints = cv->showvhints = !cv->showvhints;
7133 cv->back_img_out_of_date = true; /* only this cv */
7134 break;
7135 case MID_ShowDHints:
7136 CVShows.showdhints = cv->showdhints = !cv->showdhints;
7137 cv->back_img_out_of_date = true; /* only this cv */
7138 break;
7139 case MID_ShowBlueValues:
7140 CVShows.showblues = cv->showblues = !cv->showblues;
7141 cv->back_img_out_of_date = true; /* only this cv */
7142 break;
7143 case MID_ShowFamilyBlues:
7144 CVShows.showfamilyblues = cv->showfamilyblues = !cv->showfamilyblues;
7145 cv->back_img_out_of_date = true; /* only this cv */
7146 break;
7147 case MID_ShowAnchors:
7148 CVShows.showanchor = cv->showanchor = !cv->showanchor;
7149 break;
7150 case MID_ShowHMetrics:
7151 CVShows.showhmetrics = cv->showhmetrics = !cv->showhmetrics;
7152 break;
7153 case MID_ShowVMetrics:
7154 CVShows.showvmetrics = cv->showvmetrics = !cv->showvmetrics;
7155 break;
7156 case MID_ShowDebugChanges:
7157 CVShows.showdebugchanges = cv->showdebugchanges = !cv->showdebugchanges;
7158 break;
7159 default:
7160 IError("Unexpected call to CVMenuShowHints");
7161 break;
7162 }
7163 SavePrefs(true);
7164 GDrawRequestExpose(cv->v,NULL,false);
7165 /* !!!! In this interim version we should request an expose on cvlayers */
7166 /* but that's private to cvpalettes, and later we won't need to */
7167 }
7168
_CVMenuShowHideRulers(CharView * cv)7169 static void _CVMenuShowHideRulers(CharView *cv) {
7170 GRect pos;
7171
7172 CVShows.showrulers = cv->showrulers = !cv->showrulers;
7173 pos.y = cv->mbh+cv->charselectorh+cv->infoh;
7174 pos.x = 0;
7175 if ( cv->showrulers ) {
7176 cv->height -= cv->rulerh;
7177 cv->width -= cv->rulerh;
7178 pos.y += cv->rulerh;
7179 pos.x += cv->rulerh;
7180 } else {
7181 cv->height += cv->rulerh;
7182 cv->width += cv->rulerh;
7183 }
7184 cv->back_img_out_of_date = true;
7185 pos.width = cv->width; pos.height = cv->height;
7186 GDrawMoveResize(cv->v,pos.x,pos.y,pos.width,pos.height);
7187 GDrawSync(NULL);
7188 GDrawRequestExpose(cv->v,NULL,false);
7189 SavePrefs(true);
7190 }
7191
CVMenuShowHideRulers(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))7192 static void CVMenuShowHideRulers(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
7193 CharView *cv = (CharView *) GDrawGetUserData(gw);
7194 _CVMenuShowHideRulers(cv);
7195 }
7196
CVMenuFill(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))7197 static void CVMenuFill(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
7198 CharView *cv = (CharView *) GDrawGetUserData(gw);
7199
7200 CVShows.showfilled = cv->showfilled = !cv->showfilled;
7201 CVRegenFill(cv);
7202 GDrawRequestExpose(cv->v,NULL,false);
7203 }
7204
cvshowsCopyTo(struct cvshows * dst,CharView * src)7205 static struct cvshows* cvshowsCopyTo( struct cvshows* dst, CharView* src )
7206 {
7207 dst->showfore = src->showfore;
7208 dst->showgrids = src->showgrids;
7209 dst->showhhints = src->showhhints;
7210 dst->showvhints = src->showvhints;
7211 dst->showdhints = src->showdhints;
7212 dst->showpoints = src->showpoints;
7213 dst->alwaysshowcontrolpoints = src->alwaysshowcontrolpoints;
7214 dst->showfilled = src->showfilled;
7215 dst->showrulers = src->showrulers;
7216 dst->showrounds = src->showrounds;
7217 dst->showmdx = src->showmdx;
7218 dst->showmdy = src->showmdy;
7219 dst->showhmetrics = src->showhmetrics;
7220 dst->showvmetrics = src->showvmetrics;
7221 dst->markextrema = src->markextrema;
7222 dst->markpoi = src->markpoi;
7223 dst->showblues = src->showblues;
7224 dst->showfamilyblues = src->showfamilyblues;
7225 dst->showanchor = src->showanchor;
7226 dst->showcpinfo = src->showcpinfo;
7227 dst->showtabs = src->showtabs;
7228 dst->showsidebearings = src->showsidebearings;
7229 dst->showrefnames = src->showrefnames;
7230 dst->snapoutlines = src->snapoutlines;
7231 dst->showalmosthvlines = src->showalmosthvlines;
7232 dst->showalmosthvcurves = src->showalmosthvcurves;
7233 dst->hvoffset = src->hvoffset;
7234 dst->checkselfintersects = src->checkselfintersects;
7235 dst->showdebugchanges = src->showdebugchanges;
7236 return dst;
7237 }
7238
cvshowsCopyFrom(CharView * dst,struct cvshows * src)7239 static CharView* cvshowsCopyFrom( CharView* dst, struct cvshows* src )
7240 {
7241 dst->showfore = src->showfore;
7242 dst->showgrids = src->showgrids;
7243 dst->showhhints = src->showhhints;
7244 dst->showvhints = src->showvhints;
7245 dst->showdhints = src->showdhints;
7246 dst->showpoints = src->showpoints;
7247 dst->alwaysshowcontrolpoints = src->alwaysshowcontrolpoints;
7248 dst->showfilled = src->showfilled;
7249 dst->showrulers = src->showrulers;
7250 dst->showrounds = src->showrounds;
7251 dst->showmdx = src->showmdx;
7252 dst->showmdy = src->showmdy;
7253 dst->showhmetrics = src->showhmetrics;
7254 dst->showvmetrics = src->showvmetrics;
7255 dst->markextrema = src->markextrema;
7256 dst->markpoi = src->markpoi;
7257 dst->showblues = src->showblues;
7258 dst->showfamilyblues = src->showfamilyblues;
7259 dst->showanchor = src->showanchor;
7260 dst->showcpinfo = src->showcpinfo;
7261 dst->showtabs = src->showtabs;
7262 dst->showsidebearings = src->showsidebearings;
7263 dst->showrefnames = src->showrefnames;
7264 dst->snapoutlines = src->snapoutlines;
7265 dst->showalmosthvlines = src->showalmosthvlines;
7266 dst->showalmosthvcurves = src->showalmosthvcurves;
7267 dst->hvoffset = src->hvoffset;
7268 dst->checkselfintersects = src->checkselfintersects;
7269 dst->showdebugchanges = src->showdebugchanges;
7270 return dst;
7271 }
7272
CVPreviewModeSet(GWindow gw,int checked)7273 static void CVPreviewModeSet(GWindow gw, int checked ) {
7274 CharView *cv = (CharView *) GDrawGetUserData(gw);
7275 if( checked == cv->inPreviewMode )
7276 return;
7277
7278 cv->inPreviewMode = checked;
7279 if( checked ) {
7280 cvshowsCopyTo( &CVShowsPrevewToggleSavedState, cv );
7281 cv->showfore = 1;
7282 cv->showgrids = 0;
7283 cv->showhhints = 0;
7284 cv->showvhints = 0;
7285 cv->showdhints = 0;
7286 cv->showpoints = 0;
7287 cv->alwaysshowcontrolpoints = 0;
7288 cv->showfilled = 1;
7289 cv->showrounds = 0;
7290 cv->showanchor = 0;
7291 cv->showrefnames = 0;
7292 cv->showhmetrics = 0;
7293 cv->showvmetrics = 0;
7294 } else {
7295 cvshowsCopyFrom( cv, &CVShowsPrevewToggleSavedState );
7296 }
7297 CVRegenFill(cv);
7298 GDrawRequestExpose(cv->v,NULL,false);
7299 }
7300
CVMenuPreview(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))7301 static void CVMenuPreview(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
7302 int checked = mi->ti.checked;
7303
7304 #if 0
7305 // This has the effect of breaking the button since cv_auto_goto and HaveModifiers tend to be false.
7306 // The purpose of these checks is unclear.
7307 if( !cv_auto_goto ) {
7308 if( !HaveModifiers )
7309 return;
7310 }
7311 #endif // 0
7312
7313 CVPreviewModeSet(gw, checked);
7314 }
7315
CVMenuDraggingComparisonOutline(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))7316 static void CVMenuDraggingComparisonOutline(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e))
7317 {
7318 CharView *cv = (CharView *) GDrawGetUserData(gw);
7319
7320 int checked = mi->ti.checked;
7321 SplinePointListFree(cv->p.pretransform_spl);
7322 cv->p.pretransform_spl = NULL;
7323 prefs_create_dragging_comparison_outline = checked;
7324 SavePrefs(true);
7325 }
7326
7327
CVMenuShowGridFit(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))7328 static void CVMenuShowGridFit(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
7329 CharView *cv = (CharView *) GDrawGetUserData(gw);
7330
7331 if ( !hasFreeType() || cv->dv!=NULL )
7332 return;
7333 cv->show_ft_results_live_update = 0;
7334 CVFtPpemDlg(cv,false);
7335 }
7336
CVMenuShowGridFitLiveUpdate(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))7337 static void CVMenuShowGridFitLiveUpdate(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
7338 CharView *cv = (CharView *) GDrawGetUserData(gw);
7339
7340 if ( !hasFreeType() || cv->dv!=NULL )
7341 return;
7342 cv->show_ft_results_live_update = 1;
7343 CVFtPpemDlg(cv,false);
7344 }
7345
CVMenuChangePointSize(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))7346 static void CVMenuChangePointSize(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
7347 CharView *cv = (CharView *) GDrawGetUserData(gw);
7348
7349 if ( !hasFreeType() || cv->dv!=NULL || !cv->show_ft_results )
7350 return;
7351
7352 if ( mi->mid==MID_GridFitOff ) {
7353 cv->show_ft_results = false;
7354 cv->show_ft_results_live_update = false;
7355
7356 SplinePointListsFree(cv->b.gridfit); cv->b.gridfit = NULL;
7357 FreeType_FreeRaster(cv->raster); cv->raster = NULL;
7358 GDrawRequestExpose(cv->v,NULL,false);
7359 } else {
7360 if ( mi->mid==MID_Bigger ) {
7361 ++cv->ft_pointsizex;
7362 ++cv->ft_pointsizey;
7363 } else if ( mi->mid==MID_Smaller ) {
7364 if ( cv->ft_pointsizex>1 )
7365 --cv->ft_pointsizex;
7366 if ( cv->ft_pointsizey>1 )
7367 --cv->ft_pointsizey;
7368 }
7369
7370 if ( mi->mid==MID_GridFitAA )
7371 cv->ft_depth = cv->ft_depth==8 ? 1 : 8;
7372 cv->ft_ppemx = rint(cv->ft_pointsizex*cv->ft_dpi/72.0);
7373 cv->ft_ppemy = rint(cv->ft_pointsizey*cv->ft_dpi/72.0);
7374 CVGridFitChar(cv);
7375 }
7376 SCRefreshTitles(cv->b.sc);
7377 }
7378
CVMenuEditInstrs(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))7379 static void CVMenuEditInstrs(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
7380 CharView *cv = (CharView *) GDrawGetUserData(gw);
7381 SCEditInstructions(cv->b.sc);
7382 }
7383
CVMenuDebug(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))7384 static void CVMenuDebug(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
7385 CharView *cv = (CharView *) GDrawGetUserData(gw);
7386
7387 if ( !hasFreeTypeDebugger())
7388 return;
7389 CVFtPpemDlg(cv,true);
7390 }
7391
CVMenuDeltas(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))7392 static void CVMenuDeltas(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
7393 CharView *cv = (CharView *) GDrawGetUserData(gw);
7394
7395 if ( !hasFreeTypeDebugger())
7396 return;
7397 DeltaSuggestionDlg(NULL,cv);
7398 }
7399
CVMenuClearInstrs(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))7400 static void CVMenuClearInstrs(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
7401 CharView *cv = (CharView *) GDrawGetUserData(gw);
7402
7403 if ( cv->b.sc->ttf_instrs_len!=0 ) {
7404 free(cv->b.sc->ttf_instrs);
7405 cv->b.sc->ttf_instrs = NULL;
7406 cv->b.sc->ttf_instrs_len = 0;
7407 cv->b.sc->instructions_out_of_date = false;
7408 SCCharChangedUpdate(cv->b.sc,ly_none);
7409 SCMarkInstrDlgAsChanged(cv->b.sc);
7410 cv->b.sc->complained_about_ptnums = false; /* Should be after CharChanged */
7411 }
7412 }
7413
CVMenuKernPairs(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))7414 static void CVMenuKernPairs(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
7415 CharView *cv = (CharView *) GDrawGetUserData(gw);
7416 SFShowKernPairs(cv->b.sc->parent,cv->b.sc,NULL,CVLayer((CharViewBase *) cv));
7417 }
7418
CVMenuLigatures(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))7419 static void CVMenuLigatures(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
7420 CharView *cv = (CharView *) GDrawGetUserData(gw);
7421 SFShowLigatures(cv->b.fv->sf,cv->b.sc);
7422 }
7423
CVMenuAnchorPairs(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))7424 static void CVMenuAnchorPairs(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
7425 CharView *cv = (CharView *) GDrawGetUserData(gw);
7426 SFShowKernPairs(cv->b.sc->parent,cv->b.sc,(AnchorClass *) (-1),CVLayer((CharViewBase *) cv));
7427 }
7428
CVMenuAPDetach(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))7429 static void CVMenuAPDetach(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
7430 CharView *cv = (CharView *) GDrawGetUserData(gw);
7431 cv->apmine = cv->apmatch = NULL;
7432 cv->apsc = NULL;
7433 GDrawRequestExpose(cv->v,NULL,false);
7434 }
7435
CVMenuAPAttachSC(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))7436 static void CVMenuAPAttachSC(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
7437 CharView *cv = (CharView *) GDrawGetUserData(gw);
7438 enum anchor_type type;
7439 AnchorPoint *ap;
7440 AnchorClass *ac;
7441
7442 for ( ap = cv->b.sc->anchor; ap!=NULL && !ap->selected; ap=ap->next );
7443 if ( ap==NULL )
7444 ap = cv->b.sc->anchor;
7445 if ( ap==NULL )
7446 return;
7447 type = ap->type;
7448 cv->apmine = ap;
7449 ac = ap->anchor;
7450 cv->apsc = mi->ti.userdata;
7451 for ( ap = cv->apsc->anchor; ap!=NULL ; ap=ap->next ) {
7452 if ( ap->anchor==ac &&
7453 ((type==at_centry && ap->type==at_cexit) ||
7454 (type==at_cexit && ap->type==at_centry) ||
7455 (type==at_mark && ap->type!=at_mark) ||
7456 ((type==at_basechar || type==at_baselig || type==at_basemark) && ap->type==at_mark)) )
7457 break;
7458 }
7459 cv->apmatch = ap;
7460 GDrawRequestExpose(cv->v,NULL,false);
7461 }
7462
GlyphsMatchingAP(SplineFont * sf,AnchorPoint * ap)7463 static SplineChar **GlyphsMatchingAP(SplineFont *sf, AnchorPoint *ap) {
7464 SplineChar *sc;
7465 AnchorClass *ac = ap->anchor;
7466 enum anchor_type type = ap->type;
7467 int i, k, gcnt;
7468 SplineChar **glyphs;
7469
7470 glyphs = NULL;
7471 for ( k=0; k<2; ++k ) {
7472 gcnt = 0;
7473 for ( i=0; i<sf->glyphcnt; ++i ) if ( (sc=sf->glyphs[i])!=NULL ) {
7474 for ( ap = sc->anchor; ap!=NULL; ap=ap->next ) {
7475 if ( ap->anchor == ac &&
7476 ((type==at_centry && ap->type==at_cexit) ||
7477 (type==at_cexit && ap->type==at_centry) ||
7478 (type==at_mark && ap->type!=at_mark) ||
7479 ((type==at_basechar || type==at_baselig || type==at_basemark) && ap->type==at_mark)) )
7480 break;
7481 }
7482 if ( ap!=NULL ) {
7483 if ( k )
7484 glyphs[gcnt] = sc;
7485 ++gcnt;
7486 }
7487 }
7488 if ( !k ) {
7489 if ( gcnt==0 )
7490 return( NULL );
7491 glyphs = malloc((gcnt+1)*sizeof(SplineChar *));
7492 } else
7493 glyphs[gcnt] = NULL;
7494 }
7495 return( glyphs );
7496 }
7497
_CVMenuChangeChar(CharView * cv,int mid)7498 static void _CVMenuChangeChar(CharView *cv, int mid) {
7499 SplineFont *sf = cv->b.sc->parent;
7500 int pos = -1;
7501 int gid;
7502 EncMap *map = cv->b.fv->map;
7503 Encoding *enc = map->enc;
7504
7505 if ( cv->b.container!=NULL ) {
7506 if ( cv->b.container->funcs->doNavigate!=NULL && mid != MID_Former)
7507 (cv->b.container->funcs->doNavigate)(cv->b.container,
7508 mid==MID_Next ? nt_next :
7509 mid==MID_Prev ? nt_prev :
7510 mid==MID_NextDef ? nt_next :
7511 /* mid==MID_PrevDef ?*/ nt_prev);
7512 return;
7513 }
7514
7515 int curenc = CVCurEnc(cv);
7516
7517 if( cv->charselector )
7518 {
7519 char* txt = GGadgetGetTitle8( cv->charselector );
7520 if( txt && strlen(txt) > 1 )
7521 {
7522 int offset = 1;
7523 if ( mid == MID_Prev )
7524 offset = -1;
7525
7526 unichar_t *txtu = GGadgetGetTitle( cv->charselector );
7527 unichar_t* r = Wordlist_advanceSelectedCharsBy( cv->b.sc->parent,
7528 ((FontView *) (cv->b.fv))->b.map,
7529 txtu, offset );
7530 free( txtu );
7531
7532 GGadgetSetTitle( cv->charselector, r );
7533 // Force any extra chars to be setup and drawn
7534 GEvent e;
7535 e.type=et_controlevent;
7536 e.u.control.subtype = et_textchanged;
7537 e.u.control.u.tf_changed.from_pulldown = 0;
7538 CV_OnCharSelectorTextChanged( cv->charselector, &e );
7539 return;
7540 }
7541 }
7542
7543 if ( mid == MID_Next ) {
7544 pos = curenc+1;
7545 } else if ( mid == MID_Prev ) {
7546 pos = curenc-1;
7547 } else if ( mid == MID_NextDef ) {
7548 for ( pos = CVCurEnc(cv)+1; pos<map->enccount &&
7549 ((gid=map->map[pos])==-1 || !SCWorthOutputting(sf->glyphs[gid])); ++pos );
7550 if ( pos>=map->enccount ) {
7551 if ( enc->is_tradchinese ) {
7552 if ( strstrmatch(enc->enc_name,"hkscs")!=NULL ) {
7553 if ( CVCurEnc(cv)<0x8140 )
7554 pos = 0x8140;
7555 } else {
7556 if ( CVCurEnc(cv)<0xa140 )
7557 pos = 0xa140;
7558 }
7559 } else if ( CVCurEnc(cv)<0x8431 && strstrmatch(enc->enc_name,"johab")!=NULL )
7560 pos = 0x8431;
7561 else if ( CVCurEnc(cv)<0xa1a1 && strstrmatch(enc->iconv_name?enc->iconv_name:enc->enc_name,"EUC")!=NULL )
7562 pos = 0xa1a1;
7563 else if ( CVCurEnc(cv)<0x8140 && strstrmatch(enc->enc_name,"sjis")!=NULL )
7564 pos = 0x8140;
7565 else if ( CVCurEnc(cv)<0xe040 && strstrmatch(enc->enc_name,"sjis")!=NULL )
7566 pos = 0xe040;
7567 if ( pos>=map->enccount )
7568 return;
7569 }
7570 } else if ( mid == MID_PrevDef ) {
7571 for ( pos = CVCurEnc(cv)-1; pos>=0 &&
7572 ((gid=map->map[pos])==-1 || !SCWorthOutputting(sf->glyphs[gid])); --pos );
7573 if ( pos<0 )
7574 return;
7575 } else if ( mid == MID_Former ) {
7576 if ( cv->former_cnt<=1 )
7577 return;
7578 for ( gid=sf->glyphcnt-1; gid>=0; --gid )
7579 if ( sf->glyphs[gid]!=NULL &&
7580 strcmp(sf->glyphs[gid]->name,cv->former_names[1])==0 )
7581 break;
7582 if ( gid<0 )
7583 return;
7584 pos = map->backmap[gid];
7585 }
7586 /* Werner doesn't think it should wrap */
7587 if ( pos<0 ) /* pos = map->enccount-1; */
7588 return;
7589 else if ( pos>= map->enccount ) /* pos = 0; */
7590 return;
7591
7592 if ( pos>=0 && pos<map->enccount )
7593 CVChangeChar(cv,pos);
7594 }
7595
7596
CVMenuChangeChar(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))7597 static void CVMenuChangeChar(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
7598 CharView *cv = (CharView *) GDrawGetUserData(gw);
7599 _CVMenuChangeChar(cv,mi->mid);
7600 }
7601
CVMoveToNextInWordList(GGadget * g,GEvent * e)7602 static int CVMoveToNextInWordList(GGadget *g, GEvent *e)
7603 {
7604 if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
7605 CharView *cv = GDrawGetUserData(GGadgetGetWindow(g));
7606 CVMoveInWordListByOffset( cv, 1 );
7607 }
7608 return 1;
7609 }
CVMoveToPrevInWordList(GGadget * g,GEvent * e)7610 static int CVMoveToPrevInWordList(GGadget *g, GEvent *e)
7611 {
7612 if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
7613 CharView *cv = GDrawGetUserData(GGadgetGetWindow(g));
7614 CVMoveInWordListByOffset( cv, -1 );
7615 }
7616 return 1;
7617 }
7618
7619 /**
7620 * If the prev/next BCP is selected than add those to the hash table
7621 * at "ret".
7622 */
getSelectedControlPointsVisitor(SplinePoint * splfirst,Spline * s,SplinePoint * sp,void * udata)7623 static void getSelectedControlPointsVisitor(SplinePoint* splfirst, Spline* s, SplinePoint* sp, void* udata )
7624 {
7625 GHashTable* ret = (GHashTable*)udata;
7626 if( sp->nextcpselected )
7627 g_hash_table_insert( ret, sp, 0 );
7628 if( sp->prevcpselected )
7629 g_hash_table_insert( ret, sp, 0 );
7630 }
getAllControlPointsVisitor(SplinePoint * splfirst,Spline * s,SplinePoint * sp,void * udata)7631 static void getAllControlPointsVisitor(SplinePoint* splfirst, Spline* s, SplinePoint* sp, void* udata )
7632 {
7633 GHashTable* ret = (GHashTable*)udata;
7634 g_hash_table_insert( ret, sp, 0 );
7635 g_hash_table_insert( ret, sp, 0 );
7636 }
7637
7638 /**
7639 * Get a hash table with all the selected BCP in it.
7640 *
7641 * The caller must call g_hash_table_destroy() on the return value.
7642 */
getSelectedControlPoints(CharView * cv,PressedOn * p)7643 static GHashTable* getSelectedControlPoints( CharView *cv, PressedOn *p )
7644 {
7645 Layer* l = cv->b.layerheads[cv->b.drawmode];
7646 if( !l || !l->splines )
7647 return 0;
7648
7649 GHashTable* ret = g_hash_table_new( g_direct_hash, g_direct_equal );
7650 SplinePointList* spl = l->splines;
7651 for( ; spl; spl = spl->next )
7652 {
7653 SPLFirstVisitPoints( spl->first, getSelectedControlPointsVisitor, ret );
7654 }
7655
7656 return ret;
7657 }
getAllControlPoints(CharView * cv,PressedOn * p)7658 static GHashTable* getAllControlPoints( CharView *cv, PressedOn *p )
7659 {
7660 Layer* l = cv->b.layerheads[cv->b.drawmode];
7661 if( !l || !l->splines )
7662 return 0;
7663
7664 GHashTable* ret = g_hash_table_new( g_direct_hash, g_direct_equal );
7665 SplinePointList* spl = l->splines;
7666 for( ; spl; spl = spl->next )
7667 {
7668 SPLFirstVisitPoints( spl->first, getAllControlPointsVisitor, ret );
7669 }
7670 return ret;
7671 }
7672
FE_touchControlPoint(void * key,void * value,SplinePoint * sp,BasePoint * which,bool isnext,void * udata)7673 void FE_touchControlPoint( void* key,
7674 void* value,
7675 SplinePoint* sp,
7676 BasePoint *which,
7677 bool isnext,
7678 void* udata )
7679 {
7680 TRACE("FE_touchControlPoint() which:%p\n", which );
7681 SPTouchControl( sp, which, (int)(intptr_t)udata );
7682 }
7683
FE_unselectBCP(void * key,void * value,SplinePoint * sp,BasePoint * which,bool isnext,void * udata)7684 void FE_unselectBCP( void* key,
7685 void* value,
7686 SplinePoint* sp,
7687 BasePoint *which,
7688 bool isnext,
7689 void* udata )
7690 {
7691 sp->nextcpselected = 0;
7692 sp->prevcpselected = 0;
7693 }
7694
FE_adjustBCPByDelta(void * key,void * value,SplinePoint * sp,BasePoint * which,bool isnext,void * udata)7695 void FE_adjustBCPByDelta( void* key,
7696 void* value,
7697 SplinePoint* sp,
7698 BasePoint *which,
7699 bool isnext,
7700 void* udata )
7701 {
7702 FE_adjustBCPByDeltaData* data = (FE_adjustBCPByDeltaData*)udata;
7703 CharView *cv = data->cv;
7704
7705 TRACE("FE_adjustBCPByDelta %p %d\n", which, isnext );
7706 BasePoint to;
7707 to.x = which->x + data->dx;
7708 to.y = which->y + data->dy;
7709 SPAdjustControl(sp,which,&to,cv->b.layerheads[cv->b.drawmode]->order2);
7710 CVSetCharChanged(cv,true);
7711 }
7712
FE_adjustBCPByDeltaWhilePreservingBCPAngle(void * key,void * value,SplinePoint * sp,BasePoint * which,bool isnext,void * udata)7713 void FE_adjustBCPByDeltaWhilePreservingBCPAngle( void* key,
7714 void* value,
7715 SplinePoint* sp,
7716 BasePoint *which,
7717 bool isnext,
7718 void* udata )
7719 {
7720 FE_adjustBCPByDeltaData* data = (FE_adjustBCPByDeltaData*)udata;
7721 CharView *cv = data->cv;
7722
7723 // TRACE("FE_adjustBCPByDeltaWhilePreservingBCPAngle which:%p data:%p isnext:%d\n", which, data, isnext );
7724 // TRACE("FE_adjustBCPByDeltaWhilePreservingBCPAngle delta %f %f\n", data->dx, data->dy );
7725 BasePoint to;
7726 to.x = which->x + data->dx;
7727 to.y = which->y + data->dy;
7728
7729 // work out near and far BCP for this movement
7730 BasePoint* near = &sp->nextcp;
7731 BasePoint* far = &sp->prevcp;
7732 if( !isnext )
7733 {
7734 near = &sp->prevcp;
7735 far = &sp->nextcp;
7736 }
7737
7738 real dx = near->x - far->x;
7739 if( !fabs(dx) )
7740 {
7741 // flatline protection
7742 to.x = which->x + data->dx;
7743 to.y = which->y + data->dy;
7744 }
7745 else
7746 {
7747 // we have a workable gradient
7748 real m = (near->y - far->y) / dx;
7749
7750 // should we lean to x or y for the change?
7751 // all this is based on m = y2-y1/x2-x1
7752 // we use m from near and far and extrapolate to the new location
7753 // based on either x or y and calculate the other ordinate from the
7754 // gradiant function above.
7755 if( fabs(m) < 1.0 )
7756 {
7757 real datadx = data->dx;
7758 if( data->keyboarddx && !datadx )
7759 {
7760 datadx = data->dy;
7761 if( m < 0 )
7762 datadx *= -1;
7763 }
7764
7765 real dx = near->x - far->x;
7766 real m = (near->y - far->y) / dx;
7767 to.x = which->x + datadx;
7768 to.y = m * (to.x - near->x) + near->y;
7769 }
7770 else
7771 {
7772 real datady = data->dy;
7773 if( data->keyboarddx && !datady )
7774 {
7775 datady = data->dx;
7776 if( m < 0 )
7777 datady *= -1;
7778 }
7779 real dx = near->x - far->x;
7780 real m = (near->y - far->y) / dx;
7781 to.y = which->y + datady;
7782 to.x = (to.y - near->y + m*near->x) / m;
7783 }
7784 }
7785
7786 // move the point and update
7787 SPAdjustControl(sp,which,&to,cv->b.layerheads[cv->b.drawmode]->order2);
7788 CVSetCharChanged(cv,true);
7789 }
7790
7791 /**
7792 * Container for arguments to FE_visitSelectedControlPoints.
7793 */
7794 typedef struct visitSelectedControlPoints_CallbackDataS
7795 {
7796 int count; // number of times visitor is called.
7797 int sel;
7798 visitSelectedControlPointsVisitor func; // Visitor function to delegate to
7799 gpointer udata; // user data to use when calling above func()
7800
7801 } visitSelectedControlPoints_CallbackData;
7802
7803 /**
7804 * Visitor function: calls a delegate visitor function for any prev
7805 * and next BCP which are selected for each spline point. This is a
7806 * handy visitor when your BCP handling code for the most part doesn't
7807 * care if it will operate on the next or prev BCP, ie your visitor
7808 * simply wants to visit all the selected BCP.
7809 */
FE_visitSelectedControlPoints(gpointer key,gpointer value,gpointer udata)7810 static void FE_visitSelectedControlPoints( gpointer key,
7811 gpointer value,
7812 gpointer udata )
7813 {
7814 visitSelectedControlPoints_CallbackData* d = (visitSelectedControlPoints_CallbackData*)udata;
7815 SplinePoint* sp = (SplinePoint*)key;
7816
7817 d->count++;
7818 if( sp->nextcpselected )
7819 {
7820 BasePoint *which = &sp->nextcp;
7821 d->func( key, value, sp, which, true, d->udata );
7822 }
7823 if( sp->prevcpselected )
7824 {
7825 BasePoint *which = &sp->prevcp;
7826 d->func( key, value, sp, which, false, d->udata );
7827 }
7828 }
FE_visitAllControlPoints(gpointer key,gpointer value,gpointer udata)7829 static void FE_visitAllControlPoints( gpointer key,
7830 gpointer value,
7831 gpointer udata )
7832 {
7833 visitSelectedControlPoints_CallbackData* d = (visitSelectedControlPoints_CallbackData*)udata;
7834 SplinePoint* sp = (SplinePoint*)key;
7835
7836 d->count++;
7837 {
7838 BasePoint *which = &sp->nextcp;
7839 d->func( key, value, sp, which, true, d->udata );
7840 }
7841 {
7842 BasePoint *which = &sp->prevcp;
7843 d->func( key, value, sp, which, false, d->udata );
7844 }
7845 }
FE_visitAdjacentToSelectedControlPoints(gpointer key,gpointer value,gpointer udata)7846 static void FE_visitAdjacentToSelectedControlPoints( gpointer key,
7847 gpointer value,
7848 gpointer udata )
7849 {
7850 visitSelectedControlPoints_CallbackData* d = (visitSelectedControlPoints_CallbackData*)udata;
7851 SplinePoint* sp = (SplinePoint*)key;
7852
7853 if( sp->selected )
7854 return;
7855
7856 d->count++;
7857 if( sp->prev && sp->prev->from && sp->prev->from->selected )
7858 {
7859 d->func( key, value, sp, &sp->nextcp, true, d->udata );
7860 d->func( key, value, sp, &sp->prevcp, true, d->udata );
7861 }
7862 if( sp->next && sp->next->to && sp->next->to->selected )
7863 {
7864 d->func( key, value, sp, &sp->nextcp, true, d->udata );
7865 d->func( key, value, sp, &sp->prevcp, true, d->udata );
7866 }
7867 }
7868
visitSelectedControlPoints(GHashTable * col,visitSelectedControlPointsVisitor f,gpointer udata)7869 void visitSelectedControlPoints( GHashTable *col, visitSelectedControlPointsVisitor f, gpointer udata )
7870 {
7871 visitSelectedControlPoints_CallbackData d;
7872 d.func = f;
7873 d.udata = udata;
7874 d.count = 0;
7875 g_hash_table_foreach( col, FE_visitSelectedControlPoints, &d );
7876 }
7877
visitAllControlPoints(GHashTable * col,visitSelectedControlPointsVisitor f,gpointer udata)7878 void visitAllControlPoints( GHashTable *col, visitSelectedControlPointsVisitor f, gpointer udata )
7879 {
7880 visitSelectedControlPoints_CallbackData d;
7881 d.func = f;
7882 d.udata = udata;
7883 d.count = 0;
7884 g_hash_table_foreach( col, FE_visitAllControlPoints, &d );
7885 }
visitAdjacentToSelectedControlPoints(GHashTable * col,visitSelectedControlPointsVisitor f,gpointer udata)7886 static void visitAdjacentToSelectedControlPoints( GHashTable *col, visitSelectedControlPointsVisitor f, gpointer udata )
7887 {
7888 visitSelectedControlPoints_CallbackData d;
7889 d.func = f;
7890 d.udata = udata;
7891 d.count = 0;
7892 g_hash_table_foreach( col, FE_visitAdjacentToSelectedControlPoints, &d );
7893 }
7894
CVFindAndVisitSelectedControlPoints(CharView * cv,bool preserveState,visitSelectedControlPointsVisitor f,void * udata)7895 void CVFindAndVisitSelectedControlPoints( CharView *cv, bool preserveState,
7896 visitSelectedControlPointsVisitor f, void* udata )
7897 {
7898 // TRACE("CVFindAndVisitSelectedControlPoints(top) cv->p.sp:%p\n", cv->p.sp );
7899 GHashTable* col = getSelectedControlPoints( cv, &cv->p );
7900 if(!col)
7901 return;
7902
7903 if( g_hash_table_size( col ) )
7904 {
7905 if( preserveState )
7906 CVPreserveState(&cv->b);
7907 visitSelectedControlPoints( col, f, udata );
7908 }
7909 g_hash_table_destroy(col);
7910 }
7911
CVVisitAllControlPoints(CharView * cv,bool preserveState,visitSelectedControlPointsVisitor f,void * udata)7912 void CVVisitAllControlPoints( CharView *cv, bool preserveState,
7913 visitSelectedControlPointsVisitor f, void* udata )
7914 {
7915 TRACE("CVVisitAllControlPoints(top) cv->p.spl:%p cv->p.sp:%p\n", cv->p.spl, cv->p.sp );
7916 if( !cv->p.spl || !cv->p.sp )
7917 return;
7918
7919 GHashTable* col = getAllControlPoints( cv, &cv->p );
7920 if( g_hash_table_size( col ) )
7921 {
7922 if( preserveState )
7923 CVPreserveState(&cv->b);
7924 visitAllControlPoints( col, f, udata );
7925 }
7926 g_hash_table_destroy(col);
7927 }
7928
CVVisitAdjacentToSelectedControlPoints(CharView * cv,bool preserveState,visitSelectedControlPointsVisitor f,void * udata)7929 void CVVisitAdjacentToSelectedControlPoints( CharView *cv, bool preserveState,
7930 visitSelectedControlPointsVisitor f, void* udata )
7931 {
7932 // TRACE("CVVisitAdjacentToSelectedControlPoints(top) cv->p.sp:%p\n", cv->p.sp );
7933 if( !cv->p.spl || !cv->p.sp )
7934 return;
7935
7936 GHashTable* col = getAllControlPoints( cv, &cv->p );
7937 if( !col )
7938 return;
7939
7940 if( g_hash_table_size( col ) )
7941 {
7942 if( preserveState )
7943 CVPreserveState(&cv->b);
7944 visitAdjacentToSelectedControlPoints( col, f, udata );
7945 }
7946 g_hash_table_destroy(col);
7947 }
7948
7949
7950
CVChar(CharView * cv,GEvent * event)7951 void CVChar(CharView *cv, GEvent *event ) {
7952 extern float arrowAmount, arrowAccelFactor;
7953 extern int navigation_mask;
7954
7955 if( !cv_auto_goto )
7956 {
7957 if( event->u.chr.keysym == GK_Control_L
7958 || event->u.chr.keysym == GK_Control_R )
7959 {
7960 HaveModifiers = 1;
7961 }
7962 bool isImmediateKeyTogglePreview = isImmediateKey( cv->gw, "TogglePreview", event ) != NULL;
7963
7964 if( !HaveModifiers && isImmediateKeyTogglePreview ) {
7965 PressingTilde = 1;
7966 CVPreviewModeSet( cv->gw, true );
7967 return;
7968 }
7969 }
7970
7971 /* TRACE("GK_Control_L:%d\n", ( event->u.chr.keysym == GK_Control_L )); */
7972 /* TRACE("GK_Meta_L:%d\n", ( event->u.chr.keysym == GK_Meta_L )); */
7973
7974 int oldactiveModifierControl = cv->activeModifierControl;
7975 int oldactiveModifierAlt = cv->activeModifierAlt;
7976 cv->activeModifierControl |= ( event->u.chr.keysym == GK_Control_L || event->u.chr.keysym == GK_Control_R
7977 || event->u.chr.keysym == GK_Meta_L || event->u.chr.keysym == GK_Meta_R );
7978 cv->activeModifierAlt |= ( event->u.chr.keysym == GK_Alt_L || event->u.chr.keysym == GK_Alt_R
7979 || event->u.chr.keysym == GK_Mode_switch );
7980
7981 if( oldactiveModifierControl != cv->activeModifierControl
7982 || oldactiveModifierAlt != cv->activeModifierAlt )
7983 {
7984 CVInfoDraw(cv,cv->gw);
7985 }
7986
7987
7988 #if _ModKeysAutoRepeat
7989 /* Under cygwin these keys auto repeat, they don't under normal X */
7990 if ( cv->autorpt!=NULL ) {
7991 GDrawCancelTimer(cv->autorpt); cv->autorpt = NULL;
7992 if ( cv->keysym == event->u.chr.keysym ) /* It's an autorepeat, ignore it */
7993 return;
7994 CVToolsSetCursor(cv,cv->oldstate,NULL);
7995 }
7996 #endif
7997
7998 #if MyMemory
7999 if ( event->u.chr.keysym == GK_F2 ) {
8000 fprintf( stderr, "Malloc debug on\n" );
8001 __malloc_debug(5);
8002 } else if ( event->u.chr.keysym == GK_F3 ) {
8003 fprintf( stderr, "Malloc debug off\n" );
8004 __malloc_debug(0);
8005 }
8006 #endif
8007
8008 if ( !HaveModifiers && event->u.chr.keysym==' ' && cv->spacebar_hold==0 ) {
8009 cv->p.x = event->u.mouse.x;
8010 cv->p.y = event->u.mouse.y;
8011 update_spacebar_hand_tool(cv);
8012 }
8013
8014 CVPaletteActivate(cv);
8015 CVToolsSetCursor(cv,TrueCharState(event),NULL);
8016
8017
8018 /* The window check is to prevent infinite loops since DVChar can */
8019 /* call CVChar too */
8020 if ( cv->dv!=NULL && (event->w==cv->gw || event->w==cv->v) && DVChar(cv->dv,event))
8021 {
8022 /* All Done */;
8023 }
8024 else if ( event->u.chr.keysym=='s' &&
8025 (event->u.chr.state&ksm_control) &&
8026 (event->u.chr.state&ksm_meta) )
8027 MenuSaveAll(NULL,NULL,NULL);
8028 else if ( event->u.chr.keysym=='q' &&
8029 (event->u.chr.state&ksm_control) &&
8030 (event->u.chr.state&ksm_meta) )
8031 MenuExit(NULL,NULL,NULL);
8032 else if ( event->u.chr.keysym == GK_Shift_L || event->u.chr.keysym == GK_Shift_R ||
8033 event->u.chr.keysym == GK_Alt_L || event->u.chr.keysym == GK_Alt_R ||
8034 event->u.chr.keysym == GK_Meta_L || event->u.chr.keysym == GK_Meta_R ) {
8035 CVFakeMove(cv, event);
8036 } else if (( event->u.chr.keysym == GK_Tab || event->u.chr.keysym == GK_BackTab) &&
8037 (event->u.chr.state&ksm_control) && cv->showtabs && cv->former_cnt>1 ) {
8038 GGadgetDispatchEvent(cv->tabs,event);
8039 } else if ( (event->u.chr.state&ksm_meta) &&
8040 !(event->u.chr.state&(ksm_control|ksm_shift)) &&
8041 event->u.chr.chars[0]!='\0' ) {
8042 CVPaletteMnemonicCheck(event);
8043 } else if ( !(event->u.chr.state&(ksm_control|ksm_meta)) &&
8044 event->u.chr.keysym == GK_BackSpace ) {
8045 /* Menu does delete */
8046 CVClear(cv->gw,NULL,NULL);
8047 } else if ( event->u.chr.keysym == GK_Help ) {
8048 MenuHelp(NULL,NULL,NULL); /* Menu does F1 */
8049 } else if ( event->u.chr.keysym=='<' && (event->u.chr.state&ksm_control) ) {
8050 /* European keyboards do not need shift to get < */
8051 CVDoFindInFontView(cv);
8052 } else if ( (event->u.chr.keysym=='[' || event->u.chr.keysym==']') &&
8053 (event->u.chr.state&ksm_control) ) {
8054 /* European keyboards need a funky modifier to get [] */
8055 _CVMenuChangeChar(cv,event->u.chr.keysym=='[' ? MID_Prev : MID_Next );
8056 } else if ( (event->u.chr.keysym=='{' || event->u.chr.keysym=='}') &&
8057 (event->u.chr.state&ksm_control) ) {
8058 /* European keyboards need a funky modifier to get {} */
8059 _CVMenuChangeChar(cv,event->u.chr.keysym=='{' ? MID_PrevDef : MID_NextDef );
8060 } else if ( event->u.chr.keysym=='\\' && (event->u.chr.state&ksm_control) ) {
8061 /* European keyboards need a funky modifier to get \ */
8062 CVDoTransform(cv,cvt_none);
8063 } else if ( (event->u.chr.keysym=='F' || event->u.chr.keysym=='B') &&
8064 !(event->u.chr.state&(ksm_control|ksm_meta)) ) {
8065 CVLSelectLayer(cv, event->u.chr.keysym=='F' ? 1 : 0);
8066 } else if ( (event->u.chr.state&ksm_control) && (event->u.chr.keysym=='-' || event->u.chr.keysym==0xffad/*XK_KP_Subtract*/) ){
8067 _CVMenuScale(cv, MID_ZoomOut);
8068 } else if ( (event->u.chr.state&ksm_control) && (event->u.chr.keysym=='=' || event->u.chr.keysym==0xffab/*XK_KP_Add*/) ){
8069 _CVMenuScale(cv, MID_ZoomIn);
8070 }
8071 else if ( event->u.chr.keysym == GK_Left ||
8072 event->u.chr.keysym == GK_Up ||
8073 event->u.chr.keysym == GK_Right ||
8074 event->u.chr.keysym == GK_Down ||
8075 event->u.chr.keysym == GK_KP_Left ||
8076 event->u.chr.keysym == GK_KP_Up ||
8077 event->u.chr.keysym == GK_KP_Right ||
8078 event->u.chr.keysym == GK_KP_Down )
8079 {
8080 TRACE("key left/right/up/down...\n");
8081
8082 GGadget *active = GWindowGetFocusGadgetOfWindow(cv->gw);
8083 if( active == cv->charselector )
8084 {
8085 if ( event->u.chr.keysym == GK_Left ||event->u.chr.keysym == GK_Right )
8086 {
8087 TRACE("left/right on the charselector!\n");
8088 }
8089 int dir = ( event->u.chr.keysym == GK_Up || event->u.chr.keysym==GK_KP_Up ) ? -1 : 1;
8090 Wordlist_MoveByOffset( cv->charselector, &cv->charselectoridx, dir );
8091
8092 return;
8093 }
8094
8095
8096 real dx=0, dy=0; int anya;
8097 switch ( event->u.chr.keysym ) {
8098 case GK_Left: case GK_KP_Left:
8099 dx = -1;
8100 break;
8101 case GK_Right: case GK_KP_Right:
8102 dx = 1;
8103 break;
8104 case GK_Up: case GK_KP_Up:
8105 dy = 1;
8106 break;
8107 case GK_Down: case GK_KP_Down:
8108 dy = -1;
8109 break;
8110 }
8111 if ( event->u.chr.state & (ksm_control|ksm_capslock) ) {
8112 struct sbevent sb;
8113 sb.type = dy>0 || dx<0 ? et_sb_halfup : et_sb_halfdown;
8114 if ( dx==0 )
8115 CVVScroll(cv,&sb);
8116 else
8117 CVHScroll(cv,&sb);
8118 }
8119 else
8120 {
8121 // TRACE("cvchar( moving points? ) shift:%d\n", ( event->u.chr.state & (ksm_shift) ));
8122 FE_adjustBCPByDeltaData d;
8123 memset( &d, 0, sizeof(FE_adjustBCPByDeltaData));
8124 visitSelectedControlPointsVisitor func = FE_adjustBCPByDelta;
8125 if ( event->u.chr.state & ksm_meta )
8126 {
8127 // move the bcp 1 unit in the direction it already has
8128 func = FE_adjustBCPByDeltaWhilePreservingBCPAngle;
8129 // allow that func to work it's magic on any gradient
8130 d.keyboarddx = 1;
8131 }
8132 /* if ( event->u.chr.state & (ksm_shift) ) */
8133 /* dx -= dy*tan((cv->b.sc->parent->italicangle)*(FF_PI/180) ); */
8134 if ( event->u.chr.state & (ksm_shift) )
8135 {
8136 dx *= arrowAccelFactor; dy *= arrowAccelFactor;
8137 }
8138
8139 if (( cv->p.sp!=NULL || cv->lastselpt!=NULL ) &&
8140 (cv->p.nextcp || cv->p.prevcp) )
8141 {
8142 // This code moves 1 or more BCP
8143
8144 SplinePoint *old = cv->p.sp;
8145 d.cv = cv;
8146 d.dx = dx * arrowAmount;
8147 d.dy = dy * arrowAmount;
8148 CVFindAndVisitSelectedControlPoints( cv, true,
8149 func, &d );
8150 cv->p.sp = old;
8151 SCUpdateAll(cv->b.sc);
8152
8153 }
8154 else if ( CVAnySel(cv,NULL,NULL,NULL,&anya) || cv->widthsel || cv->vwidthsel )
8155 {
8156 CVPreserveState(&cv->b);
8157 CVMoveSelection(cv,dx*arrowAmount,dy*arrowAmount, event->u.chr.state);
8158 if ( cv->widthsel )
8159 SCSynchronizeWidth(cv->b.sc,cv->b.sc->width,cv->b.sc->width-dx,NULL);
8160 _CV_CharChangedUpdate(cv,2);
8161 CVInfoDraw(cv,cv->gw);
8162 }
8163 CVGridHandlePossibleFitChar( cv );
8164 }
8165 } else if ( event->u.chr.keysym == GK_Page_Up ||
8166 event->u.chr.keysym == GK_KP_Page_Up ||
8167 event->u.chr.keysym == GK_Prior ||
8168 event->u.chr.keysym == GK_Page_Down ||
8169 event->u.chr.keysym == GK_KP_Page_Down ||
8170 event->u.chr.keysym == GK_Next ) {
8171 /* Um... how do we scroll horizontally??? */
8172 struct sbevent sb;
8173 sb.type = et_sb_uppage;
8174 if ( event->u.chr.keysym == GK_Page_Down ||
8175 event->u.chr.keysym == GK_KP_Page_Down ||
8176 event->u.chr.keysym == GK_Next )
8177 sb.type = et_sb_downpage;
8178 CVVScroll(cv,&sb);
8179 } else if ( event->u.chr.keysym == GK_Home ) {
8180 CVFit(cv);
8181 } else if ( event->u.chr.keysym==' ' && cv->spacebar_hold ){
8182 } else if ( (event->u.chr.state&((GMenuMask()|navigation_mask)&~(ksm_shift|ksm_capslock)))==navigation_mask &&
8183 event->type == et_char &&
8184 event->u.chr.keysym!=0 &&
8185 (event->u.chr.keysym<GK_Special /*|| event->u.chr.keysym>=0x10000*/)) {
8186 SplineFont *sf = cv->b.sc->parent;
8187 int i;
8188 EncMap *map = cv->b.fv->map;
8189 extern int cv_auto_goto;
8190 if ( cv_auto_goto ) {
8191 i = SFFindSlot(sf,map,event->u.chr.keysym,NULL);
8192 if ( i!=-1 )
8193 CVChangeChar(cv,i);
8194 }
8195 }
8196 }
8197
CVShowPoint(CharView * cv,BasePoint * me)8198 void CVShowPoint(CharView *cv, BasePoint *me) {
8199 CharViewTab* tab = CVGetActiveTab(cv);
8200 int x, y;
8201 int fudge = 30;
8202
8203 if ( cv->width<60 )
8204 fudge = cv->width/3;
8205 if ( cv->height<60 && fudge>cv->height/3 )
8206 fudge = cv->height/3;
8207
8208 /* Make sure the point is visible and has some context around it */
8209 x = tab->xoff + rint(me->x*tab->scale);
8210 y = -tab->yoff + cv->height - rint(me->y*tab->scale);
8211 if ( x<fudge || y<fudge || x>cv->width-fudge || y>cv->height-fudge )
8212 CVMagnify(cv,me->x,me->y,0,0);
8213 }
8214
CVSelectContours(CharView * cv)8215 static void CVSelectContours(CharView *cv) {
8216 SplineSet *spl;
8217 SplinePoint *sp;
8218 int sel;
8219 int i;
8220
8221 for ( spl=cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL; spl=spl->next ) {
8222 sel = false;
8223 if ( cv->b.sc->inspiro && hasspiro()) {
8224 for ( i=0; i<spl->spiro_cnt-1; ++i ) {
8225 if ( SPIRO_SELECTED(&spl->spiros[i]) ) {
8226 sel = true;
8227 break;
8228 }
8229 }
8230 if ( sel ) {
8231 for ( i=0; i<spl->spiro_cnt-1; ++i )
8232 SPIRO_SELECT(&spl->spiros[i]);
8233 }
8234 } else {
8235 for ( sp=spl->first ; ; ) {
8236 if ( sp->selected ) {
8237 sel = true;
8238 break;
8239 }
8240 if ( sp->next==NULL )
8241 break;
8242 sp = sp->next->to;
8243 if ( sp==spl->first )
8244 break;
8245 }
8246 if ( sel ) {
8247 for ( sp=spl->first ; ; ) {
8248 sp->selected = true;
8249 if ( sp->next==NULL )
8250 break;
8251 sp = sp->next->to;
8252 if ( sp==spl->first )
8253 break;
8254 }
8255 }
8256 }
8257 }
8258 SCUpdateAll(cv->b.sc);
8259 }
8260
CVMenuSelectContours(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))8261 static void CVMenuSelectContours(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8262 CharView *cv = (CharView *) GDrawGetUserData(gw);
8263 CVSelectContours(cv);
8264 }
8265
CVMenuSelectPointAt(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))8266 static void CVMenuSelectPointAt(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8267 CharView *cv = (CharView *) GDrawGetUserData(gw);
8268 CVSelectPointAt(cv);
8269 }
8270
CVNextPrevSpiroPt(CharView * cv,struct gmenuitem * mi)8271 static void CVNextPrevSpiroPt(CharView *cv, struct gmenuitem *mi) {
8272 CharViewTab* tab = CVGetActiveTab(cv);
8273 RefChar *r; ImageList *il;
8274 SplineSet *spl, *ss;
8275 SplinePoint *junk;
8276 int x, y;
8277 spiro_cp *selcp = NULL, *other;
8278 int index;
8279
8280 if ( mi->mid == MID_FirstPt ) {
8281 if ( cv->b.layerheads[cv->b.drawmode]->splines==NULL )
8282 return;
8283 CVClearSel(cv);
8284 other = &cv->b.layerheads[cv->b.drawmode]->splines->spiros[0];
8285 } else {
8286 if ( !CVOneThingSel(cv,&junk,&spl,&r,&il,NULL,&selcp) || spl==NULL )
8287 return;
8288 other = selcp;
8289 if ( spl==NULL )
8290 return;
8291 index = selcp - spl->spiros;
8292 if ( mi->mid == MID_NextPt ) {
8293 if ( index!=spl->spiro_cnt-2 )
8294 other = &spl->spiros[index+1];
8295 else {
8296 if ( spl->next == NULL )
8297 spl = cv->b.layerheads[cv->b.drawmode]->splines;
8298 else
8299 spl = spl->next;
8300 other = &spl->spiros[0];
8301 }
8302 } else if ( mi->mid == MID_PrevPt ) {
8303 if ( index!=0 ) {
8304 other = &spl->spiros[index-1];
8305 } else {
8306 if ( spl==cv->b.layerheads[cv->b.drawmode]->splines ) {
8307 for ( ss = cv->b.layerheads[cv->b.drawmode]->splines; ss->next!=NULL; ss=ss->next );
8308 } else {
8309 for ( ss = cv->b.layerheads[cv->b.drawmode]->splines; ss->next!=spl; ss=ss->next );
8310 }
8311 spl = ss;
8312 other = &ss->spiros[ss->spiro_cnt-2];
8313 }
8314 } else if ( mi->mid == MID_FirstPtNextCont ) {
8315 if ( spl->next!=NULL )
8316 other = &spl->next->spiros[0];
8317 else
8318 other = NULL;
8319 }
8320 }
8321 if ( selcp!=NULL )
8322 SPIRO_DESELECT(selcp);
8323 if ( other!=NULL )
8324 SPIRO_SELECT(other);
8325 cv->p.sp = NULL;
8326 cv->lastselpt = NULL;
8327 cv->lastselcp = other;
8328
8329 /* Make sure the point is visible and has some context around it */
8330 if ( other!=NULL ) {
8331 x = tab->xoff + rint(other->x*tab->scale);
8332 y = -tab->yoff + cv->height - rint(other->y*tab->scale);
8333 if ( x<40 || y<40 || x>cv->width-40 || y>cv->height-40 )
8334 CVMagnify(cv,other->x,other->y,0,0);
8335 }
8336
8337 CVInfoDraw(cv,cv->gw);
8338 SCUpdateAll(cv->b.sc);
8339 }
8340
CVNextPrevPt(CharView * cv,struct gmenuitem * mi)8341 static void CVNextPrevPt(CharView *cv, struct gmenuitem *mi) {
8342 CharViewTab* tab = CVGetActiveTab(cv);
8343 SplinePoint *selpt=NULL, *other;
8344 RefChar *r; ImageList *il;
8345 SplineSet *spl, *ss;
8346 int x, y;
8347 spiro_cp *junk;
8348
8349 if ( cv->b.sc->inspiro && hasspiro()) {
8350 CVNextPrevSpiroPt(cv,mi);
8351 return;
8352 }
8353
8354 if ( mi->mid == MID_FirstPt ) {
8355 if ( cv->b.layerheads[cv->b.drawmode]->splines==NULL )
8356 return;
8357 other = (cv->b.layerheads[cv->b.drawmode]->splines)->first;
8358 CVClearSel(cv);
8359 } else {
8360 if ( !CVOneThingSel(cv,&selpt,&spl,&r,&il,NULL,&junk) || spl==NULL )
8361 return;
8362 other = selpt;
8363 if ( spl==NULL )
8364 return;
8365 else if ( mi->mid == MID_NextPt ) {
8366 if ( other->next!=NULL && other->next->to!=spl->first )
8367 other = other->next->to;
8368 else {
8369 if ( spl->next == NULL )
8370 spl = cv->b.layerheads[cv->b.drawmode]->splines;
8371 else
8372 spl = spl->next;
8373 other = spl->first;
8374 }
8375 } else if ( mi->mid == MID_PrevPt ) {
8376 if ( other!=spl->first ) {
8377 other = other->prev->from;
8378 } else {
8379 if ( spl==cv->b.layerheads[cv->b.drawmode]->splines ) {
8380 for ( ss = cv->b.layerheads[cv->b.drawmode]->splines; ss->next!=NULL; ss=ss->next );
8381 } else {
8382 for ( ss = cv->b.layerheads[cv->b.drawmode]->splines; ss->next!=spl; ss=ss->next );
8383 }
8384 spl = ss;
8385 other = ss->last;
8386 if ( spl->last==spl->first && spl->last->prev!=NULL )
8387 other = other->prev->from;
8388 }
8389 } else if ( mi->mid == MID_FirstPtNextCont ) {
8390 if ( spl->next!=NULL )
8391 other = spl->next->first;
8392 else
8393 other = NULL;
8394 }
8395 }
8396 if ( selpt!=NULL )
8397 selpt->selected = false;
8398 if ( other!=NULL )
8399 other->selected = true;
8400 cv->p.sp = NULL;
8401 cv->lastselpt = other;
8402 cv->p.spiro = cv->lastselcp = NULL;
8403
8404 /* Make sure the point is visible and has some context around it */
8405 if ( other!=NULL ) {
8406 x = tab->xoff + rint(other->me.x*tab->scale);
8407 y = -tab->yoff + cv->height - rint(other->me.y*tab->scale);
8408 if ( x<40 || y<40 || x>cv->width-40 || y>cv->height-40 )
8409 CVMagnify(cv,other->me.x,other->me.y,0,0);
8410 }
8411
8412 CVInfoDraw(cv,cv->gw);
8413 SCUpdateAll(cv->b.sc);
8414 }
8415
CVMenuNextPrevPt(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))8416 static void CVMenuNextPrevPt(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
8417 CharView *cv = (CharView *) GDrawGetUserData(gw);
8418 CVNextPrevPt(cv, mi);
8419 }
8420
CVNextPrevCPt(CharView * cv,struct gmenuitem * mi)8421 static void CVNextPrevCPt(CharView *cv, struct gmenuitem *mi) {
8422 SplinePoint *selpt=NULL;
8423 RefChar *r; ImageList *il;
8424 SplineSet *spl;
8425 spiro_cp *junk;
8426
8427 if ( !CVOneThingSel(cv,&selpt,&spl,&r,&il,NULL,&junk))
8428 return;
8429 if ( selpt==NULL )
8430 return;
8431 cv->p.nextcp = mi->mid==MID_NextCP;
8432 cv->p.prevcp = mi->mid==MID_PrevCP;
8433 SCUpdateAll(cv->b.sc);
8434 }
8435
CVMenuNextPrevCPt(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))8436 static void CVMenuNextPrevCPt(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
8437 CharView *cv = (CharView *) GDrawGetUserData(gw);
8438 CVNextPrevCPt(cv, mi);
8439 }
8440
CVMenuGotoChar(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))8441 static void CVMenuGotoChar(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8442 CharView *cv = (CharView *) GDrawGetUserData(gw);
8443 int pos;
8444
8445 if ( cv->b.container ) {
8446 (cv->b.container->funcs->doNavigate)(cv->b.container,nt_goto);
8447 return;
8448 }
8449
8450 pos = GotoChar(cv->b.fv->sf,cv->b.fv->map,NULL);
8451 if ( pos!=-1 )
8452 CVChangeChar(cv,pos);
8453 }
8454
CVMenuFindInFontView(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))8455 static void CVMenuFindInFontView(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8456 CharView *cv = (CharView *) GDrawGetUserData(gw);
8457 CVDoFindInFontView(cv);
8458 }
8459
CVMenuPalettesDock(GWindow UNUSED (gw),struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))8460 static void CVMenuPalettesDock(GWindow UNUSED(gw), struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8461 PalettesChangeDocking();
8462 }
8463
CVMenuPaletteShow(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))8464 static void CVMenuPaletteShow(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
8465 CharView *cv = (CharView *) GDrawGetUserData(gw);
8466 CVPaletteSetVisible(cv, mi->mid==MID_Tools, !CVPaletteIsVisible(cv, mi->mid==MID_Tools));
8467 }
8468
cv_pllistcheck(CharView * cv,struct gmenuitem * mi)8469 static void cv_pllistcheck(CharView *cv, struct gmenuitem *mi) {
8470 extern int palettes_docked;
8471
8472 for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
8473 switch ( mi->mid ) {
8474 case MID_Tools:
8475 mi->ti.checked = CVPaletteIsVisible(cv,1);
8476 break;
8477 case MID_Layers:
8478 mi->ti.checked = CVPaletteIsVisible(cv,0);
8479 break;
8480 case MID_DockPalettes:
8481 mi->ti.checked = palettes_docked;
8482 break;
8483 }
8484 }
8485 }
8486
pllistcheck(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))8487 static void pllistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
8488 CharView *cv = (CharView *) GDrawGetUserData(gw);
8489 cv_pllistcheck(cv, mi);
8490 }
8491
8492 /*
8493 * Unused
8494 static void tablistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
8495 GDrawGetUserData(gw);
8496 }
8497 */
8498
CVUndo(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))8499 static void CVUndo(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8500 CharView *cv = (CharView *) GDrawGetUserData(gw);
8501
8502 CVDoUndo(&cv->b);
8503 cv->lastselpt = NULL;
8504 }
8505
CVRedo(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))8506 static void CVRedo(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8507 CharView *cv = (CharView *) GDrawGetUserData(gw);
8508
8509 CVDoRedo(&cv->b);
8510 cv->lastselpt = NULL;
8511 }
8512
_CVCopy(CharView * cv)8513 static void _CVCopy(CharView *cv) {
8514 int desel = false, anya;
8515
8516 /* If nothing is selected, copy everything. Do that by temporarily selecting everything */
8517 if ( !CVAnySel(cv,NULL,NULL,NULL,&anya))
8518 if ( !(desel = CVSetSel(cv,-1)))
8519 return;
8520 CopySelected(&cv->b,cv->showanchor);
8521 if ( desel )
8522 CVClearSel(cv);
8523 }
8524
CVCopy(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))8525 static void CVCopy(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8526 CharView *cv = (CharView *) GDrawGetUserData(gw);
8527 _CVCopy(cv);
8528 }
8529
CVCopyLookupData(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))8530 static void CVCopyLookupData(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8531 CharView *cv = (CharView *) GDrawGetUserData(gw);
8532 SCCopyLookupData(cv->b.sc);
8533 }
8534
CVCopyRef(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))8535 static void CVCopyRef(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8536 CharView *cv = (CharView *) GDrawGetUserData(gw);
8537 CopyReference(cv->b.sc);
8538 }
8539
CVMenuCopyGridFit(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))8540 static void CVMenuCopyGridFit(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8541 CharView *cv = (CharView *) GDrawGetUserData(gw);
8542 CVCopyGridFit(&cv->b);
8543 }
8544
CVCopyWidth(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))8545 static void CVCopyWidth(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
8546 CharView *cv = (CharView *) GDrawGetUserData(gw);
8547 if ( mi->mid==MID_CopyVWidth && !cv->b.sc->parent->hasvmetrics )
8548 return;
8549 CopyWidth(&cv->b,mi->mid==MID_CopyWidth?ut_width:
8550 mi->mid==MID_CopyVWidth?ut_vwidth:
8551 mi->mid==MID_CopyLBearing?ut_lbearing:
8552 ut_rbearing);
8553 }
8554
CVDoClear(CharView * cv)8555 static void CVDoClear(CharView *cv) {
8556 ImageList *prev, *imgs, *next;
8557 RefChar *refs, *rnext;
8558 int layer = CVLayer((CharViewBase *) cv);
8559 int anyimages;
8560
8561 CVPreserveState(&cv->b);
8562 if ( cv->b.drawmode==dm_fore )
8563 SCRemoveSelectedMinimumDistances(cv->b.sc,2);
8564 cv->b.layerheads[cv->b.drawmode]->splines = SplinePointListRemoveSelected(cv->b.sc,
8565 cv->b.layerheads[cv->b.drawmode]->splines);
8566 for ( refs=cv->b.layerheads[cv->b.drawmode]->refs; refs!=NULL; refs = rnext ) {
8567 rnext = refs->next;
8568 if ( refs->selected )
8569 SCRemoveDependent(cv->b.sc,refs,layer);
8570 }
8571 if ( cv->b.drawmode==dm_fore ) {
8572 AnchorPoint *ap, *aprev=NULL, *anext;
8573 if ( cv->showanchor ) for ( ap=cv->b.sc->anchor; ap!=NULL; ap=anext ) {
8574 anext = ap->next;
8575 if ( ap->selected ) {
8576 if ( aprev!=NULL )
8577 aprev->next = anext;
8578 else
8579 cv->b.sc->anchor = anext;
8580 ap->next = NULL;
8581 AnchorPointsFree(ap);
8582 } else
8583 aprev = ap;
8584 }
8585 }
8586 anyimages = false;
8587 for ( prev = NULL, imgs=cv->b.layerheads[cv->b.drawmode]->images; imgs!=NULL; imgs = next ) {
8588 next = imgs->next;
8589 if ( !imgs->selected )
8590 prev = imgs;
8591 else {
8592 if ( prev==NULL )
8593 cv->b.layerheads[cv->b.drawmode]->images = next;
8594 else
8595 prev->next = next;
8596 chunkfree(imgs,sizeof(ImageList));
8597 /* garbage collection of images????!!!! */
8598 anyimages = true;
8599 }
8600 }
8601 if ( anyimages )
8602 SCOutOfDateBackground(cv->b.sc);
8603 if ( cv->lastselpt!=NULL || cv->p.sp!=NULL || cv->p.spiro!=NULL || cv->lastselcp!=NULL ) {
8604 cv->lastselpt = NULL; cv->p.sp = NULL;
8605 cv->p.spiro = cv->lastselcp = NULL;
8606 CVInfoDraw(cv,cv->gw);
8607 }
8608 }
8609
CVClear(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))8610 static void CVClear(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8611 CharView *cv = (CharView *) GDrawGetUserData(gw);
8612 int anyanchor;
8613
8614 if ( !CVAnySel(cv,NULL,NULL,NULL,&anyanchor))
8615 return;
8616 CVDoClear(cv);
8617 CVGridHandlePossibleFitChar( cv );
8618 CVCharChangedUpdate(&cv->b);
8619 }
8620
CVClearBackground(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))8621 static void CVClearBackground(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8622 CharView *cv = (CharView *) GDrawGetUserData(gw);
8623 SCClearBackground(cv->b.sc);
8624 }
8625
_CVPaste(CharView * cv)8626 static void _CVPaste(CharView *cv) {
8627 enum undotype ut = CopyUndoType();
8628 int was_empty = cv->b.drawmode==dm_fore && cv->b.sc->hstem==NULL && cv->b.sc->vstem==NULL && cv->b.layerheads[cv->b.drawmode]->splines==NULL && cv->b.layerheads[cv->b.drawmode]->refs==NULL;
8629 if ( ut!=ut_lbearing ) /* The lbearing code does this itself */
8630 CVPreserveStateHints(&cv->b);
8631 if ( ut!=ut_width && ut!=ut_vwidth && ut!=ut_lbearing && ut!=ut_rbearing && ut!=ut_possub )
8632 CVClearSel(cv);
8633 PasteToCV(&cv->b);
8634 cv->lastselpt = NULL;
8635 CVCharChangedUpdate(&cv->b);
8636 if ( was_empty && (cv->b.sc->hstem != NULL || cv->b.sc->vstem!=NULL ))
8637 cv->b.sc->changedsincelasthinted = false;
8638 }
8639
CVPaste(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))8640 static void CVPaste(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8641 CharView *cv = (CharView *) GDrawGetUserData(gw);
8642 _CVPaste(cv);
8643 // Before July 2019, all pastes would reset the view such that all splines
8644 // were visible. This is wrong in most cases, e.g. tracing many letters
8645 // from one manuscript page, or copying and pasting parts of a glyph.
8646 //
8647 // A more complete fix would be to make it so only selected points were put
8648 // into view, but it was deemed not worth it at the time, and this comment
8649 // was left instead. See Github issue №3783 and PR №3813 for more details.
8650 // CVInkscapeAdjust(cv);
8651 }
8652
_CVMerge(CharView * cv,int elide)8653 static void _CVMerge(CharView *cv, int elide) {
8654 int anyp = 0;
8655
8656 if ( !CVAnySel(cv,&anyp,NULL,NULL,NULL) || !anyp)
8657 return;
8658 CVPreserveState(&cv->b);
8659 SplineCharMerge(cv->b.sc,&cv->b.layerheads[cv->b.drawmode]->splines,!elide);
8660 SCClearSelPt(cv->b.sc);
8661 CVCharChangedUpdate(&cv->b);
8662 }
8663
CVMerge(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))8664 void CVMerge(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8665 CharView *cv = (CharView *) GDrawGetUserData(gw);
8666 _CVMerge(cv,false);
8667 }
8668
_CVMergeToLine(CharView * cv,int elide)8669 static void _CVMergeToLine(CharView *cv, int elide) {
8670 int anyp = 0;
8671
8672 if ( !CVAnySel(cv,&anyp,NULL,NULL,NULL) || !anyp)
8673 return;
8674 CVPreserveState(&cv->b);
8675 SplineCharMerge(cv->b.sc,&cv->b.layerheads[cv->b.drawmode]->splines,!elide);
8676
8677 // Select the other side of the new curve
8678 if (!CVInSpiro(cv)) {
8679 GList_Glib* gl = CVGetSelectedPoints( cv );
8680 if( g_list_first(gl) )
8681 SPSelectPrevPoint( (SplinePoint*)g_list_first(gl)->data, 1 );
8682 g_list_free( gl );
8683 }
8684
8685 // And make the curve between the two active points a line
8686 _CVMenuMakeLine( (CharViewBase*) cv, 0, 0 );
8687 SCClearSelPt(cv->b.sc);
8688 CVCharChangedUpdate(&cv->b);
8689 }
8690
CVMergeToLine(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))8691 void CVMergeToLine(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8692 CharView *cv = (CharView *) GDrawGetUserData(gw);
8693 _CVMergeToLine(cv,false);
8694
8695 }
8696
_CVJoin(CharView * cv)8697 static void _CVJoin(CharView *cv) {
8698 CharViewTab* tab = CVGetActiveTab(cv);
8699 int anyp = 0, changed;
8700 extern float joinsnap;
8701
8702 CVAnySel(cv,&anyp,NULL,NULL,NULL);
8703 CVPreserveState(&cv->b);
8704 cv->b.layerheads[cv->b.drawmode]->splines = SplineSetJoin(cv->b.layerheads[cv->b.drawmode]->splines,!anyp,joinsnap/tab->scale,&changed);
8705 if ( changed )
8706 CVCharChangedUpdate(&cv->b);
8707 }
8708
CVJoin(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))8709 static void CVJoin(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8710 CharView *cv = (CharView *) GDrawGetUserData(gw);
8711 _CVJoin(cv);
8712 }
8713
_CVCut(CharView * cv)8714 static void _CVCut(CharView *cv) {
8715 int anya;
8716
8717 if ( !CVAnySel(cv,NULL,NULL,NULL,&anya))
8718 return;
8719 _CVCopy(cv);
8720 CVDoClear(cv);
8721 CVCharChangedUpdate(&cv->b);
8722 }
8723
CVCut(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))8724 static void CVCut(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8725 CharView *cv = (CharView *) GDrawGetUserData(gw);
8726 _CVCut(cv);
8727 }
8728
CVCopyFgBg(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))8729 static void CVCopyFgBg(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8730 CharView *cv = (CharView *) GDrawGetUserData(gw);
8731
8732 if ( cv->b.sc->layers[ly_fore].splines==NULL )
8733 return;
8734 SCCopyLayerToLayer(cv->b.sc,ly_fore,ly_back,false);
8735 }
8736
CVMenuCopyL2L(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))8737 static void CVMenuCopyL2L(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8738 CharView *cv = (CharView *) GDrawGetUserData(gw);
8739 CVCopyLayerToLayer(cv);
8740 }
8741
CVMenuCompareL2L(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))8742 static void CVMenuCompareL2L(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8743 CharView *cv = (CharView *) GDrawGetUserData(gw);
8744 CVCompareLayerToLayer(cv);
8745 }
8746
CVSelectAll(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))8747 static void CVSelectAll(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
8748 CharView *cv = (CharView *) GDrawGetUserData(gw);
8749 int mask = -1;
8750
8751 if ( mi->mid==MID_SelectAllPoints )
8752 mask = 1;
8753 else if ( mi->mid==MID_SelectAnchors )
8754 mask = 2;
8755 else if ( mi->mid==MID_SelAll ) {
8756 mask = 1;
8757 if (cv->b.drawmode==dm_fore) mask+=2;
8758 /* TODO! Should we also check if this is the right foreground layer? */
8759 }
8760
8761 if ( CVSetSel(cv,mask))
8762 SCUpdateAll(cv->b.sc);
8763 }
8764
CVSelectOpenContours(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))8765 static void CVSelectOpenContours(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8766 CharView *cv = (CharView *) GDrawGetUserData(gw);
8767 SplineSet *ss;
8768 int i;
8769 SplinePoint *sp;
8770 int changed = CVClearSel(cv);
8771
8772 for ( ss=cv->b.layerheads[cv->b.drawmode]->splines; ss!=NULL; ss=ss->next ) {
8773 if ( ss->first->prev==NULL ) {
8774 changed = true;
8775 if ( cv->b.sc->inspiro && hasspiro()) {
8776 for ( i=0; i<ss->spiro_cnt; ++i )
8777 SPIRO_SELECT(&ss->spiros[i]);
8778 } else {
8779 for ( sp=ss->first ;; ) {
8780 sp->selected = true;
8781 if ( sp->next==NULL )
8782 break;
8783 sp = sp->next->to;
8784 }
8785 }
8786 }
8787 }
8788 if ( changed )
8789 SCUpdateAll(cv->b.sc);
8790 }
8791
CVSelectNone(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))8792 static void CVSelectNone(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8793 CharView *cv = (CharView *) GDrawGetUserData(gw);
8794 if ( CVClearSel(cv))
8795 SCUpdateAll(cv->b.sc);
8796 }
8797
CVSelectInvert(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))8798 static void CVSelectInvert(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8799 CharView *cv = (CharView *) GDrawGetUserData(gw);
8800 CVInvertSel(cv);
8801 SCUpdateAll(cv->b.sc);
8802 }
8803
CVSelectWidth(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))8804 static void CVSelectWidth(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8805 CharView *cv = (CharView *) GDrawGetUserData(gw);
8806 if ( HasUseMyMetrics(cv->b.sc,CVLayer((CharViewBase *) cv))!=NULL )
8807 return;
8808 cv->widthsel = !cv->widthsel;
8809 cv->oldwidth = cv->b.sc->width;
8810 SCUpdateAll(cv->b.sc);
8811 }
8812
CVSelectVWidth(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))8813 static void CVSelectVWidth(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8814 CharView *cv = (CharView *) GDrawGetUserData(gw);
8815 if ( !cv->showvmetrics || !cv->b.sc->parent->hasvmetrics )
8816 return;
8817 if ( HasUseMyMetrics(cv->b.sc,CVLayer((CharViewBase *) cv))!=NULL )
8818 return;
8819 cv->vwidthsel = !cv->widthsel;
8820 cv->oldvwidth = cv->b.sc->vwidth;
8821 SCUpdateAll(cv->b.sc);
8822 }
8823
CVSelectHM(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))8824 static void CVSelectHM(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8825 CharView *cv = (CharView *) GDrawGetUserData(gw);
8826 SplinePoint *sp; SplineSet *spl; RefChar *r; ImageList *im;
8827 spiro_cp *junk;
8828 int exactlyone = CVOneThingSel(cv,&sp,&spl,&r,&im,NULL,&junk);
8829
8830 if ( !exactlyone || sp==NULL || sp->hintmask == NULL || spl==NULL )
8831 return;
8832 while ( sp!=NULL ) {
8833 if ( sp->prev==NULL )
8834 break;
8835 sp = sp->prev->from;
8836 if ( sp == spl->first )
8837 break;
8838 if ( sp->hintmask!=NULL )
8839 goto done;
8840 sp->selected = true;
8841 }
8842 for ( spl = spl->next; spl!=NULL; spl = spl->next ) {
8843 for ( sp=spl->first; sp!=NULL; ) {
8844 if ( sp->hintmask!=NULL )
8845 goto done;
8846 sp->selected = true;
8847 if ( sp->prev==NULL )
8848 break;
8849 sp = sp->prev->from;
8850 if ( sp == spl->first )
8851 break;
8852 }
8853 }
8854 done:
8855 SCUpdateAll(cv->b.sc);
8856 }
8857
_CVUnlinkRef(CharView * cv)8858 static void _CVUnlinkRef(CharView *cv) {
8859 int anyrefs=0;
8860 RefChar *rf, *next;
8861
8862 if ( cv->b.layerheads[cv->b.drawmode]->refs!=NULL ) {
8863 CVPreserveState(&cv->b);
8864 for ( rf=cv->b.layerheads[cv->b.drawmode]->refs; rf!=NULL && !anyrefs; rf=rf->next )
8865 if ( rf->selected ) anyrefs = true;
8866 for ( rf=cv->b.layerheads[cv->b.drawmode]->refs; rf!=NULL ; rf=next ) {
8867 next = rf->next;
8868 if ( rf->selected || !anyrefs) {
8869 SCRefToSplines(cv->b.sc,rf,CVLayer((CharViewBase *) cv));
8870 }
8871 }
8872 CVSetCharChanged(cv,true);
8873 SCUpdateAll(cv->b.sc);
8874 /* Don't need to update dependancies, their splines won't have changed*/
8875 }
8876 }
8877
CVUnlinkRef(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))8878 static void CVUnlinkRef(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8879 CharView *cv = (CharView *) GDrawGetUserData(gw);
8880 _CVUnlinkRef(cv);
8881 }
8882
8883 typedef struct getValueDialogData
8884 {
8885 int done;
8886 int cancelled;
8887 CharView *cv;
8888 GWindow gw;
8889 char* ret;
8890 GTextInfo label;
8891 } GetValueDialogData;
8892
getValueDialogData_e_h(GWindow gw,GEvent * event)8893 static int getValueDialogData_e_h(GWindow gw, GEvent *event) {
8894 if ( event->type==et_close ) {
8895 GetValueDialogData *hd = GDrawGetUserData(gw);
8896 hd->done = true;
8897 } else if ( event->type == et_char ) {
8898 return( false );
8899 } else if ( event->type == et_map ) {
8900 /* Above palettes */
8901 GDrawRaise(gw);
8902 }
8903 return( true );
8904 }
8905
getValueFromUser_OK(GGadget * g,GEvent * e)8906 static int getValueFromUser_OK(GGadget *g, GEvent *e)
8907 {
8908 if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
8909 GetValueDialogData *hd = GDrawGetUserData(GGadgetGetWindow(g));
8910 strcpy( hd->ret, u_to_c(hd->label.text));
8911 strcpy( hd->ret, GGadgetGetTitle8(GWidgetGetControl(hd->gw,CID_getValueFromUser)));
8912 hd->done = true;
8913 }
8914 return( true );
8915 }
8916
getValueFromUser_Cancel(GGadget * g,GEvent * e)8917 static int getValueFromUser_Cancel(GGadget *g, GEvent *e) {
8918 if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
8919 GetValueDialogData *hd = GDrawGetUserData(GGadgetGetWindow(g));
8920 hd->cancelled = true;
8921 hd->done = true;
8922 }
8923 return( true );
8924 }
8925
getValueFromUser(CharView * cv,const char * windowTitle,const char * msg,const char * defaultValue)8926 static char* getValueFromUser( CharView *cv, const char* windowTitle, const char* msg, const char* defaultValue )
8927 {
8928 const int retsz = 4096;
8929 static char ret[4097];
8930 static GetValueDialogData DATA;
8931 GRect pos;
8932 GWindow gw;
8933 GWindowAttrs wattrs;
8934 GGadgetCreateData gcd[9], *harray1[4], *harray2[9], *barray[7], *varray[5][2], boxes[5];
8935 GTextInfo label[9];
8936
8937 DATA.cancelled = false;
8938 DATA.done = false;
8939 DATA.cv = cv;
8940 DATA.ret = ret;
8941 ret[0] = '\0';
8942
8943 if ( DATA.gw==NULL ) {
8944 memset(&wattrs,0,sizeof(wattrs));
8945 wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict;
8946 wattrs.event_masks = ~(1<<et_charup);
8947 wattrs.restrict_input_to_me = 1;
8948 wattrs.undercursor = 1;
8949 wattrs.cursor = ct_pointer;
8950 wattrs.utf8_window_title = windowTitle;
8951 wattrs.is_dlg = true;
8952 pos.x = pos.y = 0;
8953 pos.width = GGadgetScale(GDrawPointsToPixels(NULL,170));
8954 pos.height = GDrawPointsToPixels(NULL,90);
8955 DATA.gw = gw = GDrawCreateTopWindow(NULL,&pos,getValueDialogData_e_h,&DATA,&wattrs);
8956
8957 memset(&label,0,sizeof(label));
8958 memset(&gcd, 0,sizeof(gcd));
8959 memset(&boxes,0,sizeof(boxes));
8960
8961 label[0].text = (unichar_t *) msg;
8962 label[0].text_is_1byte = true;
8963 label[0].text_in_resource = true;
8964 gcd[0].gd.label = &label[0];
8965 gcd[0].gd.pos.x = 5;
8966 gcd[0].gd.pos.y = 5;
8967 gcd[0].gd.flags = gg_enabled|gg_visible;
8968 gcd[0].creator = GLabelCreate;
8969 harray1[0] = GCD_Glue;
8970 harray1[1] = &gcd[0];
8971 harray1[2] = 0;
8972
8973 label[1].text = (unichar_t *) defaultValue;
8974 label[1].text_is_1byte = true;
8975 DATA.label = label[1];
8976 gcd[1].gd.label = &label[1];
8977 gcd[1].gd.pos.x = 5;
8978 gcd[1].gd.pos.y = 17+5;
8979 gcd[1].gd.pos.width = 40;
8980 gcd[1].gd.flags = gg_enabled|gg_visible;
8981 gcd[1].gd.cid = CID_getValueFromUser;
8982 gcd[1].creator = GTextFieldCreate;
8983 harray2[0] = &gcd[1];
8984 harray2[1] = 0;
8985
8986 int idx = 2;
8987 gcd[idx].gd.pos.x = 20-3;
8988 gcd[idx].gd.pos.y = 17+37;
8989 gcd[idx].gd.pos.width = -1;
8990 gcd[idx].gd.pos.height = 0;
8991 gcd[idx].gd.flags = gg_visible | gg_enabled | gg_but_default;
8992 label[idx].text = (unichar_t *) _("_OK");
8993 label[idx].text_is_1byte = true;
8994 label[idx].text_in_resource = true;
8995 gcd[idx].gd.mnemonic = 'O';
8996 gcd[idx].gd.label = &label[idx];
8997 gcd[idx].gd.handle_controlevent = getValueFromUser_OK;
8998 gcd[idx].creator = GButtonCreate;
8999 barray[0] = GCD_Glue;
9000 barray[1] = &gcd[idx];
9001 barray[2] = GCD_Glue;
9002
9003 ++idx;
9004 gcd[idx].gd.pos.x = -20;
9005 gcd[idx].gd.pos.y = 17+37+3;
9006 gcd[idx].gd.pos.width = -1;
9007 gcd[idx].gd.pos.height = 0;
9008 gcd[idx].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
9009 label[idx].text = (unichar_t *) _("_Cancel");
9010 label[idx].text_is_1byte = true;
9011 label[idx].text_in_resource = true;
9012 gcd[idx].gd.label = &label[idx];
9013 gcd[idx].gd.mnemonic = 'C';
9014 gcd[idx].gd.handle_controlevent = getValueFromUser_Cancel;
9015 gcd[idx].creator = GButtonCreate;
9016 barray[3] = GCD_Glue;
9017 barray[4] = &gcd[idx];
9018 barray[5] = GCD_Glue;
9019 barray[6] = NULL;
9020
9021 gcd[7].gd.pos.x = 5;
9022 gcd[7].gd.pos.y = 17+31;
9023 gcd[7].gd.pos.width = 170-10;
9024 gcd[7].gd.flags = gg_enabled|gg_visible;
9025 gcd[7].creator = GLineCreate;
9026
9027 boxes[2].gd.flags = gg_enabled|gg_visible;
9028 boxes[2].gd.u.boxelements = harray1;
9029 boxes[2].creator = GHBoxCreate;
9030
9031 boxes[3].gd.flags = gg_enabled|gg_visible;
9032 boxes[3].gd.u.boxelements = harray2;
9033 boxes[3].creator = GHBoxCreate;
9034
9035 boxes[4].gd.flags = gg_enabled|gg_visible;
9036 boxes[4].gd.u.boxelements = barray;
9037 boxes[4].creator = GHBoxCreate;
9038
9039 varray[0][0] = &boxes[2]; varray[0][1] = NULL;
9040 varray[1][0] = &boxes[3]; varray[1][1] = NULL;
9041 varray[2][0] = &gcd[7]; varray[2][1] = NULL;
9042 varray[3][0] = &boxes[4]; varray[3][1] = NULL;
9043 varray[4][0] = NULL;
9044
9045 boxes[0].gd.pos.x = boxes[0].gd.pos.y = 2;
9046 boxes[0].gd.flags = gg_enabled|gg_visible;
9047 boxes[0].gd.u.boxelements = varray[0];
9048 boxes[0].creator = GHVGroupCreate;
9049
9050 GGadgetsCreate(gw,boxes);
9051 GHVBoxSetExpandableCol(boxes[2].ret,gb_expandglue);
9052 GHVBoxSetExpandableCol(boxes[3].ret,gb_expandglue);
9053 GHVBoxSetExpandableCol(boxes[4].ret,gb_expandgluesame);
9054 GHVBoxFitWindow(boxes[0].ret);
9055 } else {
9056 gw = DATA.gw;
9057 snprintf( ret, retsz, "%s", defaultValue );
9058 GGadgetSetTitle8(GWidgetGetControl(gw,CID_getValueFromUser),ret);
9059 GDrawSetTransientFor(gw,(GWindow) -1);
9060 }
9061
9062 GWidgetIndicateFocusGadget(GWidgetGetControl(gw,CID_getValueFromUser));
9063 GTextFieldSelect(GWidgetGetControl(gw,CID_getValueFromUser),0,-1);
9064
9065 GWidgetHidePalettes();
9066 GDrawSetVisible(gw,true);
9067 while ( !DATA.done )
9068 GDrawProcessOneEvent(NULL);
9069 GDrawSetVisible(gw,false);
9070
9071 if( DATA.cancelled )
9072 return 0;
9073 return ret;
9074 }
9075
9076
9077
CVRemoveUndoes(GWindow gw,struct gmenuitem * mi,GEvent * e)9078 static void CVRemoveUndoes(GWindow gw,struct gmenuitem *mi,GEvent *e)
9079 {
9080 CharView *cv = (CharView *) GDrawGetUserData(gw);
9081 static int lastValue = 10;
9082 int v = toint(getValueFromUser( cv,
9083 _("Trimming Undo Information"),
9084 _("How many most-recent Undos should be kept?"),
9085 tostr(lastValue)));
9086 lastValue = v;
9087 UndoesFreeButRetainFirstN(&cv->b.layerheads[cv->b.drawmode]->undoes,v);
9088 UndoesFreeButRetainFirstN(&cv->b.layerheads[cv->b.drawmode]->redoes,v);
9089 }
9090
9091
9092 /* We can only paste if there's something in the copy buffer */
9093 /* we can only copy if there's something selected to copy */
9094 /* figure out what things are possible from the edit menu before the user */
9095 /* pulls it down */
cv_edlistcheck(CharView * cv,struct gmenuitem * mi)9096 static void cv_edlistcheck(CharView *cv, struct gmenuitem *mi) {
9097 int anypoints, anyrefs, anyimages, anyanchor;
9098
9099 CVAnySel(cv,&anypoints,&anyrefs,&anyimages,&anyanchor);
9100
9101 for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
9102 switch ( mi->mid ) {
9103 case MID_Join:
9104 mi->ti.disabled = cv->b.layerheads[cv->b.drawmode]->splines==NULL;
9105 break;
9106 case MID_Merge:
9107 mi->ti.disabled = !anypoints;
9108 break;
9109 case MID_MergeToLine:
9110 mi->ti.disabled = !anypoints;
9111 break;
9112 case MID_Clear: case MID_Cut: /*case MID_Copy:*/
9113 /* If nothing is selected, copy copies everything */
9114 /* In spiro mode copy will copy all contours with at least (spiro) one point selected */
9115 mi->ti.disabled = !anypoints && !anyrefs && !anyimages && !anyanchor;
9116 break;
9117 case MID_CopyLBearing: case MID_CopyRBearing:
9118 mi->ti.disabled = cv->b.drawmode!=dm_fore ||
9119 (cv->b.layerheads[cv->b.drawmode]->splines==NULL && cv->b.layerheads[cv->b.drawmode]->refs==NULL);
9120 break;
9121 case MID_CopyFgToBg:
9122 mi->ti.disabled = cv->b.sc->layers[ly_fore].splines==NULL;
9123 break;
9124 case MID_CopyGridFit:
9125 mi->ti.disabled = cv->b.gridfit==NULL;
9126 break;
9127 case MID_Paste:
9128 mi->ti.disabled = !CopyContainsSomething() && !SCClipboardHasPasteableContents();
9129 break;
9130 case MID_Undo:
9131 mi->ti.disabled = cv->b.layerheads[cv->b.drawmode]->undoes==NULL;
9132 break;
9133 case MID_Redo:
9134 mi->ti.disabled = cv->b.layerheads[cv->b.drawmode]->redoes==NULL;
9135 break;
9136 case MID_RemoveUndoes:
9137 mi->ti.disabled = cv->b.layerheads[cv->b.drawmode]->undoes==NULL && cv->b.layerheads[cv->b.drawmode]->redoes==NULL;
9138 break;
9139 case MID_CopyRef:
9140 mi->ti.disabled = cv->b.drawmode!=dm_fore || cv->b.container!=NULL;
9141 break;
9142 case MID_CopyLookupData:
9143 mi->ti.disabled = (cv->b.sc->possub==NULL && cv->b.sc->kerns==NULL && cv->b.sc->vkerns==NULL) ||
9144 cv->b.container!=NULL;
9145 break;
9146 case MID_UnlinkRef:
9147 mi->ti.disabled = cv->b.layerheads[cv->b.drawmode]->refs==NULL;
9148 break;
9149 }
9150 }
9151 }
9152
edlistcheck(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))9153 static void edlistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
9154 CharView *cv = (CharView *) GDrawGetUserData(gw);
9155 cv_edlistcheck(cv, mi);
9156 }
9157
CVMenuAcceptableExtrema(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))9158 static void CVMenuAcceptableExtrema(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
9159 CharView *cv = (CharView *) GDrawGetUserData(gw);
9160 SplineSet *ss;
9161 Spline *s, *first;
9162
9163 for ( ss = cv->b.layerheads[cv->b.drawmode]->splines; ss!=NULL ; ss = ss->next ) {
9164 first = NULL;
9165 for ( s=ss->first->next; s!=NULL && s!=first; s = s->to->next ) {
9166 if ( first == NULL )
9167 first = s;
9168 if ( s->from->selected && s->to->selected )
9169 s->acceptableextrema = !s->acceptableextrema;
9170 }
9171 }
9172 }
9173
_CVMenuPointType(CharView * cv,struct gmenuitem * mi)9174 static void _CVMenuPointType(CharView *cv, struct gmenuitem *mi) {
9175 int pointtype = mi->mid==MID_Corner?pt_corner:mi->mid==MID_Tangent?pt_tangent:
9176 mi->mid==MID_Curve?pt_curve:pt_hvcurve;
9177 SplinePointList *spl;
9178 Spline *spline, *first;
9179
9180 CVPreserveState(&cv->b); /* We should only get here if there's a selection */
9181 for ( spl = cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL ; spl = spl->next ) {
9182 first = NULL;
9183 if ( spl->first->selected ) {
9184 if ( spl->first->pointtype!=pointtype )
9185 SPChangePointType(spl->first,pointtype);
9186 }
9187 for ( spline=spl->first->next; spline!=NULL && spline!=first ; spline = spline->to->next ) {
9188 if ( spline->to->selected ) {
9189 if ( spline->to->pointtype!=pointtype )
9190 SPChangePointType(spline->to,pointtype);
9191 }
9192 if ( first == NULL ) first = spline;
9193 }
9194 }
9195 CVCharChangedUpdate(&cv->b);
9196 }
9197
_CVMenuSpiroPointType(CharView * cv,struct gmenuitem * mi)9198 static void _CVMenuSpiroPointType(CharView *cv, struct gmenuitem *mi) {
9199 int pointtype = mi->mid==MID_SpiroCorner?SPIRO_CORNER:
9200 mi->mid==MID_SpiroG4?SPIRO_G4:
9201 mi->mid==MID_SpiroG2?SPIRO_G2:
9202 mi->mid==MID_SpiroLeft?SPIRO_LEFT:SPIRO_RIGHT;
9203 SplinePointList *spl;
9204 int i, changes;
9205
9206 CVPreserveState(&cv->b); /* We should only get here if there's a selection */
9207 for ( spl = cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL ; spl = spl->next ) {
9208 changes = false;
9209 for ( i=0; i<spl->spiro_cnt-1; ++i ) {
9210 if ( SPIRO_SELECTED(&spl->spiros[i]) ) {
9211 if ( (spl->spiros[i].ty&0x7f)!=SPIRO_OPEN_CONTOUR ) {
9212 spl->spiros[i].ty = pointtype|0x80;
9213 changes = true;
9214 }
9215 }
9216 }
9217 if ( changes )
9218 SSRegenerateFromSpiros(spl);
9219 }
9220 CVCharChangedUpdate(&cv->b);
9221 }
9222
9223
CVMenuPointType(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))9224 void CVMenuPointType(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
9225 CharView *cv = (CharView *) GDrawGetUserData(gw);
9226 if ( cv->b.sc->inspiro && hasspiro())
9227 _CVMenuSpiroPointType(cv, mi);
9228 else
9229 _CVMenuPointType(cv, mi);
9230 }
9231
_CVMenuImplicit(CharView * cv,struct gmenuitem * mi)9232 static void _CVMenuImplicit(CharView *cv, struct gmenuitem *mi) {
9233 SplinePointList *spl;
9234 Spline *spline, *first;
9235 int dontinterpolate = mi->mid==MID_NoImplicitPt;
9236
9237 if ( !cv->b.layerheads[cv->b.drawmode]->order2 )
9238 return;
9239 CVPreserveState(&cv->b); /* We should only get here if there's a selection */
9240 for ( spl = cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL ; spl = spl->next ) {
9241 first = NULL;
9242 if ( spl->first->selected ) {
9243 spl->first->dontinterpolate = dontinterpolate;
9244 }
9245 for ( spline=spl->first->next; spline!=NULL && spline!=first ; spline = spline->to->next ) {
9246 if ( spline->to->selected ) {
9247 spline->to->dontinterpolate = dontinterpolate;
9248 }
9249 if ( first == NULL ) first = spline;
9250 }
9251 }
9252 CVCharChangedUpdate(&cv->b);
9253 }
9254
CVMenuImplicit(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))9255 static void CVMenuImplicit(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
9256 CharView *cv = (CharView *) GDrawGetUserData(gw);
9257 _CVMenuImplicit(cv, mi);
9258 }
9259
9260 static GMenuItem2 spiroptlist[], ptlist[];
cv_ptlistcheck(CharView * cv,struct gmenuitem * mi)9261 static void cv_ptlistcheck(CharView *cv, struct gmenuitem *mi) {
9262 int type = -2, cnt=0, ccp_cnt=0, spline_selected=0;
9263 int spirotype = -2, opencnt=0, spirocnt=0;
9264 SplinePointList *spl, *sel=NULL, *onlysel=NULL;
9265 Spline *spline, *first;
9266 SplinePoint *selpt=NULL;
9267 int notimplicit = -1;
9268 int acceptable = -1;
9269 uint16 junk;
9270 int i;
9271
9272 if ( cv->showing_spiro_pt_menu != (cv->b.sc->inspiro && hasspiro())) {
9273 GMenuItemArrayFree(mi->sub);
9274 mi->sub = GMenuItem2ArrayCopy(cv->b.sc->inspiro && hasspiro()?spiroptlist:ptlist,&junk);
9275 cv->showing_spiro_pt_menu = cv->b.sc->inspiro && hasspiro();
9276 }
9277 for ( spl = cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL; spl = spl->next ) {
9278 first = NULL;
9279 if ( spl->first->selected ) {
9280 sel = spl;
9281 if ( onlysel==NULL || onlysel==spl ) onlysel = spl; else onlysel = (SplineSet *) (-1);
9282 selpt = spl->first; ++cnt;
9283 if ( type==-2 ) type = spl->first->pointtype;
9284 else if ( type!=spl->first->pointtype ) type = -1;
9285 if ( !spl->first->nonextcp && !spl->first->noprevcp && spl->first->prev!=NULL )
9286 ++ccp_cnt;
9287 if ( notimplicit==-1 ) notimplicit = spl->first->dontinterpolate;
9288 else if ( notimplicit!=spl->first->dontinterpolate ) notimplicit = -2;
9289 }
9290 for ( spline=spl->first->next; spline!=NULL && spline!=first; spline = spline->to->next ) {
9291 if ( spline->to->selected ) {
9292 if ( type==-2 ) type = spline->to->pointtype;
9293 else if ( type!=spline->to->pointtype ) type = -1;
9294 selpt = spline->to;
9295 if ( onlysel==NULL || onlysel==spl ) onlysel = spl; else onlysel = (SplineSet *) (-1);
9296 sel = spl; ++cnt;
9297 if ( !spline->to->nonextcp && !spline->to->noprevcp && spline->to->next!=NULL )
9298 ++ccp_cnt;
9299 if ( notimplicit==-1 ) notimplicit = spline->to->dontinterpolate;
9300 else if ( notimplicit!=spline->to->dontinterpolate ) notimplicit = -2;
9301 if ( spline->from->selected )
9302 ++spline_selected;
9303 }
9304 if ( spline->to->selected && spline->from->selected ) {
9305 if ( acceptable==-1 )
9306 acceptable = spline->acceptableextrema;
9307 else if ( acceptable!=spline->acceptableextrema )
9308 acceptable = -2;
9309 }
9310 if ( first == NULL ) first = spline;
9311 }
9312 for ( i=0; i<spl->spiro_cnt-1; ++i ) {
9313 if ( SPIRO_SELECTED(&spl->spiros[i])) {
9314 int ty = spl->spiros[i].ty&0x7f;
9315 ++spirocnt;
9316 if ( ty==SPIRO_OPEN_CONTOUR )
9317 ++opencnt;
9318 else if ( spirotype==-2 )
9319 spirotype = ty;
9320 else if ( spirotype!=ty )
9321 spirotype = -1;
9322 if ( onlysel==NULL || onlysel==spl ) onlysel = spl; else onlysel = (SplineSet *) (-1);
9323 }
9324 }
9325 }
9326
9327 for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
9328 switch ( mi->mid ) {
9329 case MID_Corner:
9330 mi->ti.disabled = type==-2;
9331 mi->ti.checked = type==pt_corner;
9332 break;
9333 case MID_Tangent:
9334 mi->ti.disabled = type==-2;
9335 mi->ti.checked = type==pt_tangent;
9336 break;
9337 case MID_Curve:
9338 mi->ti.disabled = type==-2;
9339 mi->ti.checked = type==pt_curve;
9340 break;
9341 case MID_HVCurve:
9342 mi->ti.disabled = type==-2;
9343 mi->ti.checked = type==pt_hvcurve;
9344 break;
9345 case MID_SpiroG4:
9346 mi->ti.disabled = spirotype==-2;
9347 mi->ti.checked = spirotype==SPIRO_G4;
9348 break;
9349 case MID_SpiroG2:
9350 mi->ti.disabled = spirotype==-2;
9351 mi->ti.checked = spirotype==SPIRO_G2;
9352 break;
9353 case MID_SpiroCorner:
9354 mi->ti.disabled = spirotype==-2;
9355 mi->ti.checked = spirotype==SPIRO_CORNER;
9356 break;
9357 case MID_SpiroLeft:
9358 mi->ti.disabled = spirotype==-2;
9359 mi->ti.checked = spirotype==SPIRO_LEFT;
9360 break;
9361 case MID_SpiroRight:
9362 mi->ti.disabled = spirotype==-2;
9363 mi->ti.checked = spirotype==SPIRO_RIGHT;
9364 break;
9365 case MID_MakeFirst:
9366 mi->ti.disabled = cnt!=1 || sel->first->prev==NULL || sel->first==selpt;
9367 break;
9368 case MID_SpiroMakeFirst:
9369 mi->ti.disabled = opencnt!=0 || spirocnt!=1;
9370 break;
9371 case MID_MakeLine: case MID_MakeArc:
9372 mi->ti.disabled = cnt<2;
9373 break;
9374 case MID_AcceptableExtrema:
9375 mi->ti.disabled = acceptable<0;
9376 mi->ti.checked = acceptable==1;
9377 break;
9378 case MID_NamePoint:
9379 mi->ti.disabled = onlysel==NULL || onlysel == (SplineSet *) -1;
9380 break;
9381 case MID_NameContour:
9382 mi->ti.disabled = onlysel==NULL || onlysel == (SplineSet *) -1;
9383 break;
9384 case MID_ClipPath:
9385 mi->ti.disabled = !cv->b.sc->parent->multilayer;
9386 break;
9387 case MID_InsertPtOnSplineAt:
9388 mi->ti.disabled = spline_selected!=1;
9389 break;
9390 case MID_CenterCP:
9391 mi->ti.disabled = ccp_cnt==0;
9392 break;
9393 case MID_ImplicitPt:
9394 mi->ti.disabled = !cv->b.layerheads[cv->b.drawmode]->order2;
9395 mi->ti.checked = notimplicit==0;
9396 break;
9397 case MID_NoImplicitPt:
9398 mi->ti.disabled = !cv->b.layerheads[cv->b.drawmode]->order2;
9399 mi->ti.checked = notimplicit==1;
9400 break;
9401 case MID_AddAnchor:
9402 mi->ti.disabled = cv->b.container!=NULL;
9403 break;
9404 }
9405 }
9406 }
9407
ptlistcheck(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))9408 static void ptlistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
9409 CharView *cv = (CharView *) GDrawGetUserData(gw);
9410 cv_ptlistcheck(cv, mi);
9411 }
9412
_CVMenuDir(CharView * cv,struct gmenuitem * mi)9413 static void _CVMenuDir(CharView *cv, struct gmenuitem *mi) {
9414 int splinepoints, dir;
9415 SplinePointList *spl;
9416 Spline *spline, *first;
9417 int needsrefresh = false;
9418
9419 for ( spl = cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL; spl = spl->next ) {
9420 first = NULL;
9421 splinepoints = 0;
9422 if ( cv->b.sc->inspiro && hasspiro()) {
9423 int i;
9424 for ( i=0; i<spl->spiro_cnt-1; ++i )
9425 if ( SPIRO_SELECTED(&spl->spiros[i])) {
9426 splinepoints = true;
9427 break;
9428 }
9429 } else {
9430 if ( spl->first->selected ) splinepoints = true;
9431 for ( spline=spl->first->next; spline!=NULL && spline!=first && !splinepoints; spline = spline->to->next ) {
9432 if ( spline->to->selected ) splinepoints = true;
9433 if ( first == NULL ) first = spline;
9434 }
9435 }
9436 if ( splinepoints && spl->first->prev!=NULL ) {
9437 dir = SplinePointListIsClockwise(spl);
9438 if ( (mi->mid==MID_Clockwise && dir==0) || (mi->mid==MID_Counter && dir==1)) {
9439 if ( !needsrefresh )
9440 CVPreserveState(&cv->b);
9441 SplineSetReverse(spl);
9442 needsrefresh = true;
9443 }
9444 }
9445 }
9446 if ( needsrefresh )
9447 CVCharChangedUpdate(&cv->b);
9448 }
9449
CVMenuDir(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))9450 static void CVMenuDir(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
9451 CharView *cv = (CharView *) GDrawGetUserData(gw);
9452 _CVMenuDir(cv, mi);
9453 }
9454
CVMenuCheckSelf(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))9455 static void CVMenuCheckSelf(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
9456 CharView *cv = (CharView *) GDrawGetUserData(gw);
9457 CVShows.checkselfintersects = cv->checkselfintersects = !cv->checkselfintersects;
9458 }
9459
CVMenuGlyphSelfIntersects(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))9460 static void CVMenuGlyphSelfIntersects(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
9461 CharView *cv = (CharView *) GDrawGetUserData(gw);
9462 Spline *s=NULL, *s2=NULL;
9463 SplineSet *ss;
9464 DBounds b;
9465 double off;
9466
9467 ss = LayerAllSplines(cv->b.layerheads[cv->b.drawmode]);
9468 SplineSetIntersect(ss,&s,&s2);
9469 LayerUnAllSplines(cv->b.layerheads[cv->b.drawmode]);
9470
9471 if ( s!=NULL || s2!=NULL ) {
9472 memset(&b,0,sizeof(b));
9473 CVClearSel(cv);
9474 if ( s!=NULL ) {
9475 b.minx = b.maxx = s->from->me.x;
9476 b.miny = b.maxy = s->from->me.y;
9477 } else if ( s2!=NULL ) {
9478 b.minx = b.maxx = s2->from->me.x;
9479 b.miny = b.maxy = s2->from->me.y;
9480 }
9481 if ( s!=NULL ) {
9482 s->from->selected = s->to->selected = true;
9483 if ( s->to->me.x>b.maxx ) b.maxx = s->to->me.x;
9484 if ( s->to->me.x<b.minx ) b.minx = s->to->me.x;
9485 if ( s->to->me.y>b.maxy ) b.maxy = s->to->me.y;
9486 if ( s->to->me.y<b.miny ) b.miny = s->to->me.y;
9487 }
9488 if ( s2!=NULL ) {
9489 s2->from->selected = s2->to->selected = true;
9490 if ( s2->from->me.x>b.maxx ) b.maxx = s2->from->me.x;
9491 if ( s2->from->me.x<b.minx ) b.minx = s2->from->me.x;
9492 if ( s2->from->me.y>b.maxy ) b.maxy = s2->from->me.y;
9493 if ( s2->from->me.y<b.miny ) b.miny = s2->from->me.y;
9494 if ( s2->to->me.x>b.maxx ) b.maxx = s2->to->me.x;
9495 if ( s2->to->me.x<b.minx ) b.minx = s2->to->me.x;
9496 if ( s2->to->me.y>b.maxy ) b.maxy = s2->to->me.y;
9497 if ( s2->to->me.y<b.miny ) b.miny = s2->to->me.y;
9498 }
9499 off = (b.maxx-b.minx)/10;
9500 if ( off==0 ) off = 1;
9501 b.minx -= off; b.maxx += off;
9502 off = (b.maxy-b.miny)/10;
9503 if ( off==0 ) off = 1;
9504 b.miny -= off; b.maxy += off;
9505 _CVFit(cv,&b,false);
9506 } else
9507 ff_post_notice(_("No Intersections"),_("No Intersections"));
9508 }
9509
getorigin(void * d,BasePoint * base,int index)9510 static int getorigin(void *d,BasePoint *base,int index) {
9511 CharView *cv = (CharView *) d;
9512
9513 base->x = base->y = 0;
9514 switch ( index ) {
9515 case 0: /* Character origin */
9516 /* all done */
9517 break;
9518 case 1: /* Center of selection */
9519 CVFindCenter(cv,base,!CVAnySel(cv,NULL,NULL,NULL,NULL));
9520 break;
9521 case 2: /* last press */
9522 base->x = cv->p.cx;
9523 base->y = cv->p.cy;
9524 /* I don't have any way of telling if a press has happened. if one */
9525 /* hasn't they'll just get a 0,0 origin. oh well */
9526 break;
9527 default:
9528 return( false );
9529 }
9530 return( true );
9531 }
9532
TransRef(RefChar * ref,real transform[6],enum fvtrans_flags flags)9533 static void TransRef(RefChar *ref,real transform[6], enum fvtrans_flags flags) {
9534 int j;
9535 real t[6];
9536
9537 for ( j=0; j<ref->layer_cnt; ++j )
9538 SplinePointListTransform(ref->layers[j].splines,transform,tpt_AllPoints);
9539 t[0] = ref->transform[0]*transform[0] +
9540 ref->transform[1]*transform[2];
9541 t[1] = ref->transform[0]*transform[1] +
9542 ref->transform[1]*transform[3];
9543 t[2] = ref->transform[2]*transform[0] +
9544 ref->transform[3]*transform[2];
9545 t[3] = ref->transform[2]*transform[1] +
9546 ref->transform[3]*transform[3];
9547 t[4] = ref->transform[4]*transform[0] +
9548 ref->transform[5]*transform[2] +
9549 transform[4];
9550 t[5] = ref->transform[4]*transform[1] +
9551 ref->transform[5]*transform[3] +
9552 transform[5];
9553 if ( flags&fvt_round_to_int ) {
9554 t[4] = rint( t[4] );
9555 t[5] = rint( t[5] );
9556 }
9557 memcpy(ref->transform,t,sizeof(t));
9558 RefCharFindBounds(ref);
9559 }
9560
CVTransFuncLayer(CharView * cv,Layer * ly,real transform[6],enum fvtrans_flags flags)9561 void CVTransFuncLayer(CharView *cv,Layer *ly,real transform[6], enum fvtrans_flags flags)
9562 {
9563 int anysel = cv->p.transany;
9564 RefChar *refs;
9565 ImageList *img;
9566 AnchorPoint *ap;
9567 KernPair *kp;
9568 PST *pst;
9569 int l, cvlayer;
9570 enum transformPointMask tpmask = 0;
9571
9572 if ( cv->b.sc->inspiro && hasspiro() )
9573 SplinePointListSpiroTransform(ly->splines,transform,!anysel);
9574 else
9575 {
9576 if( cv->active_tool==cvt_scale )
9577 tpmask |= tpmask_operateOnSelectedBCP;
9578
9579 SplinePointListTransformExtended(
9580 ly->splines, transform,
9581 !anysel?tpt_AllPoints: interpCPsOnMotion?tpt_OnlySelectedInterpCPs:tpt_OnlySelected,
9582 tpmask );
9583 }
9584
9585 if ( flags&fvt_round_to_int )
9586 SplineSetsRound2Int(ly->splines,1.0,cv->b.sc->inspiro && hasspiro(),!anysel);
9587 if ( ly->images!=NULL ) {
9588 ImageListTransform(ly->images,transform,!anysel);
9589 SCOutOfDateBackground(cv->b.sc);
9590 }
9591 for ( refs = ly->refs; refs!=NULL; refs=refs->next )
9592 if ( refs->selected || !anysel )
9593 TransRef(refs,transform,flags);
9594 if ( cv->showanchor ) {
9595 for ( ap=cv->b.sc->anchor; ap!=NULL; ap=ap->next ) if ( ap->selected || !anysel )
9596 ApTransform(ap,transform);
9597 }
9598 if ( !anysel ) {
9599 if ( flags & fvt_scalepstpos ) {
9600 for ( kp=cv->b.sc->kerns; kp!=NULL; kp=kp->next )
9601 kp->off = rint(kp->off*transform[0]);
9602 for ( kp=cv->b.sc->vkerns; kp!=NULL; kp=kp->next )
9603 kp->off = rint(kp->off*transform[3]);
9604 for ( pst = cv->b.sc->possub; pst!=NULL; pst=pst->next ) {
9605 if ( pst->type == pst_position )
9606 VrTrans(&pst->u.pos,transform);
9607 else if ( pst->type==pst_pair ) {
9608 VrTrans(&pst->u.pair.vr[0],transform);
9609 VrTrans(&pst->u.pair.vr[1],transform);
9610 }
9611 }
9612 }
9613 if ( transform[1]==0 && transform[2]==0 ) {
9614 TransHints(cv->b.sc->hstem,transform[3],transform[5],transform[0],transform[4],flags&fvt_round_to_int);
9615 TransHints(cv->b.sc->vstem,transform[0],transform[4],transform[3],transform[5],flags&fvt_round_to_int);
9616 TransDStemHints(cv->b.sc->dstem,transform[0],transform[4],transform[3],transform[5],flags&fvt_round_to_int);
9617 }
9618 if ( transform[0]==1 && transform[3]==1 && transform[1]==0 &&
9619 transform[2]==0 && transform[5]==0 &&
9620 transform[4]!=0 && CVAllSelected(cv) &&
9621 cv->b.sc->unicodeenc!=-1 && isalpha(cv->b.sc->unicodeenc)) {
9622 SCUndoSetLBearingChange(cv->b.sc,(int) rint(transform[4]));
9623 SCSynchronizeLBearing(cv->b.sc,transform[4],CVLayer((CharViewBase *) cv));
9624 }
9625 }
9626 if ( !(flags&fvt_dontmovewidth) && (cv->widthsel || !anysel))
9627 if ( transform[0]>0 && transform[3]>0 && transform[1]==0 &&
9628 transform[2]==0 && transform[4]!=0 )
9629 SCSynchronizeWidth(cv->b.sc,cv->b.sc->width*transform[0]+transform[4],cv->b.sc->width,NULL);
9630 if ( !(flags&fvt_dontmovewidth) && (cv->vwidthsel || !anysel))
9631 if ( transform[0]==1 && transform[3]==1 && transform[1]==0 &&
9632 transform[2]==0 && transform[5]!=0 )
9633 cv->b.sc->vwidth+=transform[5];
9634 if ( (flags&fvt_alllayers) && !anysel ) {
9635 /* SCPreserveBackground(cv->b.sc); */ /* done by caller */
9636 cvlayer = CVLayer( (CharViewBase *) cv );
9637 for ( l=0; l<cv->b.sc->layer_cnt; ++l ) if ( l!=cvlayer ) {
9638 for ( img = cv->b.sc->layers[l].images; img!=NULL; img=img->next )
9639 BackgroundImageTransform(cv->b.sc, img, transform);
9640 SplinePointListTransform(cv->b.sc->layers[l].splines,
9641 transform,tpt_AllPoints);
9642 for ( refs=cv->b.sc->layers[l].refs; refs!=NULL; refs=refs->next )
9643 TransRef(refs,transform,flags);
9644 }
9645 }
9646 }
9647
CVTransFunc(CharView * cv,real transform[6],enum fvtrans_flags flags)9648 void CVTransFunc(CharView *cv,real transform[6], enum fvtrans_flags flags)
9649 {
9650 Layer *ly = cv->b.layerheads[cv->b.drawmode];
9651 CVTransFuncLayer( cv, ly, transform, flags );
9652 }
9653
CVTransFuncAllLayers(CharView * cv,real transform[6],enum fvtrans_flags flags)9654 void CVTransFuncAllLayers(CharView *cv,real transform[6], enum fvtrans_flags flags)
9655 {
9656 int idx;
9657 for( idx = 0; idx < cv->b.sc->layer_cnt; ++idx )
9658 {
9659 Layer *ly = &cv->b.sc->layers[ idx ];
9660 CVTransFuncLayer( cv, ly, transform, flags );
9661 }
9662 }
9663
transfunc(void * d,real transform[6],int otype,BVTFunc * bvts,enum fvtrans_flags flags)9664 static void transfunc(void *d,real transform[6],int otype,BVTFunc *bvts,
9665 enum fvtrans_flags flags) {
9666 CharView *cv = (CharView *) d;
9667 int anya, l, cvlayer = CVLayer((CharViewBase *) cv);
9668
9669 if ( cv->b.layerheads[cv->b.drawmode]->undoes!=NULL &&
9670 cv->b.layerheads[cv->b.drawmode]->undoes->undotype==ut_tstate )
9671 {
9672 CVDoUndo(&cv->b);
9673 }
9674
9675 if ( flags&fvt_revert )
9676 return;
9677
9678 cv->p.transany = CVAnySel(cv,NULL,NULL,NULL,&anya);
9679 if ( flags&fvt_justapply )
9680 CVPreserveTState(cv);
9681 else {
9682 CVPreserveStateHints(&cv->b);
9683 if ( flags&fvt_alllayers )
9684 for ( l=0; l<cv->b.sc->layer_cnt; ++l ) if ( l!=cvlayer )
9685 SCPreserveLayer(cv->b.sc,l,false);
9686 }
9687
9688 CVPreserveMaybeState( cv, flags&fvt_justapply );
9689 CVTransFunc(cv,transform,flags);
9690 CVCharChangedUpdate(&cv->b);
9691 }
9692
CVDoTransform(CharView * cv,enum cvtools cvt)9693 void CVDoTransform(CharView *cv, enum cvtools cvt ) {
9694 int anysel = CVAnySel(cv,NULL,NULL,NULL,NULL);
9695 TransformDlgCreate(cv,transfunc,getorigin,!anysel?(tdf_enableback|tdf_addapply):tdf_addapply,
9696 cvt);
9697 }
9698
CVMenuTransform(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))9699 static void CVMenuTransform(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
9700 CharView *cv = (CharView *) GDrawGetUserData(gw);
9701 CVDoTransform(cv,cvt_none);
9702 }
9703
CVMenuPOV(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))9704 static void CVMenuPOV(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
9705 CharView *cv = (CharView *) GDrawGetUserData(gw);
9706 struct pov_data pov_data;
9707 if ( PointOfViewDlg(&pov_data,cv->b.sc->parent,true)==-1 )
9708 return;
9709 CVPointOfView(cv,&pov_data);
9710 }
9711
CVMenuNLTransform(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))9712 static void CVMenuNLTransform(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
9713 CharView *cv = (CharView *) GDrawGetUserData(gw);
9714 cv->lastselpt = NULL; cv->lastselcp = NULL;
9715 NonLinearDlg(NULL,cv);
9716 }
9717
CVMenuConstrain(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))9718 void CVMenuConstrain(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
9719 CharView *cv = (CharView *) GDrawGetUserData(gw);
9720 CVConstrainSelection( cv,
9721 mi->mid==MID_Average ? constrainSelection_AveragePoints :
9722 mi->mid==MID_SpacePts ? constrainSelection_SpacePoints :
9723 constrainSelection_SpaceSelectedRegions );
9724 }
9725
CVMenuMakeParallel(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))9726 static void CVMenuMakeParallel(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
9727 CharView *cv = (CharView *) GDrawGetUserData(gw);
9728 CVMakeParallel(cv);
9729 }
9730
_CVMenuRound2Int(CharView * cv,double factor)9731 static void _CVMenuRound2Int(CharView *cv, double factor) {
9732 int anysel = CVAnySel(cv,NULL,NULL,NULL,NULL);
9733 RefChar *r;
9734 AnchorPoint *ap;
9735
9736 CVPreserveState(&cv->b);
9737 SplineSetsRound2Int(cv->b.layerheads[cv->b.drawmode]->splines,factor,
9738 cv->b.sc->inspiro && hasspiro(), anysel);
9739 for ( r=cv->b.layerheads[cv->b.drawmode]->refs; r!=NULL; r=r->next ) {
9740 if ( r->selected || !anysel ) {
9741 r->transform[4] = rint(r->transform[4]*factor)/factor;
9742 r->transform[5] = rint(r->transform[5]*factor)/factor;
9743 }
9744 }
9745 if ( cv->b.drawmode==dm_fore ) {
9746 for ( ap=cv->b.sc->anchor; ap!=NULL; ap=ap->next ) {
9747 if ( ap->selected || !anysel ) {
9748 ap->me.x = rint(ap->me.x*factor)/factor;
9749 ap->me.y = rint(ap->me.y*factor)/factor;
9750 }
9751 }
9752 }
9753 CVCharChangedUpdate(&cv->b);
9754 }
9755
CVMenuRound2Int(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))9756 static void CVMenuRound2Int(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
9757 CharView *cv = (CharView *) GDrawGetUserData(gw);
9758 _CVMenuRound2Int(cv,1.0);
9759 }
9760
CVMenuRound2Hundredths(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))9761 static void CVMenuRound2Hundredths(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
9762 CharView *cv = (CharView *) GDrawGetUserData(gw);
9763 _CVMenuRound2Int(cv,100.0);
9764 }
9765
CVMenuCluster(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))9766 static void CVMenuCluster(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
9767 CharView *cv = (CharView *) GDrawGetUserData(gw);
9768 int layer = cv->b.drawmode == dm_grid ? ly_grid :
9769 cv->b.drawmode == dm_back ? ly_back
9770 : cv->b.layerheads[dm_fore] - cv->b.sc->layers;
9771 SCRoundToCluster(cv->b.sc,layer,true,.1,.5);
9772 }
9773
CVMenuStroke(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))9774 static void CVMenuStroke(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
9775 CharView *cv = (CharView *) GDrawGetUserData(gw);
9776 CVStroke(cv);
9777 }
9778
9779 #ifdef FONTFORGE_CONFIG_TILEPATH
CVMenuTilePath(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))9780 static void CVMenuTilePath(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
9781 CharView *cv = (CharView *) GDrawGetUserData(gw);
9782 CVTile(cv);
9783 }
9784
CVMenuPatternTile(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))9785 static void CVMenuPatternTile(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
9786 CharView *cv = (CharView *) GDrawGetUserData(gw);
9787 CVPatternTile(cv);
9788 }
9789 #endif
9790
_CVMenuOverlap(CharView * cv,enum overlap_type ot)9791 static void _CVMenuOverlap(CharView *cv,enum overlap_type ot) {
9792 /* We know it's more likely that we'll find a problem in the overlap code */
9793 /* than anywhere else, so let's save the current state against a crash */
9794 int layer = cv->b.drawmode == dm_grid ? ly_grid :
9795 cv->b.drawmode == dm_back ? ly_back
9796 : cv->b.layerheads[dm_fore] - cv->b.sc->layers;
9797
9798 DoAutoSaves();
9799 #if 0
9800 // We await testing on the necessity of this operation.
9801 if ( !SCRoundToCluster(cv->b.sc,layer,false,.03,.12))
9802 CVPreserveState(&cv->b); /* SCRound2Cluster does this when it makes a change, not otherwise */
9803 #else
9804 CVPreserveState(&cv->b);
9805 #endif // 0
9806 if ( cv->b.drawmode==dm_fore ) {
9807 MinimumDistancesFree(cv->b.sc->md);
9808 cv->b.sc->md = NULL;
9809 }
9810 cv->b.layerheads[cv->b.drawmode]->splines = SplineSetRemoveOverlap(cv->b.sc,cv->b.layerheads[cv->b.drawmode]->splines,ot);
9811 // Check for removal of last selected points.
9812 if ( cv->b.sc->inspiro && hasspiro()) {
9813 // Detection is not implemented for Spiro, so just clear them.
9814 // TODO: Detect point survival in Spiro mode.
9815 cv->p.sp = cv->lastselpt = NULL;
9816 cv->p.spiro = cv->lastselcp = NULL;
9817 } else {
9818 // Check whether the last selected point is still in the spline set.
9819 // If not, remove the reference to it.
9820 if (cv->lastselpt != NULL &&
9821 !SplinePointListContainsPoint(cv->b.layerheads[cv->b.drawmode]->splines, cv->lastselpt))
9822 cv->p.sp = cv->lastselpt = NULL;
9823 cv->p.spiro = cv->lastselcp = NULL;
9824 }
9825 CVCharChangedUpdate(&cv->b);
9826 }
9827
CVMenuOverlap(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))9828 static void CVMenuOverlap(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
9829 CharView *cv = (CharView *) GDrawGetUserData(gw);
9830 int anysel;
9831
9832 (void) CVAnySel(cv,&anysel,NULL,NULL,NULL);
9833 _CVMenuOverlap(cv,mi->mid==MID_RmOverlap ? (anysel ? over_rmselected: over_remove) :
9834 mi->mid==MID_Intersection ? (anysel ? over_intersel : over_intersect ) :
9835 mi->mid==MID_Exclude ? over_exclude :
9836 (anysel ? over_fisel : over_findinter));
9837 }
9838
CVMenuOrder(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))9839 static void CVMenuOrder(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
9840 CharView *cv = (CharView *) GDrawGetUserData(gw);
9841 SplinePointList *spl;
9842 RefChar *r;
9843 ImageList *im;
9844 int exactlyone = CVOneContourSel(cv,&spl,&r,&im);
9845
9846 if ( !exactlyone )
9847 return;
9848
9849 CVPreserveState(&cv->b);
9850 if ( spl!=NULL ) {
9851 SplinePointList *p, *pp, *t;
9852 p = pp = NULL;
9853 for ( t=cv->b.layerheads[cv->b.drawmode]->splines; t!=NULL && t!=spl; t=t->next ) {
9854 pp = p; p = t;
9855 }
9856 switch ( mi->mid ) {
9857 case MID_First:
9858 if ( p!=NULL ) {
9859 p->next = spl->next;
9860 spl->next = cv->b.layerheads[cv->b.drawmode]->splines;
9861 cv->b.layerheads[cv->b.drawmode]->splines = spl;
9862 }
9863 break;
9864 case MID_Earlier:
9865 if ( p!=NULL ) {
9866 p->next = spl->next;
9867 spl->next = p;
9868 if ( pp==NULL ) {
9869 cv->b.layerheads[cv->b.drawmode]->splines = spl;
9870 } else {
9871 pp->next = spl;
9872 }
9873 }
9874 break;
9875 case MID_Last:
9876 if ( spl->next!=NULL ) {
9877 for ( t=cv->b.layerheads[cv->b.drawmode]->splines; t->next!=NULL; t=t->next );
9878 t->next = spl;
9879 if ( p==NULL )
9880 cv->b.layerheads[cv->b.drawmode]->splines = spl->next;
9881 else
9882 p->next = spl->next;
9883 spl->next = NULL;
9884 }
9885 break;
9886 case MID_Later:
9887 if ( spl->next!=NULL ) {
9888 t = spl->next;
9889 spl->next = t->next;
9890 t->next = spl;
9891 if ( p==NULL )
9892 cv->b.layerheads[cv->b.drawmode]->splines = t;
9893 else
9894 p->next = t;
9895 }
9896 break;
9897 }
9898 } else if ( r!=NULL ) {
9899 RefChar *p, *pp, *t;
9900 p = pp = NULL;
9901 for ( t=cv->b.layerheads[cv->b.drawmode]->refs; t!=NULL && t!=r; t=t->next ) {
9902 pp = p; p = t;
9903 }
9904 switch ( mi->mid ) {
9905 case MID_First:
9906 if ( p!=NULL ) {
9907 p->next = r->next;
9908 r->next = cv->b.layerheads[cv->b.drawmode]->refs;
9909 cv->b.layerheads[cv->b.drawmode]->refs = r;
9910 }
9911 break;
9912 case MID_Earlier:
9913 if ( p!=NULL ) {
9914 p->next = r->next;
9915 r->next = p;
9916 if ( pp==NULL ) {
9917 cv->b.layerheads[cv->b.drawmode]->refs = r;
9918 } else {
9919 pp->next = r;
9920 }
9921 }
9922 break;
9923 case MID_Last:
9924 if ( r->next!=NULL ) {
9925 for ( t=cv->b.layerheads[cv->b.drawmode]->refs; t->next!=NULL; t=t->next );
9926 t->next = r;
9927 if ( p==NULL )
9928 cv->b.layerheads[cv->b.drawmode]->refs = r->next;
9929 else
9930 p->next = r->next;
9931 r->next = NULL;
9932 }
9933 break;
9934 case MID_Later:
9935 if ( r->next!=NULL ) {
9936 t = r->next;
9937 r->next = t->next;
9938 t->next = r;
9939 if ( p==NULL )
9940 cv->b.layerheads[cv->b.drawmode]->refs = t;
9941 else
9942 p->next = t;
9943 }
9944 break;
9945 }
9946 } else if ( im!=NULL ) {
9947 ImageList *p, *pp, *t;
9948 p = pp = NULL;
9949 for ( t=cv->b.layerheads[cv->b.drawmode]->images; t!=NULL && t!=im; t=t->next ) {
9950 pp = p; p = t;
9951 }
9952 switch ( mi->mid ) {
9953 case MID_First:
9954 if ( p!=NULL ) {
9955 p->next = im->next;
9956 im->next = cv->b.layerheads[cv->b.drawmode]->images;
9957 cv->b.layerheads[cv->b.drawmode]->images = im;
9958 }
9959 break;
9960 case MID_Earlier:
9961 if ( p!=NULL ) {
9962 p->next = im->next;
9963 im->next = p;
9964 if ( pp==NULL ) {
9965 cv->b.layerheads[cv->b.drawmode]->images = im;
9966 } else {
9967 pp->next = im;
9968 }
9969 }
9970 break;
9971 case MID_Last:
9972 if ( im->next!=NULL ) {
9973 for ( t=cv->b.layerheads[cv->b.drawmode]->images; t->next!=NULL; t=t->next );
9974 t->next = im;
9975 if ( p==NULL )
9976 cv->b.layerheads[cv->b.drawmode]->images = im->next;
9977 else
9978 p->next = im->next;
9979 im->next = NULL;
9980 }
9981 break;
9982 case MID_Later:
9983 if ( im->next!=NULL ) {
9984 t = im->next;
9985 im->next = t->next;
9986 t->next = im;
9987 if ( p==NULL )
9988 cv->b.layerheads[cv->b.drawmode]->images = t;
9989 else
9990 p->next = t;
9991 }
9992 break;
9993 }
9994 }
9995 CVCharChangedUpdate(&cv->b);
9996 }
9997
_CVMenuAddExtrema(CharView * cv)9998 static void _CVMenuAddExtrema(CharView *cv) {
9999 int anysel;
10000 SplineFont *sf = cv->b.sc->parent;
10001
10002 (void) CVAnySel(cv,&anysel,NULL,NULL,NULL);
10003 CVPreserveState(&cv->b);
10004 SplineCharAddExtrema(cv->b.sc,cv->b.layerheads[cv->b.drawmode]->splines,
10005 anysel?ae_between_selected:ae_only_good,sf->ascent+sf->descent);
10006 CVCharChangedUpdate(&cv->b);
10007 }
10008
CVMenuAddExtrema(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))10009 static void CVMenuAddExtrema(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
10010 CharView *cv = (CharView *) GDrawGetUserData(gw);
10011 _CVMenuAddExtrema(cv);
10012 }
10013
CVSimplify(CharView * cv,int type)10014 static void CVSimplify(CharView *cv,int type) {
10015 static struct simplifyinfo smpls[] = {
10016 { sf_normal, 0, 0, 0, 0, 0, 0 },
10017 { sf_normal,.75,.05,0,-1, 0, 0 },
10018 { sf_normal,.75,.05,0,-1, 0, 0 }};
10019 struct simplifyinfo *smpl = &smpls[type+1];
10020
10021 if ( smpl->linelenmax==-1 || (type==0 && !smpl->set_as_default)) {
10022 smpl->err = (cv->b.sc->parent->ascent+cv->b.sc->parent->descent)/1000.;
10023 smpl->linelenmax = (cv->b.sc->parent->ascent+cv->b.sc->parent->descent)/100.;
10024 }
10025
10026 if ( type==1 ) {
10027 if ( !SimplifyDlg(cv->b.sc->parent,smpl))
10028 return;
10029 if ( smpl->set_as_default )
10030 smpls[1] = *smpl;
10031 }
10032
10033 CVPreserveState(&cv->b);
10034 smpl->check_selected_contours = true;
10035 cv->b.layerheads[cv->b.drawmode]->splines = SplineCharSimplify(cv->b.sc,cv->b.layerheads[cv->b.drawmode]->splines,
10036 smpl);
10037 CVCharChangedUpdate(&cv->b);
10038 }
10039
CVMenuSimplify(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))10040 static void CVMenuSimplify(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
10041 CharView *cv = (CharView *) GDrawGetUserData(gw);
10042 CVSimplify(cv,0);
10043 }
10044
CVMenuSimplifyMore(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))10045 static void CVMenuSimplifyMore(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
10046 CharView *cv = (CharView *) GDrawGetUserData(gw);
10047 CVSimplify(cv,1);
10048 }
10049
CVMenuCleanupGlyph(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))10050 static void CVMenuCleanupGlyph(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
10051 CharView *cv = (CharView *) GDrawGetUserData(gw);
10052 CVSimplify(cv,-1);
10053 }
10054
SPLSelected(SplineSet * ss)10055 static int SPLSelected(SplineSet *ss) {
10056 SplinePoint *sp;
10057
10058 for ( sp=ss->first ;; ) {
10059 if ( sp->selected )
10060 return( true );
10061 if ( sp->next==NULL )
10062 return( false );
10063 sp = sp->next->to;
10064 if ( sp==ss->first )
10065 return( false );
10066 }
10067 }
10068
CVCanonicalStart(CharView * cv)10069 static void CVCanonicalStart(CharView *cv) {
10070 SplineSet *ss;
10071 int changed = 0;
10072
10073 for ( ss = cv->b.layerheads[cv->b.drawmode]->splines; ss!=NULL; ss=ss->next )
10074 if ( ss->first==ss->last && SPLSelected(ss)) {
10075 SPLStartToLeftmost(cv->b.sc,ss,&changed);
10076 /* The above clears the spiros if needed */
10077 }
10078 }
10079
CVMenuCanonicalStart(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))10080 static void CVMenuCanonicalStart(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
10081 CharView *cv = (CharView *) GDrawGetUserData(gw);
10082 CVCanonicalStart(cv);
10083 }
10084
CVCanonicalContour(CharView * cv)10085 static void CVCanonicalContour(CharView *cv) {
10086 CanonicalContours(cv->b.sc,CVLayer((CharViewBase *) cv));
10087 }
10088
CVMenuCanonicalContours(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))10089 static void CVMenuCanonicalContours(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
10090 CharView *cv = (CharView *) GDrawGetUserData(gw);
10091 CVCanonicalContour(cv);
10092 }
10093
_CVMenuMakeFirst(CharView * cv)10094 static void _CVMenuMakeFirst(CharView *cv) {
10095 SplinePoint *selpt = NULL;
10096 int anypoints = 0, splinepoints;
10097 SplinePointList *spl, *sel;
10098 Spline *spline, *first;
10099
10100 sel = NULL;
10101 for ( spl = cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL; spl = spl->next ) {
10102 first = NULL;
10103 splinepoints = 0;
10104 if ( spl->first->selected ) { splinepoints = 1; sel = spl; selpt=spl->first; }
10105 for ( spline=spl->first->next; spline!=NULL && spline!=first && !splinepoints; spline = spline->to->next ) {
10106 if ( spline->to->selected ) { ++splinepoints; sel = spl; selpt=spline->to; }
10107 if ( first == NULL ) first = spline;
10108 }
10109 anypoints += splinepoints;
10110 }
10111
10112 if ( anypoints!=1 || sel->first->prev==NULL || sel->first==selpt )
10113 return;
10114
10115 CVPreserveState(&cv->b);
10116 sel->first = sel->last = selpt;
10117 CVCharChangedUpdate(&cv->b);
10118 }
10119
CVMenuMakeFirst(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))10120 static void CVMenuMakeFirst(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
10121 CharView *cv = (CharView *) GDrawGetUserData(gw);
10122 _CVMenuMakeFirst(cv);
10123 }
10124
_CVMenuSpiroMakeFirst(CharView * cv)10125 static void _CVMenuSpiroMakeFirst(CharView *cv) {
10126 int anypoints = 0, which;
10127 SplinePointList *spl, *sel;
10128 int i;
10129 spiro_cp *newspiros;
10130
10131 sel = NULL;
10132 for ( spl = cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL; spl = spl->next ) {
10133 for ( i=0; i<spl->spiro_cnt-1; ++i ) {
10134 if ( SPIRO_SELECTED(&spl->spiros[i])) {
10135 if ( SPIRO_SPL_OPEN(spl))
10136 return;
10137 ++anypoints;
10138 sel = spl;
10139 which = i;
10140 }
10141 }
10142 }
10143
10144 if ( anypoints!=1 || sel==NULL )
10145 return;
10146
10147 CVPreserveState(&cv->b);
10148 newspiros = malloc((sel->spiro_max+1)*sizeof(spiro_cp));
10149 memcpy(newspiros,sel->spiros+which,(sel->spiro_cnt-1-which)*sizeof(spiro_cp));
10150 memcpy(newspiros+(sel->spiro_cnt-1-which),sel->spiros,which*sizeof(spiro_cp));
10151 memcpy(newspiros+sel->spiro_cnt-1,sel->spiros+sel->spiro_cnt-1,sizeof(spiro_cp));
10152 free(sel->spiros);
10153 sel->spiros = newspiros;
10154 SSRegenerateFromSpiros(sel);
10155 CVCharChangedUpdate(&cv->b);
10156 }
10157
CVMenuSpiroMakeFirst(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))10158 static void CVMenuSpiroMakeFirst(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
10159 CharView *cv = (CharView *) GDrawGetUserData(gw);
10160 _CVMenuSpiroMakeFirst(cv);
10161 }
10162
CVMenuMakeLine(GWindow gw,struct gmenuitem * mi,GEvent * e)10163 static void CVMenuMakeLine(GWindow gw, struct gmenuitem *mi, GEvent *e) {
10164 CharView *cv = (CharView *) GDrawGetUserData(gw);
10165 _CVMenuMakeLine((CharViewBase *) cv,mi->mid==MID_MakeArc, e!=NULL && (e->u.mouse.state&ksm_meta));
10166 }
10167
_CVMenuNamePoint(CharView * cv,SplinePoint * sp)10168 void _CVMenuNamePoint(CharView *cv, SplinePoint *sp) {
10169 char *ret, *name, *oldname;
10170
10171 oldname = (sp->name && *sp->name) ? sp->name : NULL;
10172 ret = gwwv_ask_string(_("Name this point"), oldname,
10173 _("Please name this point"));
10174 if ( ret!=NULL ) {
10175 name = *ret ? ret : NULL;
10176 if (name != oldname || (name && oldname && strcmp(name,oldname))) {
10177 sp->name = name;
10178 CVCharChangedUpdate(&cv->b);
10179 }
10180 if (name != ret) { free(ret); ret = NULL; }
10181 if (name != oldname) { free(oldname); oldname = NULL; }
10182 }
10183 }
10184
CVMenuNamePoint(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))10185 static void CVMenuNamePoint(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
10186 CharView *cv = (CharView *) GDrawGetUserData(gw);
10187 SplinePointList *spl;
10188 SplinePoint *sp;
10189 RefChar *r;
10190 ImageList *il;
10191 spiro_cp *junk;
10192
10193 if ( CVOneThingSel( cv, &sp, &spl, &r, &il, NULL, &junk ) && sp) {
10194 _CVMenuNamePoint(cv, sp);
10195 }
10196 }
10197
_CVMenuNameContour(CharView * cv)10198 void _CVMenuNameContour(CharView *cv) {
10199 SplinePointList *spl, *onlysel = NULL;
10200 SplinePoint *sp;
10201 char *ret;
10202 int i;
10203
10204 for ( spl = cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL; spl = spl->next ) {
10205 if ( !cv->b.sc->inspiro || !hasspiro()) {
10206 for ( sp=spl->first; ; ) {
10207 if ( sp->selected ) {
10208 if ( onlysel==NULL )
10209 onlysel = spl;
10210 else if ( onlysel!=spl )
10211 return;
10212 }
10213 if ( sp->next==NULL )
10214 break;
10215 sp = sp->next->to;
10216 if ( sp==spl->first )
10217 break;
10218 }
10219 } else {
10220 for ( i=0; i<spl->spiro_cnt; ++i ) {
10221 if ( SPIRO_SELECTED(&spl->spiros[i])) {
10222 if ( onlysel==NULL )
10223 onlysel = spl;
10224 else if ( onlysel!=spl )
10225 return;
10226 }
10227 }
10228 }
10229 }
10230
10231 if ( onlysel!=NULL ) {
10232 ret = gwwv_ask_string(_("Name this contour"),onlysel->contour_name,
10233 _("Please name this contour"));
10234 if ( ret!=NULL ) {
10235 free(onlysel->contour_name);
10236 if ( *ret!='\0' )
10237 onlysel->contour_name = ret;
10238 else {
10239 onlysel->contour_name = NULL;
10240 free(ret);
10241 }
10242 CVCharChangedUpdate(&cv->b);
10243 }
10244 }
10245 }
10246
CVMenuNameContour(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))10247 static void CVMenuNameContour(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
10248 CharView *cv = (CharView *) GDrawGetUserData(gw);
10249 _CVMenuNameContour(cv);
10250 }
10251
10252 struct insertonsplineat {
10253 int done;
10254 GWindow gw;
10255 Spline *s;
10256 CharView *cv;
10257 };
10258
10259 #define CID_X 1001
10260 #define CID_Y 1002
10261 #define CID_XR 1003
10262 #define CID_YR 1004
10263
IOSA_OK(GGadget * g,GEvent * e)10264 static int IOSA_OK(GGadget *g, GEvent *e) {
10265
10266 if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
10267 int err = false;
10268 struct insertonsplineat *iosa = GDrawGetUserData(GGadgetGetWindow(g));
10269 double val;
10270 extended ts[3];
10271 int which;
10272 SplinePoint *sp;
10273
10274 if ( GGadgetIsChecked(GWidgetGetControl(iosa->gw,CID_XR)) ) {
10275 val = GetReal8(iosa->gw,CID_X,"X",&err);
10276 which = 0;
10277 } else {
10278 val = GetReal8(iosa->gw,CID_Y,"Y",&err);
10279 which = 1;
10280 }
10281 if ( err )
10282 return(true);
10283 if ( CubicSolve(&iosa->s->splines[which],val,ts)==0 ) {
10284 ff_post_error(_("Out of Range"),_("The spline does not reach %g"), (double) val );
10285 return( true );
10286 }
10287 iosa->done = true;
10288 CVPreserveState(&iosa->cv->b);
10289 for (;;) {
10290 sp = SplineBisect(iosa->s,ts[0]);
10291 SplinePointCategorize(sp);
10292 if ( which==0 ) {
10293 double off = val-sp->me.x;
10294 sp->me.x = val; sp->nextcp.x += off; sp->prevcp.x += off;
10295 } else {
10296 double off = val-sp->me.y;
10297 sp->me.y = val; sp->nextcp.y += off; sp->prevcp.y += off;
10298 }
10299 SplineRefigure(sp->prev); SplineRefigure(sp->next);
10300 if ( ts[1]==-1 ) {
10301 CVCharChangedUpdate(&iosa->cv->b);
10302 return( true );
10303 }
10304 iosa->s = sp->next;
10305 if ( CubicSolve(&iosa->s->splines[which],val,ts)==0 ) {
10306 /* Odd. We found one earlier */
10307 CVCharChangedUpdate(&iosa->cv->b);
10308 return( true );
10309 }
10310 }
10311 }
10312 return( true );
10313 }
10314
IOSA_Cancel(GGadget * g,GEvent * e)10315 static int IOSA_Cancel(GGadget *g, GEvent *e) {
10316 if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
10317 struct insertonsplineat *iosa = GDrawGetUserData(GGadgetGetWindow(g));
10318 iosa->done = true;
10319 }
10320 return( true );
10321 }
10322
IOSA_FocusChange(GGadget * g,GEvent * e)10323 static int IOSA_FocusChange(GGadget *g, GEvent *e) {
10324 if ( e->type==et_controlevent && e->u.control.subtype == et_textfocuschanged ) {
10325 struct insertonsplineat *iosa = GDrawGetUserData(GGadgetGetWindow(g));
10326 int cid = (intpt) GGadgetGetUserData(g);
10327 GGadgetSetChecked(GWidgetGetControl(iosa->gw,cid),true);
10328 }
10329 return( true );
10330 }
10331
IOSA_RadioChange(GGadget * g,GEvent * e)10332 static int IOSA_RadioChange(GGadget *g, GEvent *e) {
10333 if ( e->type==et_controlevent && e->u.control.subtype == et_radiochanged ) {
10334 struct insertonsplineat *iosa = GDrawGetUserData(GGadgetGetWindow(g));
10335 int cid = (intpt) GGadgetGetUserData(g);
10336 GWidgetIndicateFocusGadget(GWidgetGetControl(iosa->gw,cid));
10337 GTextFieldSelect(GWidgetGetControl(iosa->gw,cid),0,-1);
10338 }
10339 return( true );
10340 }
10341
iosa_e_h(GWindow gw,GEvent * event)10342 static int iosa_e_h(GWindow gw, GEvent *event) {
10343 if ( event->type==et_close ) {
10344 struct insertonsplineat *iosa = GDrawGetUserData(gw);
10345 iosa->done = true;
10346 } else if ( event->type == et_char ) {
10347 return( false );
10348 } else if ( event->type == et_map ) {
10349 /* Above palettes */
10350 GDrawRaise(gw);
10351 }
10352 return( true );
10353 }
10354
_CVMenuInsertPt(CharView * cv)10355 void _CVMenuInsertPt(CharView *cv) {
10356 SplineSet *spl;
10357 Spline *s, *found=NULL, *first;
10358 struct insertonsplineat iosa;
10359 GRect pos;
10360 GWindowAttrs wattrs;
10361 GGadgetCreateData gcd[11], boxes[2], topbox[2], *hvs[13], *varray[8], *buttons[6];
10362 GTextInfo label[11];
10363
10364 for ( spl = cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL; spl = spl->next ) {
10365 first = NULL;
10366 for ( s=spl->first->next; s!=NULL && s!=first ; s = s->to->next ) {
10367 if ( first==NULL ) first=s;
10368 if ( s->from->selected && s->to->selected ) {
10369 if ( found!=NULL )
10370 return; /* Can only work with one spline */
10371 found = s;
10372 }
10373 }
10374 }
10375 if ( found==NULL )
10376 return; /* Need a spline */
10377
10378 memset(&iosa,0,sizeof(iosa));
10379 iosa.s = found;
10380 iosa.cv = cv;
10381 memset(&wattrs,0,sizeof(wattrs));
10382 wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict;
10383 wattrs.event_masks = ~(1<<et_charup);
10384 wattrs.restrict_input_to_me = 1;
10385 wattrs.undercursor = 1;
10386 wattrs.cursor = ct_pointer;
10387 wattrs.utf8_window_title = _("Insert a point on the given spline at either...");
10388 wattrs.is_dlg = true;
10389 pos.x = pos.y = 0;
10390 pos.width = GGadgetScale(GDrawPointsToPixels(NULL,210));
10391 pos.height = GDrawPointsToPixels(NULL,120);
10392 iosa.gw = GDrawCreateTopWindow(NULL,&pos,iosa_e_h,&iosa,&wattrs);
10393
10394 memset(&label,0,sizeof(label));
10395 memset(&gcd,0,sizeof(gcd));
10396
10397 label[0].text = (unichar_t *) _("_X:");
10398 label[0].text_is_1byte = true;
10399 label[0].text_in_resource = true;
10400 gcd[0].gd.label = &label[0];
10401 gcd[0].gd.pos.x = 5; gcd[0].gd.pos.y = 5;
10402 gcd[0].gd.flags = gg_enabled|gg_visible|gg_cb_on;
10403 gcd[0].gd.cid = CID_XR;
10404 gcd[0].gd.handle_controlevent = IOSA_RadioChange;
10405 gcd[0].data = (void *) CID_X;
10406 gcd[0].creator = GRadioCreate;
10407
10408 label[1].text = (unichar_t *) _("_Y:");
10409 label[1].text_is_1byte = true;
10410 label[1].text_in_resource = true;
10411 gcd[1].gd.label = &label[1];
10412 gcd[1].gd.pos.x = 5; gcd[1].gd.pos.y = 32;
10413 gcd[1].gd.flags = gg_enabled|gg_visible|gg_rad_continueold ;
10414 gcd[1].gd.cid = CID_YR;
10415 gcd[1].gd.handle_controlevent = IOSA_RadioChange;
10416 gcd[1].data = (void *) CID_Y;
10417 gcd[1].creator = GRadioCreate;
10418
10419 gcd[2].gd.pos.x = 131; gcd[2].gd.pos.y = 5; gcd[2].gd.pos.width = 60;
10420 gcd[2].gd.flags = gg_enabled|gg_visible;
10421 gcd[2].gd.cid = CID_X;
10422 gcd[2].gd.handle_controlevent = IOSA_FocusChange;
10423 gcd[2].data = (void *) CID_XR;
10424 gcd[2].creator = GTextFieldCreate;
10425
10426 gcd[3].gd.pos.x = 131; gcd[3].gd.pos.y = 32; gcd[3].gd.pos.width = 60;
10427 gcd[3].gd.flags = gg_enabled|gg_visible;
10428 gcd[3].gd.cid = CID_Y;
10429 gcd[3].gd.handle_controlevent = IOSA_FocusChange;
10430 gcd[3].data = (void *) CID_YR;
10431 gcd[3].creator = GTextFieldCreate;
10432
10433 gcd[4].gd.pos.x = 20-3; gcd[4].gd.pos.y = 120-32-3;
10434 gcd[4].gd.pos.width = -1; gcd[4].gd.pos.height = 0;
10435 gcd[4].gd.flags = gg_visible | gg_enabled | gg_but_default;
10436 label[4].text = (unichar_t *) _("_OK");
10437 label[4].text_is_1byte = true;
10438 label[4].text_in_resource = true;
10439 gcd[4].gd.mnemonic = 'O';
10440 gcd[4].gd.label = &label[4];
10441 gcd[4].gd.handle_controlevent = IOSA_OK;
10442 gcd[4].creator = GButtonCreate;
10443
10444 gcd[5].gd.pos.x = -20; gcd[5].gd.pos.y = 120-32;
10445 gcd[5].gd.pos.width = -1; gcd[5].gd.pos.height = 0;
10446 gcd[5].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
10447 label[5].text = (unichar_t *) _("_Cancel");
10448 label[5].text_is_1byte = true;
10449 label[5].text_in_resource = true;
10450 gcd[5].gd.label = &label[5];
10451 gcd[5].gd.mnemonic = 'C';
10452 gcd[5].gd.handle_controlevent = IOSA_Cancel;
10453 gcd[5].creator = GButtonCreate;
10454
10455 hvs[0] = &gcd[0]; hvs[1] = &gcd[2]; hvs[2] = NULL;
10456 hvs[3] = &gcd[1]; hvs[4] = &gcd[3]; hvs[5] = NULL;
10457 hvs[6] = NULL;
10458
10459 buttons[0] = buttons[2] = buttons[4] = GCD_Glue; buttons[5] = NULL;
10460 buttons[1] = &gcd[4]; buttons[3] = &gcd[5];
10461
10462 varray[0] = &boxes[1]; varray[1] = NULL;
10463 varray[2] = GCD_Glue; varray[3] = NULL;
10464 varray[4] = &boxes[0]; varray[5] = NULL;
10465 varray[6] = NULL;
10466
10467 memset(boxes,0,sizeof(boxes));
10468 boxes[0].gd.flags = gg_enabled|gg_visible;
10469 boxes[0].gd.u.boxelements = buttons;
10470 boxes[0].creator = GHBoxCreate;
10471
10472 boxes[1].gd.flags = gg_enabled|gg_visible;
10473 boxes[1].gd.u.boxelements = hvs;
10474 boxes[1].creator = GHVBoxCreate;
10475
10476 memset(topbox,0,sizeof(topbox));
10477 topbox[0].gd.pos.x = topbox[0].gd.pos.y = 2;
10478 topbox[0].gd.pos.width = pos.width-4; topbox[0].gd.pos.height = pos.height-4;
10479 topbox[0].gd.flags = gg_enabled|gg_visible;
10480 topbox[0].gd.u.boxelements = varray;
10481 topbox[0].creator = GHVGroupCreate;
10482
10483
10484 GGadgetsCreate(iosa.gw,topbox);
10485 GHVBoxSetExpandableRow(topbox[0].ret,1);
10486 GHVBoxSetExpandableCol(boxes[0].ret,gb_expandgluesame);
10487 GHVBoxSetExpandableCol(boxes[1].ret,1);
10488 GWidgetIndicateFocusGadget(GWidgetGetControl(iosa.gw,CID_X));
10489 GTextFieldSelect(GWidgetGetControl(iosa.gw,CID_X),0,-1);
10490 GHVBoxFitWindow(topbox[0].ret);
10491
10492 GDrawSetVisible(iosa.gw,true);
10493 while ( !iosa.done )
10494 GDrawProcessOneEvent(NULL);
10495 GDrawDestroyWindow(iosa.gw);
10496 }
10497
CVMenuInsertPt(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))10498 static void CVMenuInsertPt(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
10499 CharView *cv = (CharView *) GDrawGetUserData(gw);
10500 _CVMenuInsertPt(cv);
10501 }
10502
_CVCenterCP(CharView * cv)10503 static void _CVCenterCP(CharView *cv) {
10504 SplinePointList *spl;
10505 SplinePoint *sp;
10506 int changed = false;
10507 enum movething { mt_pt, mt_ncp, mt_pcp } movething = mt_pt;
10508
10509 for ( spl = cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL; spl = spl->next ) {
10510 for ( sp=spl->first; ; ) {
10511 if ( sp->selected && sp->prev!=NULL && sp->next!=NULL &&
10512 !sp->noprevcp && !sp->nonextcp ) {
10513 if ( sp->me.x != (sp->nextcp.x+sp->prevcp.x)/2 ||
10514 sp->me.y != (sp->nextcp.y+sp->prevcp.y)/2 ) {
10515 if ( !changed ) {
10516 CVPreserveState(&cv->b);
10517 changed = true;
10518 }
10519 switch ( movething ) {
10520 case mt_pt:
10521 sp->me.x = (sp->nextcp.x+sp->prevcp.x)/2;
10522 sp->me.y = (sp->nextcp.y+sp->prevcp.y)/2;
10523 SplineRefigure(sp->prev);
10524 SplineRefigure(sp->next);
10525 break;
10526 case mt_ncp:
10527 sp->nextcp.x = sp->me.x - (sp->prevcp.x-sp->me.x);
10528 sp->nextcp.y = sp->me.y - (sp->prevcp.y-sp->me.y);
10529 if ( sp->next->order2 ) {
10530 sp->next->to->prevcp = sp->nextcp;
10531 sp->next->to->noprevcp = false;
10532 }
10533 SplineRefigure(sp->prev);
10534 SplineRefigureFixup(sp->next);
10535 break;
10536 case mt_pcp:
10537 sp->prevcp.x = sp->me.x - (sp->nextcp.x-sp->me.x);
10538 sp->prevcp.y = sp->me.y - (sp->nextcp.y-sp->me.y);
10539 if ( sp->prev->order2 ) {
10540 sp->prev->from->nextcp = sp->prevcp;
10541 sp->prev->from->nonextcp = false;
10542 }
10543 SplineRefigureFixup(sp->prev);
10544 SplineRefigure(sp->next);
10545 break;
10546 }
10547 }
10548 }
10549 if ( sp->next==NULL )
10550 break;
10551 sp = sp->next->to;
10552 if ( sp==spl->first )
10553 break;
10554 }
10555 }
10556
10557 if ( changed )
10558 CVCharChangedUpdate(&cv->b);
10559 }
10560
CVMenuCenterCP(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))10561 static void CVMenuCenterCP(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
10562 CharView *cv = (CharView *) GDrawGetUserData(gw);
10563 _CVCenterCP(cv);
10564 }
10565
CVMakeClipPath(CharView * cv)10566 void CVMakeClipPath(CharView *cv) {
10567 SplineSet *ss;
10568 SplinePoint *sp;
10569 int sel;
10570 int changed=false;
10571
10572 for ( ss=cv->b.layerheads[cv->b.drawmode]->splines; ss!=NULL; ss=ss->next ) {
10573 sel = false;
10574 for ( sp=ss->first; ; ) {
10575 if ( sp->selected ) {
10576 sel = true;
10577 break;
10578 }
10579 if ( sp->next==NULL )
10580 break;
10581 sp = sp->next->to;
10582 if ( sp==ss->first )
10583 break;
10584 }
10585 if ( sel!=ss->is_clip_path ) {
10586 if ( !changed )
10587 CVPreserveState((CharViewBase *) cv);
10588 changed = true;
10589 ss->is_clip_path = sel;
10590 }
10591 }
10592 if ( changed )
10593 CVCharChangedUpdate((CharViewBase *) cv);
10594 }
10595
CVMenuClipPath(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))10596 static void CVMenuClipPath(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
10597 CharView *cv = (CharView *) GDrawGetUserData(gw);
10598 CVMakeClipPath(cv);
10599 }
10600
CVAddAnchor(CharView * cv)10601 void CVAddAnchor(CharView *cv) {
10602 int waslig;
10603
10604 if ( AnchorClassUnused(cv->b.sc,&waslig)==NULL ) {
10605 SplineFont *sf = cv->b.sc->parent;
10606 AnchorClass *ac;
10607 GTextInfo **ti;
10608 int j;
10609 char *name = gwwv_ask_string(_("Anchor Class Name"),"",_("Please enter the name of a Anchor point class to create"));
10610 if ( name==NULL )
10611 return;
10612 ac = SFFindOrAddAnchorClass(sf,name,NULL);
10613 free(name);
10614 if ( AnchorClassUnused(cv->b.sc,&waslig)==NULL )
10615 return;
10616 }
10617 ApGetInfo(cv,NULL);
10618 }
10619
CVMenuAddAnchor(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))10620 static void CVMenuAddAnchor(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
10621 CharView *cv = (CharView *) GDrawGetUserData(gw);
10622 CVAddAnchor(cv);
10623 }
10624
CVMenuAutotrace(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * e)10625 static void CVMenuAutotrace(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *e) {
10626 CharView *cv = (CharView *) GDrawGetUserData(gw);
10627 GCursor ct;
10628
10629 ct = GDrawGetCursor(cv->v);
10630 GDrawSetCursor(cv->v,ct_watch);
10631 ff_progress_allow_events();
10632 SCAutoTrace(cv->b.sc,CVLayer((CharViewBase *) cv),e!=NULL && (e->u.mouse.state&ksm_shift));
10633 GDrawSetCursor(cv->v,ct);
10634 }
10635
CVMenuBuildAccent(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))10636 static void CVMenuBuildAccent(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
10637 CharView *cv = (CharView *) GDrawGetUserData(gw);
10638 extern int onlycopydisplayed;
10639 int layer = CVLayer((CharViewBase *) cv);
10640
10641 if ( SFIsRotatable(cv->b.fv->sf,cv->b.sc))
10642 /* It's ok */;
10643 else if ( !SFIsSomethingBuildable(cv->b.fv->sf,cv->b.sc,layer,true) )
10644 return;
10645 SCBuildComposit(cv->b.fv->sf,cv->b.sc,layer,NULL,onlycopydisplayed,true);
10646 }
10647
CVMenuBuildComposite(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))10648 static void CVMenuBuildComposite(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
10649 CharView *cv = (CharView *) GDrawGetUserData(gw);
10650 extern int onlycopydisplayed;
10651 int layer = CVLayer((CharViewBase *) cv);
10652
10653 if ( SFIsRotatable(cv->b.fv->sf,cv->b.sc))
10654 /* It's ok */;
10655 else if ( !SFIsCompositBuildable(cv->b.fv->sf,cv->b.sc->unicodeenc,cv->b.sc,layer) )
10656 return;
10657 SCBuildComposit(cv->b.fv->sf,cv->b.sc,layer,NULL,onlycopydisplayed,false);
10658 }
10659
CVMenuReverseDir(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))10660 static void CVMenuReverseDir(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
10661 CharView *cv = (CharView *) GDrawGetUserData(gw);
10662 int changed=false;
10663 SplineSet *ss;
10664
10665 for ( ss = cv->b.layerheads[cv->b.drawmode]->splines; ss!=NULL; ss=ss->next )
10666 if ( PointListIsSelected(ss)) {
10667 if ( !changed ) {
10668 CVPreserveState(&cv->b);
10669 cv->lastselpt = NULL; cv->lastselcp = NULL;
10670 changed = true;
10671 }
10672 SplineSetReverse(ss);
10673 }
10674
10675 if ( changed )
10676 CVCharChangedUpdate(&cv->b);
10677 }
10678
CVMenuCorrectDir(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))10679 static void CVMenuCorrectDir(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
10680 CharView *cv = (CharView *) GDrawGetUserData(gw);
10681 int changed=false, refchanged=false;
10682 RefChar *ref;
10683 int asked=-1;
10684 int layer = CVLayer( (CharViewBase *) cv);
10685
10686 for ( ref=cv->b.sc->layers[layer].refs; ref!=NULL; ref=ref->next ) {
10687 if ( ref->transform[0]*ref->transform[3]<0 ||
10688 (ref->transform[0]==0 && ref->transform[1]*ref->transform[2]>0)) {
10689 if ( asked==-1 ) {
10690 char *buts[4];
10691 buts[0] = _("_Unlink");
10692 buts[1] = _("_No");
10693 buts[2] = _("_Cancel");
10694 buts[3] = NULL;
10695 asked = gwwv_ask(_("Flipped Reference"),(const char **) buts,0,2,_("%.50s contains a flipped reference. This cannot be corrected as is. Would you like me to unlink it and then correct it?"), cv->b.sc->name );
10696 if ( asked==2 )
10697 return;
10698 else if ( asked==1 )
10699 break;
10700 }
10701 if ( asked==0 ) {
10702 if ( !refchanged ) {
10703 refchanged = true;
10704 CVPreserveState(&cv->b);
10705 }
10706 SCRefToSplines(cv->b.sc,ref,layer);
10707 }
10708 }
10709 }
10710
10711 if ( !refchanged )
10712 CVPreserveState(&cv->b);
10713
10714 cv->b.layerheads[cv->b.drawmode]->splines = SplineSetsCorrect(cv->b.layerheads[cv->b.drawmode]->splines,&changed);
10715 if ( changed || refchanged )
10716 CVCharChangedUpdate(&cv->b);
10717 }
10718
CVMenuInsertText(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))10719 static void CVMenuInsertText(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
10720 CharView *cv = (CharView *) GDrawGetUserData(gw);
10721 InsertTextDlg(cv);
10722 }
10723
CVMenuGetInfo(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))10724 static void CVMenuGetInfo(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
10725 CharView *cv = (CharView *) GDrawGetUserData(gw);
10726 CVGetInfo(cv);
10727 }
10728
CVMenuCharInfo(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))10729 static void CVMenuCharInfo(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
10730 CharView *cv = (CharView *) GDrawGetUserData(gw);
10731 SCCharInfo(cv->b.sc,CVLayer((CharViewBase *) cv),cv->b.fv->map,CVCurEnc(cv));
10732 }
10733
CVMenuShowDependentRefs(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))10734 static void CVMenuShowDependentRefs(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
10735 CharView *cv = (CharView *) GDrawGetUserData(gw);
10736 SCRefBy(cv->b.sc);
10737 }
10738
CVMenuShowDependentSubs(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))10739 static void CVMenuShowDependentSubs(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
10740 CharView *cv = (CharView *) GDrawGetUserData(gw);
10741 SCSubBy(cv->b.sc);
10742 }
10743
CVMenuBitmaps(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))10744 static void CVMenuBitmaps(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
10745 CharView *cv = (CharView *) GDrawGetUserData(gw);
10746 BitmapDlg((FontView *) (cv->b.fv),cv->b.sc,mi->mid==MID_RemoveBitmaps?-1: (mi->mid==MID_AvailBitmaps) );
10747 }
10748
cv_allistcheck(CharView * cv,struct gmenuitem * mi)10749 static void cv_allistcheck(CharView *cv, struct gmenuitem *mi) {
10750 int selpoints = 0;
10751 SplinePointList *spl;
10752 SplinePoint *sp=NULL;
10753
10754 for ( spl = cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL; spl = spl->next ) {
10755 sp=spl->first;
10756 while ( 1 ) {
10757 if ( sp->selected )
10758 ++selpoints;
10759 if ( sp->next==NULL )
10760 break;
10761 sp = sp->next->to;
10762 if ( sp==spl->first )
10763 break;
10764 }
10765 }
10766
10767 for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
10768 switch ( mi->mid ) {
10769 case MID_Average:
10770 mi->ti.disabled = selpoints<2;
10771 break;
10772 case MID_SpacePts:
10773 mi->ti.disabled = ((selpoints<3) && (selpoints!=1));
10774 break;
10775 case MID_SpaceRegion:
10776 mi->ti.disabled = selpoints<3;
10777 break;
10778 case MID_MakeParallel:
10779 mi->ti.disabled = selpoints!=4;
10780 break;
10781 }
10782 }
10783 }
10784
allistcheck(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))10785 static void allistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
10786 CharView *cv = (CharView *) GDrawGetUserData(gw);
10787 cv_allistcheck(cv, mi);
10788 }
10789
cv_balistcheck(CharView * cv,struct gmenuitem * mi)10790 static void cv_balistcheck(CharView *cv, struct gmenuitem *mi) {
10791 int layer = CVLayer((CharViewBase *) cv);
10792
10793 for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
10794 switch ( mi->mid ) {
10795 case MID_BuildAccent:
10796 mi->ti.disabled = !SFIsSomethingBuildable(cv->b.fv->sf,cv->b.sc,layer,true);
10797 break;
10798 case MID_BuildComposite:
10799 mi->ti.disabled = !SFIsSomethingBuildable(cv->b.fv->sf,cv->b.sc,layer,false);
10800 break;
10801 }
10802 }
10803 }
10804
balistcheck(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))10805 static void balistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
10806 CharView *cv = (CharView *) GDrawGetUserData(gw);
10807 cv_balistcheck(cv, mi);
10808 }
10809
delistcheck(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))10810 static void delistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
10811 CharView *cv = (CharView *) GDrawGetUserData(gw);
10812
10813 for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
10814 switch ( mi->mid ) {
10815 case MID_ShowDependentRefs:
10816 mi->ti.disabled = cv->b.sc->dependents==NULL;
10817 break;
10818 case MID_ShowDependentSubs:
10819 mi->ti.disabled = !SCUsedBySubs(cv->b.sc);
10820 break;
10821 }
10822 }
10823 }
10824
rndlistcheck(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))10825 static void rndlistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
10826 CharView *cv = (CharView *) GDrawGetUserData(gw);
10827
10828 for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
10829 switch ( mi->mid ) {
10830 case MID_RoundToCluster:
10831 mi->ti.disabled = cv->b.sc->inspiro && hasspiro();
10832 break;
10833 }
10834 }
10835 }
10836
cv_ellistcheck(CharView * cv,struct gmenuitem * mi)10837 static void cv_ellistcheck(CharView *cv, struct gmenuitem *mi) {
10838 int anypoints = 0, splinepoints, dir = -2;
10839 int self_intersects=-2;
10840 SplinePointList *spl;
10841 Spline *spline, *first;
10842 AnchorPoint *ap;
10843 spiro_cp *cp;
10844 int i;
10845
10846 #ifdef FONTFORGE_CONFIG_TILEPATH
10847 int badsel = false;
10848 RefChar *ref;
10849 ImageList *il;
10850
10851 for ( ref=cv->b.layerheads[cv->b.drawmode]->refs; ref!=NULL; ref=ref->next )
10852 if ( ref->selected )
10853 badsel = true;
10854
10855 for ( il=cv->b.layerheads[cv->b.drawmode]->images; il!=NULL; il=il->next )
10856 if ( il->selected )
10857 badsel = true;
10858 #endif
10859
10860 if ( cv->checkselfintersects ) {
10861 Spline *s, *s2;
10862 SplineSet *ss;
10863 ss = LayerAllSplines(cv->b.layerheads[cv->b.drawmode]);
10864 self_intersects = SplineSetIntersect(ss,&s,&s2);
10865 LayerUnAllSplines(cv->b.layerheads[cv->b.drawmode]);
10866 }
10867
10868 for ( spl = cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL; spl = spl->next ) {
10869 first = NULL;
10870 splinepoints = 0;
10871 if ( cv->b.sc->inspiro && hasspiro()) {
10872 for ( i=0; i<spl->spiro_cnt-1; ++i ) {
10873 if ( SPIRO_SELECTED(&spl->spiros[i])) {
10874 splinepoints = 1;
10875 break;
10876 }
10877 }
10878 } else {
10879 if ( spl->first->selected ) { splinepoints = 1; }
10880 for ( spline=spl->first->next; spline!=NULL && spline!=first && !splinepoints; spline = spline->to->next ) {
10881 if ( spline->to->selected ) { ++splinepoints; }
10882 if ( first == NULL ) first = spline;
10883 }
10884 }
10885 if ( splinepoints ) {
10886 anypoints += splinepoints;
10887 if ( dir==-1 )
10888 /* Do nothing */;
10889 else if ( spl->first!=spl->last || spl->first->next==NULL ) {
10890 if ( dir==-2 || dir==2 )
10891 dir = 2; /* Not a closed path, no direction */
10892 else
10893 dir = -1;
10894 } else if ( dir==-2 )
10895 dir = SplinePointListIsClockwise(spl);
10896 if ( dir==-1 )
10897 self_intersects = 1; /* Sometimes the clockwise test finds intersections the main routine can't */
10898 else {
10899 int subdir = SplinePointListIsClockwise(spl);
10900 if ( subdir==-1 )
10901 self_intersects = 1;
10902 if ( subdir!=dir )
10903 dir = -1;
10904 }
10905 }
10906 }
10907
10908 for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
10909 switch ( mi->mid ) {
10910 case MID_FontInfo: case MID_CharInfo: case MID_ShowDependentRefs:
10911 case MID_FindProblems:
10912 case MID_AvailBitmaps:
10913 mi->ti.disabled = cv->b.container!=NULL;
10914 break;
10915 case MID_GetInfo:
10916 {
10917 SplinePoint *sp; SplineSet *spl; RefChar *ref; ImageList *img;
10918 mi->ti.disabled = !CVOneThingSel(cv,&sp,&spl,&ref,&img,&ap,&cp);
10919 }
10920 break;
10921 case MID_CheckSelf:
10922 mi->ti.checked = cv->checkselfintersects;
10923 break;
10924 case MID_GlyphSelfIntersects:
10925 mi->ti.disabled = !cv->checkselfintersects;
10926 mi->ti.checked = self_intersects==1;
10927 break;
10928 case MID_Clockwise:
10929 mi->ti.disabled = !anypoints || dir==2 || dir<0;
10930 mi->ti.checked = dir==1;
10931 break;
10932 case MID_Counter:
10933 mi->ti.disabled = !anypoints || dir==2 || dir<0;
10934 mi->ti.checked = dir==0;
10935 break;
10936 case MID_Correct:
10937 mi->ti.disabled = (cv->b.layerheads[cv->b.drawmode]->splines==NULL && cv->b.layerheads[cv->b.drawmode]->refs==NULL) ||
10938 dir==2 || self_intersects==1;
10939 break;
10940 case MID_ReverseDir:
10941 mi->ti.disabled = !anypoints;
10942 break;
10943 case MID_Stroke:
10944 case MID_RmOverlap:
10945 case MID_Styles:
10946 mi->ti.disabled = cv->b.layerheads[cv->b.drawmode]->splines==NULL ||
10947 cv->b.container!=NULL;
10948 break;
10949 #ifdef FONTFORGE_CONFIG_TILEPATH
10950 case MID_TilePath:
10951 mi->ti.disabled = badsel;
10952 break;
10953 #endif
10954 case MID_RegenBitmaps: case MID_RemoveBitmaps:
10955 mi->ti.disabled = cv->b.fv->sf->bitmaps==NULL;
10956 break;
10957 case MID_AddExtrema:
10958 mi->ti.disabled = cv->b.layerheads[cv->b.drawmode]->splines==NULL || (cv->b.sc->inspiro && hasspiro());
10959 /* Like Simplify, always available, but may not do anything if */
10960 /* all extrema have points. I'm not going to check for that, too hard */
10961 break;
10962 case MID_Simplify:
10963 mi->ti.disabled = cv->b.layerheads[cv->b.drawmode]->splines==NULL || (cv->b.sc->inspiro && hasspiro());
10964 /* Simplify is always available (it may not do anything though) */
10965 /* well, ok. Disable it if there is absolutely nothing to work on */
10966 break;
10967 case MID_BuildAccent:
10968 mi->ti.disabled = !SFIsSomethingBuildable(cv->b.fv->sf,cv->b.sc,
10969 CVLayer((CharViewBase *) cv),false);
10970 break;
10971 case MID_Autotrace:
10972 mi->ti.disabled = FindAutoTraceName()==NULL || cv->b.sc->layers[ly_back].images==NULL;
10973 break;
10974 case MID_Align:
10975 mi->ti.disabled = cv->b.sc->inspiro && hasspiro();
10976 break;
10977 }
10978 }
10979 }
10980
ellistcheck(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))10981 static void ellistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
10982 CharView *cv = (CharView *) GDrawGetUserData(gw);
10983 cv_ellistcheck(cv, mi);
10984 }
10985
CVMenuAutoHint(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))10986 static void CVMenuAutoHint(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
10987 CharView *cv = (CharView *) GDrawGetUserData(gw);
10988 /*int removeOverlap = e==NULL || !(e->u.mouse.state&ksm_shift);*/
10989 int was = cv->b.sc->changedsincelasthinted;
10990
10991 /* Hint undoes are done in _SplineCharAutoHint */
10992 cv->b.sc->manualhints = false;
10993 SplineCharAutoHint(cv->b.sc,CVLayer((CharViewBase *) cv),NULL);
10994 SCUpdateAll(cv->b.sc);
10995 if ( was ) {
10996 FontView *fvs;
10997 for ( fvs=(FontView *) (cv->b.fv); fvs!=NULL; fvs=(FontView *) (fvs->b.nextsame) )
10998 GDrawRequestExpose(fvs->v,NULL,false); /* Clear any changedsincelasthinted marks */
10999 }
11000 }
11001
CVMenuAutoHintSubs(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))11002 static void CVMenuAutoHintSubs(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
11003 CharView *cv = (CharView *) GDrawGetUserData(gw);
11004 SCFigureHintMasks(cv->b.sc,CVLayer((CharViewBase *) cv));
11005 SCUpdateAll(cv->b.sc);
11006 }
11007
CVMenuAutoCounter(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))11008 static void CVMenuAutoCounter(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
11009 CharView *cv = (CharView *) GDrawGetUserData(gw);
11010 SCFigureCounterMasks(cv->b.sc);
11011 }
11012
CVMenuDontAutoHint(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))11013 static void CVMenuDontAutoHint(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
11014 CharView *cv = (CharView *) GDrawGetUserData(gw);
11015 cv->b.sc->manualhints = !cv->b.sc->manualhints;
11016 }
11017
CVMenuNowakAutoInstr(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))11018 static void CVMenuNowakAutoInstr(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
11019 CharView *cv = (CharView *) GDrawGetUserData(gw);
11020 SplineChar *sc = cv->b.sc;
11021 GlobalInstrCt gic;
11022
11023 if ( cv->b.layerheads[cv->b.drawmode]->splines!=NULL && sc->hstem==NULL && sc->vstem==NULL
11024 && sc->dstem==NULL && !no_windowing_ui )
11025 ff_post_notice(_("Things could be better..."), _("Glyph, %s, has no hints. FontForge will not produce many instructions."),
11026 sc->name );
11027
11028 InitGlobalInstrCt(&gic, sc->parent, CVLayer((CharViewBase *) cv), NULL);
11029 NowakowskiSCAutoInstr(&gic, sc);
11030 FreeGlobalInstrCt(&gic);
11031 SCUpdateAll(sc);
11032 }
11033
CVMenuClearHints(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))11034 static void CVMenuClearHints(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
11035 CharView *cv = (CharView *) GDrawGetUserData(gw);
11036
11037 SCPreserveHints(cv->b.sc,CVLayer((CharViewBase *) cv));
11038 SCHintsChanged(cv->b.sc);
11039 if ( mi->mid==MID_ClearHStem ) {
11040 StemInfosFree(cv->b.sc->hstem);
11041 cv->b.sc->hstem = NULL;
11042 cv->b.sc->hconflicts = false;
11043 } else if ( mi->mid==MID_ClearVStem ) {
11044 StemInfosFree(cv->b.sc->vstem);
11045 cv->b.sc->vstem = NULL;
11046 cv->b.sc->vconflicts = false;
11047 } else if ( mi->mid==MID_ClearDStem ) {
11048 DStemInfosFree(cv->b.sc->dstem);
11049 cv->b.sc->dstem = NULL;
11050 }
11051 cv->b.sc->manualhints = true;
11052
11053 if ( mi->mid != MID_ClearDStem ) {
11054 SCClearHintMasks(cv->b.sc,CVLayer((CharViewBase *) cv),true);
11055 }
11056 SCOutOfDateBackground(cv->b.sc);
11057 SCUpdateAll(cv->b.sc);
11058 }
11059
11060 /* This is an improved version of the older CVTwoForePointsSelected function. */
11061 /* Unlike the former, it doesn't just check if there are exactly two points */
11062 /* selected, but rather returns the number of selected points (whatever this */
11063 /* number can be) and puts references to those points into an array. It is up */
11064 /* to the calling code to see if the returned result is satisfiable (there */
11065 /* should be exactly two points selected for specifying a vertical or */
11066 /* horizontal stem and four points for a diagonal stem). */
CVNumForePointsSelected(CharView * cv,BasePoint ** bp)11067 static int CVNumForePointsSelected(CharView *cv, BasePoint **bp) {
11068 SplineSet *spl;
11069 SplinePoint *test, *first;
11070 BasePoint *bps[5];
11071 int i, cnt;
11072
11073 if ( cv->b.drawmode!=dm_fore )
11074 return( 0 ) ;
11075 cnt = 0;
11076 for ( spl = cv->b.sc->layers[ly_fore].splines; spl!=NULL; spl = spl->next ) {
11077 first = NULL;
11078 for ( test = spl->first; test!=first; test = test->next->to ) {
11079 if ( test->selected ) {
11080 bps[cnt++] = &(test->me);
11081 if ( cnt>4 )
11082 return( 0 );
11083 }
11084 if ( first == NULL ) first = test;
11085 if ( test->next==NULL )
11086 break;
11087 }
11088 }
11089 for (i=0; i<cnt; i++) {
11090 bp[i] = bps[i];
11091 }
11092 return( cnt );
11093 }
11094
CVMenuAddHint(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))11095 static void CVMenuAddHint(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
11096 CharView *cv = (CharView *) GDrawGetUserData(gw);
11097 BasePoint *bp[4], unit;
11098 StemInfo *h=NULL;
11099 DStemInfo *d;
11100 int num;
11101 int layer = CVLayer((CharViewBase *) cv);
11102
11103 num = CVNumForePointsSelected( cv,bp );
11104
11105 /* We need exactly 2 points to specify a horizontal or vertical stem */
11106 /* and exactly 4 points to specify a diagonal stem */
11107 if ( !(num == 2 && mi->mid != MID_AddDHint) &&
11108 !(num == 4 && mi->mid == MID_AddDHint))
11109 return;
11110
11111 SCPreserveHints(cv->b.sc,CVLayer((CharViewBase *) cv));
11112 SCHintsChanged(cv->b.sc);
11113 if ( mi->mid==MID_AddHHint ) {
11114 if ( bp[0]->y==bp[1]->y )
11115 return;
11116 h = chunkalloc(sizeof(StemInfo));
11117 if ( bp[1]->y>bp[0]->y ) {
11118 h->start = bp[0]->y;
11119 h->width = bp[1]->y-bp[0]->y;
11120 } else {
11121 h->start = bp[1]->y;
11122 h->width = bp[0]->y-bp[1]->y;
11123 }
11124 SCGuessHHintInstancesAndAdd(cv->b.sc,layer,h,bp[0]->x,bp[1]->x);
11125 cv->b.sc->hconflicts = StemListAnyConflicts(cv->b.sc->hstem);
11126 } else if ( mi->mid==MID_AddVHint ) {
11127 if ( bp[0]->x==bp[1]->x )
11128 return;
11129 h = chunkalloc(sizeof(StemInfo));
11130 if ( bp[1]->x>bp[0]->x ) {
11131 h->start = bp[0]->x;
11132 h->width = bp[1]->x-bp[0]->x;
11133 } else {
11134 h->start = bp[1]->x;
11135 h->width = bp[0]->x-bp[1]->x;
11136 }
11137 SCGuessVHintInstancesAndAdd(cv->b.sc,layer,h,bp[0]->y,bp[1]->y);
11138 cv->b.sc->vconflicts = StemListAnyConflicts(cv->b.sc->vstem);
11139 } else {
11140 if ( !PointsDiagonalable( cv->b.sc->parent,bp,&unit ))
11141 return;
11142 /* No additional tests, as the points should have already been */
11143 /* reordered by PointsDiagonalable */
11144 d = chunkalloc(sizeof(DStemInfo));
11145 d->where = NULL;
11146 d->left = *bp[0];
11147 d->right = *bp[1];
11148 d->unit = unit;
11149 SCGuessDHintInstances( cv->b.sc,layer,d );
11150 if ( d->where == NULL )
11151 DStemInfoFree( d );
11152 else
11153 MergeDStemInfo( cv->b.sc->parent,&cv->b.sc->dstem,d );
11154 }
11155 cv->b.sc->manualhints = true;
11156
11157 /* Hint Masks are not relevant for diagonal stems, so modifying */
11158 /* diagonal stems should not affect them */
11159 if ( (mi->mid==MID_AddVHint) || (mi->mid==MID_AddHHint) ) {
11160 if ( h!=NULL && cv->b.sc->parent->mm==NULL )
11161 SCModifyHintMasksAdd(cv->b.sc,layer,h);
11162 else
11163 SCClearHintMasks(cv->b.sc,layer,true);
11164 }
11165 SCOutOfDateBackground(cv->b.sc);
11166 SCUpdateAll(cv->b.sc);
11167 }
11168
CVMenuCreateHint(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))11169 static void CVMenuCreateHint(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
11170 CharView *cv = (CharView *) GDrawGetUserData(gw);
11171 CVCreateHint(cv,mi->mid==MID_CreateHHint,true);
11172 }
11173
CVMenuReviewHints(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))11174 static void CVMenuReviewHints(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
11175 CharView *cv = (CharView *) GDrawGetUserData(gw);
11176
11177 if ( cv->b.sc->hstem==NULL && cv->b.sc->vstem==NULL )
11178 return;
11179 CVReviewHints(cv);
11180 }
11181
htlistcheck(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))11182 static void htlistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
11183 CharView *cv = (CharView *) GDrawGetUserData(gw);
11184 int cvlayer = CVLayer((CharViewBase *) cv);
11185 BasePoint *bp[4], unit;
11186 int multilayer = cv->b.sc->parent->multilayer;
11187 int i=0, num = 0;
11188
11189 for (i=0; i<4; i++) {bp[i]=NULL;}
11190
11191 num = CVNumForePointsSelected(cv,bp);
11192
11193 for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
11194 switch ( mi->mid ) {
11195 case MID_AutoHint:
11196 mi->ti.disabled = cvlayer == ly_grid || multilayer;
11197 break;
11198 case MID_HintSubsPt:
11199 mi->ti.disabled = multilayer ||
11200 cv->b.layerheads[cv->b.drawmode]->order2 ||
11201 cvlayer == ly_grid;
11202 break;
11203 case MID_AutoCounter:
11204 mi->ti.disabled = multilayer;
11205 break;
11206 case MID_DontAutoHint:
11207 mi->ti.disabled = cv->b.layerheads[cv->b.drawmode]->order2 || multilayer;
11208 mi->ti.checked = cv->b.sc->manualhints;
11209 break;
11210 case MID_AutoInstr:
11211 case MID_EditInstructions:
11212 mi->ti.disabled = multilayer ||
11213 !cv->b.layerheads[cv->b.drawmode]->order2 ||
11214 cvlayer == ly_grid;
11215 break;
11216 case MID_Debug:
11217 mi->ti.disabled = multilayer ||
11218 !cv->b.layerheads[cv->b.drawmode]->order2 ||
11219 !hasFreeTypeDebugger();
11220 break;
11221 case MID_Deltas:
11222 mi->ti.disabled = multilayer ||
11223 !cv->b.layerheads[cv->b.drawmode]->order2 ||
11224 !hasFreeTypeDebugger();
11225 break;
11226 case MID_ClearHStem:
11227 case MID_ClearVStem:
11228 case MID_ClearDStem:
11229 mi->ti.disabled = cvlayer == ly_grid;
11230 break;
11231 case MID_ClearInstr:
11232 mi->ti.disabled = cv->b.sc->ttf_instrs_len==0;
11233 break;
11234 case MID_AddHHint:
11235 mi->ti.disabled = num != 2 || bp[1]->y==bp[0]->y || multilayer;
11236 break;
11237 case MID_AddVHint:
11238 mi->ti.disabled = num != 2 || bp[1]->x==bp[0]->x || multilayer;
11239 break;
11240 case MID_AddDHint:
11241 mi->ti.disabled = num != 4 || !PointsDiagonalable( cv->b.sc->parent,bp,&unit ) || multilayer;
11242 break;
11243 case MID_CreateHHint:
11244 case MID_CreateVHint:
11245 mi->ti.disabled = cvlayer == ly_grid;
11246 break;
11247 case MID_ReviewHints:
11248 mi->ti.disabled = (cv->b.sc->hstem==NULL && cv->b.sc->vstem==NULL ) || multilayer;
11249 break;
11250 }
11251 }
11252 }
11253
mtlistcheck(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))11254 static void mtlistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
11255 CharView *cv = (CharView *) GDrawGetUserData(gw);
11256 RefChar *r = HasUseMyMetrics(cv->b.sc,CVLayer((CharViewBase *) cv));
11257
11258 for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
11259 switch ( mi->mid ) {
11260 case MID_RemoveKerns:
11261 mi->ti.disabled = cv->b.sc->kerns==NULL;
11262 break;
11263 case MID_RemoveVKerns:
11264 mi->ti.disabled = cv->b.sc->vkerns==NULL;
11265 break;
11266 case MID_SetVWidth:
11267 mi->ti.disabled = !cv->b.sc->parent->hasvmetrics || r!=NULL;
11268 break;
11269 case MID_AnchorsAway:
11270 mi->ti.disabled = cv->b.sc->anchor==NULL;
11271 break;
11272 case MID_SetWidth: case MID_SetLBearing: case MID_SetRBearing: case MID_SetBearings:
11273 mi->ti.disabled = r!=NULL;
11274 break;
11275 }
11276 }
11277 }
11278
cv_sllistcheck(CharView * cv,struct gmenuitem * mi)11279 static void cv_sllistcheck(CharView *cv, struct gmenuitem *mi) {
11280 SplinePoint *sp; SplineSet *spl; RefChar *r; ImageList *im;
11281 spiro_cp *scp;
11282 SplineSet *test;
11283 int exactlyone = CVOneThingSel(cv,&sp,&spl,&r,&im,NULL,&scp);
11284
11285 for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
11286 switch ( mi->mid ) {
11287 case MID_NextCP: case MID_PrevCP:
11288 mi->ti.disabled = !exactlyone || sp==NULL || (cv->b.sc->inspiro && hasspiro());
11289 break;
11290 case MID_NextPt: case MID_PrevPt:
11291 case MID_FirstPtNextCont:
11292 mi->ti.disabled = !exactlyone || (sp==NULL && scp==NULL);
11293 break;
11294 case MID_FirstPt: case MID_SelPointAt:
11295 mi->ti.disabled = cv->b.layerheads[cv->b.drawmode]->splines==NULL;
11296 break;
11297 case MID_Contours:
11298 mi->ti.disabled = !CVAnySelPoints(cv);
11299 break;
11300 case MID_SelectOpenContours:
11301 mi->ti.disabled = true;
11302 for ( test=cv->b.layerheads[cv->b.drawmode]->splines; test!=NULL; test=test->next ) {
11303 if ( test->first->prev==NULL ) {
11304 mi->ti.disabled = false;
11305 break;
11306 }
11307 }
11308 break;
11309 case MID_SelectWidth:
11310 mi->ti.disabled = !cv->showhmetrics;
11311 if ( HasUseMyMetrics(cv->b.sc,CVLayer((CharViewBase *) cv))!=NULL )
11312 mi->ti.disabled = true;
11313 if ( !mi->ti.disabled ) {
11314 free(mi->ti.text);
11315 mi->ti.text = utf82u_copy(cv->widthsel?_("Deselect Width"):_("Width"));
11316 }
11317 break;
11318 case MID_SelectVWidth:
11319 mi->ti.disabled = !cv->showvmetrics || !cv->b.sc->parent->hasvmetrics;
11320 if ( HasUseMyMetrics(cv->b.sc,CVLayer((CharViewBase *) cv))!=NULL )
11321 mi->ti.disabled = true;
11322 if ( !mi->ti.disabled ) {
11323 free(mi->ti.text);
11324 mi->ti.text = utf82u_copy(cv->vwidthsel?_("Deselect VWidth"):_("VWidth"));
11325 }
11326 break;
11327 case MID_SelectHM:
11328 mi->ti.disabled = !exactlyone || sp==NULL || sp->hintmask==NULL;
11329 break;
11330 }
11331 }
11332 }
11333
sllistcheck(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))11334 static void sllistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
11335 CharView *cv = (CharView *) GDrawGetUserData(gw);
11336 cv_sllistcheck(cv, mi);
11337 }
11338
cv_cblistcheck(CharView * cv,struct gmenuitem * mi)11339 static void cv_cblistcheck(CharView *cv, struct gmenuitem *mi) {
11340 int i;
11341 KernPair *kp;
11342 SplineChar *sc = cv->b.sc;
11343 SplineFont *sf = sc->parent;
11344 PST *pst;
11345 char *name;
11346
11347 for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
11348 switch ( mi->mid ) {
11349 case MID_AnchorPairs:
11350 mi->ti.disabled = sc->anchor==NULL;
11351 break;
11352 case MID_AnchorControl:
11353 mi->ti.disabled = sc->anchor==NULL;
11354 break;
11355 case MID_AnchorGlyph:
11356 if ( cv->apmine!=NULL )
11357 mi->ti.disabled = false;
11358 else
11359 mi->ti.disabled = sc->anchor==NULL;
11360 break;
11361 case MID_KernPairs:
11362 mi->ti.disabled = sc->kerns==NULL;
11363 if ( sc->kerns==NULL ) {
11364 for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
11365 for ( kp = sf->glyphs[i]->kerns; kp!=NULL; kp=kp->next ) {
11366 if ( kp->sc == sc ) {
11367 mi->ti.disabled = false;
11368 goto out;
11369 }
11370 }
11371 }
11372 out:;
11373 }
11374 break;
11375 case MID_Ligatures:
11376 name = sc->name;
11377 for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
11378 for ( pst=sf->glyphs[i]->possub; pst!=NULL; pst=pst->next ) {
11379 if ( pst->type==pst_ligature &&
11380 PSTContains(pst->u.lig.components,name)) {
11381 mi->ti.disabled = false;
11382 goto break_out_2;
11383 }
11384 }
11385 }
11386 mi->ti.disabled = true;
11387 break_out_2:;
11388 break;
11389 }
11390 }
11391 }
11392
cv_nplistcheck(CharView * cv,struct gmenuitem * mi)11393 static void cv_nplistcheck(CharView *cv, struct gmenuitem *mi) {
11394 SplineChar *sc = cv->b.sc;
11395 int order2 = cv->b.layerheads[cv->b.drawmode]->order2;
11396 int is_grid_layer = cv->b.drawmode == dm_grid;
11397
11398 for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
11399 switch ( mi->mid ) {
11400 case MID_PtsNone:
11401 mi->ti.disabled = !order2 || is_grid_layer;
11402 mi->ti.checked = (cv->showpointnumbers == 0);
11403 break;
11404 case MID_PtsTrue:
11405 mi->ti.disabled = !order2 || is_grid_layer;
11406 mi->ti.checked = cv->showpointnumbers && order2;
11407 break;
11408 case MID_PtsPost:
11409 mi->ti.disabled = order2 || is_grid_layer;
11410 mi->ti.checked = cv->showpointnumbers && !order2 && sc->numberpointsbackards;
11411 break;
11412 case MID_PtsSVG:
11413 mi->ti.disabled = order2 || is_grid_layer;
11414 mi->ti.checked = cv->showpointnumbers && !order2 && !sc->numberpointsbackards;
11415 break;
11416 case MID_PtsPos:
11417 mi->ti.disabled = is_grid_layer;
11418 mi->ti.checked = (cv->showpointnumbers == 2);
11419 }
11420 }
11421 }
11422
gflistcheck(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))11423 static void gflistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
11424 CharView *cv = (CharView *) GDrawGetUserData(gw);
11425
11426 for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
11427 switch ( mi->mid ) {
11428 case MID_ShowGridFit:
11429 mi->ti.disabled = !hasFreeType() || cv->dv!=NULL;
11430 mi->ti.checked = cv->show_ft_results;
11431 break;
11432 case MID_ShowGridFitLiveUpdate:
11433 mi->ti.disabled = !hasFreeType() || cv->dv!=NULL;
11434 mi->ti.checked = cv->show_ft_results_live_update;
11435 break;
11436 case MID_Bigger:
11437 mi->ti.disabled = !cv->show_ft_results;
11438 break;
11439 case MID_Smaller:
11440 mi->ti.disabled = !cv->show_ft_results || cv->ft_pointsizex<2 || cv->ft_pointsizey<2;
11441 break;
11442 case MID_GridFitAA:
11443 mi->ti.disabled = !cv->show_ft_results;
11444 mi->ti.checked = cv->ft_depth==8;
11445 break;
11446 case MID_GridFitOff:
11447 mi->ti.disabled = !cv->show_ft_results;
11448 break;
11449 }
11450 }
11451 }
11452
swlistcheck(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))11453 static void swlistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
11454 CharView *cv = (CharView *) GDrawGetUserData(gw);
11455 SplineFont *sf = cv->b.sc->parent;
11456
11457 for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
11458 switch ( mi->mid ) {
11459 case MID_MarkExtrema:
11460 mi->ti.checked = cv->markextrema;
11461 mi->ti.disabled = cv->b.sc->inspiro && hasspiro();
11462 break;
11463 case MID_MarkPointsOfInflection:
11464 mi->ti.checked = cv->markpoi;
11465 mi->ti.disabled = cv->b.sc->inspiro && hasspiro();
11466 break;
11467 case MID_ShowAlmostHV:
11468 mi->ti.checked = cv->showalmosthvlines;
11469 break;
11470 case MID_ShowAlmostHVCurves:
11471 mi->ti.checked = cv->showalmosthvcurves;
11472 break;
11473 case MID_DefineAlmost:
11474 mi->ti.disabled = !cv->showalmosthvlines && !cv->showalmosthvcurves;
11475 break;
11476 case MID_ShowCPInfo:
11477 mi->ti.checked = cv->showcpinfo;
11478 break;
11479 case MID_DraggingComparisonOutline:
11480 mi->ti.checked = prefs_create_dragging_comparison_outline;
11481 break;
11482 case MID_ShowSideBearings:
11483 mi->ti.checked = cv->showsidebearings;
11484 break;
11485 case MID_ShowRefNames:
11486 mi->ti.checked = cv->showrefnames;
11487 break;
11488 case MID_ShowTabs:
11489 mi->ti.checked = cv->showtabs;
11490 mi->ti.disabled = cv->former_cnt<=1;
11491 break;
11492 case MID_HidePoints:
11493 mi->ti.checked = cv->showpoints;
11494 break;
11495 case MID_HideControlPoints:
11496 mi->ti.checked = cv->alwaysshowcontrolpoints;
11497 break;
11498 case MID_HideRulers:
11499 mi->ti.checked = cv->showrulers;
11500 break;
11501 case MID_Fill:
11502 mi->ti.checked = cv->showfilled;
11503 break;
11504 case MID_ShowHHints:
11505 mi->ti.checked = cv->showhhints;
11506 mi->ti.disabled = sf->multilayer;
11507 break;
11508 case MID_ShowVHints:
11509 mi->ti.checked = cv->showvhints;
11510 mi->ti.disabled = sf->multilayer;
11511 break;
11512 case MID_ShowDHints:
11513 mi->ti.checked = cv->showdhints;
11514 mi->ti.disabled = sf->multilayer;
11515 break;
11516 case MID_ShowBlueValues:
11517 mi->ti.checked = cv->showblues;
11518 mi->ti.disabled = sf->multilayer;
11519 break;
11520 case MID_ShowFamilyBlues:
11521 mi->ti.checked = cv->showfamilyblues;
11522 mi->ti.disabled = sf->multilayer;
11523 break;
11524 case MID_ShowAnchors:
11525 mi->ti.checked = cv->showanchor;
11526 mi->ti.disabled = sf->multilayer;
11527 break;
11528 case MID_ShowHMetrics:
11529 mi->ti.checked = cv->showhmetrics;
11530 break;
11531 case MID_ShowVMetrics:
11532 mi->ti.checked = cv->showvmetrics;
11533 mi->ti.disabled = !sf->hasvmetrics;
11534 break;
11535 case MID_ShowDebugChanges:
11536 mi->ti.checked = cv->showdebugchanges;
11537 break;
11538 case MID_SnapOutlines:
11539 #ifndef _NO_LIBCAIRO
11540 if ( GDrawHasCairo(cv->v)&gc_alpha ) {
11541 mi->ti.checked = cv->snapoutlines;
11542 mi->ti.disabled = false;
11543 } else
11544 #endif
11545 {
11546 mi->ti.checked = true;
11547 mi->ti.disabled = true;
11548 }
11549 break;
11550 }
11551 }
11552 }
11553
cv_vwlistcheck(CharView * cv,struct gmenuitem * mi)11554 static void cv_vwlistcheck(CharView *cv, struct gmenuitem *mi) {
11555 int pos, gid;
11556 SplineFont *sf = cv->b.sc->parent;
11557 EncMap *map = cv->b.fv->map;
11558
11559 for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
11560 switch ( mi->mid ) {
11561 case MID_NextDef:
11562 if ( cv->b.container==NULL ) {
11563 for ( pos = CVCurEnc(cv)+1; pos<map->enccount && ((gid=map->map[pos])==-1 || !SCWorthOutputting(sf->glyphs[gid])); ++pos );
11564 mi->ti.disabled = pos==map->enccount;
11565 } else
11566 mi->ti.disabled = !(cv->b.container->funcs->canNavigate)(cv->b.container,nt_nextdef);
11567 break;
11568 case MID_PrevDef:
11569 if ( cv->b.container==NULL ) {
11570 for ( pos = CVCurEnc(cv)-1; pos>=0 && ((gid=map->map[pos])==-1 || !SCWorthOutputting(sf->glyphs[gid])); --pos );
11571 mi->ti.disabled = pos<0 || cv->b.container!=NULL;
11572 } else
11573 mi->ti.disabled = !(cv->b.container->funcs->canNavigate)(cv->b.container,nt_nextdef);
11574 break;
11575 case MID_Next:
11576 mi->ti.disabled = cv->b.container==NULL ? CVCurEnc(cv)==map->enccount-1 : !(cv->b.container->funcs->canNavigate)(cv->b.container,nt_nextdef);
11577 break;
11578 case MID_Prev:
11579 mi->ti.disabled = cv->b.container==NULL ? CVCurEnc(cv)==0 : !(cv->b.container->funcs->canNavigate)(cv->b.container,nt_nextdef);
11580 break;
11581 case MID_Former:
11582 if ( cv->former_cnt<=1 )
11583 pos = -1;
11584 else for ( pos = sf->glyphcnt-1; pos>=0 ; --pos )
11585 if ( sf->glyphs[pos]!=NULL && strcmp(sf->glyphs[pos]->name,cv->former_names[1])==0 )
11586 break;
11587 mi->ti.disabled = pos==-1 || cv->b.container!=NULL;
11588 break;
11589 case MID_Goto:
11590 mi->ti.disabled = cv->b.container!=NULL && !(cv->b.container->funcs->canNavigate)(cv->b.container,nt_goto);
11591 break;
11592 case MID_FindInFontView:
11593 mi->ti.disabled = cv->b.container!=NULL;
11594 break;
11595 #if HANYANG
11596 case MID_DisplayCompositions:
11597 mi->ti.disabled = !cv->b.sc->compositionunit || cv->b.sc->parent->rules==NULL;
11598 break;
11599 #endif
11600 }
11601 }
11602 }
11603
cblistcheck(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))11604 static void cblistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
11605 CharView *cv = (CharView *) GDrawGetUserData(gw);
11606 cv_cblistcheck(cv, mi);
11607 }
11608
nplistcheck(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))11609 static void nplistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
11610 CharView *cv = (CharView *) GDrawGetUserData(gw);
11611 cv_nplistcheck(cv, mi);
11612 }
11613
vwlistcheck(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))11614 static void vwlistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
11615 CharView *cv = (CharView *) GDrawGetUserData(gw);
11616 cv_vwlistcheck(cv, mi);
11617 }
11618
CVMenuCenter(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))11619 static void CVMenuCenter(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
11620 CharView *cv = (CharView *) GDrawGetUserData(gw);
11621 DBounds bb;
11622 real transform[6];
11623 int drawmode = cv->b.drawmode;
11624
11625 cv->b.drawmode = dm_fore;
11626
11627 memset(transform,0,sizeof(transform));
11628 transform[0] = transform[3] = 1.0;
11629 transform[1] = transform[2] = transform[5] = 0.0;
11630 if ( cv->b.sc->parent->italicangle==0 )
11631 SplineCharFindBounds(cv->b.sc,&bb);
11632 else {
11633 SplineSet *base, *temp;
11634 base = LayerAllSplines(cv->b.layerheads[cv->b.drawmode]);
11635 transform[2] = tan( cv->b.sc->parent->italicangle * FF_PI/180.0 );
11636 temp = SplinePointListTransform(SplinePointListCopy(base),transform,tpt_AllPoints);
11637 transform[2] = 0;
11638 LayerUnAllSplines(cv->b.layerheads[cv->b.drawmode]);
11639 SplineSetFindBounds(temp,&bb);
11640 SplinePointListsFree(temp);
11641 }
11642
11643 if ( mi->mid==MID_Center )
11644 transform[4] = (cv->b.sc->width-(bb.maxx-bb.minx))/2 - bb.minx;
11645 else
11646 transform[4] = (cv->b.sc->width-(bb.maxx-bb.minx))/3 - bb.minx;
11647 if ( transform[4]!=0 ) {
11648 cv->p.transany = false;
11649 CVPreserveState(&cv->b);
11650 CVTransFuncAllLayers(cv, transform, fvt_dontmovewidth );
11651 CVCharChangedUpdate(&cv->b);
11652 }
11653 cv->b.drawmode = drawmode;
11654 }
11655
CVMenuSetWidth(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))11656 static void CVMenuSetWidth(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
11657 CharView *cv = (CharView *) GDrawGetUserData(gw);
11658
11659 if ( mi->mid == MID_SetVWidth && !cv->b.sc->parent->hasvmetrics )
11660 return;
11661 CVSetWidth(cv,mi->mid==MID_SetWidth?wt_width:
11662 mi->mid==MID_SetLBearing?wt_lbearing:
11663 mi->mid==MID_SetRBearing?wt_rbearing:
11664 mi->mid==MID_SetBearings?wt_bearings:
11665 wt_vwidth);
11666 }
11667
CVMenuRemoveKern(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))11668 static void CVMenuRemoveKern(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
11669 CharView *cv = (CharView *) GDrawGetUserData(gw);
11670 SCRemoveKern(cv->b.sc);
11671 }
11672
CVMenuRemoveVKern(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))11673 static void CVMenuRemoveVKern(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
11674 CharView *cv = (CharView *) GDrawGetUserData(gw);
11675 SCRemoveVKern(cv->b.sc);
11676 }
11677
CVMenuKPCloseup(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))11678 static void CVMenuKPCloseup(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
11679 CharView *cv = (CharView *) GDrawGetUserData(gw);
11680 KernPairD(cv->b.sc->parent,cv->b.sc,NULL,CVLayer((CharViewBase *) cv),false);
11681 }
11682
CVMenuAnchorsAway(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))11683 static void CVMenuAnchorsAway(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
11684 CharView *cv = (CharView *) GDrawGetUserData(gw);
11685 AnchorPoint *ap;
11686
11687 ap = mi->ti.userdata;
11688 if ( ap==NULL )
11689 for ( ap = cv->b.sc->anchor; ap!=NULL && !ap->selected; ap = ap->next );
11690 if ( ap==NULL ) ap= cv->b.sc->anchor;
11691 if ( ap==NULL )
11692 return;
11693
11694 GDrawSetCursor(cv->v,ct_watch);
11695 GDrawSync(NULL);
11696 GDrawProcessPendingEvents(NULL);
11697 AnchorControl(cv->b.sc,ap,CVLayer((CharViewBase *) cv));
11698 GDrawSetCursor(cv->v,ct_pointer);
11699 }
11700
11701 static GMenuItem2 wnmenu[] = {
11702 { { (unichar_t *) N_("New O_utline Window"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 1, 0, 0, 0, 0, 0, 1, 1, 0, 'u' }, H_("New Outline Window|No Shortcut"), NULL, NULL, /* No function, never avail */NULL, 0 },
11703 { { (unichar_t *) N_("New _Bitmap Window"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'B' }, H_("New Bitmap Window|No Shortcut"), NULL, NULL, CVMenuOpenBitmap, MID_OpenBitmap },
11704 { { (unichar_t *) N_("New _Metrics Window"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'M' }, H_("New Metrics Window|No Shortcut"), NULL, NULL, CVMenuOpenMetrics, 0 },
11705 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11706 { { (unichar_t *) N_("Warnings"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'M' }, H_("Warnings|No Shortcut"), NULL, NULL, _MenuWarnings, MID_Warnings },
11707 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11708 GMENUITEM2_EMPTY
11709 };
11710
CVWindowMenuBuild(GWindow gw,struct gmenuitem * mi,GEvent * e)11711 static void CVWindowMenuBuild(GWindow gw, struct gmenuitem *mi, GEvent *e) {
11712 CharView *cv = (CharView *) GDrawGetUserData(gw);
11713 struct gmenuitem *wmi;
11714
11715 WindowMenuBuild(gw,mi,e);
11716 for ( wmi = mi->sub; wmi->ti.text!=NULL || wmi->ti.line ; ++wmi ) {
11717 switch ( wmi->mid ) {
11718 case MID_OpenBitmap:
11719 wmi->ti.disabled = cv->b.sc->parent->bitmaps==NULL;
11720 break;
11721 case MID_Warnings:
11722 wmi->ti.disabled = ErrorWindowExists();
11723 break;
11724 }
11725 }
11726 if ( cv->b.container!=NULL ) {
11727 int canopen = (cv->b.container->funcs->canOpen)(cv->b.container);
11728 if ( !canopen ) {
11729 for ( wmi = mi->sub; wmi->ti.text!=NULL || wmi->ti.line ; ++wmi ) {
11730 wmi->ti.disabled = true;
11731 }
11732 }
11733 }
11734 }
11735
11736 static GMenuItem2 dummyitem[] = {
11737 { { (unichar_t *) N_("Font|_New"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'N' }, NULL, NULL, NULL, NULL, 0 },
11738 GMENUITEM2_EMPTY
11739 };
11740 static GMenuItem2 fllist[] = {
11741 { { (unichar_t *) N_("Font|_New"), (GImage *) "filenew.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'N' }, H_("New|No Shortcut"), NULL, NULL, MenuNew, MID_New },
11742 { { (unichar_t *) N_("_Open"), (GImage *) "fileopen.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'O' }, H_("Open|No Shortcut"), NULL, NULL, CVMenuOpen, MID_Open },
11743 { { (unichar_t *) N_("Recen_t"), (GImage *) "filerecent.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 't' }, NULL, dummyitem, MenuRecentBuild, NULL, MID_Recent },
11744 { { (unichar_t *) N_("_Close"), (GImage *) "fileclose.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'C' }, H_("Close|No Shortcut"), NULL, NULL, CVMenuClose, MID_Close },
11745 { { (unichar_t *) N_("C_lose Tab"), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'C' }, H_("Close Tab|No Shortcut"), NULL, NULL, CVMenuCloseTab, MID_CloseTab },
11746 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11747 { { (unichar_t *) N_("_Save"), (GImage *) "filesave.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'S' }, H_("Save|No Shortcut"), NULL, NULL, CVMenuSave, 0 },
11748 { { (unichar_t *) N_("S_ave as..."), (GImage *) "filesaveas.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'a' }, H_("Save as...|No Shortcut"), NULL, NULL, CVMenuSaveAs, 0 },
11749 { { (unichar_t *) N_("_Generate Fonts..."), (GImage *) "filegenerate.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'G' }, H_("Generate Fonts...|No Shortcut"), NULL, NULL, CVMenuGenerate, 0 },
11750 { { (unichar_t *) N_("Generate Mac _Family..."), (GImage *) "filegeneratefamily.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'F' }, H_("Generate Mac Family...|No Shortcut"), NULL, NULL, CVMenuGenerateFamily, 0 },
11751 { { (unichar_t *) N_("Generate TTC..."), (GImage *) "filegeneratefamily.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'F' }, H_("Generate TTC...|No Shortcut"), NULL, NULL, CVMenuGenerateTTC, MID_GenerateTTC },
11752 { { (unichar_t *) N_("E_xport..."), (GImage *) "fileexport.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 't' }, H_("Export...|No Shortcut"), NULL, NULL, CVMenuExport, 0 },
11753 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11754 { { (unichar_t *) N_("_Import..."), (GImage *) "fileimport.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'I' }, H_("Import...|No Shortcut"), NULL, NULL, CVMenuImport, 0 },
11755 { { (unichar_t *) N_("_Revert File"), (GImage *) "filerevert.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'R' }, H_("Revert File|No Shortcut"), NULL, NULL, CVMenuRevert, MID_Revert },
11756 { { (unichar_t *) N_("Revert Gl_yph"), (GImage *) "filerevertglyph.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'R' }, H_("Revert Glyph|No Shortcut"), NULL, NULL, CVMenuRevertGlyph, MID_RevertGlyph },
11757 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11758 { { (unichar_t *) N_("Load Word List..."), (GImage *) 0, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'M' }, H_("Load Word List...|No Shortcut"), NULL, NULL, CVAddWordList, 0 },
11759 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11760 { { (unichar_t *) N_("_Print..."), (GImage *) "fileprint.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'P' }, H_("Print...|No Shortcut"), NULL, NULL, CVMenuPrint, 0 },
11761 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11762 #if !defined(_NO_PYTHON)
11763 { { (unichar_t *) N_("E_xecute Script..."), (GImage *) "python.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'x' }, H_("Execute Script...|No Shortcut"), NULL, NULL, CVMenuExecute, 0 },
11764 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11765 #endif
11766 { { (unichar_t *) N_("Pr_eferences..."), (GImage *) "fileprefs.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'e' }, H_("Preferences...|No Shortcut"), NULL, NULL, MenuPrefs, 0 },
11767 { { (unichar_t *) N_("_X Resource Editor..."), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'e' }, H_("X Resource Editor...|No Shortcut"), NULL, NULL, MenuXRes, 0 },
11768 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11769 { { (unichar_t *) N_("_Quit"), (GImage *) "filequit.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'Q' }, H_("Quit|No Shortcut"), NULL, NULL, MenuExit, MID_Quit },
11770 GMENUITEM2_EMPTY
11771 };
11772
11773 static GMenuItem2 sllist[] = {
11774 { { (unichar_t *) N_("Select _All"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'A' }, H_("Select All|No Shortcut"), NULL, NULL, CVSelectAll, MID_SelAll },
11775 { { (unichar_t *) N_("_Invert Selection"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'I' }, H_("Invert Selection|No Shortcut"), NULL, NULL, CVSelectInvert, MID_SelInvert },
11776 { { (unichar_t *) N_("_Deselect All"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'o' }, H_("Deselect All|Escape"), NULL, NULL, CVSelectNone, MID_SelNone },
11777 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11778 { { (unichar_t *) N_("_First Point"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'F' }, H_("First Point|No Shortcut"), NULL, NULL, CVMenuNextPrevPt, MID_FirstPt },
11779 { { (unichar_t *) N_("First P_oint, Next Contour"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'F' }, H_("First Point, Next Contour|No Shortcut"), NULL, NULL, CVMenuNextPrevPt, MID_FirstPtNextCont },
11780 { { (unichar_t *) N_("_Next Point"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'N' }, H_("Next Point|No Shortcut"), NULL, NULL, CVMenuNextPrevPt, MID_NextPt },
11781 { { (unichar_t *) N_("_Prev Point"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'P' }, H_("Prev Point|No Shortcut"), NULL, NULL, CVMenuNextPrevPt, MID_PrevPt },
11782 { { (unichar_t *) N_("Ne_xt Control Point"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'x' }, H_("Next Control Point|No Shortcut"), NULL, NULL, CVMenuNextPrevCPt, MID_NextCP },
11783 { { (unichar_t *) N_("P_rev Control Point"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'r' }, H_("Prev Control Point|No Shortcut"), NULL, NULL, CVMenuNextPrevCPt, MID_PrevCP },
11784 { { (unichar_t *) N_("Points on Selected _Contours"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'r' }, H_("Points on Selected Contours|No Shortcut"), NULL, NULL, CVMenuSelectContours, MID_Contours },
11785 { { (unichar_t *) N_("Point A_t"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'r' }, H_("Point At|No Shortcut"), NULL, NULL, CVMenuSelectPointAt, MID_SelPointAt },
11786 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11787 { { (unichar_t *) N_("Select All _Points & Refs"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'P' }, H_("Select All Points & Refs|No Shortcut"), NULL, NULL, CVSelectAll, MID_SelectAllPoints },
11788 { { (unichar_t *) N_("Select Open Contours"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'P' }, H_("Select Open Contours|No Shortcut"), NULL, NULL, CVSelectOpenContours, MID_SelectOpenContours },
11789 { { (unichar_t *) N_("Select Anc_hors"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'c' }, H_("Select Anchors|No Shortcut"), NULL, NULL, CVSelectAll, MID_SelectAnchors },
11790 { { (unichar_t *) N_("_Width"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Width|No Shortcut"), NULL, NULL, CVSelectWidth, MID_SelectWidth },
11791 { { (unichar_t *) N_("_VWidth"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("VWidth|No Shortcut"), NULL, NULL, CVSelectVWidth, MID_SelectVWidth },
11792 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11793 { { (unichar_t *) N_("Select Points Affected by HM"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'V' }, H_("Select Points Affected by HM|No Shortcut"), NULL, NULL, CVSelectHM, MID_SelectHM },
11794 GMENUITEM2_EMPTY
11795 };
11796
11797 static GMenuItem2 edlist[] = {
11798 { { (unichar_t *) N_("_Undo"), (GImage *) "editundo.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'U' }, H_("Undo|No Shortcut"), NULL, NULL, CVUndo, MID_Undo },
11799 { { (unichar_t *) N_("_Redo"), (GImage *) "editredo.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'R' }, H_("Redo|No Shortcut"), NULL, NULL, CVRedo, MID_Redo },
11800 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11801 { { (unichar_t *) N_("Cu_t"), (GImage *) "editcut.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 't' }, H_("Cut|No Shortcut"), NULL, NULL, CVCut, MID_Cut },
11802 { { (unichar_t *) N_("_Copy"), (GImage *) "editcopy.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'C' }, H_("Copy|No Shortcut"), NULL, NULL, CVCopy, MID_Copy },
11803 { { (unichar_t *) N_("C_opy Reference"), (GImage *) "editcopyref.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'o' }, H_("Copy Reference|No Shortcut"), NULL, NULL, CVCopyRef, MID_CopyRef },
11804 { { (unichar_t *) N_("Copy Loo_kup Data"), (GImage *) "editcopylookupdata.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'o' }, H_("Copy Lookup Data|No Shortcut"), NULL, NULL, CVCopyLookupData, MID_CopyLookupData },
11805 { { (unichar_t *) N_("Copy _Width"), (GImage *) "editcopywidth.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'W' }, H_("Copy Width|No Shortcut"), NULL, NULL, CVCopyWidth, MID_CopyWidth },
11806 { { (unichar_t *) N_("Co_py LBearing"), (GImage *) "editcopylbearing.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'p' }, H_("Copy LBearing|No Shortcut"), NULL, NULL, CVCopyWidth, MID_CopyLBearing },
11807 { { (unichar_t *) N_("Copy RBearin_g"), (GImage *) "editcopyrbearing.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'g' }, H_("Copy RBearing|No Shortcut"), NULL, NULL, CVCopyWidth, MID_CopyRBearing },
11808 { { (unichar_t *) N_("_Paste"), (GImage *) "editpaste.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'P' }, H_("Paste|No Shortcut"), NULL, NULL, CVPaste, MID_Paste },
11809 { { (unichar_t *) N_("C_hop"), (GImage *) "editclear.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'h' }, H_("Chop|Delete"), NULL, NULL, CVClear, MID_Clear },
11810 { { (unichar_t *) N_("Clear _Background"), (GImage *) "editclearback.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'B' }, H_("Clear Background|No Shortcut"), NULL, NULL, CVClearBackground, 0 },
11811 { { (unichar_t *) N_("points|_Merge"), (GImage *) "editmerge.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'M' }, H_("Merge|No Shortcut"), NULL, NULL, CVMerge, MID_Merge },
11812 { { (unichar_t *) N_("points|Merge to Line"), (GImage *) "editmergetoline.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'M' }, H_("Merge to Line|No Shortcut"), NULL, NULL, CVMergeToLine, MID_MergeToLine },
11813 /*{ { (unichar_t *) N_("_Elide"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'M' }, H_("Elide|No Shortcut"), NULL, NULL, CVElide, MID_Elide },*/
11814 { { (unichar_t *) N_("_Join"), (GImage *) "editjoin.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'J' }, H_("Join|No Shortcut"), NULL, NULL, CVJoin, MID_Join },
11815 { { (unichar_t *) N_("Copy _Fg To Bg"), (GImage *) "editcopyfg2bg.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'F' }, H_("Copy Fg To Bg|No Shortcut"), NULL, NULL, CVCopyFgBg, MID_CopyFgToBg },
11816 { { (unichar_t *) N_("Cop_y Layer To Layer..."), (GImage *) "editcopylayer2layer.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'F' }, H_("Copy Layer To Layer...|No Shortcut"), NULL, NULL, CVMenuCopyL2L, MID_CopyBgToFg },
11817 { { (unichar_t *) N_("Copy Gri_d Fit"), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Copy Grid Fit|No Shortcut"), NULL, NULL, CVMenuCopyGridFit, MID_CopyGridFit },
11818 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11819 { { (unichar_t *) N_("_Select"), (GImage *) "editselect.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'S' }, H_("Select|No Shortcut"), sllist, sllistcheck, NULL, 0 },
11820 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11821 { { (unichar_t *) N_("U_nlink Reference"), (GImage *) "editunlink.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'U' }, H_("Unlink Reference|No Shortcut"), NULL, NULL, CVUnlinkRef, MID_UnlinkRef },
11822 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11823 { { (unichar_t *) N_("Remo_ve Undoes..."), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'e' }, H_("Remove Undoes...|No Shortcut"), NULL, NULL, CVRemoveUndoes, MID_RemoveUndoes },
11824 GMENUITEM2_EMPTY
11825 };
11826
11827 static GMenuItem2 ptlist[] = {
11828 { { (unichar_t *) N_("_Curve"), (GImage *) "pointscurve.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'C' }, H_("Curve|No Shortcut"), NULL, NULL, CVMenuPointType, MID_Curve },
11829 { { (unichar_t *) N_("_HVCurve"), (GImage *) "pointshvcurve.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'o' }, H_("HVCurve|No Shortcut"), NULL, NULL, CVMenuPointType, MID_HVCurve },
11830 { { (unichar_t *) N_("C_orner"), (GImage *) "pointscorner.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'o' }, H_("Corner|No Shortcut"), NULL, NULL, CVMenuPointType, MID_Corner },
11831 { { (unichar_t *) N_("_Tangent"), (GImage *) "pointstangent.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Tangent|No Shortcut"), NULL, NULL, CVMenuPointType, MID_Tangent },
11832 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11833 /* GT: Make this (selected) point the first point in the glyph */
11834 { { (unichar_t *) N_("_Make First"), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'M' }, H_("Make First|No Shortcut"), NULL, NULL, CVMenuMakeFirst, MID_MakeFirst },
11835 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11836 { { (unichar_t *) N_("Can Be _Interpolated"), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Can Be Interpolated|No Shortcut"), NULL, NULL, CVMenuImplicit, MID_ImplicitPt },
11837 { { (unichar_t *) N_("Can't _Be Interpolated"), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Can't Be Interpolated|No Shortcut"), NULL, NULL, CVMenuImplicit, MID_NoImplicitPt },
11838 { { (unichar_t *) N_("Center Bet_ween Control Points"), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'M' }, H_("Center Between Control Points|No Shortcut"), NULL, NULL, CVMenuCenterCP, MID_CenterCP },
11839 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11840 { { (unichar_t *) N_("_Add Anchor"), (GImage *) "pointsaddanchor.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'A' }, H_("Add Anchor|No Shortcut"), NULL, NULL, CVMenuAddAnchor, MID_AddAnchor },
11841 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11842 { { (unichar_t *) N_("Acceptable _Extrema"), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'C' }, H_("Acceptable Extrema|No Shortcut"), NULL, NULL, CVMenuAcceptableExtrema, MID_AcceptableExtrema },
11843 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11844 { { (unichar_t *) N_("Make _Line"), (GImage *) "pointsmakeline.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'M' }, H_("Make Line|No Shortcut"), NULL, NULL, CVMenuMakeLine, MID_MakeLine },
11845 { { (unichar_t *) N_("Ma_ke Arc"), (GImage *) "pointsmakearc.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'M' }, H_("Make Arc|No Shortcut"), NULL, NULL, CVMenuMakeLine, MID_MakeArc },
11846 { { (unichar_t *) N_("Inse_rt Point On Spline At..."), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'M' }, H_("Insert Point On Spline At...|No Shortcut"), NULL, NULL, CVMenuInsertPt, MID_InsertPtOnSplineAt },
11847 { { (unichar_t *) N_("_Name Point"), (GImage *) "pointsnamepoint.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'M' }, H_("Name Point|No Shortcut"), NULL, NULL, CVMenuNamePoint, MID_NamePoint },
11848 { { (unichar_t *) N_("_Name Contour"), (GImage *) "pointsnamecontour.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'M' }, H_("Name Contour|No Shortcut"), NULL, NULL, CVMenuNameContour, MID_NameContour },
11849 { { (unichar_t *) N_("Make Clip _Path"), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'M' }, H_("Make Clip Path|No Shortcut"), NULL, NULL, CVMenuClipPath, MID_ClipPath },
11850 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11851 { { (unichar_t *) N_("Tool_s"), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'M' }, H_("Tools|No Shortcut"), cvtoollist, cvtoollist_check, NULL, MID_Tools },
11852 GMENUITEM2_EMPTY
11853 };
11854
11855 static GMenuItem2 spiroptlist[] = {
11856 { { (unichar_t *) N_("G4 _Curve"), (GImage *) "pointscurve.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'C' }, H_("G4 Curve|No Shortcut"), NULL, NULL, CVMenuPointType, MID_SpiroG4 },
11857 { { (unichar_t *) N_("_G2 Curve"), (GImage *) "pointsG2curve.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'o' }, H_("G2 Curve|No Shortcut"), NULL, NULL, CVMenuPointType, MID_SpiroG2 },
11858 { { (unichar_t *) N_("C_orner"), (GImage *) "pointscorner.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'o' }, H_("Corner|No Shortcut"), NULL, NULL, CVMenuPointType, MID_SpiroCorner },
11859 { { (unichar_t *) N_("_Left Constraint"), (GImage *) "pointsspiroprev.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Left Constraint|No Shortcut"), NULL, NULL, CVMenuPointType, MID_SpiroLeft },
11860 { { (unichar_t *) N_("_Right Constraint"), (GImage *) "pointsspironext.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Right Constraint|No Shortcut"), NULL, NULL, CVMenuPointType, MID_SpiroRight },
11861 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11862 /* GT: Make this (selected) point the first point in the glyph */
11863 { { (unichar_t *) N_("_Make First"), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'M' }, H_("Make First|No Shortcut"), NULL, NULL, CVMenuSpiroMakeFirst, MID_SpiroMakeFirst },
11864 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11865 { { (unichar_t *) N_("_Add Anchor"), (GImage *) "pointsaddanchor.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'A' }, H_("Add Anchor|No Shortcut"), NULL, NULL, CVMenuAddAnchor, MID_AddAnchor },
11866 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11867 { { (unichar_t *) N_("_Name Point"), (GImage *) "pointsnamepoint.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'M' }, H_("Name Point|No Shortcut"), NULL, NULL, CVMenuNamePoint, MID_NamePoint },
11868 { { (unichar_t *) N_("_Name Contour"), (GImage *) "pointsnamecontour.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'M' }, H_("Name Contour|No Shortcut"), NULL, NULL, CVMenuNameContour, MID_NameContour },
11869 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11870 { { (unichar_t *) N_("Tool_s"), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'M' }, NULL, cvspirotoollist, cvtoollist_check, NULL, MID_Tools },
11871 GMENUITEM2_EMPTY
11872 };
11873
11874 static GMenuItem2 allist[] = {
11875 /* GT: Align these points to their average position */
11876 { { (unichar_t *) N_("_Align Points"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'A' }, H_("Align Points|No Shortcut"), NULL, NULL, CVMenuConstrain, MID_Average },
11877 { { (unichar_t *) N_("_Space Points"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'S' }, H_("Space Points|No Shortcut"), NULL, NULL, CVMenuConstrain, MID_SpacePts },
11878 { { (unichar_t *) N_("Space _Regions..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'R' }, H_("Space Regions...|No Shortcut"), NULL, NULL, CVMenuConstrain, MID_SpaceRegion },
11879 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11880 { { (unichar_t *) N_("Make _Parallel..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'P' }, H_("Make Parallel...|No Shortcut"), NULL, NULL, CVMenuMakeParallel, MID_MakeParallel },
11881 GMENUITEM2_EMPTY
11882 };
11883
11884 static GMenuItem2 smlist[] = {
11885 { { (unichar_t *) N_("_Simplify"), (GImage *) "elementsimplify.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'S' }, H_("Simplify|No Shortcut"), NULL, NULL, CVMenuSimplify, MID_Simplify },
11886 { { (unichar_t *) N_("Simplify More..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'M' }, H_("Simplify More...|No Shortcut"), NULL, NULL, CVMenuSimplifyMore, MID_SimplifyMore },
11887 { { (unichar_t *) N_("Clea_nup Glyph"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'n' }, H_("Cleanup Glyph|No Shortcut"), NULL, NULL, CVMenuCleanupGlyph, MID_CleanupGlyph },
11888 { { (unichar_t *) N_("Canonical Start _Point"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'n' }, H_("Canonical Start Point|No Shortcut"), NULL, NULL, CVMenuCanonicalStart, MID_CanonicalStart },
11889 { { (unichar_t *) N_("Canonical _Contours"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'n' }, H_("Canonical Contours|No Shortcut"), NULL, NULL, CVMenuCanonicalContours, MID_CanonicalContours },
11890 GMENUITEM2_EMPTY
11891 };
11892
smlistcheck(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))11893 static void smlistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
11894 CharView *cv = (CharView *) GDrawGetUserData(gw);
11895
11896 for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
11897 switch ( mi->mid ) {
11898 case MID_Simplify:
11899 case MID_CleanupGlyph:
11900 case MID_SimplifyMore:
11901 mi->ti.disabled = cv->b.layerheads[cv->b.drawmode]->splines==NULL;
11902 break;
11903 case MID_CanonicalStart:
11904 mi->ti.disabled = cv->b.layerheads[cv->b.drawmode]->splines==NULL ||
11905 (cv->b.sc->inspiro && hasspiro());
11906 break;
11907 case MID_CanonicalContours:
11908 mi->ti.disabled = cv->b.layerheads[cv->b.drawmode]->splines==NULL ||
11909 cv->b.layerheads[cv->b.drawmode]->splines->next==NULL ||
11910 cv->b.drawmode!=dm_fore;
11911 break;
11912 }
11913 }
11914 }
11915
11916 static GMenuItem2 orlist[] = {
11917 { { (unichar_t *) N_("_First"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'S' }, H_("First|No Shortcut"), NULL, NULL, CVMenuOrder, MID_First },
11918 { { (unichar_t *) N_("_Earlier"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'M' }, H_("Earlier|No Shortcut"), NULL, NULL, CVMenuOrder, MID_Earlier },
11919 { { (unichar_t *) N_("L_ater"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'n' }, H_("Later|No Shortcut"), NULL, NULL, CVMenuOrder, MID_Later },
11920 { { (unichar_t *) N_("_Last"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'n' }, H_("Last|No Shortcut"), NULL, NULL, CVMenuOrder, MID_Last },
11921 GMENUITEM2_EMPTY
11922 };
11923
orlistcheck(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))11924 static void orlistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
11925 CharView *cv = (CharView *) GDrawGetUserData(gw);
11926 SplinePointList *spl;
11927 RefChar *r;
11928 ImageList *im;
11929 int exactlyone = CVOneContourSel(cv,&spl,&r,&im);
11930 int isfirst, islast;
11931
11932 isfirst = islast = false;
11933 if ( spl!=NULL ) {
11934 isfirst = cv->b.layerheads[cv->b.drawmode]->splines==spl;
11935 islast = spl->next==NULL;
11936 } else if ( r!=NULL ) {
11937 isfirst = cv->b.layerheads[cv->b.drawmode]->refs==r;
11938 islast = r->next==NULL;
11939 } else if ( im!=NULL ) {
11940 isfirst = cv->b.layerheads[cv->b.drawmode]->images==im;
11941 islast = im->next==NULL;
11942 }
11943
11944 for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
11945 switch ( mi->mid ) {
11946 case MID_First:
11947 case MID_Earlier:
11948 mi->ti.disabled = !exactlyone || isfirst;
11949 break;
11950 case MID_Last:
11951 case MID_Later:
11952 mi->ti.disabled = !exactlyone || islast;
11953 break;
11954 }
11955 }
11956 }
11957
11958 static GMenuItem2 rmlist[] = {
11959 { { (unichar_t *) N_("_Remove Overlap"), (GImage *) "overlaprm.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, true, 0, 0, 0, 0, 1, 1, 0, 'R' }, H_("Remove Overlap|No Shortcut"), NULL, NULL, CVMenuOverlap, MID_RmOverlap },
11960 { { (unichar_t *) N_("_Intersect"), (GImage *) "overlapintersection.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, true, 0, 0, 0, 0, 1, 1, 0, 'I' }, H_("Intersect|No Shortcut"), NULL, NULL, CVMenuOverlap, MID_Intersection },
11961 { { (unichar_t *) N_("_Exclude"), (GImage *) "overlapexclude.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, true, 0, 0, 0, 0, 1, 1, 0, 'E' }, H_("Exclude|No Shortcut"), NULL, NULL, CVMenuOverlap, MID_Exclude },
11962 { { (unichar_t *) N_("_Find Intersections"), (GImage *) "overlapfindinter.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, true, 0, 0, 0, 0, 1, 1, 0, 'F' }, H_("Find Intersections|No Shortcut"), NULL, NULL, CVMenuOverlap, MID_FindInter },
11963 GMENUITEM2_EMPTY
11964 };
11965
11966 static GMenuItem2 eflist[] = {
11967 { { (unichar_t *) N_("Change _Weight..."), (GImage *) "styleschangeweight.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, true, 0, 0, 0, 0, 1, 1, 0, 'M' }, H_("Change Weight...|No Shortcut"), NULL, NULL, CVMenuEmbolden, MID_Embolden },
11968 { { (unichar_t *) N_("_Italic..."), (GImage *) "stylesitalic.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, true, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Italic...|No Shortcut"), NULL, NULL, CVMenuItalic, MID_Italic },
11969 { { (unichar_t *) N_("Obli_que..."), (GImage *) "stylesoblique.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, true, 0, 0, 0, 0, 1, 1, 0, 'M' }, H_("Oblique...|No Shortcut"), NULL, NULL, CVMenuOblique, 0 },
11970 { { (unichar_t *) N_("_Condense/Extend..."), (GImage *) "stylesextendcondense.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, true, 0, 0, 0, 0, 1, 1, 0, 'M' }, H_("Condense/Extend...|No Shortcut"), NULL, NULL, CVMenuCondense, MID_Condense },
11971 { { (unichar_t *) N_("Change _X-Height..."), (GImage *) "styleschangexheight.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, true, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Change X-Height...|No Shortcut"), NULL, NULL, CVMenuChangeXHeight, MID_ChangeXHeight },
11972 { { (unichar_t *) N_("Change _Glyph..."), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, true, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Change Glyph...|No Shortcut"), NULL, NULL, CVMenuChangeGlyph, MID_ChangeGlyph },
11973 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11974 { { (unichar_t *) N_("In_line..."), (GImage *) "stylesinline.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, true, 0, 0, 0, 0, 1, 1, 0, 'O' }, H_("Inline...|No Shortcut"), NULL, NULL, CVMenuInline, 0 },
11975 { { (unichar_t *) N_("_Outline..."), (GImage *) "stylesoutline.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, true, 0, 0, 0, 0, 1, 1, 0, 'I' }, H_("Outline...|No Shortcut"), NULL, NULL, CVMenuOutline, 0 },
11976 { { (unichar_t *) N_("S_hadow..."), (GImage *) "stylesshadow.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, true, 0, 0, 0, 0, 1, 1, 0, 'S' }, H_("Shadow...|No Shortcut"), NULL, NULL, CVMenuShadow, 0 },
11977 { { (unichar_t *) N_("_Wireframe..."), (GImage *) "styleswireframe.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, true, 0, 0, 0, 0, 1, 1, 0, 'W' }, H_("Wireframe...|No Shortcut"), NULL, NULL, CVMenuWireframe, 0 },
11978 GMENUITEM2_EMPTY
11979 };
11980
11981 static GMenuItem2 balist[] = {
11982 { { (unichar_t *) N_("_Build Accented Glyph"), (GImage *) "elementbuildaccent.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'u' }, H_("Build Accented Glyph|No Shortcut"), NULL, NULL, CVMenuBuildAccent, MID_BuildAccent },
11983 { { (unichar_t *) N_("Build _Composite Glyph"), (GImage *) "elementbuildcomposite.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'B' }, H_("Build Composite Glyph|No Shortcut"), NULL, NULL, CVMenuBuildComposite, MID_BuildComposite },
11984 GMENUITEM2_EMPTY
11985 };
11986
11987 static GMenuItem2 delist[] = {
11988 { { (unichar_t *) N_("_References..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'u' }, H_("References...|No Shortcut"), NULL, NULL, CVMenuShowDependentRefs, MID_ShowDependentRefs },
11989 { { (unichar_t *) N_("_Substitutions..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'B' }, H_("Substitutions...|No Shortcut"), NULL, NULL, CVMenuShowDependentSubs, MID_ShowDependentSubs },
11990 GMENUITEM2_EMPTY
11991 };
11992
11993 static GMenuItem2 trlist[] = {
11994 { { (unichar_t *) N_("_Transform..."), (GImage *) "elementtransform.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'T' }, H_("Transform...|No Shortcut"), NULL, NULL, CVMenuTransform, 0 },
11995 { { (unichar_t *) N_("_Point of View Projection..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'T' }, H_("Point of View Projection...|No Shortcut"), NULL, NULL, CVMenuPOV, 0 },
11996 { { (unichar_t *) N_("_Non Linear Transform..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'T' }, H_("Non Linear Transform...|No Shortcut"), NULL, NULL, CVMenuNLTransform, 0 },
11997 GMENUITEM2_EMPTY
11998 };
11999
12000 static GMenuItem2 rndlist[] = {
12001 { { (unichar_t *) N_("To _Int"), (GImage *) "elementround.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'I' }, H_("To Int|No Shortcut"), NULL, NULL, CVMenuRound2Int, MID_Round },
12002 { { (unichar_t *) N_("To _Hundredths"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'I' }, H_("To Hundredths|No Shortcut"), NULL, NULL, CVMenuRound2Hundredths, 0 },
12003 { { (unichar_t *) N_("_Cluster"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'I' }, H_("Cluster|No Shortcut"), NULL, NULL, CVMenuCluster, MID_RoundToCluster },
12004 GMENUITEM2_EMPTY
12005 };
12006
12007 static GMenuItem2 ellist[] = {
12008 { { (unichar_t *) N_("_Font Info..."), (GImage *) "elementfontinfo.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'F' }, H_("Font Info...|No Shortcut"), NULL, NULL, CVMenuFontInfo, MID_FontInfo },
12009 { { (unichar_t *) N_("_Glyph Info..."), (GImage *) "elementglyphinfo.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'I' }, H_("Glyph Info...|No Shortcut"), NULL, NULL, CVMenuCharInfo, MID_CharInfo },
12010 { { (unichar_t *) N_("Get _Info..."), (GImage *) "elementgetinfo.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'I' }, H_("Get Info...|No Shortcut"), NULL, NULL, CVMenuGetInfo, MID_GetInfo },
12011 { { (unichar_t *) N_("S_how Dependent"), (GImage *) "elementshowdep.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'D' }, H_("Show Dependent|No Shortcut"), delist, delistcheck, NULL, MID_ShowDependentRefs },
12012 { { (unichar_t *) N_("Find Proble_ms..."), (GImage *) "elementfindprobs.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'o' }, H_("Find Problems...|No Shortcut"), NULL, NULL, CVMenuFindProblems, MID_FindProblems },
12013 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
12014 { { (unichar_t *) N_("Bitm_ap strikes Available..."), (GImage *) "elementbitmapsavail.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'A' }, H_("Bitmap strikes Available...|No Shortcut"), NULL, NULL, CVMenuBitmaps, MID_AvailBitmaps },
12015 { { (unichar_t *) N_("Regenerate _Bitmap Glyphs..."), (GImage *) "elementregenbitmaps.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'B' }, H_("Regenerate Bitmap Glyphs...|No Shortcut"), NULL, NULL, CVMenuBitmaps, MID_RegenBitmaps },
12016 { { (unichar_t *) N_("Remove Bitmap Glyphs..."), (GImage *) "elementremovebitmaps.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Remove Bitmap Glyphs...|No Shortcut"), NULL, NULL, CVMenuBitmaps, MID_RemoveBitmaps },
12017 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
12018 { { (unichar_t *) N_("St_yles"), (GImage *) "elementstyles.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Styles|No Shortcut"), eflist, NULL, NULL, MID_Styles },
12019 { { (unichar_t *) N_("_Transformations"), (GImage *) "elementtransform.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'T' }, H_("Transformations|No Shortcut"), trlist, NULL, NULL, 0 },
12020 { { (unichar_t *) N_("_Expand Stroke..."), (GImage *) "elementexpandstroke.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'E' }, H_("Expand Stroke...|No Shortcut"), NULL, NULL, CVMenuStroke, MID_Stroke },
12021 #ifdef FONTFORGE_CONFIG_TILEPATH
12022 { { (unichar_t *) N_("Tile _Path..."), (GImage *) "elementtilepath.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'P' }, H_("Tile Path...|No Shortcut"), NULL, NULL, CVMenuTilePath, MID_TilePath },
12023 { { (unichar_t *) N_("Tile Pattern..."), (GImage *) "elementtilepattern.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Tile Pattern...|No Shortcut"), NULL, NULL, CVMenuPatternTile, 0 },
12024 #endif
12025 { { (unichar_t *) N_("O_verlap"), (GImage *) "overlaprm.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'v' }, H_("Overlap|No Shortcut"), rmlist, NULL, NULL, MID_RmOverlap },
12026 { { (unichar_t *) N_("_Simplify"), (GImage *) "elementsimplify.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'S' }, H_("Simplify|No Shortcut"), smlist, smlistcheck, NULL, MID_Simplify },
12027 { { (unichar_t *) N_("Add E_xtrema"), (GImage *) "elementaddextrema.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'x' }, H_("Add Extrema|No Shortcut"), NULL, NULL, CVMenuAddExtrema, MID_AddExtrema },
12028 { { (unichar_t *) N_("Autot_race"), (GImage *) "elementautotrace.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'r' }, H_("Autotrace|No Shortcut"), NULL, NULL, CVMenuAutotrace, MID_Autotrace },
12029 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
12030 { { (unichar_t *) N_("A_lign"), (GImage *) "elementalign.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'l' }, H_("Align|No Shortcut"), allist, allistcheck, NULL, MID_Align },
12031 { { (unichar_t *) N_("Roun_d"), (GImage *) "elementround.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'I' }, H_("Round|No Shortcut"), rndlist, rndlistcheck, NULL, MID_Round },
12032 { { (unichar_t *) N_("_Order"), (GImage *) "elementorder.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Order|No Shortcut"), orlist, orlistcheck, NULL, 0 },
12033 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
12034 { { (unichar_t *) N_("Check Self-Intersection"), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'o' }, H_("Check Self-Intersection|No Shortcut"), NULL, NULL, CVMenuCheckSelf, MID_CheckSelf },
12035 { { (unichar_t *) N_("Glyph Self-Intersects"), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'o' }, H_("Glyph Self-Intersects|No Shortcut"), NULL, NULL, CVMenuGlyphSelfIntersects, MID_GlyphSelfIntersects },
12036 { { (unichar_t *) N_("Cloc_kwise"), (GImage *) "elementclockwise.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'o' }, H_("Clockwise|No Shortcut"), NULL, NULL, CVMenuDir, MID_Clockwise },
12037 { { (unichar_t *) N_("Cou_nter Clockwise"), (GImage *) "elementanticlock.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'n' }, H_("Counter Clockwise|No Shortcut"), NULL, NULL, CVMenuDir, MID_Counter },
12038 { { (unichar_t *) N_("_Correct Direction"), (GImage *) "elementcorrectdir.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'D' }, H_("Correct Direction|No Shortcut"), NULL, NULL, CVMenuCorrectDir, MID_Correct },
12039 { { (unichar_t *) N_("Reverse Direction"), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'D' }, H_("Reverse Direction|No Shortcut"), NULL, NULL, CVMenuReverseDir, MID_ReverseDir },
12040 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
12041 { { (unichar_t *) N_("Insert Text Outlines..."), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'D' }, H_("Insert Text Outlines...|No Shortcut"), NULL, NULL, CVMenuInsertText, MID_InsertText },
12042 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
12043 { { (unichar_t *) N_("B_uild"), (GImage *) "elementbuildaccent.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'u' }, H_("Build|No Shortcut"), balist, balistcheck, NULL, MID_BuildAccent },
12044 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
12045 { { (unichar_t *) N_("Compare Layers..."), (GImage *) "elementcomparelayers.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'u' }, H_("Compare Layers...|No Shortcut"), NULL, NULL, CVMenuCompareL2L, 0 },
12046 GMENUITEM2_EMPTY
12047 };
12048
12049 static GMenuItem2 htlist[] = {
12050 { { (unichar_t *) N_("Auto_Hint"), (GImage *) "hintsautohint.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'H' }, H_("AutoHint|No Shortcut"), NULL, NULL, CVMenuAutoHint, MID_AutoHint },
12051 { { (unichar_t *) N_("Hint _Substitution Pts"), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'H' }, H_("Hint Substitution Pts|No Shortcut"), NULL, NULL, CVMenuAutoHintSubs, MID_HintSubsPt },
12052 { { (unichar_t *) N_("Auto _Counter Hint"), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'H' }, H_("Auto Counter Hint|No Shortcut"), NULL, NULL, CVMenuAutoCounter, MID_AutoCounter },
12053 { { (unichar_t *) N_("_Don't AutoHint"), (GImage *) "hintsdontautohint.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'H' }, H_("Don't AutoHint|No Shortcut"), NULL, NULL, CVMenuDontAutoHint, MID_DontAutoHint },
12054 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
12055 { { (unichar_t *) N_("Auto_Instr"), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'T' }, H_("AutoInstr|No Shortcut"), NULL, NULL, CVMenuNowakAutoInstr, MID_AutoInstr },
12056 { { (unichar_t *) N_("_Edit Instructions..."), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'l' }, H_("Edit Instructions...|No Shortcut"), NULL, NULL, CVMenuEditInstrs, MID_EditInstructions },
12057 { { (unichar_t *) N_("_Debug..."), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'l' }, H_("Debug...|No Shortcut"), NULL, NULL, CVMenuDebug, MID_Debug },
12058 { { (unichar_t *) N_("S_uggest Deltas..."), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'l' }, H_("Suggest Deltas...|No Shortcut"), NULL, NULL, CVMenuDeltas, MID_Deltas },
12059 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
12060 { { (unichar_t *) N_("_Clear HStem"), (GImage *) "hintsclearhstems.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'C' }, H_("Clear HStem|No Shortcut"), NULL, NULL, CVMenuClearHints, MID_ClearHStem },
12061 { { (unichar_t *) N_("Clear _VStem"), (GImage *) "hintsclearvstems.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'V' }, H_("Clear VStem|No Shortcut"), NULL, NULL, CVMenuClearHints, MID_ClearVStem },
12062 { { (unichar_t *) N_("Clear DStem"), (GImage *) "hintscleardstems.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'V' }, H_("Clear DStem|No Shortcut"), NULL, NULL, CVMenuClearHints, MID_ClearDStem },
12063 { { (unichar_t *) N_("Clear Instructions"), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("Clear Instructions|No Shortcut"), NULL, NULL, CVMenuClearInstrs, MID_ClearInstr },
12064 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
12065 { { (unichar_t *) N_("_Add HHint"), (GImage *) "hintsaddhstem.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'A' }, H_("Add HHint|No Shortcut"), NULL, NULL, CVMenuAddHint, MID_AddHHint },
12066 { { (unichar_t *) N_("Add VHi_nt"), (GImage *) "hintsaddvstem.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 's' }, H_("Add VHint|No Shortcut"), NULL, NULL, CVMenuAddHint, MID_AddVHint },
12067 { { (unichar_t *) N_("Add DHint"), (GImage *) "hintsadddstem.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 't' }, H_("Add DHint|No Shortcut"), NULL, NULL, CVMenuAddHint, MID_AddDHint },
12068 { { (unichar_t *) N_("Crea_te HHint..."), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'r' }, H_("Create HHint...|No Shortcut"), NULL, NULL, CVMenuCreateHint, MID_CreateHHint },
12069 { { (unichar_t *) N_("Cr_eate VHint..."), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'e' }, H_("Create VHint...|No Shortcut"), NULL, NULL, CVMenuCreateHint, MID_CreateVHint },
12070 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
12071 { { (unichar_t *) N_("_Review Hints..."), (GImage *) "hintsreviewhints.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'R' }, H_("Review Hints...|No Shortcut"), NULL, NULL, CVMenuReviewHints, MID_ReviewHints },
12072 GMENUITEM2_EMPTY
12073 };
12074
12075 static GMenuItem2 ap2list[] = {
12076 GMENUITEM2_EMPTY
12077 };
12078
ap2listbuild(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))12079 static void ap2listbuild(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
12080 CharView *cv = (CharView *) GDrawGetUserData(gw);
12081 char buf[300];
12082 GMenuItem *sub;
12083 int k, cnt;
12084 AnchorPoint *ap;
12085
12086 if ( mi->sub!=NULL ) {
12087 GMenuItemArrayFree(mi->sub);
12088 mi->sub = NULL;
12089 }
12090
12091 for ( k=0; k<2; ++k ) {
12092 cnt = 0;
12093 for ( ap=cv->b.sc->anchor; ap!=NULL; ap=ap->next ) {
12094 if ( k ) {
12095 if ( ap->type==at_baselig )
12096 /* GT: In the next few lines the "%s" is the name of an anchor class, and the */
12097 /* GT: rest of the string identifies the type of the anchor */
12098 snprintf(buf,sizeof(buf), _("%s at ligature pos %d"), ap->anchor->name, ap->lig_index );
12099 else
12100 snprintf(buf,sizeof(buf),
12101 ap->type==at_cexit ? _("%s exit"):
12102 ap->type==at_centry ? _("%s entry"):
12103 ap->type==at_mark ? _("%s mark"):
12104 _("%s base"),ap->anchor->name );
12105 sub[cnt].ti.text = utf82u_copy(buf);
12106 sub[cnt].ti.userdata = ap;
12107 sub[cnt].ti.bg = sub[cnt].ti.fg = COLOR_DEFAULT;
12108 sub[cnt].invoke = CVMenuAnchorsAway;
12109 }
12110 ++cnt;
12111 }
12112 if ( !k )
12113 sub = calloc(cnt+1,sizeof(GMenuItem));
12114 }
12115 mi->sub = sub;
12116 }
12117
CVMenuKernByClasses(GWindow gw,struct gmenuitem * mi,GEvent * e)12118 static void CVMenuKernByClasses(GWindow gw,struct gmenuitem *mi,GEvent *e) {
12119 CharView *cv = (CharView *) GDrawGetUserData(gw);
12120 MetricsView *mv = 0;
12121 SplineFont *sf = cv->b.sc->parent;
12122 int cvlayer = CVLayer((CharViewBase *) cv);
12123 ShowKernClasses(sf, mv, cvlayer, false);
12124 }
12125
CVMenuVKernByClasses(GWindow gw,struct gmenuitem * mi,GEvent * e)12126 static void CVMenuVKernByClasses(GWindow gw,struct gmenuitem *mi,GEvent *e) {
12127 CharView *cv = (CharView *) GDrawGetUserData(gw);
12128 MetricsView *mv = 0;
12129 SplineFont *sf = cv->b.sc->parent;
12130 int cvlayer = CVLayer((CharViewBase *) cv);
12131 ShowKernClasses(sf, mv, cvlayer, true);
12132 }
12133
CVMenuVKernFromHKern(GWindow gw,struct gmenuitem * mi,GEvent * e)12134 static void CVMenuVKernFromHKern(GWindow gw,struct gmenuitem *mi,GEvent *e) {
12135 CharView *cv = (CharView *) GDrawGetUserData(gw);
12136 FVVKernFromHKern((FontViewBase *) cv->b.fv);
12137 }
12138
12139 static GMenuItem2 mtlist[] = {
12140 { { (unichar_t *) N_("New _Metrics Window"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'M' }, H_("New Metrics Window|No Shortcut"), NULL, NULL, CVMenuOpenMetrics, 0 },
12141 GMENUITEM2_LINE,
12142 { { (unichar_t *) N_("_Center in Width"), (GImage *) "metricscenter.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'C' }, H_("Center in Width|No Shortcut"), NULL, NULL, CVMenuCenter, MID_Center },
12143 { { (unichar_t *) N_("_Thirds in Width"), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'T' }, H_("Thirds in Width|No Shortcut"), NULL, NULL, CVMenuCenter, MID_Thirds },
12144 { { (unichar_t *) N_("Set _Width..."), (GImage *) "metricssetwidth.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'W' }, H_("Set Width...|No Shortcut"), NULL, NULL, CVMenuSetWidth, MID_SetWidth },
12145 { { (unichar_t *) N_("Set _LBearing..."), (GImage *) "metricssetlbearing.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'L' }, H_("Set LBearing...|No Shortcut"), NULL, NULL, CVMenuSetWidth, MID_SetLBearing },
12146 { { (unichar_t *) N_("Set _RBearing..."), (GImage *) "metricssetrbearing.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'R' }, H_("Set RBearing...|No Shortcut"), NULL, NULL, CVMenuSetWidth, MID_SetRBearing },
12147 { { (unichar_t *) N_("Set Both Bearings..."), (GImage *) "menuempty.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'R' }, H_("Set Both Bearings...|No Shortcut"), NULL, NULL, CVMenuSetWidth, MID_SetBearings },
12148 GMENUITEM2_LINE,
12149 { { (unichar_t *) N_("Set _Vertical Advance..."), (GImage *) "metricssetvwidth.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'V' }, H_("Set Vertical Advance...|No Shortcut"), NULL, NULL, CVMenuSetWidth, MID_SetVWidth },
12150 GMENUITEM2_LINE,
12151 { { (unichar_t *) N_("Ker_n By Classes..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'T' }, H_("Kern By Classes...|No Shortcut"), NULL, NULL, CVMenuKernByClasses, 0 },
12152 { { (unichar_t *) N_("VKern By Classes..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'T' }, H_("VKern By Classes...|No Shortcut"), NULL, NULL, CVMenuVKernByClasses, MID_VKernClass },
12153 { { (unichar_t *) N_("VKern From HKern"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'T' }, H_("VKern From HKern|No Shortcut"), NULL, NULL, CVMenuVKernFromHKern, MID_VKernFromHKern },
12154 { { (unichar_t *) N_("Remove Kern _Pairs"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'P' }, H_("Remove Kern Pairs|No Shortcut"), NULL, NULL, CVMenuRemoveKern, MID_RemoveKerns },
12155 { { (unichar_t *) N_("Remove VKern Pairs"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'P' }, H_("Remove VKern Pairs|No Shortcut"), NULL, NULL, CVMenuRemoveVKern, MID_RemoveVKerns },
12156 { { (unichar_t *) N_("Kern Pair Closeup..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'P' }, H_("Kern Pair Closeup...|No Shortcut"), NULL, NULL, CVMenuKPCloseup, MID_KPCloseup },
12157 GMENUITEM2_EMPTY
12158 };
12159
12160 static GMenuItem2 pllist[] = {
12161 { { (unichar_t *) N_("_Tools"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Tools|No Shortcut"), NULL, NULL, CVMenuPaletteShow, MID_Tools },
12162 { { (unichar_t *) N_("_Layers"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'L' }, H_("Layers|No Shortcut"), NULL, NULL, CVMenuPaletteShow, MID_Layers },
12163 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
12164 { { (unichar_t *) N_("_Docked Palettes"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'D' }, H_("Docked Palettes|No Shortcut"), NULL, NULL, CVMenuPalettesDock, MID_DockPalettes },
12165 GMENUITEM2_EMPTY
12166 };
12167
12168 static GMenuItem2 aplist[] = {
12169 { { (unichar_t *) N_("_Detach"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'K' }, H_("Detach|No Shortcut"), NULL, NULL, CVMenuAPDetach, 0 },
12170 GMENUITEM2_EMPTY
12171 };
12172
aplistcheck(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))12173 static void aplistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
12174 CharView *cv = (CharView *) GDrawGetUserData(gw);
12175 SplineChar *sc = cv->b.sc, **glyphs;
12176 SplineFont *sf = sc->parent;
12177 AnchorPoint *ap, *found;
12178 GMenuItem2 *mit;
12179 int cnt;
12180
12181 found = NULL;
12182 for ( ap=sc->anchor; ap!=NULL; ap=ap->next ) {
12183 if ( ap->selected ) {
12184 if ( found==NULL )
12185 found = ap;
12186 else {
12187 /* Can't deal with two selected anchors */
12188 found = NULL;
12189 break;
12190 }
12191 }
12192 }
12193
12194 GMenuItemArrayFree(mi->sub);
12195 if ( found==NULL )
12196 glyphs = NULL;
12197 else
12198 glyphs = GlyphsMatchingAP(sf,found);
12199 if ( glyphs==NULL ) {
12200 mi->sub = GMenuItem2ArrayCopy(aplist,NULL);
12201 mi->sub->ti.disabled = (cv->apmine==NULL);
12202 return;
12203 }
12204
12205 for ( cnt = 0; glyphs[cnt]!=NULL; ++cnt );
12206 mit = calloc(cnt+2,sizeof(GMenuItem2));
12207 mit[0] = aplist[0];
12208 mit[0].ti.text = (unichar_t *) copy( (char *) mit[0].ti.text );
12209 mit[0].ti.disabled = (cv->apmine==NULL);
12210 for ( cnt = 0; glyphs[cnt]!=NULL; ++cnt ) {
12211 mit[cnt+1].ti.text = (unichar_t *) copy(glyphs[cnt]->name);
12212 mit[cnt+1].ti.text_is_1byte = true;
12213 mit[cnt+1].ti.fg = mit[cnt+1].ti.bg = COLOR_DEFAULT;
12214 mit[cnt+1].ti.userdata = glyphs[cnt];
12215 mit[cnt+1].invoke = CVMenuAPAttachSC;
12216 if ( glyphs[cnt]==cv->apsc )
12217 mit[cnt+1].ti.checked = mit[cnt+1].ti.checkable = true;
12218 }
12219 free(glyphs);
12220 mi->sub = GMenuItem2ArrayCopy(mit,NULL);
12221 GMenuItem2ArrayFree(mit);
12222 }
12223
CVMoveInWordListByOffset(CharView * cv,int offset)12224 static void CVMoveInWordListByOffset( CharView* cv, int offset )
12225 {
12226 Wordlist_MoveByOffset( cv->charselector, &cv->charselectoridx, offset );
12227 }
12228
CVMenuNextLineInWordList(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))12229 static void CVMenuNextLineInWordList(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
12230 CharView* cv = (CharView*) GDrawGetUserData(gw);
12231 CVMoveInWordListByOffset( cv, 1 );
12232 }
CVMenuPrevLineInWordList(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))12233 static void CVMenuPrevLineInWordList(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
12234 CharView* cv = (CharView*) GDrawGetUserData(gw);
12235 CVMoveInWordListByOffset( cv, -1 );
12236 }
12237
12238 static GMenuItem2 cblist[] = {
12239 { { (unichar_t *) N_("_Kern Pairs"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'K' }, H_("Kern Pairs|No Shortcut"), NULL, NULL, CVMenuKernPairs, MID_KernPairs },
12240 { { (unichar_t *) N_("_Anchored Pairs"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'A' }, H_("Anchored Pairs|No Shortcut"), NULL, NULL, CVMenuAnchorPairs, MID_AnchorPairs },
12241 { { (unichar_t *) N_("_Anchor Control..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'V' }, H_("Anchor Control...|No Shortcut"), ap2list, ap2listbuild, NULL, MID_AnchorControl },
12242 { { (unichar_t *) N_("Anchor _Glyph at Point"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'A' }, H_("Anchor Glyph at Point|No Shortcut"), aplist, aplistcheck, NULL, MID_AnchorGlyph },
12243 { { (unichar_t *) N_("_Ligatures"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'L' }, H_("Ligatures|No Shortcut"), NULL, NULL, CVMenuLigatures, MID_Ligatures },
12244 GMENUITEM2_EMPTY
12245 };
12246
12247 static GMenuItem2 nplist[] = {
12248 { { (unichar_t *) N_("PointNumbers|_None"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'K' }, H_("None|No Shortcut"), NULL, NULL, CVMenuNumberPoints, MID_PtsNone },
12249 { { (unichar_t *) N_("_TrueType"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'A' }, H_("TrueType|No Shortcut"), NULL, NULL, CVMenuNumberPoints, MID_PtsTrue },
12250 { { (unichar_t *) NU_("_PostScript®"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'L' }, H_("PostScript|No Shortcut"), NULL, NULL, CVMenuNumberPoints, MID_PtsPost },
12251 { { (unichar_t *) N_("_SVG"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'L' }, H_("SVG|No Shortcut"), NULL, NULL, CVMenuNumberPoints, MID_PtsSVG },
12252 { { (unichar_t *) N_("P_ositions"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'L' }, H_("Positions|No Shortcut"), NULL, NULL, CVMenuNumberPoints, MID_PtsPos },
12253 GMENUITEM2_EMPTY
12254 };
12255
12256 static GMenuItem2 gflist[] = {
12257 { { (unichar_t *) N_("Show _Grid Fit..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'l' }, H_("Show Grid Fit...|No Shortcut"), NULL, NULL, CVMenuShowGridFit, MID_ShowGridFit },
12258 { { (unichar_t *) N_("Show _Grid Fit (Live Update)..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'l' }, H_("Show Grid Fit (Live Update)...|No Shortcut"), NULL, NULL, CVMenuShowGridFitLiveUpdate, MID_ShowGridFitLiveUpdate },
12259 { { (unichar_t *) N_("_Bigger Point Size"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'B' }, H_("Bigger Point Size|No Shortcut"), NULL, NULL, CVMenuChangePointSize, MID_Bigger },
12260 { { (unichar_t *) N_("_Smaller Point Size"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'S' }, H_("Smaller Point Size|No Shortcut"), NULL, NULL, CVMenuChangePointSize, MID_Smaller },
12261 { { (unichar_t *) N_("_Anti Alias"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'L' }, H_("Anti Alias|No Shortcut"), NULL, NULL, CVMenuChangePointSize, MID_GridFitAA },
12262 { { (unichar_t *) N_("_Off"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'S' }, H_("Off|No Shortcut"), NULL, NULL, CVMenuChangePointSize, MID_GridFitOff },
12263 GMENUITEM2_EMPTY
12264 };
12265
12266 static GMenuItem2 swlist[] = {
12267 { { (unichar_t *) N_("_Points"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'o' }, H_("Points|No Shortcut"), NULL, NULL, CVMenuShowHide, MID_HidePoints },
12268 { { (unichar_t *) N_("Control Points (Always_)"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, ')' }, H_("Control Points (Always)|No Shortcut"), NULL, NULL, CVMenuShowHideControlPoints, MID_HideControlPoints },
12269 { { (unichar_t *) N_("_Control Point Info"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'M' }, H_("Control Point Info|No Shortcut"), NULL, NULL, CVMenuShowCPInfo, MID_ShowCPInfo },
12270 { { (unichar_t *) N_("_Extrema"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'M' }, H_("Extrema|No Shortcut"), NULL, NULL, CVMenuMarkExtrema, MID_MarkExtrema },
12271 { { (unichar_t *) N_("Points of _Inflection"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'M' }, H_("Points of Inflection|No Shortcut"), NULL, NULL, CVMenuMarkPointsOfInflection, MID_MarkPointsOfInflection },
12272 { { (unichar_t *) N_("Almost Horizontal/Vertical Lines"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'M' }, H_("Almost Horizontal/Vertical Lines|No Shortcut"), NULL, NULL, CVMenuShowAlmostHV, MID_ShowAlmostHV },
12273 { { (unichar_t *) N_("Almost Horizontal/Vertical Curves"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'M' }, H_("Almost Horizontal/Vertical Curves|No Shortcut"), NULL, NULL, CVMenuShowAlmostHVCurves, MID_ShowAlmostHVCurves },
12274 { { (unichar_t *) N_("(Define \"Almost\")"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'M' }, H_("(Define \"Almost\")|No Shortcut"), NULL, NULL, CVMenuDefineAlmost, MID_DefineAlmost },
12275 { { (unichar_t *) N_("_Side Bearings"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'M' }, H_("Side Bearings|No Shortcut"), NULL, NULL, CVMenuShowSideBearings, MID_ShowSideBearings },
12276 { { (unichar_t *) N_("Reference Names"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'M' }, H_("Reference Names|No Shortcut"), NULL, NULL, CVMenuShowRefNames, MID_ShowRefNames },
12277 { { (unichar_t *) N_("_Fill"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'l' }, H_("Fill|No Shortcut"), NULL, NULL, CVMenuFill, MID_Fill },
12278 { { (unichar_t *) N_("Previe_w"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'l' }, H_("Preview|No Shortcut"), NULL, NULL, CVMenuPreview, MID_Preview },
12279 { { (unichar_t *) N_("Dragging Comparison Outline"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'l' }, H_("Dragging Comparison Outline|No Shortcut"), NULL, NULL, CVMenuDraggingComparisonOutline, MID_DraggingComparisonOutline },
12280 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
12281 { { (unichar_t *) N_("Pale_ttes"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'P' }, H_("Palettes|No Shortcut"), pllist, pllistcheck, NULL, 0 },
12282 { { (unichar_t *) N_("_Glyph Tabs"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'R' }, H_("Glyph Tabs|No Shortcut"), NULL, NULL, CVMenuShowTabs, MID_ShowTabs },
12283 { { (unichar_t *) N_("_Rulers"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'R' }, H_("Rulers|No Shortcut"), NULL, NULL, CVMenuShowHideRulers, MID_HideRulers },
12284 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
12285 { { (unichar_t *) N_("_Horizontal Hints"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'R' }, H_("Horizontal Hints|No Shortcut"), NULL, NULL, CVMenuShowHints, MID_ShowHHints },
12286 { { (unichar_t *) N_("_Vertical Hints"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'R' }, H_("Vertical Hints|No Shortcut"), NULL, NULL, CVMenuShowHints, MID_ShowVHints },
12287 { { (unichar_t *) N_("_Diagonal Hints"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'R' }, H_("Diagonal Hints|No Shortcut"), NULL, NULL, CVMenuShowHints, MID_ShowDHints },
12288 /* GT: You might not want to translate this, it's a keyword in PostScript font files */
12289 { { (unichar_t *) N_("_BlueValues"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'R' }, H_("BlueValues|No Shortcut"), NULL, NULL, CVMenuShowHints, MID_ShowBlueValues },
12290 /* GT: You might not want to translate this, it's a keyword in PostScript font files */
12291 { { (unichar_t *) N_("FamilyBl_ues"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'R' }, H_("FamilyBlues|No Shortcut"), NULL, NULL, CVMenuShowHints, MID_ShowFamilyBlues },
12292 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
12293 { { (unichar_t *) N_("_Anchors"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'R' }, H_("Anchors|No Shortcut"), NULL, NULL, CVMenuShowHints, MID_ShowAnchors },
12294 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
12295 { { (unichar_t *) N_("Debug Raster Cha_nges"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'R' }, H_("Debug Raster Changes|No Shortcut"), NULL, NULL, CVMenuShowHints, MID_ShowDebugChanges },
12296 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
12297 { { (unichar_t *) N_("Hori_zontal Metric Lines"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'R' }, H_("Horizontal Metric Lines|No Shortcut"), NULL, NULL, CVMenuShowHints, MID_ShowHMetrics },
12298 { { (unichar_t *) N_("Vertical _Metric Lines"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'R' }, H_("Vertical Metric Lines|No Shortcut"), NULL, NULL, CVMenuShowHints, MID_ShowVMetrics },
12299 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
12300 { { (unichar_t *) N_("Snap Outlines to Pi_xel Grid"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'R' }, H_("Snap Outlines to Pixel Grid|No Shortcut"), NULL, NULL, CVMenuSnapOutlines, MID_SnapOutlines },
12301 GMENUITEM2_EMPTY
12302 };
12303
12304 static GMenuItem2 vwlist[] = {
12305 { { (unichar_t *) N_("_Fit"), (GImage *) "viewfit.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'F' }, H_("Fit|No Shortcut"), NULL, NULL, CVMenuScale, MID_Fit },
12306 { { (unichar_t *) N_("Z_oom out"), (GImage *) "viewzoomout.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'o' }, H_("Zoom out|No Shortcut"), NULL, NULL, CVMenuScale, MID_ZoomOut },
12307 { { (unichar_t *) N_("Zoom _in"), (GImage *) "viewzoomin.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'i' }, H_("Zoom in|No Shortcut"), NULL, NULL, CVMenuScale, MID_ZoomIn },
12308 #if HANYANG
12309 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
12310 { { (unichar_t *) N_("_Display Compositions..."), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'i' }, H_("Display Compositions...|No Shortcut"), NULL, NULL, CVDisplayCompositions, MID_DisplayCompositions },
12311 #endif
12312 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
12313 { { (unichar_t *) N_("_Next Glyph"), (GImage *) "viewnext.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'N' }, H_("Next Glyph|No Shortcut"), NULL, NULL, CVMenuChangeChar, MID_Next },
12314 { { (unichar_t *) N_("_Prev Glyph"), (GImage *) "viewprev.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'P' }, H_("Prev Glyph|No Shortcut"), NULL, NULL, CVMenuChangeChar, MID_Prev },
12315 { { (unichar_t *) N_("Next _Defined Glyph"), (GImage *) "viewnextdef.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'D' }, H_("Next Defined Glyph|No Shortcut"), NULL, NULL, CVMenuChangeChar, MID_NextDef },
12316 { { (unichar_t *) N_("Prev Defined Gl_yph"), (GImage *) "viewprevdef.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'a' }, H_("Prev Defined Glyph|No Shortcut"), NULL, NULL, CVMenuChangeChar, MID_PrevDef },
12317 { { (unichar_t *) N_("Form_er Glyph"), (GImage *) "viewformer.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'a' }, H_("Former Glyph|No Shortcut"), NULL, NULL, CVMenuChangeChar, MID_Former },
12318 { { (unichar_t *) N_("_Goto"), (GImage *) "viewgoto.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'G' }, H_("Goto|No Shortcut"), NULL, NULL, CVMenuGotoChar, MID_Goto },
12319 { { (unichar_t *) N_("Find In Font _View"), (GImage *) "viewfindinfont.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'V' }, H_("Find In Font View|No Shortcut"), NULL, NULL, CVMenuFindInFontView, MID_FindInFontView },
12320 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
12321 { { (unichar_t *) N_("N_umber Points"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'o' }, H_("Number Points|No Shortcut"), nplist, nplistcheck, NULL, 0 },
12322 { { (unichar_t *) N_("Grid Fi_t"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'l' }, H_("Grid Fit|No Shortcut"), gflist, gflistcheck, NULL, MID_ShowGridFit },
12323 { { (unichar_t *) N_("Sho_w"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'l' }, H_("Show|No Shortcut"), swlist, swlistcheck, NULL, 0 },
12324 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
12325 { { (unichar_t *) N_("Com_binations"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'b' }, H_("Combinations|No Shortcut"), cblist, cblistcheck, NULL, 0 },
12326 GMENUITEM2_LINE,
12327 { { (unichar_t *) N_("Next _Line in Word List"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'L' }, H_("Next Line in Word List|No Shortcut"), NULL, NULL, CVMenuNextLineInWordList, MID_NextLineInWordList },
12328 { { (unichar_t *) N_("Previous Line in _Word List"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'W' }, H_("Previous Line in Word List|No Shortcut"), NULL, NULL, CVMenuPrevLineInWordList, MID_PrevLineInWordList },
12329 GMENUITEM2_EMPTY
12330 };
12331
CVMenuShowMMMask(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))12332 static void CVMenuShowMMMask(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
12333 CharView *cv = (CharView *) GDrawGetUserData(gw);
12334 uint32 changemask = (uint32) (intpt) mi->ti.userdata;
12335 /* Change which mms get displayed in the "background" */
12336
12337 if ( mi->mid==MID_MMAll ) {
12338 if ( (cv->mmvisible&changemask)==changemask ) cv->mmvisible = 0;
12339 else cv->mmvisible = changemask;
12340 } else if ( mi->mid == MID_MMNone ) {
12341 if ( cv->mmvisible==0 ) cv->mmvisible = (1<<(cv->b.sc->parent->mm->instance_count+1))-1;
12342 else cv->mmvisible = 0;
12343 } else
12344 cv->mmvisible ^= changemask;
12345 GDrawRequestExpose(cv->v,NULL,false);
12346 }
12347
12348 static GMenuItem2 mvlist[] = {
12349 { { (unichar_t *) N_("SubFonts|_All"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, (void *) 0xffffffff, NULL, 0, 0, 1, 0, 0, 0, 1, 1, 0, '\0' }, H_("All|No Shortcut"), NULL, NULL, CVMenuShowMMMask, MID_MMAll },
12350 { { (unichar_t *) N_("SubFonts|_None"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, (void *) 0, NULL, 0, 0, 1, 0, 0, 0, 1, 1, 0, '\0' }, H_("None|No Shortcut"), NULL, NULL, CVMenuShowMMMask, MID_MMNone },
12351 GMENUITEM2_EMPTY
12352 };
12353
mvlistcheck(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))12354 static void mvlistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
12355 CharView *cv = (CharView *) GDrawGetUserData(gw);
12356 int i, base, j;
12357 MMSet *mm = cv->b.sc->parent->mm;
12358 uint32 submask;
12359 SplineFont *sub;
12360 GMenuItem2 *mml;
12361
12362 base = 3;
12363 if ( mm==NULL )
12364 mml = mvlist;
12365 else {
12366 mml = calloc(base+mm->instance_count+2,sizeof(GMenuItem2));
12367 memcpy(mml,mvlist,sizeof(mvlist));
12368 mml[base-1].ti.fg = mml[base-1].ti.bg = COLOR_DEFAULT;
12369 mml[base-1].ti.line = true;
12370 submask = 0;
12371 for ( j = 0, i=base; j<mm->instance_count+1; ++i, ++j ) {
12372 if ( j==0 )
12373 sub = mm->normal;
12374 else
12375 sub = mm->instances[j-1];
12376 mml[i].ti.text = uc_copy(sub->fontname);
12377 mml[i].ti.checkable = true;
12378 mml[i].ti.checked = (cv->mmvisible & (1<<j))?1:0;
12379 mml[i].ti.userdata = (void *) (intpt) (1<<j);
12380 mml[i].invoke = CVMenuShowMMMask;
12381 mml[i].ti.fg = mml[i].ti.bg = COLOR_DEFAULT;
12382 if ( sub==cv->b.sc->parent )
12383 submask = (1<<j);
12384 }
12385 /* All */
12386 mml[0].ti.userdata = (void *) (intpt) ((1<<j)-1);
12387 mml[0].ti.checked = (cv->mmvisible == (uint32) (intpt) mml[0].ti.userdata);
12388 /* None */
12389 mml[1].ti.checked = (cv->mmvisible == 0 || cv->mmvisible == submask);
12390 }
12391 GMenuItemArrayFree(mi->sub);
12392 mi->sub = GMenuItem2ArrayCopy(mml,NULL);
12393 if ( mml!=mvlist ) {
12394 for ( i=base; mml[i].ti.text!=NULL; ++i )
12395 free( mml[i].ti.text);
12396 free(mml);
12397 }
12398 }
12399
CVMenuReblend(GWindow gw,struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))12400 static void CVMenuReblend(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
12401 CharView *cv = (CharView *) GDrawGetUserData(gw);
12402 char *err;
12403 MMSet *mm = cv->b.sc->parent->mm;
12404
12405 if ( mm==NULL || mm->apple || cv->b.sc->parent!=mm->normal )
12406 return;
12407 err = MMBlendChar(mm,cv->b.sc->orig_pos);
12408 if ( mm->normal->glyphs[cv->b.sc->orig_pos]!=NULL )
12409 _SCCharChangedUpdate(mm->normal->glyphs[cv->b.sc->orig_pos],CVLayer((CharViewBase *)cv->b.sc),-1);
12410 if ( err!=0 )
12411 ff_post_error(_("Bad Multiple Master Font"),err);
12412 }
12413
12414 static GMenuItem2 mmlist[] = {
12415 /* GT: Here (and following) MM means "MultiMaster" */
12416 { { (unichar_t *) N_("MM _Reblend"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("MM Reblend|No Shortcut"), NULL, NULL, CVMenuReblend, MID_MMReblend },
12417 { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
12418 { { (unichar_t *) N_("_View"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, NULL, mvlist, mvlistcheck, NULL, 0 },
12419 GMENUITEM2_EMPTY
12420 };
12421
CVMenuShowSubChar(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))12422 static void CVMenuShowSubChar(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
12423 CharView *cv = (CharView *) GDrawGetUserData(gw);
12424 SplineFont *new = mi->ti.userdata;
12425 /* Change to the same char in a different instance font of the mm */
12426
12427 CVChangeSC(cv,SFMakeChar(new,cv->b.fv->map,CVCurEnc(cv)));
12428 cv->b.layerheads[dm_grid] = &new->grid;
12429 }
12430
mmlistcheck(GWindow gw,struct gmenuitem * mi,GEvent * UNUSED (e))12431 static void mmlistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
12432 CharView *cv = (CharView *) GDrawGetUserData(gw);
12433 int i, base, j;
12434 MMSet *mm = cv->b.sc->parent->mm;
12435 SplineFont *sub;
12436 GMenuItem2 *mml;
12437
12438 base = sizeof(mmlist)/sizeof(mmlist[0]);
12439 if ( mm==NULL )
12440 mml = mmlist;
12441 else {
12442 mml = calloc(base+mm->instance_count+2,sizeof(GMenuItem2));
12443 memcpy(mml,mmlist,sizeof(mmlist));
12444 mml[base-1].ti.fg = mml[base-1].ti.bg = COLOR_DEFAULT;
12445 mml[base-1].ti.line = true;
12446 for ( j = 0, i=base; j<mm->instance_count+1; ++i, ++j ) {
12447 if ( j==0 )
12448 sub = mm->normal;
12449 else
12450 sub = mm->instances[j-1];
12451 mml[i].ti.text = uc_copy(sub->fontname);
12452 mml[i].ti.checkable = true;
12453 mml[i].ti.checked = sub==cv->b.sc->parent;
12454 mml[i].ti.userdata = sub;
12455 mml[i].invoke = CVMenuShowSubChar;
12456 mml[i].ti.fg = mml[i].ti.bg = COLOR_DEFAULT;
12457 }
12458 }
12459 mml[0].ti.disabled = (mm==NULL || cv->b.sc->parent!=mm->normal || mm->apple);
12460 GMenuItemArrayFree(mi->sub);
12461 mi->sub = GMenuItem2ArrayCopy(mml,NULL);
12462 if ( mml!=mmlist ) {
12463 for ( i=base; mml[i].ti.text!=NULL; ++i )
12464 free( mml[i].ti.text);
12465 free(mml);
12466 }
12467 }
12468
CVMenuContextualHelp(GWindow UNUSED (gw),struct gmenuitem * UNUSED (mi),GEvent * UNUSED (e))12469 static void CVMenuContextualHelp(GWindow UNUSED(gw), struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
12470 help("ui/mainviews/charview.html", NULL);
12471 }
12472
12473 static GMenuItem2 mblist[] = {
12474 { { (unichar_t *) N_("_File"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'F' }, H_("File|No Shortcut"), fllist, fllistcheck, NULL, 0 },
12475 { { (unichar_t *) N_("_Edit"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'E' }, H_("Edit|No Shortcut"), edlist, edlistcheck, NULL, 0 },
12476 { { (unichar_t *) N_("_Point"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'P' }, H_("Point|No Shortcut"), ptlist, ptlistcheck, NULL, 0 },
12477 { { (unichar_t *) N_("E_lement"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'l' }, H_("Element|No Shortcut"), ellist, ellistcheck, NULL, 0 },
12478 #ifndef _NO_PYTHON
12479 { { (unichar_t *) N_("_Tools"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'l' }, H_("Tools|No Shortcut"), NULL, cvpy_tllistcheck, NULL, 0 },
12480 #endif
12481 #ifdef NATIVE_CALLBACKS
12482 { { (unichar_t *) N_("Tools_2"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'l' }, H_("Tools2|No Shortcut"), NULL, cv_tl2listcheck, NULL, 0},
12483 #endif
12484 { { (unichar_t *) N_("H_ints"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'H' }, H_("Hints|No Shortcut"), htlist, htlistcheck, NULL, 0 },
12485 { { (unichar_t *) N_("_View"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'V' }, H_("View|No Shortcut"), vwlist, vwlistcheck, NULL, 0 },
12486 { { (unichar_t *) N_("_Metrics"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'M' }, H_("Metrics|No Shortcut"), mtlist, mtlistcheck, NULL, 0 },
12487 /* GT: Here (and following) MM means "MultiMaster" */
12488 { { (unichar_t *) N_("MM"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, '\0' }, H_("MM|No Shortcut"), mmlist, mmlistcheck, NULL, 0 },
12489 { { (unichar_t *) N_("_Window"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'W' }, H_("Window|No Shortcut"), wnmenu, CVWindowMenuBuild, NULL, 0 },
12490 { { (unichar_t *) N_("_Help"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'H' }, H_("Help|No Shortcut"), helplist, NULL, NULL, 0 },
12491 GMENUITEM2_EMPTY
12492 };
12493
12494 static GMenuItem2 mblist_nomm[] = {
12495 { { (unichar_t *) N_("_File"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'F' }, H_("File|No Shortcut"), fllist, fllistcheck, NULL, 0 },
12496 { { (unichar_t *) N_("_Edit"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'E' }, H_("Edit|No Shortcut"), edlist, edlistcheck, NULL, 0 },
12497 { { (unichar_t *) N_("_Point"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'P' }, H_("Point|No Shortcut"), ptlist, ptlistcheck, NULL, 0 },
12498 { { (unichar_t *) N_("E_lement"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'l' }, H_("Element|No Shortcut"), ellist, ellistcheck, NULL, 0 },
12499 #ifndef _NO_PYTHON
12500 { { (unichar_t *) N_("_Tools"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 1, 0, 0, 0, 0, 0, 1, 1, 0, 'l' }, H_("Tools|No Shortcut"), NULL, cvpy_tllistcheck, NULL, 0 },
12501 #endif
12502 #ifdef NATIVE_CALLBACKS
12503 { { (unichar_t *) N_("Tools_2"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 1, 0, 0, 0, 0, 0, 1, 1, 0, 'l' }, H_("Tools2|No Shortcut"), NULL, cv_tl2listcheck, NULL, 0},
12504 #endif
12505 { { (unichar_t *) N_("H_ints"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'H' }, H_("Hints|No Shortcut"), htlist, htlistcheck, NULL, 0 },
12506 { { (unichar_t *) N_("_View"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'V' }, H_("View|No Shortcut"), vwlist, vwlistcheck, NULL, 0 },
12507 { { (unichar_t *) N_("_Metrics"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'M' }, H_("Metrics|No Shortcut"), mtlist, mtlistcheck, NULL, 0 },
12508 { { (unichar_t *) N_("_Window"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'W' }, H_("Window|No Shortcut"), wnmenu, CVWindowMenuBuild, NULL, 0 },
12509 { { (unichar_t *) N_("_Help"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'H' }, H_("Help|No Shortcut"), helplist, NULL, NULL, 0 },
12510 GMENUITEM2_EMPTY
12511 };
12512
_CharViewCreate(CharView * cv,SplineChar * sc,FontView * fv,int enc,int show)12513 static void _CharViewCreate(CharView *cv, SplineChar *sc, FontView *fv,int enc,int show) {
12514 CharViewTab* tab = CVGetActiveTab(cv);
12515 GRect pos;
12516 GWindowAttrs wattrs;
12517 GGadgetData gd;
12518 int sbsize;
12519 FontRequest rq;
12520 int as, ds, ld;
12521 extern int updateflex;
12522 static char *infofamily=NULL;
12523 GTextBounds textbounds;
12524 /* extern int cv_auto_goto; */
12525 extern enum cvtools cv_b1_tool, cv_cb1_tool, cv_b2_tool, cv_cb2_tool;
12526
12527 if ( !cvcolsinited )
12528 CVColInit();
12529
12530 static int firstCharView = 1;
12531 if( firstCharView )
12532 {
12533 firstCharView = 0;
12534 CVShows.alwaysshowcontrolpoints = prefs_cv_show_control_points_always_initially;
12535 }
12536
12537 cv->b.sc = sc;
12538 tab->scale = .5;
12539 tab->xoff = tab->yoff = 20;
12540 cv->b.next = sc->views;
12541 sc->views = &cv->b;
12542 cv->b.fv = &fv->b;
12543 cv->map_of_enc = fv->b.map;
12544 cv->enc = enc;
12545 cv->p.pretransform_spl = NULL;
12546 cv->b.drawmode = dm_fore;
12547
12548 memset(cv->showback,-1,sizeof(cv->showback));
12549 if ( !CVShows.showback )
12550 cv->showback[0] &= ~1;
12551 cv->showfore = CVShows.showfore;
12552 cv->showgrids = CVShows.showgrids;
12553 cv->showhhints = CVShows.showhhints;
12554 cv->showvhints = CVShows.showvhints;
12555 cv->showdhints = CVShows.showdhints;
12556 cv->showpoints = CVShows.showpoints;
12557 cv->alwaysshowcontrolpoints = CVShows.alwaysshowcontrolpoints;
12558 cv->showrulers = CVShows.showrulers;
12559 cv->showfilled = CVShows.showfilled;
12560 cv->showrounds = CVShows.showrounds;
12561 cv->showmdx = CVShows.showmdx;
12562 cv->showmdy = CVShows.showmdy;
12563 cv->showhmetrics = CVShows.showhmetrics;
12564 cv->showvmetrics = sc->parent->hasvmetrics ? CVShows.showvmetrics : 0;
12565 cv->markextrema = CVShows.markextrema;
12566 cv->showsidebearings = CVShows.showsidebearings;
12567 cv->showrefnames = CVShows.showrefnames;
12568 cv->snapoutlines = CVShows.snapoutlines;
12569 cv->markpoi = CVShows.markpoi;
12570 cv->showalmosthvlines = CVShows.showalmosthvlines;
12571 cv->showalmosthvcurves = CVShows.showalmosthvcurves;
12572 cv->hvoffset = CVShows.hvoffset;
12573 cv->showblues = CVShows.showblues;
12574 cv->showfamilyblues = CVShows.showfamilyblues;
12575 cv->showanchor = CVShows.showanchor;
12576 cv->showcpinfo = CVShows.showcpinfo;
12577 cv->showtabs = CVShows.showtabs;
12578 cv->inPreviewMode = 0;
12579 cv->checkselfintersects = CVShows.checkselfintersects;
12580
12581 cv->showdebugchanges = CVShows.showdebugchanges;
12582
12583 cv->infoh = 13;
12584 #if defined(__MINGW32__)||defined(__CYGWIN__)
12585 cv->infoh = 26;
12586 #endif
12587 cv->rulerh = 16;
12588
12589 GDrawGetSize(cv->gw,&pos);
12590 memset(&gd,0,sizeof(gd));
12591 gd.pos.y = cv->mbh+cv->charselectorh+cv->infoh;
12592 gd.pos.width = sbsize = GDrawPointsToPixels(cv->gw,_GScrollBar_Width);
12593 gd.pos.height = pos.height-cv->mbh-cv->charselectorh-cv->infoh - sbsize;
12594 gd.pos.x = pos.width-sbsize;
12595 gd.flags = gg_visible|gg_enabled|gg_pos_in_pixels|gg_sb_vert;
12596 cv->vsb = GScrollBarCreate(cv->gw,&gd,cv);
12597
12598 gd.pos.y = pos.height-sbsize; gd.pos.height = sbsize;
12599 gd.pos.width = pos.width - sbsize;
12600 gd.pos.x = 0;
12601 gd.flags = gg_visible|gg_enabled|gg_pos_in_pixels|gg_text_xim;
12602 cv->hsb = GScrollBarCreate(cv->gw,&gd,cv);
12603
12604 GDrawGetSize(cv->gw,&pos);
12605 pos.y = cv->mbh+cv->charselectorh+cv->infoh; pos.height -= cv->mbh + cv->charselectorh + sbsize + cv->infoh;
12606 pos.x = 0; pos.width -= sbsize;
12607 if ( cv->showrulers ) {
12608 pos.y += cv->rulerh; pos.height -= cv->rulerh;
12609 pos.x += cv->rulerh; pos.width -= cv->rulerh;
12610 }
12611 memset(&wattrs,0,sizeof(wattrs));
12612 wattrs.mask = wam_events|wam_cursor|wam_backcol;
12613 wattrs.background_color = view_bgcol;
12614 wattrs.event_masks = -1;
12615 wattrs.cursor = ct_mypointer;
12616 cv->v = GWidgetCreateSubWindow(cv->gw,&pos,v_e_h,cv,&wattrs);
12617 GDrawSetWindowTypeName(cv->v, "CharView");
12618
12619 if ( GDrawRequestDeviceEvents(cv->v,input_em_cnt,input_em)>0 ) {
12620 /* Success! They've got a wacom tablet */
12621 }
12622
12623 if ( infofamily==NULL ) {
12624 infofamily = copy(GResourceFindString("CharView.InfoFamily"));
12625 /* FontConfig doesn't have access to all the X11 bitmap fonts */
12626 /* so the font I used to use isn't found, and a huge monster is */
12627 /* inserted instead */
12628 if ( infofamily==NULL )
12629 infofamily = SANS_UI_FAMILIES;
12630 }
12631
12632 memset(&rq,0,sizeof(rq));
12633 rq.utf8_family_name = infofamily;
12634 rq.point_size = GResourceFindInt("CharView.Rulers.FontSize", -10);
12635 rq.weight = 400;
12636 cv->small = GDrawInstanciateFont(cv->gw,&rq);
12637 GDrawWindowFontMetrics(cv->gw,cv->small,&as,&ds,&ld);
12638 cv->sfh = as+ds; cv->sas = as;
12639 GDrawSetFont(cv->gw,cv->small);
12640 GDrawGetText8Bounds(cv->gw,"0123456789",10,&textbounds);
12641 cv->sdh = textbounds.as+textbounds.ds+1;
12642 rq.point_size = 10;
12643 cv->normal = GDrawInstanciateFont(cv->gw,&rq);
12644 GDrawWindowFontMetrics(cv->gw,cv->normal,&as,&ds,&ld);
12645 cv->nfh = as+ds; cv->nas = as;
12646
12647 cv->height = pos.height; cv->width = pos.width;
12648 cv->gi.u.image = calloc(1,sizeof(struct _GImage));
12649 cv->gi.u.image->image_type = it_mono;
12650 cv->gi.u.image->clut = calloc(1,sizeof(GClut));
12651 cv->gi.u.image->clut->trans_index = cv->gi.u.image->trans = 0;
12652 cv->gi.u.image->clut->clut_len = 2;
12653 cv->gi.u.image->clut->clut[0] = view_bgcol;
12654 cv->gi.u.image->clut->clut[1] = fillcol;
12655 cv->b1_tool = cv_b1_tool; cv->cb1_tool = cv_cb1_tool;
12656 cv->b1_tool_old = cv->b1_tool;
12657 cv->b2_tool = cv_b2_tool; cv->cb2_tool = cv_cb2_tool;
12658 cv->s1_tool = cvt_freehand; cv->s2_tool = cvt_pen;
12659 cv->er_tool = cvt_knife;
12660 cv->showing_tool = cvt_pointer;
12661 cv->pressed_tool = cv->pressed_display = cv->active_tool = cvt_none;
12662 cv->spacebar_hold = 0;
12663 cv->b.layerheads[dm_fore] = &sc->layers[ly_fore];
12664 cv->b.layerheads[dm_back] = &sc->layers[ly_back];
12665 cv->b.layerheads[dm_grid] = &fv->b.sf->grid;
12666 if ( !sc->parent->multilayer && fv->b.active_layer!=ly_fore ) {
12667 cv->b.layerheads[dm_back] = &sc->layers[fv->b.active_layer];
12668 cv->b.drawmode = dm_back;
12669 }
12670
12671 #if HANYANG
12672 if ( sc->parent->rules!=NULL && sc->compositionunit )
12673 Disp_DefaultTemplate(cv);
12674 #endif
12675
12676 cv->olde.x = -1;
12677
12678 cv->ft_dpi = 72; cv->ft_pointsizex = cv->ft_pointsizey = 12.0;
12679 cv->ft_ppemx = cv->ft_ppemy = 12;
12680
12681 /*GWidgetHidePalettes();*/
12682 /*cv->tools = CVMakeTools(cv);*/
12683 /*cv->layers = CVMakeLayers(cv);*/
12684
12685 CVFit(cv);
12686 GDrawSetVisible(cv->v,true);
12687 GWindowClearFocusGadgetOfWindow(cv->v);
12688
12689 /*if ( cv_auto_goto )*/ /* Chinese input method steals hot key key-strokes */
12690 /* But if we don't do this, then people can't type menu short-cuts */
12691 cv->gic = GDrawCreateInputContext(cv->v,gic_root|gic_orlesser);
12692 GDrawSetGIC(cv->v,cv->gic,0,20);
12693 cv->gwgic = GDrawCreateInputContext(cv->gw,gic_root|gic_orlesser);
12694 GDrawSetGIC(cv->gw,cv->gwgic,0,20);
12695 if( show )
12696 {
12697 GDrawSetVisible(cv->gw,true);
12698 }
12699
12700 if ( (CharView *) (sc->views)==NULL && updateflex )
12701 SplineCharIsFlexible(sc,CVLayer((CharViewBase *) cv));
12702 if ( sc->inspiro && !hasspiro() && !sc->parent->complained_about_spiros ) {
12703 sc->parent->complained_about_spiros = true;
12704 #ifdef _NO_LIBSPIRO
12705 ff_post_error(_("You may not use spiros"),_("This glyph should display spiro points, but unfortunately this version of fontforge was not linked with the spiro library, so only normal bezier points will be displayed."));
12706 #else
12707 ff_post_error(_("You may not use spiros"),_("This glyph should display spiro points, but unfortunately FontForge was unable to load libspiro, spiros are not available for use, and normal bezier points will be displayed instead."));
12708 #endif
12709 }
12710
12711 }
12712
DefaultY(GRect * pos)12713 void DefaultY(GRect *pos) {
12714 static int nexty=0;
12715 GRect size;
12716
12717 GDrawGetSize(GDrawGetRoot(NULL),&size);
12718 if ( nexty!=0 ) {
12719 FontView *fv;
12720 int any=0, i;
12721 BDFFont *bdf;
12722 /* are there any open cv/bv windows? */
12723 for ( fv = fv_list; fv!=NULL && !any; fv = (FontView *) (fv->b.next) ) {
12724 for ( i=0; i<fv->b.sf->glyphcnt; ++i ) if ( fv->b.sf->glyphs[i]!=NULL ) {
12725 if ( fv->b.sf->glyphs[i]->views!=NULL ) {
12726 any = true;
12727 break;
12728 }
12729 }
12730 for ( bdf = fv->b.sf->bitmaps; bdf!=NULL && !any; bdf=bdf->next ) {
12731 for ( i=0; i<bdf->glyphcnt; ++i ) if ( bdf->glyphs[i]!=NULL ) {
12732 if ( bdf->glyphs[i]->views!=NULL ) {
12733 any = true;
12734 break;
12735 }
12736 }
12737 }
12738 }
12739 if ( !any ) nexty = 0;
12740 }
12741 pos->y = nexty;
12742 nexty += 200;
12743 if ( nexty+pos->height > size.height )
12744 nexty = 0;
12745 }
12746
12747 static void CharViewInit(void);
12748
CV_OnCharSelectorTextChanged(GGadget * g,GEvent * e)12749 static int CV_OnCharSelectorTextChanged( GGadget *g, GEvent *e )
12750 {
12751 CharView* cv = GGadgetGetUserData(g);
12752 CharViewTab* tab = CVGetActiveTab(cv);
12753 SplineChar *sc = cv->b.sc;
12754 SplineFont* sf = sc->parent;
12755
12756 if ( e->type==et_controlevent && e->u.control.subtype == et_textchanged )
12757 {
12758 int pos = e->u.control.u.tf_changed.from_pulldown;
12759
12760 if ( pos!=-1 )
12761 {
12762 int32 len;
12763 GTextInfo **ti = GGadgetGetList(g,&len);
12764 GTextInfo *cur = ti[pos];
12765 int type = (intpt) cur->userdata;
12766 if ( type < 0 )
12767 {
12768 TRACE("load wordlist...! pos:%d\n",pos);
12769
12770 WordlistLoadToGTextInfo( cv->charselector, &cv->charselectoridx );
12771 return 0;
12772 }
12773 }
12774
12775 cv->charselectoridx = pos;
12776 char* txt = GGadgetGetTitle8( cv->charselector );
12777 TRACE("char selector @%d changed to:%s\n", pos, txt );
12778 {
12779 int tabnum = GTabSetGetSel(cv->tabs);
12780 CharViewTab* t = &cv->cvtabs[tabnum];
12781 strncpy( t->tablabeltxt, txt, charviewtab_charselectedsz );
12782 TRACE("tab num: %d set to %s\n", tabnum, t->tablabeltxt);
12783 GTabSetChangeTabName(cv->tabs,t->tablabeltxt,tabnum);
12784 GTabSetRemetric(cv->tabs);
12785 GTabSetSetSel(cv->tabs,tabnum); /* This does a redraw */
12786 }
12787
12788 memset( cv->additionalCharsToShow, 0, sizeof(SplineChar*) * additionalCharsToShowLimit );
12789 cv->additionalCharsToShowActiveIndex = 0;
12790 cv->additionalCharsToShow[0] = cv->b.sc;
12791
12792 int hadSelection = 0;
12793 if( txt[0] == '\0' )
12794 {
12795 CVSetCharSelectorValueFromSC( cv, cv->b.sc );
12796 }
12797 else if( strlen(txt) > 1 )
12798 {
12799 int i=0;
12800 unichar_t *ret = GGadgetGetTitle( cv->charselector );
12801 WordListLine wll = WordlistEscapedInputStringToParsedData( sf, ret );
12802 WordListLine pt = wll;
12803 WordListLine ept = WordListLine_end(wll);
12804 WordListLine tpt = 0;
12805 for ( tpt=pt; tpt<ept; ++tpt )
12806 {
12807 if( tpt == pt )
12808 {
12809 // your own char at the leading of the text
12810 cv->additionalCharsToShow[i] = tpt->sc;
12811 i++;
12812 continue;
12813 }
12814
12815 cv->additionalCharsToShow[i] = tpt->sc;
12816
12817 i++;
12818 if( i >= additionalCharsToShowLimit )
12819 break;
12820 }
12821 free(ret);
12822
12823 if( wll->sc )
12824 {
12825 if( wll->isSelected )
12826 {
12827 // first char selected, nothing to do!
12828 }
12829 else
12830 {
12831 while( wll->sc && !(wll->isSelected))
12832 wll++;
12833 if( wll->sc && wll->isSelected )
12834 {
12835 SplineChar* xc = wll->sc;
12836 if( xc )
12837 {
12838 TRACE("selected v:%d xc:%s\n", wll->currentGlyphIndex, xc->name );
12839 int xoff = tab->xoff;
12840 CVSwitchActiveSC( cv, xc, wll->currentGlyphIndex );
12841 CVHScrollSetPos( cv, xoff );
12842 hadSelection = 1;
12843 }
12844
12845 }
12846 }
12847 }
12848 }
12849 free(txt);
12850
12851 int i=0;
12852 for( i=0; cv->additionalCharsToShow[i]; i++ )
12853 {
12854 TRACE("i:%d %p .. ", i, cv->additionalCharsToShow[i] );
12855 TRACE(" %s\n", cv->additionalCharsToShow[i]->name );
12856 }
12857
12858 if( !hadSelection )
12859 CVSwitchActiveSC( cv, 0, 0 );
12860 GDrawRequestExpose(cv->v,NULL,false);
12861 }
12862 return( true );
12863 }
12864
12865 GTextInfo cv_charselector_init[] = {
12866 { (unichar_t *) "", NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 1, 0, 1, 0, 0, '\0'},
12867 { NULL, NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 1, 0, 0, 0, '\0'},
12868 { (unichar_t *) N_("Load Word List..."), NULL, 0, 0, (void *) -1, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
12869 // { (unichar_t *) N_("Load Glyph Name List..."), NULL, 0, 0, (void *) -2, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
12870 GTEXTINFO_EMPTY
12871 };
12872
12873
CharViewCreateExtended(SplineChar * sc,FontView * fv,int enc,int show)12874 CharView *CharViewCreateExtended(SplineChar *sc, FontView *fv,int enc, int show )
12875 {
12876 CharView *cv = calloc(1,sizeof(CharView));
12877 GWindowAttrs wattrs;
12878 GRect pos, zoom;
12879 GWindow gw;
12880 GGadgetData gd;
12881 GTabInfo aspects[2];
12882 GRect gsize;
12883 char buf[300];
12884 GTextInfo label[9];
12885
12886 CharViewInit();
12887
12888 cv->b.sc = sc;
12889 cv->b.fv = &fv->b;
12890 cv->enc = enc;
12891 cv->map_of_enc = fv->b.map; /* I know this is done again in _CharViewCreate, but it needs to be done before creating the title */
12892
12893 cv->infoh = 13;
12894 #if defined(__MINGW32__)||defined(__CYGWIN__)
12895 cv->infoh = 26;
12896 #endif
12897 cv->rulerh = 16;
12898
12899 cv->ctpos = -1;
12900
12901
12902 SCLigCaretCheck(sc,false);
12903
12904 memset(&wattrs,0,sizeof(wattrs));
12905 wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_utf8_ititle;
12906 wattrs.event_masks = -1;
12907 wattrs.cursor = ct_mypointer;
12908 wattrs.utf8_icon_title = (const char*)CVMakeTitles(cv,buf,sizeof(buf));
12909 wattrs.utf8_window_title = buf;
12910 wattrs.icon = CharIcon(cv, fv);
12911 if ( wattrs.icon )
12912 wattrs.mask |= wam_icon;
12913 pos.x = GGadgetScale(104)+6;
12914 pos.width = (cv_width > 0) ? cv_width : default_cv_width;
12915 pos.height = (cv_height > 0) ? cv_height : default_cv_height;
12916 DefaultY(&pos);
12917
12918 cv->gw = gw = GDrawCreateTopWindow(NULL,&pos,cv_e_h,cv,&wattrs);
12919 free( (unichar_t *) wattrs.icon_title );
12920 free((char*)wattrs.utf8_icon_title);
12921 GDrawSetWindowTypeName(cv->gw, "CharView");
12922
12923 // FIXME: cant do this until gw is shown?
12924 GTextBounds textbounds;
12925 GDrawGetText8Bounds(cv->gw,"0123456789hl",10,&textbounds);
12926 TRACE("XXXXXX as:%d ds:%d\n", textbounds.as, textbounds.ds );
12927 cv->charselectorh = textbounds.as+textbounds.ds+1;
12928 TRACE("XXXXXX h:%d\n", GDrawGetText8Height( cv->gw, "0123456AZgplh", 10));
12929 cv->charselectorh = 35;
12930
12931
12932 GDrawGetSize(GDrawGetRoot(screen_display),&zoom);
12933 zoom.x = CVPalettesWidth(); zoom.width -= zoom.x-10;
12934 zoom.height -= 30; /* Room for title bar & such */
12935 GDrawSetZoom(gw,&zoom,-1);
12936
12937 memset(&gd,0,sizeof(gd));
12938 gd.flags = gg_visible | gg_enabled;
12939 helplist[0].invoke = CVMenuContextualHelp;
12940 #ifndef _NO_PYTHON
12941 if ( cvpy_menu!=NULL )
12942 mblist[4].ti.disabled = mblist_nomm[4].ti.disabled = false;
12943 mblist[4].sub = mblist_nomm[4].sub = cvpy_menu;
12944 #define CALLBACKS_INDEX 5 /* FIXME: There has to be a better way than this. */
12945 #else
12946 #define CALLBACKS_INDEX 4 /* FIXME: There has to be a better way than this. */
12947 #endif /* _NO_PYTHON */
12948 #ifdef NATIVE_CALLBACKS
12949 if ( cv_menu!=NULL )
12950 mblist[CALLBACKS_INDEX].ti.disabled = mblist_nomm[CALLBACKS_INDEX].ti.disabled = false;
12951 mblist[CALLBACKS_INDEX].sub = mblist_nomm[CALLBACKS_INDEX].sub = cv_menu;
12952 #endif /* NATIVE_CALLBACKS */
12953 gd.u.menu2 = sc->parent->mm==NULL ? mblist_nomm : mblist;
12954 cv->mb = GMenu2BarCreate( gw, &gd, NULL);
12955 GGadgetGetSize(cv->mb,&gsize);
12956 cv->mbh = gsize.height;
12957
12958 // TRACE("pos.x:%d pos.y:%d pos.w:%d pos.h:%d\n", pos.x, pos.y, pos.width, pos.height );
12959 GDrawGetSize(cv->gw,&pos);
12960 memset(&gd,0,sizeof(gd));
12961 // gd.pos.x = pos.x;
12962 gd.pos.x = 3;
12963 gd.pos.y = cv->mbh+2;
12964 gd.pos.height = cv->charselectorh-4;
12965 gd.pos.width = cv_width / 2;
12966 gd.flags = gg_visible|gg_enabled|gg_pos_in_pixels|gg_text_xim;
12967 gd.handle_controlevent = CV_OnCharSelectorTextChanged;
12968 gd.u.list = cv_charselector_init;
12969 cv->charselector = GListFieldCreate(cv->gw,&gd,cv);
12970 CVSetCharSelectorValueFromSC( cv, sc );
12971 GGadgetSetSkipUnQualifiedHotkeyProcessing( cv->charselector, 1 );
12972
12973 // Up and Down buttons for moving through the word list.
12974 {
12975 GGadgetData xgd = gd;
12976 gd.pos.width += 2 * xgd.pos.height + 4;
12977 memset(label, '\0', sizeof(GTextInfo));
12978 xgd.pos.x += xgd.pos.width + 2;
12979 xgd.pos.width = xgd.pos.height;
12980 xgd.flags = gg_visible|gg_enabled|gg_pos_in_pixels;
12981 xgd.handle_controlevent = CVMoveToPrevInWordList;
12982 xgd.label = &label[0];
12983 label[0].text = (unichar_t *) "⇞";
12984 label[0].text_is_1byte = true;
12985 cv->charselectorPrev = GButtonCreate(cv->gw,&xgd,cv);
12986 memset(label, '\0', sizeof(GTextInfo));
12987 xgd.pos.x += xgd.pos.width + 2;
12988 xgd.pos.width = xgd.pos.height;
12989 xgd.flags = gg_visible|gg_enabled|gg_pos_in_pixels;
12990 xgd.handle_controlevent = CVMoveToNextInWordList;
12991 xgd.label = &label[0];
12992 label[0].text = (unichar_t *) "⇟";
12993 label[0].text_is_1byte = true;
12994 cv->charselectorNext = GButtonCreate(cv->gw,&xgd,cv);
12995 }
12996
12997
12998 memset(aspects,0,sizeof(aspects));
12999 aspects[0].text = (unichar_t *) sc->name;
13000 aspects[0].text_is_1byte = true;
13001 /* NOT visible until we add a second glyph to the stack */
13002 gd.flags = gg_enabled|gg_tabset_nowindow|gg_tabset_scroll|gg_pos_in_pixels;
13003 gd.u.menu = NULL;
13004 gd.u.tabs = aspects;
13005 gd.pos.x = 0;
13006 gd.pos.y = cv->mbh;
13007 gd.handle_controlevent = CVChangeToFormer;
13008 cv->tabs = GTabSetCreate( gw, &gd, NULL );
13009 cv->former_cnt = 1;
13010 cv->former_names[0] = copy(sc->name);
13011 GTabSetSetClosable(cv->tabs, true);
13012 GTabSetSetMovable(cv->tabs, true);
13013 GTabSetSetRemoveSync(cv->tabs, CVTabSetRemoveSync);
13014 GTabSetSetSwapSync(cv->tabs, CVTabSetSwapSync);
13015 GGadgetTakesKeyboard(cv->tabs,false);
13016
13017 _CharViewCreate( cv, sc, fv, enc, show );
13018 // Frank wants to avoid needing to implement scaling twice.
13019 CVResize(cv);
13020
13021 return( cv );
13022 }
13023
CharViewCreate(SplineChar * sc,FontView * fv,int enc)13024 CharView *CharViewCreate(SplineChar *sc, FontView *fv,int enc)
13025 {
13026 return CharViewCreateExtended( sc, fv, enc, 1 );
13027 }
13028
CharViewFree(CharView * cv)13029 void CharViewFree(CharView *cv) {
13030 int i;
13031
13032 if ( cv->qg != NULL )
13033 QGRmCharView(cv->qg,cv);
13034 BDFCharFree(cv->filled);
13035 if ( cv->ruler_w ) {
13036 GDrawDestroyWindow(cv->ruler_w);
13037 cv->ruler_w = NULL;
13038 }
13039 if ( cv->ruler_linger_w ) {
13040 GDrawDestroyWindow(cv->ruler_linger_w);
13041 cv->ruler_linger_w = NULL;
13042 }
13043 free(cv->gi.u.image->clut);
13044 free(cv->gi.u.image);
13045 #if HANYANG
13046 if ( cv->jamodisplay!=NULL )
13047 Disp_DoFinish(cv->jamodisplay,true);
13048 #endif
13049
13050 CVDebugFree(cv->dv);
13051
13052 SplinePointListsFree(cv->b.gridfit);
13053 FreeType_FreeRaster(cv->oldraster);
13054 FreeType_FreeRaster(cv->raster);
13055
13056 CVDebugFree(cv->dv);
13057
13058 for ( i=0; i<cv->former_cnt; ++i )
13059 free(cv->former_names[i]);
13060
13061 free(cv->ruler_intersections);
13062 free(cv);
13063 }
13064
CVValid(SplineFont * sf,SplineChar * sc,CharView * cv)13065 int CVValid(SplineFont *sf, SplineChar *sc, CharView *cv) {
13066 /* A charview may have been closed. A splinechar may have been removed */
13067 /* from a font */
13068 CharView *test;
13069
13070 if ( cv->b.sc!=sc || sc->parent!=sf )
13071 return( false );
13072 if ( sc->orig_pos<0 || sc->orig_pos>sf->glyphcnt )
13073 return( false );
13074 if ( sf->glyphs[sc->orig_pos]!=sc )
13075 return( false );
13076 for ( test=(CharView *) (sc->views); test!=NULL; test=(CharView *) (test->b.next) )
13077 if ( test==cv )
13078 return( true );
13079
13080 return( false );
13081 }
13082
13083 static int charview_ready = false;
13084
CharViewFinish()13085 static void CharViewFinish() {
13086 // The memory leak is limited and reachable.
13087 if ( !charview_ready ) return;
13088 charview_ready = false;
13089 mb2FreeGetText(mblist);
13090 mb2FreeGetText(spiroptlist);
13091 int i;
13092 for ( i=0; mblist_nomm[i].ti.text!=NULL; ++i ) {
13093 free(mblist_nomm[i].ti.text_untranslated); mblist_nomm[i].ti.text_untranslated = NULL;
13094 }
13095 }
13096
CharViewFinishNonStatic()13097 void CharViewFinishNonStatic() {
13098 CharViewFinish();
13099 }
13100
CharViewInit(void)13101 static void CharViewInit(void) {
13102 int i;
13103 // static int done = false; // superseded by charview_ready.
13104
13105 if ( charview_ready )
13106 return;
13107 charview_ready = true;
13108 // TRACE("CharViewInit(top) mblist[0].text before translation: %s\n", mblist[0].ti.text );
13109
13110 mb2DoGetText(mblist);
13111
13112 // TRACE("CharViewInit(2) mblist[0].text after translation: %s\n", u_to_c(mblist[0].ti.text) );
13113 // TRACE("CharViewInit(2) mblist[0].text_untranslated notrans: %s\n", mblist[0].ti.text_untranslated );
13114
13115 mb2DoGetText(spiroptlist);
13116 for ( i=0; mblist_nomm[i].ti.text!=NULL; ++i )
13117 {
13118 // Note that because we are doing this ourself we have to set
13119 // the text_untranslated ourself too.
13120 if( mblist_nomm[i].shortcut )
13121 mblist_nomm[i].ti.text_untranslated = copy(mblist_nomm[i].shortcut);
13122 else
13123 mblist_nomm[i].ti.text_untranslated = copy((char*)mblist_nomm[i].ti.text);
13124
13125 mblist_nomm[i].ti.text = (unichar_t *) _((char *) mblist_nomm[i].ti.text);
13126 }
13127 atexit(&CharViewFinishNonStatic);
13128 }
13129
nested_cv_e_h(GWindow gw,GEvent * event)13130 static int nested_cv_e_h(GWindow gw, GEvent *event) {
13131 CharView *cv = (CharView *) GDrawGetUserData(gw);
13132
13133 switch ( event->type ) {
13134 case et_expose:
13135 InfoExpose(cv,gw,event);
13136 CVLogoExpose(cv,gw,event);
13137 break;
13138 case et_char:
13139 (cv->b.container->funcs->charEvent)(cv->b.container,event);
13140 break;
13141 case et_charup:
13142 CVCharUp(cv,event);
13143 break;
13144 case et_controlevent:
13145 switch ( event->u.control.subtype ) {
13146 case et_scrollbarchange:
13147 if ( event->u.control.g == cv->hsb )
13148 CVHScroll(cv,&event->u.control.u.sb);
13149 else
13150 CVVScroll(cv,&event->u.control.u.sb);
13151 break;
13152 }
13153 break;
13154 case et_map:
13155 if ( event->u.map.is_visible )
13156 CVPaletteActivate(cv);
13157 else
13158 CVPalettesHideIfMine(cv);
13159 break;
13160 case et_resize:
13161 if ( event->u.resize.sized )
13162 CVResize(cv);
13163 break;
13164 case et_destroy:
13165 if ( cv->backimgs!=NULL ) {
13166 GDrawDestroyWindow(cv->backimgs);
13167 cv->backimgs = NULL;
13168 }
13169 break;
13170 case et_mouseup: case et_mousedown:
13171 GGadgetEndPopup();
13172 CVPaletteActivate(cv);
13173 break;
13174 }
13175 return( true );
13176 }
13177
SVCharViewInits(SearchView * sv)13178 void SVCharViewInits(SearchView *sv) {
13179 GGadgetData gd;
13180 GWindowAttrs wattrs;
13181 GRect pos, gsize;
13182
13183 CharViewInit();
13184
13185 memset(&gd,0,sizeof(gd));
13186 gd.flags = gg_visible | gg_enabled;
13187 helplist[0].invoke = CVMenuContextualHelp;
13188 gd.u.menu2 = mblist_nomm;
13189 sv->mb = GMenu2BarCreate( sv->gw, &gd, NULL);
13190 GGadgetGetSize(sv->mb,&gsize);
13191 sv->mbh = gsize.height;
13192
13193 pos.y = sv->mbh+sv->fh+10; pos.height = 220;
13194 pos.width = pos.height; pos.x = 10+pos.width+20; /* Do replace first so palettes appear propperly */
13195 sv->rpl_x = pos.x; sv->cv_y = pos.y;
13196 sv->cv_height = pos.height; sv->cv_width = pos.width;
13197 memset(&wattrs,0,sizeof(wattrs));
13198 wattrs.mask = wam_events|wam_cursor;
13199 wattrs.event_masks = -1;
13200 wattrs.cursor = ct_mypointer;
13201 sv->cv_rpl.gw = GWidgetCreateSubWindow(sv->gw,&pos,nested_cv_e_h,&sv->cv_rpl,&wattrs);
13202 _CharViewCreate(&sv->cv_rpl, &sv->sd.sc_rpl, &sv->dummy_fv, 1, 1);
13203
13204 pos.x = 10;
13205 sv->cv_srch.gw = GWidgetCreateSubWindow(sv->gw,&pos,nested_cv_e_h,&sv->cv_srch,&wattrs);
13206 _CharViewCreate(&sv->cv_srch, &sv->sd.sc_srch, &sv->dummy_fv, 0, 1);
13207 }
13208
13209 /* Same for the MATH Kern dlg */
13210
MKDCharViewInits(MathKernDlg * mkd)13211 void MKDCharViewInits(MathKernDlg *mkd) {
13212 GGadgetData gd;
13213 GWindowAttrs wattrs;
13214 GRect pos, gsize;
13215 int i;
13216
13217 CharViewInit();
13218
13219 memset(&gd,0,sizeof(gd));
13220 gd.flags = gg_visible | gg_enabled;
13221 helplist[0].invoke = CVMenuContextualHelp;
13222 gd.u.menu2 = mblist_nomm;
13223 mkd->mb = GMenu2BarCreate( mkd->gw, &gd, NULL);
13224 GGadgetGetSize(mkd->mb,&gsize);
13225 mkd->mbh = gsize.height;
13226
13227 mkd->mid_space = 20;
13228 for ( i=3; i>=0; --i ) { /* Create backwards so palettes get set in topright (last created) */
13229 pos.y = mkd->fh+10; pos.height = 220; /* Size doesn't matter, adjusted later */
13230 pos.width = pos.height; pos.x = 10+i*(pos.width+20);
13231 mkd->cv_y = pos.y;
13232 mkd->cv_height = pos.height; mkd->cv_width = pos.width;
13233 memset(&wattrs,0,sizeof(wattrs));
13234 wattrs.mask = wam_events|wam_cursor;
13235 wattrs.event_masks = -1;
13236 wattrs.cursor = ct_mypointer;
13237 (&mkd->cv_topright)[i].gw = GWidgetCreateSubWindow(mkd->cvparent_w,&pos,nested_cv_e_h,(&mkd->cv_topright)+i,&wattrs);
13238 _CharViewCreate((&mkd->cv_topright)+i, (&mkd->sc_topright)+i, &mkd->dummy_fv, i, 1);
13239 }
13240 }
13241
13242 /* Same for the Tile Path dlg */
13243
13244 #ifdef FONTFORGE_CONFIG_TILEPATH
13245
TPDCharViewInits(TilePathDlg * tpd,int cid)13246 void TPDCharViewInits(TilePathDlg *tpd, int cid) {
13247 GGadgetData gd;
13248 GWindowAttrs wattrs;
13249 GRect pos, gsize;
13250 int i;
13251
13252 CharViewInit();
13253
13254 memset(&gd,0,sizeof(gd));
13255 gd.flags = gg_visible | gg_enabled;
13256 helplist[0].invoke = CVMenuContextualHelp;
13257 gd.u.menu2 = mblist_nomm;
13258 tpd->mb = GMenu2BarCreate( tpd->gw, &gd, NULL);
13259 GGadgetGetSize(tpd->mb,&gsize);
13260 tpd->mbh = gsize.height;
13261
13262 tpd->mid_space = 20;
13263 for ( i=3; i>=0; --i ) { /* Create backwards so palettes get set in topright (last created) */
13264 pos.y = 0; pos.height = 220; /* Size doesn't matter, adjusted later */
13265 pos.width = pos.height; pos.x = 0;
13266 tpd->cv_y = pos.y;
13267 tpd->cv_height = pos.height; tpd->cv_width = pos.width;
13268 memset(&wattrs,0,sizeof(wattrs));
13269 wattrs.mask = wam_events|wam_cursor;
13270 wattrs.event_masks = -1;
13271 wattrs.cursor = ct_mypointer;
13272 (&tpd->cv_first)[i].gw = GWidgetCreateSubWindow(GDrawableGetWindow(GWidgetGetControl(tpd->gw,cid+i)),
13273 &pos,nested_cv_e_h,(&tpd->cv_first)+i,&wattrs);
13274 _CharViewCreate((&tpd->cv_first)+i, (&tpd->sc_first)+i, &tpd->dummy_fv, i, 1 );
13275 }
13276 }
13277
PTDCharViewInits(TilePathDlg * tpd,int cid)13278 void PTDCharViewInits(TilePathDlg *tpd, int cid) {
13279 GGadgetData gd;
13280 GWindowAttrs wattrs;
13281 GRect pos, gsize;
13282
13283 CharViewInit();
13284
13285 memset(&gd,0,sizeof(gd));
13286 gd.flags = gg_visible | gg_enabled;
13287 helplist[0].invoke = CVMenuContextualHelp;
13288 gd.u.menu2 = mblist_nomm;
13289 tpd->mb = GMenu2BarCreate( tpd->gw, &gd, NULL);
13290 GGadgetGetSize(tpd->mb,&gsize);
13291 tpd->mbh = gsize.height;
13292
13293 tpd->mid_space = 20;
13294 {
13295 pos.y = 0; pos.height = 220; /* Size doesn't matter, adjusted later */
13296 pos.width = pos.height; pos.x = 0;
13297 tpd->cv_y = pos.y;
13298 tpd->cv_height = pos.height; tpd->cv_width = pos.width;
13299 memset(&wattrs,0,sizeof(wattrs));
13300 wattrs.mask = wam_events|wam_cursor;
13301 wattrs.event_masks = -1;
13302 wattrs.cursor = ct_mypointer;
13303 tpd->cv_first.gw = GWidgetCreateSubWindow(GDrawableGetWindow(GWidgetGetControl(tpd->gw,cid)),
13304 &pos,nested_cv_e_h,&tpd->cv_first,&wattrs);
13305 _CharViewCreate(&tpd->cv_first, &tpd->sc_first, &tpd->dummy_fv, 0, 1 );
13306 }
13307 }
13308 #endif /* TilePath */
13309
GDDCharViewInits(GradientDlg * gdd,int cid)13310 void GDDCharViewInits(GradientDlg *gdd, int cid) {
13311 GGadgetData gd;
13312 GWindowAttrs wattrs;
13313 GRect pos, gsize;
13314
13315 CharViewInit();
13316
13317 memset(&gd,0,sizeof(gd));
13318 gd.flags = gg_visible | gg_enabled;
13319 helplist[0].invoke = CVMenuContextualHelp;
13320 gd.u.menu2 = mblist_nomm;
13321 gdd->mb = GMenu2BarCreate( gdd->gw, &gd, NULL);
13322 GGadgetGetSize(gdd->mb,&gsize);
13323 gdd->mbh = gsize.height;
13324
13325 memset(&wattrs,0,sizeof(wattrs));
13326 wattrs.mask = wam_events|wam_cursor;
13327 wattrs.event_masks = -1;
13328 wattrs.cursor = ct_mypointer;
13329
13330 pos.y = 1; pos.height = 220;
13331 pos.width = pos.height; pos.x = 0;
13332 gdd->cv_grad.gw = GWidgetCreateSubWindow(
13333 GDrawableGetWindow(GWidgetGetControl(gdd->gw,cid)),
13334 &pos,nested_cv_e_h,&gdd->cv_grad,&wattrs);
13335 _CharViewCreate(&gdd->cv_grad, &gdd->sc_grad, &gdd->dummy_fv, 0, 1 );
13336 }
13337
StrokeCharViewInits(StrokeDlg * sd,int cid)13338 void StrokeCharViewInits(StrokeDlg *sd, int cid) {
13339 GGadgetData gd;
13340 GWindowAttrs wattrs;
13341 GRect pos, gsize;
13342
13343 CharViewInit();
13344
13345 memset(&gd,0,sizeof(gd));
13346 gd.flags = gg_visible | gg_enabled;
13347 helplist[0].invoke = CVMenuContextualHelp;
13348 gd.u.menu2 = mblist_nomm;
13349 sd->mb = GMenu2BarCreate( sd->gw, &gd, NULL);
13350 GGadgetGetSize(sd->mb,&gsize);
13351 sd->mbh = gsize.height;
13352
13353 memset(&wattrs,0,sizeof(wattrs));
13354 wattrs.mask = wam_events|wam_cursor;
13355 wattrs.event_masks = -1;
13356 wattrs.cursor = ct_mypointer;
13357
13358 pos.y = 1; pos.height = 220;
13359 pos.width = pos.height; pos.x = 0;
13360 sd->cv_stroke.gw = GWidgetCreateSubWindow(
13361 GDrawableGetWindow(GWidgetGetControl(sd->gw,cid)),
13362 &pos,nested_cv_e_h,&sd->cv_stroke,&wattrs);
13363 _CharViewCreate(&sd->cv_stroke, &sd->sc_stroke, &sd->dummy_fv, 0, 1 );
13364 }
13365
SC_CloseAllWindows(SplineChar * sc)13366 static void SC_CloseAllWindows(SplineChar *sc) {
13367 CharViewBase *cv, *next;
13368 BitmapView *bv, *bvnext;
13369 BDFFont *bdf;
13370 BDFChar *bfc;
13371 FontView *fvs;
13372
13373 if ( sc->views ) {
13374 for ( cv = sc->views; cv!=NULL; cv=next ) {
13375 next = cv->next;
13376 GDrawDestroyWindow(((CharView *) cv)->gw);
13377 }
13378 GDrawSync(NULL);
13379 GDrawProcessPendingEvents(NULL);
13380 GDrawSync(NULL);
13381 GDrawProcessPendingEvents(NULL);
13382 }
13383
13384 for ( bdf=sc->parent->bitmaps; bdf!=NULL; bdf = bdf->next ) {
13385 if ( sc->orig_pos<bdf->glyphcnt && (bfc = bdf->glyphs[sc->orig_pos])!= NULL ) {
13386 if ( bfc->views!=NULL ) {
13387 for ( bv= bfc->views; bv!=NULL; bv=bvnext ) {
13388 bvnext = bv->next;
13389 GDrawDestroyWindow(bv->gw);
13390 }
13391 GDrawSync(NULL);
13392 GDrawProcessPendingEvents(NULL);
13393 GDrawSync(NULL);
13394 GDrawProcessPendingEvents(NULL);
13395 }
13396 }
13397 }
13398
13399 /* Turn any searcher references to this glyph into inline copies of it */
13400 for ( fvs=(FontView *) sc->parent->fv; fvs!=NULL; fvs=(FontView *) fvs->b.nextsame ) {
13401 if ( fvs->sv!=NULL ) {
13402 RefChar *rf, *rnext;
13403 for ( rf = fvs->sv->sd.sc_srch.layers[ly_fore].refs; rf!=NULL; rf=rnext ) {
13404 rnext = rf->next;
13405 if ( rf->sc==sc )
13406 SCRefToSplines(&fvs->sv->sd.sc_srch,rf,ly_fore);
13407 }
13408 for ( rf = fvs->sv->sd.sc_rpl.layers[ly_fore].refs; rf!=NULL; rf=rnext ) {
13409 rnext = rf->next;
13410 if ( rf->sc==sc )
13411 SCRefToSplines(&fvs->sv->sd.sc_rpl,rf,ly_fore);
13412 }
13413 }
13414 }
13415 }
13416
13417 struct sc_interface gdraw_sc_interface = {
13418 SC_UpdateAll,
13419 SC_OutOfDateBackground,
13420 SC_RefreshTitles,
13421 SC_HintsChanged,
13422 SC_CharChangedUpdate,
13423 _SC_CharChangedUpdate,
13424 SC_MarkInstrDlgAsChanged,
13425 SC_CloseAllWindows,
13426 SC_MoreLayers
13427 };
13428
UI_CVGlyphRenameFixup(SplineFont * sf,const char * oldname,const char * newname)13429 static void UI_CVGlyphRenameFixup(SplineFont *sf, const char *oldname, const char *newname) {
13430 int gid, i;
13431 SplineChar *sc;
13432 CharView *cv;
13433
13434 if ( no_windowing_ui )
13435 return;
13436
13437 for ( gid=0; gid<sf->glyphcnt; ++gid ) if ( (sc=sf->glyphs[gid])!=NULL) {
13438 for ( cv=(CharView *) (sc->views); cv!=NULL; cv = (CharView *) (cv->b.next)) {
13439 for ( i=0; i<cv->former_cnt; ++i ) if ( strcmp(oldname,cv->former_names[i])==0 ) {
13440 free( cv->former_names[i] );
13441 cv->former_names[i] = copy( newname );
13442 if ( cv->tabs!=NULL ) {
13443 GTabSetChangeTabName(cv->tabs,newname,i);
13444 GTabSetRemetric(cv->tabs);
13445 GGadgetRedraw(cv->tabs);
13446 }
13447 }
13448 }
13449 }
13450 }
13451
13452 struct cv_interface gdraw_cv_interface = {
13453 (void (*)(CharViewBase *)) CV_CharChangedUpdate,
13454 (void (*)(CharViewBase *,int)) _CV_CharChangedUpdate,
13455 UI_CVGlyphRenameFixup,
13456 CV_LayerPaletteCheck
13457 };
13458
13459 extern GResInfo bitmapview_ri;
13460 GResInfo charview2_ri = {
13461 &bitmapview_ri, NULL,NULL, NULL,
13462 NULL,
13463 NULL,
13464 NULL,
13465 charview2_re,
13466 N_("Outline View 2"),
13467 N_("This window displays a single outline glyph (more data)"),
13468 "CharView",
13469 "fontforge",
13470 false,
13471 0,
13472 NULL,
13473 GBOX_EMPTY,
13474 NULL,
13475 NULL,
13476 NULL
13477 };
13478 GResInfo charview_ri = {
13479 &charview2_ri, NULL,NULL, NULL,
13480 NULL,
13481 NULL,
13482 NULL,
13483 charview_re,
13484 N_("Outline View"),
13485 N_("This window displays a single outline glyph"),
13486 "CharView",
13487 "fontforge",
13488 false,
13489 0,
13490 NULL,
13491 GBOX_EMPTY,
13492 NULL,
13493 NULL,
13494 NULL
13495 };
13496
13497
SPSelectNextPoint(SplinePoint * sp,int state)13498 void SPSelectNextPoint( SplinePoint *sp, int state )
13499 {
13500 if( !sp )
13501 return;
13502 if( !sp->next )
13503 return;
13504 if( !sp->next->to )
13505 return;
13506 sp->next->to->selected = state;
13507 }
13508
SPSelectPrevPoint(SplinePoint * sp,int state)13509 void SPSelectPrevPoint( SplinePoint *sp, int state )
13510 {
13511 if( !sp )
13512 return;
13513 if( !sp->prev )
13514 return;
13515 if( !sp->prev->from )
13516 return;
13517 sp->prev->from->selected = state;
13518 }
13519
13520
13521
SPIsNextCPSelectedSingle(SplinePoint * sp,CharView * cv)13522 bool SPIsNextCPSelectedSingle( SplinePoint *sp, CharView *cv )
13523 {
13524 if( cv )
13525 {
13526 int iscurrent = sp == (cv->p.sp!=NULL?cv->p.sp:cv->lastselpt);
13527 if( iscurrent && cv->p.nextcp )
13528 return true;
13529 }
13530 return false;
13531 }
13532
13533
SPIsNextCPSelected(SplinePoint * sp,CharView * cv)13534 bool SPIsNextCPSelected( SplinePoint *sp, CharView *cv )
13535 {
13536 if( SPIsNextCPSelectedSingle( sp, cv ))
13537 return true;
13538 return sp->nextcpselected;
13539 }
13540
SPIsPrevCPSelectedSingle(SplinePoint * sp,CharView * cv)13541 bool SPIsPrevCPSelectedSingle( SplinePoint *sp, CharView *cv )
13542 {
13543 if( cv )
13544 {
13545 int iscurrent = sp == (cv->p.sp!=NULL?cv->p.sp:cv->lastselpt);
13546 if( iscurrent && cv->p.prevcp )
13547 return true;
13548 }
13549 return false;
13550 }
13551
SPIsPrevCPSelected(SplinePoint * sp,CharView * cv)13552 bool SPIsPrevCPSelected( SplinePoint *sp, CharView *cv )
13553 {
13554 if( SPIsPrevCPSelectedSingle( sp, cv ))
13555 {
13556 return true;
13557 }
13558 return sp->prevcpselected;
13559 }
13560
CVShouldInterpolateCPsOnMotion(CharView * cv)13561 bool CVShouldInterpolateCPsOnMotion( CharView* cv )
13562 {
13563 bool ret = interpCPsOnMotion;
13564
13565 if( cv->activeModifierControl && cv->activeModifierAlt )
13566 ret = !ret;
13567
13568 return ret;
13569 }
13570
13571