Line data Source code
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 : #include <fontforge-config.h>
28 :
29 : #include "autohint.h"
30 : #include "autosave.h"
31 : #include "autotrace.h"
32 : #include "autowidth.h"
33 : #include "cvruler.h"
34 : #include "cvundoes.h"
35 : #include "dumppfa.h"
36 : #include "encoding.h"
37 : #include "fontforgeui.h"
38 : #include "fvcomposite.h"
39 : #include "fvfonts.h"
40 : #include "lookups.h"
41 : #include "mm.h"
42 : #include "namelist.h"
43 : #include "sfd.h"
44 : #include "spiro.h"
45 : #include "splinefill.h"
46 : #include "splineorder2.h"
47 : #include "splineoverlap.h"
48 : #include "splinesaveafm.h"
49 : #include "splineutil.h"
50 : #include "splineutil2.h"
51 : #include <math.h>
52 : #include <locale.h>
53 : #include <ustring.h>
54 : #include <utype.h>
55 : #include <gresource.h>
56 : #include <gresedit.h>
57 : #include <dlist.h>
58 : extern int _GScrollBar_Width;
59 : #include <gkeysym.h>
60 : #ifdef HAVE_IEEEFP_H
61 : # include <ieeefp.h> /* Solaris defines isnan in ieeefp rather than math.h */
62 : #endif
63 : #include "dlist.h"
64 : #include "c-strtod.h"
65 :
66 : #include "gutils/prefs.h"
67 : #include "collabclientui.h"
68 : #include "gutils/unicodelibinfo.h"
69 :
70 : #include "gdraw/hotkeys.h"
71 : #include "wordlistparser.h"
72 :
73 : #include "charview_private.h"
74 :
75 : /* Barry wants to be able to redefine menu bindings only in the charview (I think) */
76 : /* the menu parser will first check for something like "CV*Open|Ctl+O", and */
77 : /* if that fails will strip off "CV*" and check for "Open|Ctl+O" */
78 : #undef H_
79 : #define H_(str) ("CV*" str)
80 :
81 : extern void UndoesFreeButRetainFirstN( Undoes** undopp, int retainAmount );
82 : static void CVMoveInWordListByOffset( CharView* cv, int offset );
83 : extern void CVDebugFree( DebugView *dv );
84 :
85 : int additionalCharsToShowLimit = 50;
86 :
87 : int ItalicConstrained=true;
88 : float arrowAmount=1;
89 : float arrowAccelFactor=10.;
90 : float snapdistance=3.5;
91 : float snapdistancemeasuretool=3.5;
92 : int xorrubberlines=false;
93 : int updateflex = false;
94 : extern int clear_tt_instructions_when_needed;
95 : int use_freetype_with_aa_fill_cv = 1;
96 : int interpCPsOnMotion=false;
97 : int DrawOpenPathsWithHighlight = 1;
98 : #define default_cv_width 540
99 : #define default_cv_height 540
100 : int cv_width = default_cv_width;
101 : int cv_height = default_cv_height;
102 : int cv_show_fill_with_space = 1;
103 :
104 : #define prefs_cvEditHandleSize_default 5.0
105 : float prefs_cvEditHandleSize = prefs_cvEditHandleSize_default;
106 :
107 : int prefs_cvInactiveHandleAlpha = 255;
108 :
109 : int prefs_cv_show_control_points_always_initially = 0;
110 : int prefs_create_dragging_comparison_outline = 0;
111 :
112 : extern struct lconv localeinfo;
113 : extern char *coord_sep;
114 : struct cvshows CVShows = {
115 : 1, /* show foreground */
116 : 1, /* show background */
117 : 1, /* show grid plane */
118 : 1, /* show horizontal hints */
119 : 1, /* show vertical hints */
120 : 1, /* show diagonal hints */
121 : 1, /* show points */
122 : 0, /* show filled */
123 : 1, /* show rulers */
124 : 1, /* show points which are to be rounded to the ttf grid and aren't on hints */
125 : 1, /* show x minimum distances */
126 : 1, /* show y minimum distances */
127 : 1, /* show horizontal metrics */
128 : 0, /* show vertical metrics */
129 : 0, /* mark extrema */
130 : 0, /* show points of inflection */
131 : 1, /* show blue values */
132 : 1, /* show family blues too */
133 : 1, /* show anchor points */
134 : 0, /* show control point info when moving them */
135 : 1, /* show tabs containing names of former glyphs */
136 : 1, /* show side bearings */
137 : 1, /* show the names of references */
138 : 1, /* snap outlines to pixel grid */
139 : 0, /* show lines which are almost, but not exactly horizontal or vertical */
140 : 0, /* show curves which are almost, but not exactly horizontal or vertical at the end-points */
141 : 3, /* number of em-units a coord difference must be less than to qualify for almost hv */
142 : 1, /* Check for self-intersections in the element view */
143 : 1 /* In tt debugging, mark changed rasters differently */
144 : };
145 : struct cvshows CVShowsPrevewToggleSavedState;
146 :
147 : #define CID_Base 1001
148 : #define CID_getValueFromUser CID_Base + 1
149 :
150 :
151 : // Note that the default values supplied in CVColInit over-ride these values.
152 : static Color pointcol = 0xff0000;
153 : static Color subcol = 0xffffff;
154 : static Color firstpointcol = 0x707000;
155 : static Color selectedpointcol = 0xc8c800;
156 : static int selectedpointwidth = 2;
157 : static Color extremepointcol = 0xCAA80A;
158 : static Color pointofinflectioncol = 0x008080;
159 : static Color almosthvcol = 0x00ff80;
160 : Color nextcpcol = 0x007090;
161 : Color prevcpcol = 0xcc00cc;
162 : static Color selectedcpcol = 0xffffff;
163 : static Color coordcol = 0x808080;
164 : Color widthcol = 0x000000;
165 : static Color widthselcol = 0x00ff00;
166 : static Color lbearingselcol = 0x00ff00;
167 : static Color widthgridfitcol = 0x009800;
168 : static Color lcaretcol = 0x909040;
169 : static Color rastercol = 0xffa0a0a0; /* Translucent */
170 : static Color rasternewcol = 0xff909090;
171 : static Color rasteroldcol = 0xffc0c0c0;
172 : static Color rastergridcol = 0xffb0b0ff;
173 : static Color rasterdarkcol = 0xff606060;
174 : static Color deltagridcol = 0xcc0000;
175 : static Color italiccoordcol = 0x909090;
176 : static Color metricslabelcol = 0x00000;
177 : static Color hintlabelcol = 0x00cccc;
178 : static Color bluevalstipplecol = 0x808080ff; /* Translucent */
179 : static Color fambluestipplecol = 0x80ff7070; /* Translucent */
180 : static Color mdhintcol = 0x80e04040; /* Translucent */
181 : static Color dhintcol = 0x80d0a0a0; /* Translucent */
182 : static Color hhintcol = 0x80a0d0a0; /* Translucent */
183 : static Color vhintcol = 0x80c0c0ff; /* Translucent */
184 : static Color hflexhintcol = 0x00ff00;
185 : static Color vflexhintcol = 0x00ff00;
186 : static Color conflicthintcol = 0x00ffff;
187 : static Color hhintactivecol = 0x00a000;
188 : static Color vhintactivecol = 0x0000ff;
189 : static Color anchorcol = 0x0040ff;
190 : static Color anchoredoutlinecol = 0x0040ff;
191 : static Color templateoutlinecol = 0x009800;
192 : static Color oldoutlinecol = 0x008000;
193 : static Color transformorigincol = 0x000000;
194 : static Color guideoutlinecol = 0x808080;
195 : static Color gridfitoutlinecol = 0x009800;
196 : static Color backoutlinecol = 0x009800;
197 : static Color foreoutlinecol = 0x000000;
198 : static Color clippathcol = 0x0000ff;
199 : static Color openpathcol = 0x660000;
200 : static Color backimagecol = 0x707070;
201 : static Color fillcol = 0x80707070; /* Translucent */
202 : static Color tracecol = 0x008000;
203 : static Color rulerbigtickcol = 0x008000;
204 : static Color previewfillcol = 0x0f0f0f;
205 : static Color DraggingComparisonOutlineColor = 0x8800BB00;
206 : static Color DraggingComparisonAlphaChannelOverride = 0x88000000;
207 : static Color foreoutthicklinecol = 0x20707070;
208 : static Color backoutthicklinecol = 0x20707070;
209 : int prefs_cv_outline_thickness = 1;
210 : int cvbutton3d = 1;
211 : Color cvbutton3dedgelightcol = 0xe0e0e0;
212 : Color cvbutton3dedgedarkcol = 0x707070;
213 :
214 : // Format is 0x AA RR GG BB.
215 :
216 : static void isAnyControlPointSelectedVisitor(SplinePoint* splfirst, Spline* s, SplinePoint* sp, void* udata );
217 : static int CV_OnCharSelectorTextChanged( GGadget *g, GEvent *e );
218 : static void CVHScrollSetPos( CharView *cv, int newpos );
219 :
220 : static void CVClear(GWindow,GMenuItem *mi, GEvent *);
221 : static void CVMouseMove(CharView *cv, GEvent *event );
222 : static void CVMouseUp(CharView *cv, GEvent *event );
223 : static void CVHScroll(CharView *cv,struct sbevent *sb);
224 : static void CVVScroll(CharView *cv,struct sbevent *sb);
225 : /*static void CVElide(GWindow gw,struct gmenuitem *mi,GEvent *e);*/
226 : static void CVMenuSimplify(GWindow gw,struct gmenuitem *mi,GEvent *e);
227 : static void CVMenuSimplifyMore(GWindow gw,struct gmenuitem *mi,GEvent *e);
228 : static void CVPreviewModeSet(GWindow gw, int checked);
229 :
230 : static int cvcolsinited = false;
231 :
232 : // Note that the GResource names for these preferences are defined separately in CVColInit.
233 : // It would be wise to match any changes to these data structures with changes to the values in CVColInit.
234 :
235 : static struct resed charview_re[] = {
236 : { N_("Point Color"), "PointColor", rt_color, &pointcol, N_("The color of an on-curve point"), NULL, { 0 }, 0, 0 },
237 : { 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 },
238 : { N_("Selected Point Color"), "SelectedPointColor", rt_color, &selectedpointcol, N_("The color of a selected point"), NULL, { 0 }, 0, 0 },
239 : { N_("Selected Point Width"), "SelectedPointWidth", rt_int, &selectedpointwidth, N_("The width of the line used to draw selected points"), NULL, { 0 }, 0, 0 },
240 : { 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 },
241 : { 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 },
242 : { 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 },
243 : { 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 },
244 : { 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 },
245 : { 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 },
246 : { N_("Coordinate Line Color"), "CoordinateLineColor", rt_color, &coordcol, NULL, NULL, { 0 }, 0, 0 },
247 : { N_("Italic Coord. Color"), "ItalicCoordColor", rt_color, &italiccoordcol, NULL, NULL, { 0 }, 0, 0 },
248 : { N_("Metrics Label Color"), "MetricsLabelColor", rt_color, &metricslabelcol, NULL, NULL, { 0 }, 0, 0 },
249 : { N_("Hint Label Color"), "HintLabelColor", rt_color, &hintlabelcol,NULL, NULL, { 0 }, 0, 0 },
250 : { 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 },
251 : { 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 },
252 : { N_("Diagonal Hint Color"), "DHintColor", rt_coloralpha, &dhintcol, N_("The color used to draw diagonal hints"), NULL, { 0 }, 0, 0 },
253 : { N_("Horiz. Hint Color"), "HHintColor", rt_coloralpha, &hhintcol, N_("The color used to draw horizontal hints"), NULL, { 0 }, 0, 0 },
254 : { N_("Vert. Hint Color"), "VHintColor", rt_coloralpha, &vhintcol, N_("The color used to draw vertical hints"), NULL, { 0 }, 0, 0 },
255 : { N_("HFlex Hint Color"), "HFlexHintColor", rt_color, &hflexhintcol, NULL, NULL, { 0 }, 0, 0 },
256 : { N_("VFlex Hint Color"), "VFlexHintColor", rt_color, &vflexhintcol, NULL, NULL, { 0 }, 0, 0 },
257 : { N_("Conflict Hint Color"), "ConflictHintColor", rt_color, &conflicthintcol, N_("The color used to draw a hint which conflicts with another"), NULL, { 0 }, 0, 0 },
258 : { 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 },
259 : { 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 },
260 : { 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 },
261 : { 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 },
262 : RESED_EMPTY
263 : };
264 :
265 : static struct resed charview2_re[] = {
266 : { N_("Width Color"), "WidthColor", rt_color, &widthcol, N_("The color of the line marking the advance width"), NULL, { 0 }, 0, 0 },
267 : { 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 },
268 : { 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 },
269 : { 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 },
270 : { N_("Ligature Caret Color"), "LigatureCaretColor", rt_color, &lcaretcol, N_("The color of the line(s) marking ligature carets"), NULL, { 0 }, 0, 0 },
271 : { N_("Anchor Color"), "AnchorColor", rt_color, &anchorcol, N_("The color of anchor stars"), NULL, { 0 }, 0, 0 },
272 : { 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 },
273 : { N_("Template Color"), "TemplateOutlineColor", rt_color, &templateoutlinecol, NULL, NULL, { 0 }, 0, 0 },
274 : { N_("Old Outline Color"), "OldOutlineColor", rt_color, &oldoutlinecol, NULL, NULL, { 0 }, 0, 0 },
275 : { N_("Original Color"), "TransformOriginColor", rt_color, &transformorigincol, NULL, NULL, { 0 }, 0, 0 },
276 : { N_("Guide Layer Color"), "GuideOutlineColor", rt_color, &guideoutlinecol, NULL, NULL, { 0 }, 0, 0 },
277 : { N_("Grid Fit Color"), "GridFitOutlineColor", rt_color, &gridfitoutlinecol, N_("The color of grid-fit outlines"), NULL, { 0 }, 0, 0 },
278 : { N_("Inactive Layer Color"), "BackgroundOutlineColor", rt_color, &backoutlinecol, N_("The color of outlines in inactive layers"), NULL, { 0 }, 0, 0 },
279 : { N_("Active Layer Color"), "ForegroundOutlineColor", rt_color, &foreoutlinecol, N_("The color of outlines in the active layer"), NULL, { 0 }, 0, 0 },
280 : { N_("Inactive Thick Layer Color"), "BackgroundThickOutlineColor", rt_coloralpha, &backoutthicklinecol, N_("The color of thick outlines in inactive layers"), NULL, { 0 }, 0, 0 },
281 : { N_("Active Thick Layer Color"), "ForegroundThickOutlineColor", rt_coloralpha, &foreoutthicklinecol, N_("The color of thick outlines in the active layer"), NULL, { 0 }, 0, 0 },
282 : { N_("Clip Path Color"), "ClipPathColor", rt_color, &clippathcol, N_("The color of the clip path"), NULL, { 0 }, 0, 0 },
283 : { N_("Open Path Color"), "OpenPathColor", rt_color, &openpathcol, N_("The color of the open path"), NULL, { 0 }, 0, 0 },
284 : { 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 },
285 : { N_("Fill Color"), "FillColor", rt_coloralpha, &fillcol, N_("The color used to fill the outline if that mode is active"), NULL, { 0 }, 0, 0 },
286 : { N_("Preview Fill Color"), "PreviewFillColor", rt_coloralpha, &previewfillcol, N_("The color used to fill the outline when in preview mode"), NULL, { 0 }, 0, 0 },
287 : { N_("Trace Color"), "TraceColor", rt_color, &tracecol, NULL, NULL, { 0 }, 0, 0 },
288 : { N_("Raster Color"), "RasterColor", rt_coloralpha, &rastercol, N_("The color of grid-fit (and other) raster blocks"), NULL, { 0 }, 0, 0 },
289 : { 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 },
290 : { 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 },
291 : { N_("Raster Grid Color"), "RasterGridColor", rt_coloralpha, &rastergridcol, NULL, NULL, { 0 }, 0, 0 },
292 : { 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 },
293 : { N_("Delta Grid Color"), "DeltaGridColor", rt_color, &deltagridcol, N_("Indicates a notable grid pixel when suggesting deltas."), NULL, { 0 }, 0, 0 },
294 : { 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 },
295 : { N_("Measure Tool Line Color"), "MeasureToolLineColor", rt_color, &measuretoollinecol, N_("The color used to draw the measure tool line."), NULL, { 0 }, 0, 0 },
296 : { N_("Measure Tool Point Color"), "MeasureToolPointColor", rt_color, &measuretoolpointcol, N_("The color used to draw the measure tool points."), NULL, { 0 }, 0, 0 },
297 : { 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 },
298 : { 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 },
299 : { 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 },
300 : { N_("Measure Tool Windows Foreground Color"), "MeasureToolWindowForeground", rt_color, &measuretoolwindowforegroundcol, N_("The measure tool window foreground color."), NULL, { 0 }, 0, 0 },
301 : { N_("Measure Tool Windows Background Color"), "MeasureToolWindowBackground", rt_color, &measuretoolwindowbackgroundcol, N_("The measure tool window background color."), NULL, { 0 }, 0, 0 },
302 : RESED_EMPTY
303 : };
304 :
305 : /* return 1 if anything changed */
306 0 : static void update_spacebar_hand_tool(CharView *cv) {
307 0 : if ( GDrawKeyState(' ') ) {
308 0 : if ( !cv->spacebar_hold && !cv_auto_goto ) {
309 0 : cv->spacebar_hold = 1;
310 0 : cv->b1_tool_old = cv->b1_tool;
311 0 : cv->b1_tool = cvt_hand;
312 0 : cv->active_tool = cvt_hand;
313 0 : CVMouseDownHand(cv);
314 0 : CVPreviewModeSet(cv->gw, cv_show_fill_with_space);
315 : }
316 : } else {
317 0 : if ( cv->spacebar_hold ) {
318 0 : cv->spacebar_hold = 0;
319 0 : cv->b1_tool = cv->b1_tool_old;
320 0 : cv->active_tool = cvt_none;
321 0 : cv->b1_tool_old = cvt_none;
322 0 : CVPreviewModeSet(cv->gw, false);
323 : }
324 : }
325 0 : }
326 :
327 :
328 0 : int CVInSpiro( CharView *cv )
329 : {
330 0 : int inspiro = 0;
331 0 : int canspiro = hasspiro();
332 0 : if( cv )
333 0 : inspiro = canspiro && cv->b.sc->inspiro;
334 0 : return inspiro;
335 : }
336 :
337 : /**
338 : * Returns the number of points which are currently selected in this
339 : * charview. Handy for menus and the like which might like to grey out
340 : * if there are <2, or <3 points actively selected.
341 : */
342 0 : int CVCountSelectedPoints(CharView *cv) {
343 : SplinePointList *spl;
344 : Spline *spline, *first;
345 0 : int ret = 0;
346 :
347 0 : for ( spl = cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL; spl = spl->next ) {
348 0 : first = NULL;
349 0 : for ( spline = spl->first->next; spline!=NULL && spline!=first; spline=spline->to->next ) {
350 0 : if( spline == spl->first->next ) {
351 0 : if ( spline->from->selected ) {
352 0 : ret++;
353 : }
354 : }
355 0 : if ( spline->to->selected ) {
356 0 : if( spline->to != spl->first->next->from )
357 0 : ret++;
358 : }
359 0 : if ( first==NULL ) {
360 0 : first = spline;
361 : }
362 : }
363 : }
364 0 : return ret;
365 : }
366 :
367 :
368 :
369 : /* floor(pt) would _not_ be more correct, as we want
370 : * shapes not to cross axes multiple times while scaling.
371 : */
372 0 : static double rpt(CharView *cv, double pt) {
373 0 : return cv->snapoutlines ? rint(pt) : pt;
374 : }
375 :
376 0 : static int shouldShowFilledUsingCairo(CharView *cv) {
377 0 : if ( cv->showfilled && GDrawHasCairo(cv->v) & gc_buildpath ) {
378 0 : return 1;
379 : }
380 0 : return 0;
381 : }
382 :
383 0 : void CVColInit( void ) {
384 0 : if ( cvcolsinited )
385 0 : return;
386 0 : GResEditFind( charview_re, "CharView.");
387 0 : GResEditFind( charview2_re, "CharView.");
388 0 : cvcolsinited = true;
389 :
390 : // These value over-ride the static initializers.
391 : // Note that the base resource names are copied from charview_re and charview2_re.
392 0 : pointcol = GResourceFindColor("CharView.PointColor",0xff0000);
393 0 : firstpointcol = GResourceFindColor("CharView.FirstPointColor",0x707000);
394 0 : selectedpointcol = GResourceFindColor("CharView.SelectedPointColor",0xc8c800);
395 0 : selectedpointwidth = GResourceFindInt("CharView.SelectedPointWidth",2);
396 0 : extremepointcol = GResourceFindColor("CharView.ExtremePointColor",0xc00080);
397 0 : pointofinflectioncol = GResourceFindColor("CharView.PointOfInflectionColor",0x008080);
398 0 : almosthvcol = GResourceFindColor("CharView.AlmostHVColor",0x00ff80);
399 0 : nextcpcol = GResourceFindColor("CharView.NextCPColor",0x007090);
400 0 : prevcpcol = GResourceFindColor("CharView.PointColor",0xcc00cc);
401 0 : selectedcpcol = GResourceFindColor("CharView.SelectedCPColor",0xffffff);
402 0 : coordcol = GResourceFindColor("CharView.CoordinateColor",0x808080);
403 0 : widthcol = GResourceFindColor("CharView.WidthColor",0x000000);
404 0 : widthselcol = GResourceFindColor("CharView.WidthSelColor",0x00ff00);
405 0 : lbearingselcol = GResourceFindColor("CharView.LBearingSelColor",0x00ff00);
406 0 : widthgridfitcol = GResourceFindColor("CharView.GridFitWidthColor",0x009800);
407 0 : lcaretcol = GResourceFindColor("CharView.LigatureCaretColor",0x909040);
408 0 : rastercol = GResourceFindColor("CharView.RasterColor",0xffa0a0a0); /* Translucent */
409 0 : rasternewcol = GResourceFindColor("CharView.RasterNewColor",0xff909090);
410 0 : rasteroldcol = GResourceFindColor("CharView.RasterOldColor",0xffc0c0c0);
411 0 : rastergridcol = GResourceFindColor("CharView.RasterGridColor",0xffb0b0ff);
412 0 : rasterdarkcol = GResourceFindColor("CharView.RasterDarkColor",0xff606060);
413 0 : deltagridcol = GResourceFindColor("CharView.DeltaGridColor",0xcc0000);
414 0 : italiccoordcol = GResourceFindColor("CharView.ItalicCoordColor",0x909090);
415 0 : metricslabelcol = GResourceFindColor("CharView.MetricsLabelColor",0x00000);
416 0 : hintlabelcol = GResourceFindColor("CharView.HintLabelColor",0x00cccc);
417 0 : bluevalstipplecol = GResourceFindColor("CharView.BlueValuesStippledColor",0x808080ff); /* Translucent */
418 0 : fambluestipplecol = GResourceFindColor("CharView.FamilyBlueStippledColor",0x80ff7070); /* Translucent */
419 0 : mdhintcol = GResourceFindColor("CharView.xxxxxx",0x80e04040); /* Translucent */
420 0 : dhintcol = GResourceFindColor("CharView.DHintColor",0x80d0a0a0); /* Translucent */
421 0 : hhintcol = GResourceFindColor("CharView.HHintColor",0x80a0d0a0); /* Translucent */
422 0 : vhintcol = GResourceFindColor("CharView.VHintColor",0x80c0c0ff); /* Translucent */
423 0 : hflexhintcol = GResourceFindColor("CharView.HFlexHintColor",0x00ff00);
424 0 : vflexhintcol = GResourceFindColor("CharView.VFlexHintColor",0x00ff00);
425 0 : conflicthintcol = GResourceFindColor("CharView.ConflictHintColor",0x00ffff);
426 0 : hhintactivecol = GResourceFindColor("CharView.HHintActiveColor",0x00a000);
427 0 : vhintactivecol = GResourceFindColor("CharView.VHintActiveColor",0x0000ff);
428 0 : anchorcol = GResourceFindColor("CharView.AnchorColor",0x0040ff);
429 0 : anchoredoutlinecol = GResourceFindColor("CharView.AnchoredOutlineColor",0x0040ff);
430 0 : templateoutlinecol = GResourceFindColor("CharView.TemplateOutlineColor",0x009800);
431 0 : oldoutlinecol = GResourceFindColor("CharView.OldOutlineColor",0x008000);
432 0 : transformorigincol = GResourceFindColor("CharView.TransformOriginColor",0x000000);
433 0 : guideoutlinecol = GResourceFindColor("CharView.GuideOutlineColor",0x808080);
434 0 : gridfitoutlinecol = GResourceFindColor("CharView.GridFitOutlineColor",0x009800);
435 0 : backoutlinecol = GResourceFindColor("CharView.BackgroundOutlineColor",0x009800);
436 0 : foreoutlinecol = GResourceFindColor("CharView.ForegroundOutlineColor",0x000000);
437 0 : clippathcol = GResourceFindColor("CharView.ClipPathColor",0x0000ff);
438 0 : openpathcol = GResourceFindColor("CharView.OpenPathColor",0x660000);
439 0 : backimagecol = GResourceFindColor("CharView.BackgroundImageColor",0x707070);
440 0 : fillcol = GResourceFindColor("CharView.FillColor",0x80707070); /* Translucent */
441 0 : tracecol = GResourceFindColor("CharView.TraceColor",0x008000);
442 0 : rulerbigtickcol = GResourceFindColor("CharView.RulerBigTickColor",0x008000);
443 : // previewfillcol = GResourceFindColor(,0x0f0f0f);
444 : // The code below defaults differently from the static initializer (from which we copied this value).
445 0 : if( GResourceFindColor("CharView.PreviewFillColor", COLOR_UNKNOWN) == COLOR_UNKNOWN ) {
446 : // no explicit previewfillcolor
447 0 : previewfillcol = fillcol;
448 0 : if( GResourceFindColor("CharView.FillColor", COLOR_UNKNOWN) == COLOR_UNKNOWN ) {
449 : // no explicit fill color either
450 0 : previewfillcol = 0x000000;
451 : }
452 : }
453 0 : DraggingComparisonOutlineColor = GResourceFindColor("CharView.DraggingComparisonOutlineColor",0x8800BB00);
454 0 : DraggingComparisonAlphaChannelOverride = GResourceFindColor("CharView.DraggingComparisonAlphaChannelOverride",0x88000000);
455 0 : foreoutthicklinecol = GResourceFindColor("CharView.ForegroundThickOutlineColor",0x20707070);
456 0 : backoutthicklinecol = GResourceFindColor("CharView.BackgroundThickOutlineColor",0x20707070);
457 0 : cvbutton3d = GResourceFindInt("CharView.Button3D", 1);
458 0 : cvbutton3dedgelightcol = GResourceFindColor("CharView.Button3DEdgeLightColor", 0xe0e0e0);
459 0 : cvbutton3dedgedarkcol = GResourceFindColor("CharView.Button3DEdgeDarkColor", 0x707070);
460 : }
461 :
462 :
463 : GDevEventMask input_em[] = {
464 : /* Event masks for wacom devices */
465 : /* negative utility in opening Mouse1 */
466 : /* No point in distinguishing cursor from core mouse */
467 : { (1<<et_mousemove)|(1<<et_mousedown)|(1<<et_mouseup)|(1<<et_char), "stylus" },
468 : { (1<<et_mousemove)|(1<<et_mousedown)|(1<<et_mouseup), "eraser" },
469 : { 0, NULL }
470 : };
471 : const int input_em_cnt = sizeof(input_em)/sizeof(input_em[0])-1;
472 :
473 : /* Positions on the info line */
474 : #define RPT_BASE 5 /* Place to draw the pointer icon */
475 : #define RPT_DATA 13 /* x,y text after above */
476 : #define SPT_BASE 83 /* Place to draw selected pt icon */
477 : #define SPT_DATA 97 /* Any text for it */
478 : #define SOF_BASE 157 /* Place to draw selection to pointer icon */
479 : #define SOF_DATA 179 /* Any text for it */
480 : #define SDS_BASE 259 /* Place to draw distance icon */
481 : #define SDS_DATA 281 /* Any text for it */
482 : #define SAN_BASE 331 /* Place to draw angle icon */
483 : #define SAN_DATA 353 /* Any text for it */
484 : #define MAG_BASE 383 /* Place to draw magnification icon */
485 : #define MAG_DATA 394 /* Any text for it */
486 : #define LAYER_DATA 454 /* Text to show the current layer */
487 : #define CODERANGE_DATA 574 /* Text to show the current code range (if the debugger be active) */
488 : #define FLAGS_DATA 724 /* Text to show the current drawmode flags */
489 :
490 0 : void CVDrawRubberRect(GWindow pixmap, CharView *cv) {
491 : GRect r;
492 0 : if ( !cv->p.rubberbanding )
493 0 : return;
494 0 : r.x = cv->xoff + rint(cv->p.cx*cv->scale);
495 0 : r.y = -cv->yoff + cv->height - rint(cv->p.cy*cv->scale);
496 0 : r.width = rint( (cv->p.ex-cv->p.cx)*cv->scale );
497 0 : r.height = -rint( (cv->p.ey-cv->p.cy)*cv->scale );
498 0 : if ( r.width<0 ) {
499 0 : r.x += r.width;
500 0 : r.width = -r.width;
501 : }
502 0 : if ( r.height<0 ) {
503 0 : r.y += r.height;
504 0 : r.height = -r.height;
505 : }
506 0 : GDrawSetDashedLine(pixmap,2,2,0);
507 0 : GDrawSetLineWidth(pixmap,0);
508 0 : GDrawSetXORMode(pixmap);
509 0 : GDrawSetXORBase(pixmap,view_bgcol);
510 0 : GDrawDrawRect(pixmap,&r,oldoutlinecol);
511 0 : GDrawSetCopyMode(pixmap);
512 0 : GDrawSetDashedLine(pixmap,0,0,0);
513 : }
514 :
515 0 : static void CVDrawRubberLine(GWindow pixmap, CharView *cv) {
516 : int x,y, xend,yend;
517 0 : Color col = cv->active_tool==cvt_ruler ? measuretoollinecol : oldoutlinecol;
518 0 : if ( !cv->p.rubberlining )
519 0 : return;
520 0 : x = cv->xoff + rint(cv->p.cx*cv->scale);
521 0 : y = -cv->yoff + cv->height - rint(cv->p.cy*cv->scale);
522 0 : xend = cv->xoff + rint(cv->info.x*cv->scale);
523 0 : yend = -cv->yoff + cv->height - rint(cv->info.y*cv->scale);
524 0 : if ( xorrubberlines ) { /* XOR prevents use of CAIRO for these lines */
525 0 : GDrawSetXORMode(pixmap);
526 0 : GDrawSetLineWidth(pixmap,0);
527 0 : GDrawSetXORBase(pixmap,GDrawGetDefaultBackground(NULL));
528 : } else {
529 0 : GDrawSetCopyMode(pixmap);
530 0 : GDrawSetLineWidth(pixmap,0);
531 : }
532 0 : GDrawDrawLine(pixmap,x,y,xend,yend,col);
533 0 : GDrawSetCopyMode(pixmap);
534 : }
535 :
536 0 : static void CVDrawBB(CharView *cv, GWindow pixmap, DBounds *bb) {
537 : GRect r;
538 0 : int off = cv->xoff+cv->height-cv->yoff;
539 :
540 0 : r.x = cv->xoff + rint(bb->minx*cv->scale);
541 0 : r.y = -cv->yoff + cv->height - rint(bb->maxy*cv->scale);
542 0 : r.width = rint((bb->maxx-bb->minx)*cv->scale);
543 0 : r.height = rint((bb->maxy-bb->miny)*cv->scale);
544 0 : GDrawSetDashedLine(pixmap,1,1,off);
545 0 : GDrawDrawRect(pixmap,&r,GDrawGetDefaultForeground(NULL));
546 0 : GDrawSetDashedLine(pixmap,0,0,0);
547 0 : }
548 :
549 : /* Sigh. I have to do my own clipping because at large magnifications */
550 : /* things can easily exceed 16 bits */
551 0 : static int CVSplineOutside(CharView *cv, Spline *spline) {
552 : int x[4], y[4];
553 :
554 0 : x[0] = cv->xoff + rint(spline->from->me.x*cv->scale);
555 0 : y[0] = -cv->yoff + cv->height - rint(spline->from->me.y*cv->scale);
556 :
557 0 : x[1] = cv->xoff + rint(spline->to->me.x*cv->scale);
558 0 : y[1] = -cv->yoff + cv->height - rint(spline->to->me.y*cv->scale);
559 :
560 0 : if ( spline->from->nonextcp && spline->to->noprevcp ) {
561 0 : if ( (x[0]<0 && x[1]<0) || (x[0]>=cv->width && x[1]>=cv->width) ||
562 0 : (y[0]<0 && y[1]<0) || (y[0]>=cv->height && y[1]>=cv->height) )
563 0 : return( true );
564 : } else {
565 0 : x[2] = cv->xoff + rint(spline->from->nextcp.x*cv->scale);
566 0 : y[2] = -cv->yoff + cv->height - rint(spline->from->nextcp.y*cv->scale);
567 0 : x[3] = cv->xoff + rint(spline->to->prevcp.x*cv->scale);
568 0 : y[3] = -cv->yoff + cv->height - rint(spline->to->prevcp.y*cv->scale);
569 0 : if ( (x[0]<0 && x[1]<0 && x[2]<0 && x[3]<0) ||
570 0 : (x[0]>=cv->width && x[1]>=cv->width && x[2]>=cv->width && x[3]>=cv->width ) ||
571 0 : (y[0]<0 && y[1]<0 && y[2]<0 && y[3]<0 ) ||
572 0 : (y[0]>=cv->height && y[1]>=cv->height && y[2]>=cv->height && y[3]>=cv->height) )
573 0 : return( true );
574 : }
575 :
576 0 : return( false );
577 : }
578 :
579 0 : static int CVLinesIntersectScreen(CharView *cv, LinearApprox *lap) {
580 : LineList *l;
581 0 : int any = false;
582 : int x,y;
583 : int bothout;
584 :
585 0 : for ( l=lap->lines; l!=NULL; l=l->next ) {
586 0 : l->asend.x = l->asstart.x = cv->xoff + l->here.x;
587 0 : l->asend.y = l->asstart.y = -cv->yoff + cv->height-l->here.y;
588 0 : l->flags = 0;
589 0 : if ( l->asend.x<0 || l->asend.x>=cv->width || l->asend.y<0 || l->asend.y>=cv->height ) {
590 0 : l->flags = cvli_clipped;
591 0 : any = true;
592 : }
593 : }
594 0 : if ( !any ) {
595 0 : for ( l=lap->lines; l!=NULL; l=l->next )
596 0 : l->flags = cvli_onscreen;
597 0 : lap->any = true;
598 0 : return( true );
599 : }
600 :
601 0 : any = false;
602 0 : for ( l=lap->lines; l->next!=NULL; l=l->next ) {
603 0 : if ( !(l->flags&cvli_clipped) && !(l->next->flags&cvli_clipped) )
604 0 : l->flags = cvli_onscreen;
605 : else {
606 0 : bothout = (l->flags&cvli_clipped) && (l->next->flags&cvli_clipped);
607 0 : if (( l->asstart.x<0 && l->next->asend.x>0 ) ||
608 0 : ( l->asstart.x>0 && l->next->asend.x<0 )) {
609 0 : y = -(l->next->asend.y-l->asstart.y)*(double)l->asstart.x/(l->next->asend.x-l->asstart.x) +
610 0 : l->asstart.y;
611 0 : if ( l->asstart.x<0 ) {
612 0 : l->asstart.x = 0;
613 0 : l->asstart.y = y;
614 : } else {
615 0 : l->next->asend.x = 0;
616 0 : l->next->asend.y = y;
617 : }
618 0 : } else if ( l->asstart.x<0 && l->next->asend.x<0 )
619 0 : continue;
620 0 : if (( l->asstart.x<cv->width && l->next->asend.x>cv->width ) ||
621 0 : ( l->asstart.x>cv->width && l->next->asend.x<cv->width )) {
622 0 : y = (l->next->asend.y-l->asstart.y)*(double)(cv->width-l->asstart.x)/(l->next->asend.x-l->asstart.x) +
623 0 : l->asstart.y;
624 0 : if ( l->asstart.x>cv->width ) {
625 0 : l->asstart.x = cv->width;
626 0 : l->asstart.y = y;
627 : } else {
628 0 : l->next->asend.x = cv->width;
629 0 : l->next->asend.y = y;
630 : }
631 0 : } else if ( l->asstart.x>cv->width && l->next->asend.x>cv->width )
632 0 : continue;
633 0 : if (( l->asstart.y<0 && l->next->asend.y>0 ) ||
634 0 : ( l->asstart.y>0 && l->next->asend.y<0 )) {
635 0 : x = -(l->next->asend.x-l->asstart.x)*(double)l->asstart.y/(l->next->asend.y-l->asstart.y) +
636 0 : l->asstart.x;
637 0 : if (( x<0 || x>=cv->width ) && bothout )
638 0 : continue; /* Not on screen */;
639 0 : if ( l->asstart.y<0 ) {
640 0 : l->asstart.y = 0;
641 0 : l->asstart.x = x;
642 : } else {
643 0 : l->next->asend.y = 0;
644 0 : l->next->asend.x = x;
645 : }
646 0 : } else if ( l->asstart.y<0 && l->next->asend.y< 0 )
647 0 : continue;
648 0 : if (( l->asstart.y<cv->height && l->next->asend.y>cv->height ) ||
649 0 : ( l->asstart.y>cv->height && l->next->asend.y<cv->height )) {
650 0 : x = (l->next->asend.x-l->asstart.x)*(double)(cv->height-l->asstart.y)/(l->next->asend.y-l->asstart.y) +
651 0 : l->asstart.x;
652 0 : if (( x<0 || x>=cv->width ) && bothout )
653 0 : continue; /* Not on screen */;
654 0 : if ( l->asstart.y>cv->height ) {
655 0 : l->asstart.y = cv->height;
656 0 : l->asstart.x = x;
657 : } else {
658 0 : l->next->asend.y = cv->height;
659 0 : l->next->asend.x = x;
660 : }
661 0 : } else if ( l->asstart.y>cv->height && l->next->asend.y>cv->height )
662 0 : continue;
663 0 : l->flags |= cvli_onscreen;
664 0 : any = true;
665 : }
666 : }
667 0 : lap->any = any;
668 0 : return( any );
669 : }
670 :
671 : typedef struct gpl { struct gpl *next; GPoint *gp; int cnt; } GPointList;
672 :
673 0 : static void GPLFree(GPointList *gpl) {
674 : GPointList *next;
675 :
676 0 : while ( gpl!=NULL ) {
677 0 : next = gpl->next;
678 0 : free( gpl->gp );
679 0 : free( gpl );
680 0 : gpl = next;
681 : }
682 0 : }
683 :
684 : /* Before we did clipping this was a single polygon. Now it is a set of */
685 : /* sets of line segments. If no clipping is done, then we end up with */
686 : /* one set which is the original polygon, otherwise we get the segments */
687 : /* which are inside the screen. Each set of segments is contiguous */
688 0 : static GPointList *MakePoly(CharView *cv, SplinePointList *spl) {
689 : int i, len;
690 : LinearApprox *lap;
691 : LineList *line, *prev;
692 : Spline *spline, *first;
693 0 : GPointList *head=NULL, *last=NULL, *cur;
694 : int closed;
695 :
696 0 : for ( i=0; i<2; ++i ) {
697 0 : len = 0; first = NULL;
698 0 : closed = true;
699 0 : cur = NULL;
700 0 : for ( spline = spl->first->next; spline!=NULL && spline!=first; spline=spline->to->next ) {
701 0 : if ( !CVSplineOutside(cv,spline) && !isnan(spline->splines[0].a) && !isnan(spline->splines[1].a)) {
702 0 : lap = SplineApproximate(spline,cv->scale);
703 0 : if ( i==0 )
704 0 : CVLinesIntersectScreen(cv,lap);
705 0 : if ( lap->any ) {
706 0 : for ( prev = lap->lines, line=prev->next; line!=NULL; prev=line, line=line->next ) {
707 0 : if ( !(prev->flags&cvli_onscreen) ) {
708 0 : closed = true;
709 0 : continue;
710 : }
711 0 : if ( closed || (prev->flags&cvli_clipped) ) {
712 0 : if ( i==0 ) {
713 0 : cur = calloc(1,sizeof(GPointList));
714 0 : if ( head==NULL )
715 0 : head = cur;
716 : else {
717 0 : last->cnt = len;
718 0 : last->next = cur;
719 : }
720 0 : last = cur;
721 : } else {
722 0 : if ( cur==NULL )
723 0 : cur = head;
724 : else
725 0 : cur = cur->next;
726 0 : cur->gp = malloc(cur->cnt*sizeof(GPoint));
727 0 : cur->gp[0].x = prev->asstart.x;
728 0 : cur->gp[0].y = prev->asstart.y;
729 : }
730 0 : len=1;
731 0 : closed = false;
732 : }
733 0 : if ( i!=0 ) {
734 0 : if ( len>=cur->cnt )
735 0 : fprintf( stderr, "Clipping is screwed up, about to die %d (should be less than %d)\n", len, cur->cnt );
736 0 : cur->gp[len].x = line->asend.x;
737 0 : cur->gp[len].y = line->asend.y;
738 : }
739 0 : ++len;
740 0 : if ( line->flags&cvli_clipped )
741 0 : closed = true;
742 : }
743 : } else
744 0 : closed = true;
745 : } else
746 0 : closed = true;
747 0 : if ( first==NULL ) first = spline;
748 : }
749 0 : if ( i==0 && cur!=NULL )
750 0 : cur->cnt = len;
751 : }
752 0 : return( head );
753 : }
754 :
755 0 : static void DrawTangentPoint( GWindow pixmap, int x, int y,
756 : BasePoint *unit, int outline, Color col )
757 : {
758 : int dir;
759 0 : const int gp_sz = 4;
760 : GPoint gp[5];
761 :
762 0 : dir = 0;
763 0 : if ( unit->x!=0 || unit->y!=0 ) {
764 0 : float dx = unit->x, dy = unit->y;
765 0 : if ( dx<0 ) dx= -dx;
766 0 : if ( dy<0 ) dy= -dy;
767 0 : if ( dx>2*dy ) {
768 0 : if ( unit->x>0 ) dir = 0 /* right */;
769 0 : else dir = 1 /* left */;
770 0 : } else if ( dy>2*dx ) {
771 0 : if ( unit->y>0 ) dir = 2 /* up */;
772 0 : else dir = 3 /* down */;
773 : } else {
774 0 : if ( unit->y>0 && unit->x>0 ) dir=4;
775 0 : else if ( unit->x>0 ) dir=5;
776 0 : else if ( unit->y>0 ) dir=7;
777 0 : else dir = 6;
778 : }
779 : }
780 :
781 0 : float sizedelta = 4;
782 0 : if( prefs_cvEditHandleSize > prefs_cvEditHandleSize_default )
783 0 : sizedelta *= prefs_cvEditHandleSize / prefs_cvEditHandleSize_default;
784 :
785 0 : if ( dir==1 /* left */ || dir==0 /* right */) {
786 0 : gp[0].y = y; gp[0].x = (dir==0)?x+sizedelta:x-sizedelta;
787 0 : gp[1].y = y-sizedelta; gp[1].x = x;
788 0 : gp[2].y = y+sizedelta; gp[2].x = x;
789 0 : } else if ( dir==2 /* up */ || dir==3 /* down */ ) {
790 0 : gp[0].x = x; gp[0].y = dir==2?y-sizedelta:y+sizedelta; /* remember screen coordinates are backwards in y from character coords */
791 0 : gp[1].x = x-sizedelta; gp[1].y = y;
792 0 : gp[2].x = x+sizedelta; gp[2].y = y;
793 : } else {
794 : /* at a 45 angle, a value of 4 looks too small. I probably want 4*1.414 */
795 0 : sizedelta = 5;
796 0 : if( prefs_cvEditHandleSize > prefs_cvEditHandleSize_default )
797 0 : sizedelta *= prefs_cvEditHandleSize / prefs_cvEditHandleSize_default;
798 0 : int xdiff = unit->x > 0 ? sizedelta : -1*sizedelta;
799 0 : int ydiff = unit->y > 0 ? -1*sizedelta : sizedelta;
800 :
801 0 : gp[0].x = x+xdiff/2; gp[0].y = y+ydiff/2;
802 0 : gp[1].x = gp[0].x-xdiff; gp[1].y = gp[0].y;
803 0 : gp[2].x = gp[0].x; gp[2].y = gp[0].y-ydiff;
804 : }
805 0 : gp[3] = gp[0];
806 0 : if ( outline )
807 0 : GDrawDrawPoly(pixmap,gp,gp_sz,col);
808 : else
809 0 : GDrawFillPoly(pixmap,gp,4,col);
810 0 : }
811 :
812 0 : static GRect* DrawPoint_SetupRectForSize( GRect* r, int cx, int cy, float sz )
813 : {
814 0 : float sizedelta = sz;
815 0 : if( prefs_cvEditHandleSize > prefs_cvEditHandleSize_default )
816 0 : sizedelta *= prefs_cvEditHandleSize / prefs_cvEditHandleSize_default;
817 :
818 0 : r->x = cx - sizedelta;
819 0 : r->y = cy - sizedelta;
820 0 : r->width = 1 + sizedelta * 2;
821 0 : r->height = 1 + sizedelta * 2;
822 0 : return r;
823 : }
824 :
825 :
826 0 : static Color MaybeMaskColorToAlphaChannelOverride( Color c, Color AlphaChannelOverride )
827 : {
828 0 : if( AlphaChannelOverride )
829 : {
830 0 : c &= 0x00FFFFFF;
831 0 : c |= (AlphaChannelOverride & 0xFF000000);
832 : }
833 0 : return c;
834 : }
835 :
836 : /*
837 : * Format the given real value to .001 precision, discarding trailing
838 : * zeroes, and the decimal point if not needed.
839 : */
840 0 : static int FmtReal(char *buf, int buflen, real r)
841 : {
842 0 : if (buf && buflen > 0) {
843 : int ct;
844 :
845 0 : if ((ct = snprintf(buf, buflen, "%.3f", r)) >= buflen)
846 0 : ct = buflen-1;
847 :
848 0 : if (strchr(buf, '.')) {
849 0 : while (buf[ct-1] == '0') {
850 0 : --ct;
851 : }
852 0 : if (buf[ct-1] == '.') {
853 0 : --ct;
854 : }
855 0 : buf[ct] = '\0';
856 : }
857 0 : return ct;
858 : }
859 0 : return -1;
860 : }
861 :
862 : /*
863 : * Write the given spline point's coordinates in the form (xxx,yyy)
864 : * into the buffer provided, rounding fractions to the nearest .001
865 : * and discarding trailing zeroes.
866 : */
867 0 : static int SplinePointCoords(char *buf, int buflen, SplinePoint *sp)
868 : {
869 0 : if (buf && buflen > 0) {
870 0 : int ct = 0, clen;
871 :
872 : /* 4 chars for parens, comma and trailing NUL, then divide what
873 : remains between the two coords */
874 0 : clen = (buflen - 4) / 2;
875 0 : if (clen > 0) {
876 0 : buf[ct++] = '(';
877 0 : ct += FmtReal(buf+ct, clen, sp->me.x);
878 0 : buf[ct++] = ',';
879 0 : ct += FmtReal(buf+ct, clen, sp->me.y);
880 0 : buf[ct++] = ')';
881 : }
882 0 : buf[ct] = '\0';
883 :
884 0 : return ct;
885 : }
886 0 : return -1;
887 : }
888 :
889 0 : static void DrawPoint( CharView *cv, GWindow pixmap, SplinePoint *sp,
890 : SplineSet *spl, int onlynumber, int truetype_markup,
891 : Color AlphaChannelOverride )
892 : {
893 : GRect r;
894 : int x, y, cx, cy;
895 0 : Color col = sp==spl->first ? firstpointcol : pointcol;
896 : int pnum;
897 : char buf[16];
898 : int isfake;
899 :
900 0 : if ( DrawOpenPathsWithHighlight
901 0 : && cv->b.drawmode==dm_fore
902 0 : && spl->first
903 0 : && spl->first->prev==NULL )
904 : {
905 0 : if( sp!=spl->first )
906 0 : col = openpathcol;
907 : }
908 :
909 :
910 0 : if ( cv->markextrema && SpIsExtremum(sp) )
911 0 : col = extremepointcol;
912 0 : if ( sp->selected )
913 0 : col = selectedpointcol;
914 :
915 0 : if ( DrawOpenPathsWithHighlight
916 0 : && cv->b.drawmode==dm_fore
917 0 : && spl->first
918 0 : && spl->first->prev==NULL )
919 : {
920 : }
921 : else
922 : {
923 0 : if( !sp->selected )
924 : {
925 0 : col = col&0x00ffffff;
926 0 : col |= prefs_cvInactiveHandleAlpha << 24;
927 : }
928 : }
929 :
930 0 : col = MaybeMaskColorToAlphaChannelOverride( col, AlphaChannelOverride );
931 0 : Color subcolmasked = MaybeMaskColorToAlphaChannelOverride( subcol, AlphaChannelOverride );
932 0 : Color nextcpcolmasked = MaybeMaskColorToAlphaChannelOverride( nextcpcol, AlphaChannelOverride );
933 0 : Color prevcpcolmasked = MaybeMaskColorToAlphaChannelOverride( prevcpcol, AlphaChannelOverride );
934 0 : Color selectedpointcolmasked = MaybeMaskColorToAlphaChannelOverride( selectedpointcol, AlphaChannelOverride );
935 0 : Color selectedcpcolmasked = MaybeMaskColorToAlphaChannelOverride( selectedcpcol, AlphaChannelOverride );
936 :
937 0 : x = cv->xoff + rint(sp->me.x*cv->scale);
938 0 : y = -cv->yoff + cv->height - rint(sp->me.y*cv->scale);
939 0 : if ( x<-4000 || y<-4000 || x>cv->width+4000 || y>=cv->height+4000 )
940 0 : return;
941 :
942 : /* draw the control points if it's selected */
943 0 : if ( sp->selected
944 0 : || cv->showpointnumbers
945 0 : || cv->alwaysshowcontrolpoints
946 0 : || cv->show_ft_results
947 0 : || cv->dv )
948 : {
949 0 : if ( !sp->nonextcp ) {
950 0 : cx = cv->xoff + rint(sp->nextcp.x*cv->scale);
951 0 : cy = -cv->yoff + cv->height - rint(sp->nextcp.y*cv->scale);
952 0 : if ( cx<-100 ) { /* Clip */
953 0 : cy = cx==x ? x : (cy-y) * (double)(-100-x)/(cx-x) + y;
954 0 : cx = -100;
955 0 : } else if ( cx>cv->width+100 ) {
956 0 : cy = cx==x ? x : (cy-y) * (double)(cv->width+100-x)/(cx-x) + y;
957 0 : cx = cv->width+100;
958 : }
959 0 : if ( cy<-100 ) {
960 0 : cx = cy==y ? y : (cx-x) * (double)(-100-y)/(cy-y) + x;
961 0 : cy = -100;
962 0 : } else if ( cy>cv->height+100 ) {
963 0 : cx = cy==y ? y : (cx-x) * (double)(cv->height+100-y)/(cy-y) + x;
964 0 : cy = cv->height+100;
965 : }
966 0 : subcolmasked = nextcpcolmasked;
967 :
968 : //
969 : // If the next BCP is selected we should decorate the
970 : // drawing to let the user know that. The primary (last)
971 : // selected BCP is drawn with a backing rectangle of size
972 : // 3, the secondary BCP (2nd, 3rd, 4th last selected BCP)
973 : // are drawn with slightly smaller highlights.
974 : //
975 0 : if( !onlynumber && SPIsNextCPSelected( sp, cv ))
976 0 : {
977 0 : float sz = 2;
978 0 : if( SPIsNextCPSelectedSingle( sp, cv ))
979 0 : sz *= 1.5;
980 :
981 0 : DrawPoint_SetupRectForSize( &r, cx, cy, sz );
982 0 : GDrawFillRect(pixmap,&r, nextcpcol);
983 0 : subcolmasked = selectedcpcolmasked;
984 : }
985 0 : else if ( truetype_markup )
986 : {
987 0 : if ( sp->flexy ) {
988 : /* cp is about to be moved (or changed in some other way) */
989 0 : DrawPoint_SetupRectForSize( &r, cx, cy, 3 );
990 0 : GDrawFillRect(pixmap,&r, selectedpointcol);
991 : }
992 0 : if ( sp->flexx ) {
993 : /* cp is a reference point */
994 0 : DrawPoint_SetupRectForSize( &r, cx, cy, 5 );
995 0 : GDrawDrawElipse(pixmap,&r,selectedpointcol );
996 : }
997 : }
998 0 : if ( !onlynumber )
999 : {
1000 0 : float sizedelta = 3;
1001 0 : if( prefs_cvEditHandleSize > prefs_cvEditHandleSize_default )
1002 0 : sizedelta *= prefs_cvEditHandleSize / prefs_cvEditHandleSize_default;
1003 0 : GDrawDrawLine(pixmap,x,y,cx,cy, nextcpcolmasked );
1004 0 : GDrawDrawLine(pixmap,cx-sizedelta,cy-sizedelta,cx+sizedelta,cy+sizedelta,subcolmasked);
1005 0 : GDrawDrawLine(pixmap,cx+sizedelta,cy-sizedelta,cx-sizedelta,cy+sizedelta,subcolmasked);
1006 : }
1007 0 : if ( cv->showpointnumbers || cv->show_ft_results || cv->dv ) {
1008 0 : pnum = sp->nextcpindex;
1009 0 : if ( pnum!=0xffff && pnum!=0xfffe ) {
1010 0 : if (cv->showpointnumbers == 2)
1011 0 : SplinePointCoords( buf, sizeof(buf), sp);
1012 : else
1013 0 : sprintf( buf,"%d", pnum );
1014 0 : GDrawDrawText8(pixmap,cx,cy-6,buf,-1,nextcpcol);
1015 : }
1016 : }
1017 : }
1018 0 : if ( !sp->noprevcp ) {
1019 0 : cx = cv->xoff + rint(sp->prevcp.x*cv->scale);
1020 0 : cy = -cv->yoff + cv->height - rint(sp->prevcp.y*cv->scale);
1021 0 : if ( cx<-100 ) { /* Clip */
1022 0 : cy = cx==x ? x : (cy-y) * (double)(-100-x)/(cx-x) + y;
1023 0 : cx = -100;
1024 0 : } else if ( cx>cv->width+100 ) {
1025 0 : cy = cx==x ? x : (cy-y) * (double)(cv->width+100-x)/(cx-x) + y;
1026 0 : cx = cv->width+100;
1027 : }
1028 0 : if ( cy<-100 ) {
1029 0 : cx = cy==y ? y : (cx-x) * (double)(-100-y)/(cy-y) + x;
1030 0 : cy = -100;
1031 0 : } else if ( cy>cv->height+100 ) {
1032 0 : cx = cy==y ? y : (cx-x) * (double)(cv->height+100-y)/(cy-y) + x;
1033 0 : cy = cv->height+100;
1034 : }
1035 0 : subcolmasked = prevcpcolmasked;
1036 0 : if( !onlynumber && SPIsPrevCPSelected( sp, cv ))
1037 : {
1038 0 : float sz = 2;
1039 0 : if( SPIsPrevCPSelectedSingle( sp, cv ))
1040 0 : sz *= 1.5;
1041 0 : DrawPoint_SetupRectForSize( &r, cx, cy, sz );
1042 0 : GDrawFillRect(pixmap,&r, prevcpcol);
1043 0 : subcolmasked = selectedcpcolmasked;
1044 : }
1045 0 : if ( !onlynumber ) {
1046 0 : float sizedelta = 3;
1047 0 : if( prefs_cvEditHandleSize > prefs_cvEditHandleSize_default )
1048 0 : sizedelta *= prefs_cvEditHandleSize / prefs_cvEditHandleSize_default;
1049 0 : GDrawDrawLine(pixmap,x,y,cx,cy, prevcpcolmasked);
1050 0 : GDrawDrawLine(pixmap,cx-sizedelta,cy-sizedelta,cx+sizedelta,cy+sizedelta,subcolmasked);
1051 0 : GDrawDrawLine(pixmap,cx+sizedelta,cy-sizedelta,cx-sizedelta,cy+sizedelta,subcolmasked);
1052 : }
1053 : }
1054 : }
1055 :
1056 0 : if ( x<-4 || y<-4 || x>cv->width+4 || y>=cv->height+4 )
1057 0 : return;
1058 0 : r.x = x-2;
1059 0 : r.y = y-2;
1060 0 : r.width = r.height = 0;
1061 0 : r.width += prefs_cvEditHandleSize;
1062 0 : r.height += prefs_cvEditHandleSize;
1063 0 : if ( sp->selected )
1064 0 : GDrawSetLineWidth(pixmap,selectedpointwidth);
1065 0 : isfake = false;
1066 0 : if ( cv->b.layerheads[cv->b.drawmode]->order2 &&
1067 0 : cv->b.layerheads[cv->b.drawmode]->refs==NULL )
1068 : {
1069 0 : int mightbe_fake = SPInterpolate(sp);
1070 0 : if ( !mightbe_fake && sp->ttfindex==0xffff )
1071 0 : sp->ttfindex = 0xfffe; /* if we have no instructions we won't call instrcheck and won't notice when a point stops being fake */
1072 0 : else if ( mightbe_fake )
1073 0 : sp->ttfindex = 0xffff;
1074 0 : isfake = sp->ttfindex==0xffff;
1075 : }
1076 0 : if ( onlynumber )
1077 : {
1078 : /* Draw Nothing */;
1079 : }
1080 0 : else if ( sp->pointtype==pt_curve )
1081 : {
1082 0 : r.width +=2; r.height += 2;
1083 0 : r.x = x - r.width / 2;
1084 0 : r.y = y - r.height / 2;
1085 0 : if ( sp->selected || isfake )
1086 0 : GDrawDrawElipse(pixmap,&r,col);
1087 : else
1088 0 : GDrawFillElipse(pixmap,&r,col);
1089 : }
1090 0 : else if ( sp->pointtype==pt_corner )
1091 : {
1092 0 : r.x = x - r.width / 2;
1093 0 : r.y = y - r.height / 2;
1094 0 : if ( sp->selected || isfake )
1095 0 : GDrawDrawRect(pixmap,&r,col);
1096 : else
1097 0 : GDrawFillRect(pixmap,&r,col);
1098 : }
1099 0 : else if ( sp->pointtype==pt_hvcurve )
1100 : {
1101 0 : const int gp_sz = 5;
1102 : GPoint gp[5];
1103 :
1104 0 : float sizedelta = 3;
1105 0 : float offsetdelta = 0; // 4 * cv->scale;
1106 0 : if( prefs_cvEditHandleSize > prefs_cvEditHandleSize_default )
1107 : {
1108 0 : sizedelta *= prefs_cvEditHandleSize / prefs_cvEditHandleSize_default;
1109 0 : offsetdelta *= prefs_cvEditHandleSize / prefs_cvEditHandleSize_default;
1110 : }
1111 :
1112 0 : float basex = r.x + 3 + offsetdelta;
1113 0 : float basey = r.y + 3 + offsetdelta;
1114 0 : gp[0].x = basex - sizedelta; gp[0].y = basey + 0;
1115 0 : gp[1].x = basex + 0; gp[1].y = basey + sizedelta;
1116 0 : gp[2].x = basex + sizedelta; gp[2].y = basey + 0;
1117 0 : gp[3].x = basex + 0; gp[3].y = basey - sizedelta;
1118 0 : gp[4] = gp[0];
1119 :
1120 0 : if ( sp->selected || isfake )
1121 0 : GDrawDrawPoly(pixmap,gp,gp_sz,col);
1122 : else
1123 0 : GDrawFillPoly(pixmap,gp,gp_sz,col);
1124 : }
1125 : else
1126 : {
1127 0 : BasePoint *cp=NULL;
1128 : BasePoint unit;
1129 :
1130 0 : if ( !sp->nonextcp )
1131 0 : cp = &sp->nextcp;
1132 0 : else if ( !sp->noprevcp )
1133 0 : cp = &sp->prevcp;
1134 0 : memset(&unit,0,sizeof(unit));
1135 0 : if ( cp!=NULL ) {
1136 0 : unit.x = cp->x-sp->me.x; unit.y = cp->y-sp->me.y;
1137 : }
1138 0 : DrawTangentPoint(pixmap, x, y, &unit, sp->selected || isfake, col);
1139 : }
1140 0 : GDrawSetLineWidth(pixmap,0);
1141 0 : if ( (cv->showpointnumbers || cv->show_ft_results || cv->dv )
1142 0 : && sp->ttfindex!=0xffff )
1143 : {
1144 0 : if ( sp->ttfindex==0xfffe )
1145 0 : strcpy(buf,"??");
1146 0 : else if (cv->showpointnumbers == 2)
1147 0 : SplinePointCoords(buf, sizeof(buf), sp);
1148 : else
1149 0 : sprintf( buf,"%d", sp->ttfindex );
1150 0 : GDrawDrawText8(pixmap,x,y-6,buf,-1,col);
1151 : }
1152 0 : if ( truetype_markup && sp->roundx ) {
1153 0 : r.x = x-5; r.y = y-5;
1154 0 : r.width = r.height = 11;
1155 0 : GDrawDrawElipse(pixmap,&r,selectedpointcolmasked);
1156 0 : } else if ( !onlynumber && !truetype_markup ) {
1157 0 : if ((( sp->roundx || sp->roundy ) &&
1158 0 : (((cv->showrounds&1) && cv->scale>=.3) || (cv->showrounds&2))) ||
1159 0 : (sp->watched && cv->dv!=NULL) ||
1160 0 : sp->hintmask!=NULL ) {
1161 0 : r.x = x-5; r.y = y-5;
1162 0 : r.width = r.height = 11;
1163 0 : GDrawDrawElipse(pixmap,&r,col);
1164 : }
1165 0 : if (( sp->flexx && cv->showhhints ) || (sp->flexy && cv->showvhints)) {
1166 0 : r.x = x-5; r.y = y-5;
1167 0 : r.width = r.height = 11;
1168 0 : GDrawDrawElipse(pixmap,&r,
1169 0 : MaybeMaskColorToAlphaChannelOverride( sp->flexx ? hflexhintcol : vflexhintcol,
1170 : AlphaChannelOverride ));
1171 : }
1172 : }
1173 : }
1174 :
1175 0 : static void DrawSpiroPoint( CharView *cv, GWindow pixmap, spiro_cp *cp,
1176 : SplineSet *spl, int cp_i, Color AlphaChannelOverride )
1177 : {
1178 : GRect r;
1179 : int x, y;
1180 0 : Color col = cp==&spl->spiros[0] ? firstpointcol : pointcol;
1181 0 : char ty = cp->ty&0x7f;
1182 0 : int selected = SPIRO_SELECTED(cp);
1183 : GPoint gp[5];
1184 :
1185 0 : if ( selected )
1186 0 : col = selectedpointcol;
1187 :
1188 0 : if( !selected )
1189 : {
1190 0 : col = col & 0x00ffffff;
1191 0 : col |= prefs_cvInactiveHandleAlpha << 24;
1192 : }
1193 :
1194 0 : col = MaybeMaskColorToAlphaChannelOverride( col, AlphaChannelOverride );
1195 :
1196 :
1197 0 : x = cv->xoff + rint(cp->x*cv->scale);
1198 0 : y = -cv->yoff + cv->height - rint(cp->y*cv->scale);
1199 0 : if ( x<-4 || y<-4 || x>cv->width+4 || y>=cv->height+4 )
1200 0 : return;
1201 :
1202 0 : DrawPoint_SetupRectForSize( &r, x, y, 2 );
1203 : /* r.x = x-2; */
1204 : /* r.y = y-2; */
1205 : /* r.width = r.height = 5; */
1206 0 : if ( selected )
1207 0 : GDrawSetLineWidth(pixmap,selectedpointwidth);
1208 :
1209 0 : float sizedelta = 3;
1210 0 : if( prefs_cvEditHandleSize > prefs_cvEditHandleSize_default )
1211 0 : sizedelta *= prefs_cvEditHandleSize / prefs_cvEditHandleSize_default;
1212 :
1213 0 : if ( ty == SPIRO_RIGHT ) {
1214 0 : GDrawSetLineWidth(pixmap,2);
1215 0 : gp[0].x = x-sizedelta; gp[0].y = y-sizedelta;
1216 0 : gp[1].x = x; gp[1].y = y-sizedelta;
1217 0 : gp[2].x = x; gp[2].y = y+sizedelta;
1218 0 : gp[3].x = x-sizedelta; gp[3].y = y+sizedelta;
1219 0 : GDrawDrawPoly(pixmap,gp,4,col);
1220 0 : } else if ( ty == SPIRO_LEFT ) {
1221 0 : GDrawSetLineWidth(pixmap,2);
1222 0 : gp[0].x = x+sizedelta; gp[0].y = y-sizedelta;
1223 0 : gp[1].x = x; gp[1].y = y-sizedelta;
1224 0 : gp[2].x = x; gp[2].y = y+sizedelta;
1225 0 : gp[3].x = x+sizedelta; gp[3].y = y+sizedelta;
1226 0 : GDrawDrawPoly(pixmap,gp,4,col);
1227 0 : } else if ( ty == SPIRO_G2 ) {
1228 : GPoint gp[5];
1229 :
1230 0 : float sizedelta = 3;
1231 0 : float offsetdelta = 1;
1232 0 : if( prefs_cvEditHandleSize > prefs_cvEditHandleSize_default )
1233 : {
1234 0 : sizedelta *= prefs_cvEditHandleSize / prefs_cvEditHandleSize_default;
1235 0 : offsetdelta *= prefs_cvEditHandleSize / prefs_cvEditHandleSize_default;
1236 : }
1237 :
1238 0 : float basex = r.x + 1 + offsetdelta;
1239 0 : float basey = r.y + 1 + offsetdelta;
1240 0 : gp[0].x = basex - sizedelta; gp[0].y = basey + 0;
1241 0 : gp[1].x = basex + 0; gp[1].y = basey + sizedelta;
1242 0 : gp[2].x = basex + sizedelta; gp[2].y = basey + 0;
1243 0 : gp[3].x = basex + 0; gp[3].y = basey - sizedelta;
1244 0 : gp[4] = gp[0];
1245 0 : if ( selected )
1246 0 : GDrawDrawPoly(pixmap,gp,5,col);
1247 : else
1248 0 : GDrawFillPoly(pixmap,gp,5,col);
1249 0 : } else if ( ty==SPIRO_CORNER ) {
1250 0 : if ( selected )
1251 0 : GDrawDrawRect(pixmap,&r,col);
1252 : else
1253 0 : GDrawFillRect(pixmap,&r,col);
1254 : } else {
1255 0 : --r.x; --r.y; r.width +=2; r.height += 2;
1256 0 : if ( selected )
1257 0 : GDrawDrawElipse(pixmap,&r,col);
1258 : else
1259 0 : GDrawFillElipse(pixmap,&r,col);
1260 : }
1261 0 : GDrawSetLineWidth(pixmap,0);
1262 : }
1263 :
1264 0 : static void DrawLine(CharView *cv, GWindow pixmap,
1265 : real x1, real y1, real x2, real y2, Color fg) {
1266 0 : int ix1 = cv->xoff + rint(x1*cv->scale);
1267 0 : int iy1 = -cv->yoff + cv->height - rint(y1*cv->scale);
1268 0 : int ix2 = cv->xoff + rint(x2*cv->scale);
1269 0 : int iy2 = -cv->yoff + cv->height - rint(y2*cv->scale);
1270 0 : if ( iy1==iy2 ) {
1271 0 : if ( iy1<0 || iy1>cv->height )
1272 0 : return;
1273 0 : if ( ix1<0 ) ix1 = 0;
1274 0 : if ( ix2>cv->width ) ix2 = cv->width;
1275 0 : } else if ( ix1==ix2 ) {
1276 0 : if ( ix1<0 || ix1>cv->width )
1277 0 : return;
1278 0 : if ( iy1<0 ) iy1 = 0;
1279 0 : if ( iy2<0 ) iy2 = 0;
1280 0 : if ( iy1>cv->height ) iy1 = cv->height;
1281 0 : if ( iy2>cv->height ) iy2 = cv->height;
1282 : }
1283 0 : GDrawDrawLine(pixmap, ix1,iy1, ix2,iy2, fg );
1284 : }
1285 :
1286 0 : static void DrawDirection(CharView *cv,GWindow pixmap, SplinePoint *sp) {
1287 : BasePoint dir, *other;
1288 : double len;
1289 : int x,y,xe,ye;
1290 : SplinePoint *test;
1291 :
1292 0 : if ( sp->next==NULL )
1293 0 : return;
1294 :
1295 0 : x = cv->xoff + rint(sp->me.x*cv->scale);
1296 0 : y = -cv->yoff + cv->height - rint(sp->me.y*cv->scale);
1297 0 : if ( x<0 || y<0 || x>cv->width || y>cv->width )
1298 0 : return;
1299 :
1300 : /* Werner complained when the first point and the second point were at */
1301 : /* the same location... */ /* Damn. They weren't at the same location */
1302 : /* the were off by a rounding error. I'm not going to fix for that */
1303 0 : for ( test=sp; ; ) {
1304 0 : if ( test->me.x!=sp->me.x || test->me.y!=sp->me.y ) {
1305 0 : other = &test->me;
1306 0 : break;
1307 0 : } else if ( !test->nonextcp ) {
1308 0 : other = &test->nextcp;
1309 0 : break;
1310 : }
1311 0 : if ( test->next==NULL )
1312 0 : return;
1313 0 : test = test->next->to;
1314 0 : if ( test==sp )
1315 0 : return;
1316 0 : }
1317 :
1318 0 : dir.x = other->x-sp->me.x;
1319 0 : dir.y = sp->me.y-other->y; /* screen coordinates are the mirror of user coords */
1320 0 : len = sqrt(dir.x*dir.x + dir.y*dir.y);
1321 0 : dir.x /= len; dir.y /= len;
1322 :
1323 0 : x += rint(5*dir.y);
1324 0 : y -= rint(5*dir.x);
1325 0 : xe = x + rint(7*dir.x);
1326 0 : ye = y + rint(7*dir.y);
1327 0 : GDrawDrawLine(pixmap,x,y,xe,ye,firstpointcol);
1328 0 : GDrawDrawLine(pixmap,xe,ye,xe+rint(2*(dir.y-dir.x)),ye+rint(2*(-dir.y-dir.x)), firstpointcol);
1329 0 : GDrawDrawLine(pixmap,xe,ye,xe+rint(2*(-dir.y-dir.x)),ye+rint(2*(dir.x-dir.y)), firstpointcol);
1330 : }
1331 :
1332 0 : static void CVMarkInterestingLocations(CharView *cv, GWindow pixmap,
1333 : SplinePointList *spl) {
1334 : Spline *s, *first;
1335 : extended interesting[6];
1336 : int i, ecnt, cnt;
1337 : GRect r;
1338 :
1339 0 : for ( s=spl->first->next, first=NULL; s!=NULL && s!=first; s=s->to->next ) {
1340 0 : if ( first==NULL ) first = s;
1341 0 : cnt = ecnt = 0;
1342 0 : if ( cv->markextrema )
1343 0 : ecnt = cnt = Spline2DFindExtrema(s,interesting);
1344 :
1345 0 : if ( cv->markpoi ) {
1346 0 : cnt += Spline2DFindPointsOfInflection(s,interesting+cnt);
1347 : }
1348 0 : r.width = r.height = 9;
1349 0 : for ( i=0; i<cnt; ++i ) if ( interesting[i]>0 && interesting[i]<1.0 ) {
1350 0 : Color col = i<ecnt ? extremepointcol : pointofinflectioncol;
1351 0 : double x = ((s->splines[0].a*interesting[i]+s->splines[0].b)*interesting[i]+s->splines[0].c)*interesting[i]+s->splines[0].d;
1352 0 : double y = ((s->splines[1].a*interesting[i]+s->splines[1].b)*interesting[i]+s->splines[1].c)*interesting[i]+s->splines[1].d;
1353 0 : double sx = cv->xoff + rint(x*cv->scale);
1354 0 : double sy = -cv->yoff + cv->height - rint(y*cv->scale);
1355 0 : if ( sx<-5 || sy<-5 || sx>10000 || sy>10000 )
1356 0 : continue;
1357 0 : GDrawDrawLine(pixmap,sx-4,sy,sx+4,sy, col);
1358 0 : GDrawDrawLine(pixmap,sx,sy-4,sx,sy+4, col);
1359 0 : r.x = sx-4; r.y = sy-4;
1360 0 : GDrawDrawElipse(pixmap,&r,col);
1361 : }
1362 : }
1363 0 : }
1364 :
1365 0 : static void CVMarkAlmostHV(CharView *cv, GWindow pixmap,
1366 : SplinePointList *spl) {
1367 : Spline *s, *first;
1368 : double dx, dy;
1369 : int x1,x2,y1,y2;
1370 :
1371 0 : for ( s=spl->first->next, first=NULL; s!=NULL && s!=first; s=s->to->next ) {
1372 0 : if ( first==NULL ) first = s;
1373 :
1374 0 : if ( s->islinear ) {
1375 0 : if ( !cv->showalmosthvlines )
1376 0 : continue;
1377 0 : if ( (dx = s->from->me.x - s->to->me.x)<0 ) dx = -dx;
1378 0 : if ( (dy = s->from->me.y - s->to->me.y)<0 ) dy = -dy;
1379 0 : if ( dx<=cv->hvoffset && dy<=cv->hvoffset )
1380 0 : continue;
1381 0 : if ( dx==0 || dy==0 )
1382 0 : continue;
1383 0 : if ( dx<cv->hvoffset || dy<cv->hvoffset ) {
1384 0 : x1 = cv->xoff + rint(s->from->me.x*cv->scale);
1385 0 : y1 = -cv->yoff + cv->height - rint(s->from->me.y*cv->scale);
1386 0 : x2 = cv->xoff + rint(s->to->me.x*cv->scale);
1387 0 : y2 = -cv->yoff + cv->height - rint(s->to->me.y*cv->scale);
1388 0 : GDrawDrawLine(pixmap,x1,y1,x2,y2,almosthvcol);
1389 : }
1390 : } else {
1391 0 : if ( !cv->showalmosthvcurves )
1392 0 : continue;
1393 0 : if ( (dx = s->from->me.x - s->from->nextcp.x)<0 ) dx = -dx;
1394 0 : if ( (dy = s->from->me.y - s->from->nextcp.y)<0 ) dy = -dy;
1395 0 : if ( dx<=cv->hvoffset && dy<=cv->hvoffset )
1396 : /* Ignore */;
1397 0 : else if ( dx==0 || dy==0 )
1398 : /* It's right */;
1399 0 : else if ( dx<cv->hvoffset || dy<cv->hvoffset ) {
1400 0 : x2 = x1 = cv->xoff + rint(s->from->me.x*cv->scale);
1401 0 : y2 = y1 = -cv->yoff + cv->height - rint(s->from->me.y*cv->scale);
1402 0 : if ( dx<cv->hvoffset ) {
1403 0 : if ( s->from->me.y<s->from->nextcp.y )
1404 0 : y2 += 15;
1405 : else
1406 0 : y2 -= 15;
1407 : } else {
1408 0 : if ( s->from->me.x<s->from->nextcp.x )
1409 0 : x2 += 15;
1410 : else
1411 0 : x2 -= 15;
1412 : }
1413 0 : GDrawDrawLine(pixmap,x1,y1,x2,y2,almosthvcol);
1414 : }
1415 :
1416 0 : if ( (dx = s->to->me.x - s->to->prevcp.x)<0 ) dx = -dx;
1417 0 : if ( (dy = s->to->me.y - s->to->prevcp.y)<0 ) dy = -dy;
1418 0 : if ( dx<=cv->hvoffset && dy<=cv->hvoffset )
1419 : /* Ignore */;
1420 0 : else if ( dx==0 || dy==0 )
1421 : /* It's right */;
1422 0 : else if ( dx<cv->hvoffset || dy<cv->hvoffset ) {
1423 0 : x2 = x1 = cv->xoff + rint(s->to->me.x*cv->scale);
1424 0 : y2 = y1 = -cv->yoff + cv->height - rint(s->to->me.y*cv->scale);
1425 0 : if ( dx<cv->hvoffset ) {
1426 0 : if ( s->to->me.y<s->to->prevcp.y )
1427 0 : y2 += 15;
1428 : else
1429 0 : y2 -= 15;
1430 : } else {
1431 0 : if ( s->to->me.x<s->to->prevcp.x )
1432 0 : x2 += 15;
1433 : else
1434 0 : x2 -= 15;
1435 : }
1436 0 : GDrawDrawLine(pixmap,x1,y1,x2,y2,almosthvcol);
1437 : }
1438 : }
1439 : }
1440 0 : }
1441 :
1442 0 : static void CVDrawPointName(CharView *cv, GWindow pixmap, SplinePoint *sp, Color fg)
1443 : {
1444 0 : if (sp->name && *sp->name) {
1445 : int32 theight;
1446 :
1447 0 : GDrawSetFont(pixmap, cv->normal);
1448 0 : theight = GDrawGetText8Height(pixmap, sp->name, -1);
1449 0 : GDrawDrawText8(pixmap,
1450 0 : cv->xoff + rint(sp->me.x*cv->scale),
1451 0 : cv->height-cv->yoff - rint(sp->me.y*cv->scale) + theight + 3,
1452 0 : sp->name,-1,fg);
1453 0 : GDrawSetFont(pixmap,cv->small); /* For point numbers */
1454 : }
1455 0 : }
1456 :
1457 0 : static void CVDrawContourName(CharView *cv, GWindow pixmap, SplinePointList *ss,
1458 : Color fg ) {
1459 : SplinePoint *sp, *topright;
1460 : GPoint tr;
1461 :
1462 : /* Find the top right point of the contour. This is where we will put the */
1463 : /* label */
1464 0 : for ( sp = topright = ss->first; ; ) {
1465 0 : if ( sp->me.y>topright->me.y || (sp->me.y==topright->me.y && sp->me.x>topright->me.x) )
1466 0 : topright = sp;
1467 0 : if ( sp->next==NULL )
1468 0 : break;
1469 0 : sp = sp->next->to;
1470 0 : if ( sp==ss->first )
1471 0 : break;
1472 0 : }
1473 0 : tr.x = cv->xoff + rint(topright->me.x*cv->scale);
1474 0 : tr.y = cv->height-cv->yoff - rint(topright->me.y*cv->scale);
1475 :
1476 : /* If the top edge of the contour is off the bottom of the screen */
1477 : /* then the contour won't show */
1478 0 : if ( tr.y>cv->height )
1479 0 : return;
1480 :
1481 0 : GDrawSetFont(pixmap,cv->normal);
1482 :
1483 0 : if ( ss->first->prev==NULL && ss->first->next!=NULL &&
1484 0 : ss->first->next->to->next==NULL && ss->first->next->knownlinear &&
1485 0 : (tr.y < cv->nfh || tr.x>cv->width-cv->nfh) ) {
1486 : /* It's a simple line */
1487 : /* A special case because: It's common, and it's important to get it */
1488 : /* right and label lines even if the point to which we'd normally */
1489 : /* attach a label is offscreen */
1490 0 : SplinePoint *sp1 = ss->first, *sp2 = ss->first->next->to;
1491 : double dx, dy, slope, off, yinter, xinter;
1492 :
1493 0 : if ( (dx = sp1->me.x-sp2->me.x)<0 ) dx = -dx;
1494 0 : if ( (dy = sp1->me.y-sp2->me.y)<0 ) dy = -dy;
1495 0 : if ( dx==0 ) {
1496 : /* Vertical line */
1497 0 : tr.y = cv->nfh;
1498 0 : tr.x += 2;
1499 0 : } else if ( dy==0 ) {
1500 : /* Horizontal line */
1501 0 : tr.x = cv->width - cv->nfh - GDrawGetText8Width(pixmap,ss->contour_name,-1);
1502 : } else {
1503 : /* y = slope*x + off; */
1504 0 : slope = (sp1->me.y-sp2->me.y)/(sp1->me.x-sp2->me.x);
1505 0 : off = sp1->me.y - slope*sp1->me.x;
1506 : /* Now translate to screen coords */
1507 0 : off = (cv->height-cv->yoff)+slope*cv->xoff - cv->scale*off;
1508 0 : slope = -slope;
1509 0 : xinter = (0-off)/slope;
1510 0 : yinter = slope*cv->width + off;
1511 0 : if ( xinter>0 && xinter<cv->width ) {
1512 0 : tr.x = xinter+2;
1513 0 : tr.y = cv->nfh;
1514 0 : } else if ( yinter>0 && yinter<cv->height ) {
1515 0 : tr.x = cv->width - cv->nfh - GDrawGetText8Width(pixmap,ss->contour_name,-1);
1516 0 : tr.y = yinter;
1517 : }
1518 : }
1519 : } else {
1520 0 : tr.y -= cv->nfh/2;
1521 0 : tr.x -= GDrawGetText8Width(pixmap,ss->contour_name,-1)/2;
1522 : }
1523 :
1524 0 : GDrawDrawText8(pixmap,tr.x,tr.y,ss->contour_name,-1,fg);
1525 0 : GDrawSetFont(pixmap,cv->small); /* For point numbers */
1526 : }
1527 :
1528 0 : void CVDrawSplineSet(CharView *cv, GWindow pixmap, SplinePointList *set,
1529 : Color fg, int dopoints, DRect *clip ) {
1530 0 : CVDrawSplineSetSpecialized( cv, pixmap, set, fg, dopoints, clip,
1531 : sfm_stroke, 0 );
1532 0 : }
1533 :
1534 :
1535 0 : void CVDrawSplineSetOutlineOnly(CharView *cv, GWindow pixmap, SplinePointList *set,
1536 : Color fg, int dopoints, DRect *clip, enum outlinesfm_flags strokeFillMode ) {
1537 : SplinePointList *spl;
1538 0 : int currentSplineCounter = 0;
1539 0 : int activelayer = CVLayer(&cv->b);
1540 :
1541 0 : if( strokeFillMode == sfm_fill ) {
1542 0 : GDrawFillRuleSetWinding(pixmap);
1543 : }
1544 :
1545 0 : for ( spl = set; spl!=NULL; spl = spl->next ) {
1546 :
1547 0 : Color fc = spl->is_clip_path ? clippathcol : fg;
1548 : /**
1549 : * Only make the outline red if this is not a grid layer
1550 : * and we want to highlight open paths
1551 : * and the activelayer is sane
1552 : * and the activelayer contains the given splinepointlist
1553 : * and the path is open
1554 : */
1555 0 : if ( cv->b.drawmode!=dm_grid
1556 0 : && DrawOpenPathsWithHighlight
1557 0 : && activelayer < cv->b.sc->layer_cnt
1558 0 : && activelayer >= 0
1559 0 : && SplinePointListContains( cv->b.sc->layers[activelayer].splines, spl )
1560 0 : && spl->first
1561 0 : && spl->first->prev==NULL )
1562 : {
1563 0 : fc = openpathcol;
1564 : }
1565 :
1566 0 : if ( GDrawHasCairo(pixmap)&gc_buildpath ) {
1567 : Spline *first, *spline;
1568 : double x,y, cx1, cy1, cx2, cy2, dx,dy;
1569 0 : GDrawPathStartSubNew(pixmap);
1570 0 : x = rpt(cv, cv->xoff + spl->first->me.x*cv->scale);
1571 0 : y = rpt(cv, -cv->yoff + cv->height - spl->first->me.y*cv->scale);
1572 0 : GDrawPathMoveTo(pixmap,x+.5,y+.5);
1573 0 : currentSplineCounter++;
1574 0 : for ( spline=spl->first->next, first=NULL; spline!=first && spline!=NULL; spline=spline->to->next ) {
1575 0 : x = rpt(cv, cv->xoff + spline->to->me.x*cv->scale);
1576 0 : y = rpt(cv, -cv->yoff + cv->height - spline->to->me.y*cv->scale);
1577 0 : if ( spline->knownlinear )
1578 0 : GDrawPathLineTo(pixmap,x+.5,y+.5);
1579 0 : else if ( spline->order2 ) {
1580 0 : dx = rint(spline->from->me.x*cv->scale) - spline->from->me.x*cv->scale;
1581 0 : dy = rint(spline->from->me.y*cv->scale) - spline->from->me.y*cv->scale;
1582 0 : cx1 = spline->from->me.x + spline->splines[0].c/3;
1583 0 : cy1 = spline->from->me.y + spline->splines[1].c/3;
1584 0 : cx2 = cx1 + (spline->splines[0].b+spline->splines[0].c)/3;
1585 0 : cy2 = cy1 + (spline->splines[1].b+spline->splines[1].c)/3;
1586 0 : cx1 = cv->xoff + cx1*cv->scale + dx;
1587 0 : cy1 = -cv->yoff + cv->height - cy1*cv->scale - dy;
1588 0 : dx = rint(spline->to->me.x*cv->scale) - spline->to->me.x*cv->scale;
1589 0 : dy = rint(spline->to->me.y*cv->scale) - spline->to->me.y*cv->scale;
1590 0 : cx2 = cv->xoff + cx2*cv->scale + dx;
1591 0 : cy2 = -cv->yoff + cv->height - cy2*cv->scale - dy;
1592 0 : GDrawPathCurveTo(pixmap,cx1+.5,cy1+.5,cx2+.5,cy2+.5,x+.5,y+.5);
1593 : } else {
1594 0 : dx = rint(spline->from->me.x*cv->scale) - spline->from->me.x*cv->scale;
1595 0 : dy = rint(spline->from->me.y*cv->scale) - spline->from->me.y*cv->scale;
1596 0 : cx1 = cv->xoff + spline->from->nextcp.x*cv->scale + dx;
1597 0 : cy1 = -cv->yoff + cv->height - spline->from->nextcp.y*cv->scale - dy;
1598 0 : dx = rint(spline->to->me.x*cv->scale) - spline->to->me.x*cv->scale;
1599 0 : dy = rint(spline->to->me.y*cv->scale) - spline->to->me.y*cv->scale;
1600 0 : cx2 = cv->xoff + spline->to->prevcp.x*cv->scale + dx;
1601 0 : cy2 = -cv->yoff + cv->height - spline->to->prevcp.y*cv->scale - dy;
1602 0 : GDrawPathCurveTo(pixmap,cx1+.5,cy1+.5,cx2+.5,cy2+.5,x+.5,y+.5);
1603 : }
1604 0 : if ( first==NULL )
1605 0 : first = spline;
1606 : }
1607 0 : if ( spline!=NULL )
1608 0 : GDrawPathClose(pixmap);
1609 :
1610 0 : switch( strokeFillMode ) {
1611 : case sfm_stroke_trans:
1612 0 : GDrawPathStroke( pixmap, fc );
1613 0 : break;
1614 : case sfm_stroke:
1615 0 : GDrawPathStroke( pixmap, fc | 0xff000000 );
1616 0 : break;
1617 : case sfm_clip_preserve:
1618 0 : GDrawClipPreserve( pixmap );
1619 : case sfm_fill:
1620 : case sfm_nothing:
1621 0 : break;
1622 : }
1623 : } else {
1624 0 : GPointList *gpl = MakePoly(cv,spl), *cur;
1625 0 : for ( cur=gpl; cur!=NULL; cur=cur->next )
1626 0 : GDrawDrawPoly(pixmap,cur->gp,cur->cnt,fc);
1627 0 : GPLFree(gpl);
1628 : }
1629 : }
1630 :
1631 0 : Color c = fillcol;
1632 0 : switch( strokeFillMode ) {
1633 : case sfm_fill:
1634 0 : if( cv->inPreviewMode ) {
1635 0 : c = previewfillcol;
1636 : }
1637 0 : GDrawPathFill( pixmap, c|0xff000000);
1638 0 : break;
1639 : case sfm_stroke:
1640 : case sfm_nothing:
1641 0 : break;
1642 : }
1643 0 : }
1644 :
1645 :
1646 :
1647 0 : void CVDrawSplineSetSpecialized( CharView *cv, GWindow pixmap, SplinePointList *set,
1648 : Color fg, int dopoints, DRect *clip,
1649 : enum outlinesfm_flags strokeFillMode,
1650 : Color AlphaChannelOverride )
1651 : {
1652 : Spline *spline, *first;
1653 : SplinePointList *spl;
1654 0 : int truetype_markup = set==cv->b.gridfit && cv->dv!=NULL;
1655 :
1656 0 : if ( cv->inactive )
1657 0 : dopoints = false;
1658 :
1659 0 : if( strokeFillMode == sfm_fill ) {
1660 0 : CVDrawSplineSetOutlineOnly( cv, pixmap, set,
1661 : fg, dopoints, clip, strokeFillMode );
1662 : }
1663 :
1664 0 : GDrawSetFont(pixmap,cv->small); /* For point numbers */
1665 0 : for ( spl = set; spl!=NULL; spl = spl->next ) {
1666 0 : if ( spl->contour_name!=NULL )
1667 0 : CVDrawContourName(cv,pixmap,spl,fg);
1668 0 : if ( dopoints>0 || (dopoints==-1 && cv->showpointnumbers) ) {
1669 0 : first = NULL;
1670 0 : if ( dopoints>0 )
1671 0 : DrawDirection(cv,pixmap,spl->first);
1672 0 : if ( cv->b.sc->inspiro && hasspiro()) {
1673 0 : if ( dopoints>=0 ) {
1674 : int i;
1675 0 : if ( spl->spiros==NULL ) {
1676 0 : spl->spiros = SplineSet2SpiroCP(spl,&spl->spiro_cnt);
1677 0 : spl->spiro_max = spl->spiro_cnt;
1678 : }
1679 0 : for ( i=0; i<spl->spiro_cnt-1; ++i )
1680 0 : DrawSpiroPoint(cv,pixmap,&spl->spiros[i],spl,i, AlphaChannelOverride );
1681 : }
1682 : } else {
1683 0 : for ( spline = spl->first->next; spline!=NULL && spline!=first; spline=spline->to->next ) {
1684 0 : DrawPoint(cv,pixmap,spline->from,spl,dopoints<0,truetype_markup, AlphaChannelOverride );
1685 0 : CVDrawPointName(cv,pixmap,spline->from,fg);
1686 0 : if ( first==NULL ) first = spline;
1687 : }
1688 0 : if ( spline==NULL ) {
1689 0 : DrawPoint(cv,pixmap,spl->last,spl,dopoints<0,truetype_markup, AlphaChannelOverride );
1690 0 : CVDrawPointName(cv,pixmap,spl->last,fg);
1691 : }
1692 : }
1693 : }
1694 : }
1695 :
1696 0 : if( strokeFillMode != sfm_nothing ) {
1697 :
1698 : /*
1699 : * If we were filling, we have to stroke the outline again to properly show
1700 : * clip path splines which will possibly have a different stroke color
1701 : */
1702 0 : Color thinfgcolor = fg;
1703 0 : enum outlinesfm_flags fgstrokeFillMode = sfm_stroke;
1704 0 : if( strokeFillMode==sfm_stroke_trans )
1705 0 : fgstrokeFillMode = sfm_stroke_trans;
1706 0 : if( shouldShowFilledUsingCairo(cv) ) {
1707 0 : if (cv->inPreviewMode)
1708 0 : thinfgcolor = (thinfgcolor | 0x01000000) & 0x01ffffff;
1709 0 : fgstrokeFillMode = sfm_stroke_trans;
1710 : }
1711 0 : CVDrawSplineSetOutlineOnly( cv, pixmap, set,
1712 : thinfgcolor, dopoints, clip,
1713 : fgstrokeFillMode );
1714 :
1715 0 : if( prefs_cv_outline_thickness > 1 )
1716 : {
1717 0 : SplinePointList *spl = 0;
1718 0 : for ( spl = set; spl!=NULL; spl = spl->next )
1719 : {
1720 : // we only draw the inner half, so we double the user's expected
1721 : // thickness here.
1722 0 : int strokeWidth = prefs_cv_outline_thickness * 2 * cv->scale;
1723 0 : Color strokefg = foreoutthicklinecol;
1724 :
1725 0 : if( shouldShowFilledUsingCairo(cv) && cv->inPreviewMode ) {
1726 0 : strokefg = (strokefg | 0x01000000) & 0x01ffffff;
1727 : }
1728 :
1729 : GRect old;
1730 0 : GDrawPushClipOnly( pixmap );
1731 0 : CVDrawSplineSetOutlineOnly( cv, pixmap, spl,
1732 : strokefg, dopoints, clip,
1733 : sfm_clip_preserve );
1734 0 : int16 oldwidth = GDrawGetLineWidth( pixmap );
1735 0 : GDrawSetLineWidth( pixmap, strokeWidth );
1736 0 : CVDrawSplineSetOutlineOnly( cv, pixmap, spl,
1737 : strokefg, dopoints, clip,
1738 : sfm_stroke_trans );
1739 0 : GDrawPopClip( pixmap, &old );
1740 0 : GDrawSetLineWidth( pixmap, oldwidth );
1741 : }
1742 : }
1743 :
1744 :
1745 : }
1746 :
1747 0 : for ( spl = set; spl!=NULL; spl = spl->next ) {
1748 0 : if (( cv->markextrema || cv->markpoi ) && dopoints && !cv->b.sc->inspiro )
1749 0 : CVMarkInterestingLocations(cv,pixmap,spl);
1750 0 : if ( (cv->showalmosthvlines || cv->showalmosthvcurves ) && dopoints )
1751 0 : CVMarkAlmostHV(cv,pixmap,spl);
1752 : }
1753 0 : }
1754 :
1755 0 : static void CVDrawLayerSplineSet(CharView *cv, GWindow pixmap, Layer *layer,
1756 : Color fg, int dopoints, DRect *clip, enum outlinesfm_flags strokeFillMode ) {
1757 0 : int active = cv->b.layerheads[cv->b.drawmode]==layer;
1758 0 : int ml = cv->b.sc->parent->multilayer;
1759 :
1760 0 : if ( ml && layer->dostroke ) {
1761 0 : if ( layer->stroke_pen.brush.col!=COLOR_INHERITED &&
1762 0 : layer->stroke_pen.brush.col!=view_bgcol )
1763 0 : fg = layer->stroke_pen.brush.col;
1764 : }
1765 0 : if ( ml && layer->dofill ) {
1766 0 : if ( layer->fill_brush.col!=COLOR_INHERITED &&
1767 0 : layer->fill_brush.col!=view_bgcol )
1768 0 : fg = layer->fill_brush.col;
1769 : }
1770 :
1771 0 : if ( ml && !active && layer!=&cv->b.sc->layers[ly_back] )
1772 0 : GDrawSetDashedLine(pixmap,5,5,cv->xoff+cv->height-cv->yoff);
1773 :
1774 0 : CVDrawSplineSetSpecialized( cv, pixmap, layer->splines,
1775 : fg, dopoints && active, clip,
1776 : strokeFillMode, 0 );
1777 :
1778 0 : if ( ml && !active && layer!=&cv->b.sc->layers[ly_back] )
1779 0 : GDrawSetDashedLine(pixmap,0,0,0);
1780 0 : }
1781 :
1782 0 : static void CVDrawTemplates(CharView *cv,GWindow pixmap,SplineChar *template,DRect *clip) {
1783 : RefChar *r;
1784 :
1785 0 : CVDrawSplineSet(cv,pixmap,template->layers[ly_fore].splines,templateoutlinecol,false,clip);
1786 0 : for ( r=template->layers[ly_fore].refs; r!=NULL; r=r->next )
1787 0 : CVDrawSplineSet(cv,pixmap,r->layers[0].splines,templateoutlinecol,false,clip);
1788 0 : }
1789 :
1790 0 : static void CVShowDHintInstance(CharView *cv, GWindow pixmap, BasePoint *bp) {
1791 : IPoint ip[40], ip2[40];
1792 : GPoint clipped[13];
1793 : int i,j, tot,last;
1794 :
1795 0 : ip[0].x = cv->xoff + rint( bp[0].x*cv->scale );
1796 0 : ip[0].y = -cv->yoff + cv->height - rint( bp[0].y*cv->scale );
1797 0 : ip[1].x = cv->xoff + rint(bp[1].x*cv->scale);
1798 0 : ip[1].y = -cv->yoff + cv->height - rint( bp[1].y*cv->scale );
1799 0 : ip[2].x = cv->xoff + rint( bp[2].x*cv->scale );
1800 0 : ip[2].y = -cv->yoff + cv->height - rint( bp[2].y*cv->scale );
1801 0 : ip[3].x = cv->xoff + rint( bp[3].x*cv->scale );
1802 0 : ip[3].y = -cv->yoff + cv->height - rint( bp[3].y*cv->scale );
1803 :
1804 0 : if (( ip[0].x<0 && ip[1].x<0 && ip[2].x<0 && ip[3].x<0 ) ||
1805 0 : ( ip[0].x>=cv->width && ip[1].x>=cv->width && ip[2].x>=cv->width && ip[3].x>=cv->width ) ||
1806 0 : ( ip[0].y<0 && ip[1].y<0 && ip[2].y<0 && ip[3].y<0 ) ||
1807 0 : ( ip[0].y>=cv->height && ip[1].y>=cv->height && ip[2].y>=cv->height && ip[3].y>=cv->height ))
1808 0 : return; /* Offscreen */
1809 :
1810 : /* clip to left edge */
1811 0 : tot = 4;
1812 0 : for ( i=j=0; i<tot; ++i ) {
1813 0 : last = i==0?tot-1:i-1;
1814 0 : if ( ip[i].x>=0 && ip[last].x>=0) {
1815 0 : ip2[j++] = ip[i];
1816 0 : } else if ( ip[i].x<0 && ip[last].x<0 ) {
1817 0 : if ( j==0 || ip2[j-1].x!=0 || ip2[j-1].y!=ip[i].y ) {
1818 0 : ip2[j].x = 0;
1819 0 : ip2[j++].y = ip[i].y;
1820 : }
1821 : } else {
1822 0 : ip2[j].x = 0;
1823 0 : ip2[j++].y = ip[last].y - ip[last].x * ((real) (ip[i].y-ip[last].y))/(ip[i].x-ip[last].x);
1824 0 : if ( ip[i].x>0 )
1825 0 : ip2[j++] = ip[i];
1826 : else {
1827 0 : ip2[j].x = 0;
1828 0 : ip2[j++].y = ip[i].y;
1829 : }
1830 : }
1831 : }
1832 : /* clip to right edge */
1833 0 : tot = j;
1834 0 : for ( i=j=0; i<tot; ++i ) {
1835 0 : last = i==0?tot-1:i-1;
1836 0 : if ( ip2[i].x<cv->width && ip2[last].x<cv->width ) {
1837 0 : ip[j++] = ip2[i];
1838 0 : } else if ( ip2[i].x>=cv->width && ip2[last].x>=cv->width ) {
1839 0 : if ( j==0 || ip[j-1].x!=cv->width-1 || ip[j-1].y!=ip2[i].y ) {
1840 0 : ip[j].x = cv->width-1;
1841 0 : ip[j++].y = ip2[i].y;
1842 : }
1843 : } else {
1844 0 : ip[j].x = cv->width-1;
1845 0 : 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);
1846 0 : if ( ip2[i].x<cv->width )
1847 0 : ip[j++] = ip2[i];
1848 : else {
1849 0 : ip[j].x = cv->width-1;
1850 0 : ip[j++].y = ip2[i].y;
1851 : }
1852 : }
1853 : }
1854 : /* clip to bottom edge */
1855 0 : tot = j;
1856 0 : for ( i=j=0; i<tot; ++i ) {
1857 0 : last = i==0?tot-1:i-1;
1858 0 : if ( ip[i].y>=0 && ip[last].y>=0) {
1859 0 : ip2[j++] = ip[i];
1860 0 : } else if ( ip[i].y<0 && ip[last].y<0 ) {
1861 0 : ip2[j].y = 0;
1862 0 : ip2[j++].x = ip[i].x;
1863 : } else {
1864 0 : ip2[j].y = 0;
1865 0 : ip2[j++].x = ip[last].x - ip[last].y * ((real) (ip[i].x-ip[last].x))/(ip[i].y-ip[last].y);
1866 0 : if ( ip[i].y>0 )
1867 0 : ip2[j++] = ip[i];
1868 : else {
1869 0 : ip2[j].y = 0;
1870 0 : ip2[j++].x = ip[i].x;
1871 : }
1872 : }
1873 : }
1874 : /* clip to top edge */
1875 0 : tot = j;
1876 0 : for ( i=j=0; i<tot; ++i ) {
1877 0 : last = i==0?tot-1:i-1;
1878 0 : if ( ip2[i].y<cv->height && ip2[last].y<cv->height ) {
1879 0 : ip[j++] = ip2[i];
1880 0 : } else if ( ip2[i].y>=cv->height && ip2[last].y>=cv->height ) {
1881 0 : ip[j].y = cv->height-1;
1882 0 : ip[j++].x = ip2[i].x;
1883 : } else {
1884 0 : ip[j].y = cv->height-1;
1885 0 : 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);
1886 0 : if ( ip2[i].y<cv->height )
1887 0 : ip[j++] = ip2[i];
1888 : else {
1889 0 : ip[j].y = cv->height-1;
1890 0 : ip[j++].x = ip2[i].x;
1891 : }
1892 : }
1893 : }
1894 :
1895 0 : tot=j;
1896 0 : clipped[0].x = ip[0].x; clipped[0].y = ip[0].y;
1897 0 : for ( i=j=1; i<tot; ++i ) {
1898 0 : if ( ip[i].x!=ip[i-1].x || ip[i].y!=ip[i-1].y ) {
1899 0 : clipped[j].x = ip[i].x; clipped[j++].y = ip[i].y;
1900 : }
1901 : }
1902 0 : clipped[j++] = clipped[0];
1903 0 : GDrawFillPoly(pixmap,clipped,j,dhintcol);
1904 : }
1905 :
1906 0 : static void CVShowDHint ( CharView *cv, GWindow pixmap, DStemInfo *dstem ) {
1907 : BasePoint bp[4];
1908 : HintInstance *hi;
1909 : double roff;
1910 :
1911 0 : roff = ( dstem->right.x - dstem->left.x ) * dstem->unit.x +
1912 0 : ( dstem->right.y - dstem->left.y ) * dstem->unit.y;
1913 :
1914 0 : for ( hi=dstem->where; hi!=NULL; hi=hi->next ) {
1915 0 : bp[0].x = dstem->left.x + dstem->unit.x * hi->begin;
1916 0 : bp[0].y = dstem->left.y + dstem->unit.y * hi->begin;
1917 0 : bp[1].x = dstem->right.x + dstem->unit.x * ( hi->begin - roff );
1918 0 : bp[1].y = dstem->right.y + dstem->unit.y * ( hi->begin - roff );
1919 0 : bp[2].x = dstem->right.x + dstem->unit.x * ( hi->end - roff );
1920 0 : bp[2].y = dstem->right.y + dstem->unit.y * ( hi->end - roff );
1921 0 : bp[3].x = dstem->left.x + dstem->unit.x * hi->end;
1922 0 : bp[3].y = dstem->left.y + dstem->unit.y * hi->end;
1923 0 : CVShowDHintInstance( cv, pixmap, bp );
1924 : }
1925 0 : }
1926 :
1927 0 : static void CVShowMinimumDistance(CharView *cv, GWindow pixmap,MinimumDistance *md) {
1928 : int x1,y1, x2,y2;
1929 : int xa, ya;
1930 0 : int off = cv->xoff+cv->height-cv->yoff;
1931 :
1932 0 : if (( md->x && !cv->showmdx ) || (!md->x && !cv->showmdy))
1933 0 : return;
1934 0 : if ( md->sp1==NULL && md->sp2==NULL )
1935 0 : return;
1936 0 : if ( md->sp1!=NULL ) {
1937 0 : x1 = cv->xoff + rint( md->sp1->me.x*cv->scale );
1938 0 : y1 = -cv->yoff + cv->height - rint(md->sp1->me.y*cv->scale);
1939 : } else {
1940 0 : x1 = cv->xoff + rint( cv->b.sc->width*cv->scale );
1941 0 : y1 = 0x80000000;
1942 : }
1943 0 : if ( md->sp2!=NULL ) {
1944 0 : x2 = cv->xoff + rint( md->sp2->me.x*cv->scale );
1945 0 : y2 = -cv->yoff + cv->height - rint(md->sp2->me.y*cv->scale);
1946 : } else {
1947 0 : x2 = cv->xoff + rint( cv->b.sc->width*cv->scale );
1948 0 : y2 = y1-8;
1949 : }
1950 0 : if ( y1==0x80000000 )
1951 0 : y1 = y2-8;
1952 0 : if ( md->x ) {
1953 0 : ya = (y1+y2)/2;
1954 0 : GDrawDrawArrow(pixmap, x1,ya, x2,ya, 2, mdhintcol);
1955 0 : GDrawSetDashedLine(pixmap,5,5,off);
1956 0 : GDrawDrawLine(pixmap, x1,ya, x1,y1, mdhintcol);
1957 0 : GDrawDrawLine(pixmap, x2,ya, x2,y2, mdhintcol);
1958 : } else {
1959 0 : xa = (x1+x2)/2;
1960 0 : GDrawDrawArrow(pixmap, xa,y1, xa,y2, 2, mdhintcol);
1961 0 : GDrawSetDashedLine(pixmap,5,5,off);
1962 0 : GDrawDrawLine(pixmap, xa,y1, x1,y1, mdhintcol);
1963 0 : GDrawDrawLine(pixmap, xa,y2, x2,y2, mdhintcol);
1964 : }
1965 0 : GDrawSetDashedLine(pixmap,0,0,0);
1966 : }
1967 :
1968 0 : static void dtos(char *buf,real val) {
1969 : char *pt;
1970 :
1971 0 : sprintf( buf,"%.1f", (double) val);
1972 0 : pt = buf+strlen(buf);
1973 0 : if ( pt[-1]=='0' && pt[-2]=='.' ) pt[-2] = '\0';
1974 0 : }
1975 :
1976 0 : static void CVDrawBlues(CharView *cv,GWindow pixmap,char *bluevals,char *others,
1977 : Color col) {
1978 : double blues[24];
1979 : char *pt, *end;
1980 0 : int i=0, bcnt=0;
1981 : GRect r;
1982 : char buf[20];
1983 : int len,len2;
1984 :
1985 0 : if ( bluevals!=NULL ) {
1986 0 : for ( pt = bluevals; isspace( *pt ) || *pt=='['; ++pt);
1987 0 : while ( i<14 && *pt!='\0' && *pt!=']' ) {
1988 0 : blues[i] = c_strtod(pt,&end);
1989 0 : if ( pt==end )
1990 0 : break;
1991 0 : ++i;
1992 0 : pt = end;
1993 0 : while ( isspace( *pt )) ++pt;
1994 : }
1995 0 : if ( i&1 ) --i;
1996 : }
1997 0 : if ( others!=NULL ) {
1998 0 : for ( pt = others; isspace( *pt ) || *pt=='['; ++pt);
1999 0 : while ( i<24 && *pt!='\0' && *pt!=']' ) {
2000 0 : blues[i] = c_strtod(pt,&end);
2001 0 : if ( pt==end )
2002 0 : break;
2003 0 : ++i;
2004 0 : pt = end;
2005 0 : while ( isspace( *pt )) ++pt;
2006 : }
2007 0 : if ( i&1 ) --i;
2008 : }
2009 0 : bcnt = i;
2010 0 : if ( i==0 )
2011 0 : return;
2012 :
2013 0 : r.x = 0; r.width = cv->width;
2014 0 : for ( i=0; i<bcnt; i += 2 ) {
2015 : int first, other;
2016 0 : first = -cv->yoff + cv->height - rint(blues[i]*cv->scale);
2017 0 : other = -cv->yoff + cv->height - rint(blues[i+1]*cv->scale);
2018 0 : r.y = first;
2019 0 : if ( ( r.y<0 && other<0 ) || (r.y>cv->height && other>cv->height))
2020 0 : continue;
2021 0 : if ( r.y<0 ) r.y = 0;
2022 0 : else if ( r.y>cv->height ) r.y = cv->height;
2023 0 : if ( other<0 ) other = 0;
2024 0 : else if ( other>cv->height ) other = cv->height;
2025 0 : if ( other<r.y ) {
2026 0 : r.height = r.y-other;
2027 0 : r.y = other;
2028 : } else
2029 0 : r.height = other-r.y;
2030 0 : if ( r.height==0 ) r.height = 1; /* show something */
2031 0 : GDrawSetStippled(pixmap,2, 0,0);
2032 0 : GDrawFillRect(pixmap,&r,col);
2033 0 : GDrawSetStippled(pixmap,0, 0,0);
2034 :
2035 0 : if ( first>-20 && first<cv->height+20 ) {
2036 0 : dtos( buf, blues[i]);
2037 0 : len = GDrawGetText8Width(pixmap,buf,-1);
2038 0 : GDrawDrawText8(pixmap,cv->width-len-5,first-3,buf,-1,hintlabelcol);
2039 : } else
2040 0 : len = 0;
2041 0 : if ( other>-20 && other<cv->height+20 ) {
2042 0 : dtos( buf, blues[i+1]-blues[i]);
2043 0 : len2 = GDrawGetText8Width(pixmap,buf,-1);
2044 0 : GDrawDrawText8(pixmap,cv->width-len-5-len2-5,other+cv->sas-3,buf,-1,hintlabelcol);
2045 : }
2046 : }
2047 : }
2048 :
2049 0 : static void CVShowHints(CharView *cv, GWindow pixmap) {
2050 : StemInfo *hint;
2051 : GRect r;
2052 : HintInstance *hi;
2053 : int end;
2054 : Color col;
2055 : DStemInfo *dstem;
2056 : MinimumDistance *md;
2057 : char *blues, *others;
2058 0 : struct psdict *private = cv->b.sc->parent->private;
2059 : char buf[20];
2060 : int len, len2;
2061 : SplinePoint *sp;
2062 : SplineSet *spl;
2063 :
2064 0 : GDrawSetFont(pixmap,cv->small);
2065 0 : blues = PSDictHasEntry(private,"BlueValues"); others = PSDictHasEntry(private,"OtherBlues");
2066 0 : if ( cv->showblues && (blues!=NULL || others!=NULL))
2067 0 : CVDrawBlues(cv,pixmap,blues,others,bluevalstipplecol);
2068 0 : blues = PSDictHasEntry(private,"FamilyBlues"); others = PSDictHasEntry(private,"FamilyOtherBlues");
2069 0 : if ( cv->showfamilyblues && (blues!=NULL || others!=NULL))
2070 0 : CVDrawBlues(cv,pixmap,blues,others,fambluestipplecol);
2071 :
2072 0 : if ( cv->showdhints ) for ( dstem = cv->b.sc->dstem; dstem!=NULL; dstem = dstem->next ) {
2073 0 : CVShowDHint(cv,pixmap,dstem);
2074 : }
2075 :
2076 0 : if ( cv->showhhints && cv->b.sc->hstem!=NULL ) {
2077 0 : GDrawSetDashedLine(pixmap,5,5,cv->xoff);
2078 0 : for ( hint = cv->b.sc->hstem; hint!=NULL; hint = hint->next ) {
2079 0 : if ( hint->width<0 ) {
2080 0 : r.y = -cv->yoff + cv->height - rint(hint->start*cv->scale);
2081 0 : r.height = rint(-hint->width*cv->scale)+1;
2082 : } else {
2083 0 : r.y = -cv->yoff + cv->height - rint((hint->start+hint->width)*cv->scale);
2084 0 : r.height = rint(hint->width*cv->scale)+1;
2085 : }
2086 0 : col = hint->active ? hhintactivecol : hhintcol;
2087 : /* XRectangles are shorts! */
2088 0 : if ( r.y<32767 && r.y+r.height>-32768 ) {
2089 0 : if ( r.y<-32768 ) {
2090 0 : r.height -= (-32768-r.y);
2091 0 : r.y = -32768;
2092 : }
2093 0 : if ( r.y+r.height>32767 )
2094 0 : r.height = 32767-r.y;
2095 0 : for ( hi=hint->where; hi!=NULL; hi=hi->next ) {
2096 0 : r.x = cv->xoff + rint(hi->begin*cv->scale);
2097 0 : end = cv->xoff + rint(hi->end*cv->scale);
2098 0 : if ( end>=0 && r.x<=cv->width ) {
2099 0 : r.width = end-r.x+1;
2100 0 : GDrawFillRect(pixmap,&r,col);
2101 : }
2102 : }
2103 : }
2104 0 : col = (!hint->active && hint->hasconflicts) ? conflicthintcol : col;
2105 0 : if ( r.y>=0 && r.y<=cv->height )
2106 0 : GDrawDrawLine(pixmap,0,r.y,cv->width,r.y,col);
2107 0 : if ( r.y+r.height>=0 && r.y+r.height<=cv->width )
2108 0 : GDrawDrawLine(pixmap,0,r.y+r.height-1,cv->width,r.y+r.height-1,col);
2109 :
2110 0 : r.y = -cv->yoff + cv->height - rint(hint->start*cv->scale);
2111 0 : r.y += ( hint->width>0 ) ? -3 : cv->sas+3;
2112 0 : if ( r.y>-20 && r.y<cv->height+20 ) {
2113 0 : dtos( buf, hint->start);
2114 0 : len = GDrawGetText8Width(pixmap,buf,-1);
2115 0 : GDrawDrawText8(pixmap,cv->width-len-5,r.y,buf,-1,hintlabelcol);
2116 : } else
2117 0 : len = 0;
2118 0 : r.y = -cv->yoff + cv->height - rint((hint->start+hint->width)*cv->scale);
2119 0 : r.y += ( hint->width>0 ) ? cv->sas+3 : -3;
2120 0 : if ( r.y>-20 && r.y<cv->height+20 ) {
2121 0 : if ( hint->ghost ) {
2122 0 : buf[0] = 'G';
2123 0 : buf[1] = ' ';
2124 0 : dtos(buf+2, hint->width);
2125 : } else
2126 0 : dtos( buf, hint->width);
2127 0 : len2 = GDrawGetText8Width(pixmap,buf,-1);
2128 0 : GDrawDrawText8(pixmap,cv->width-len-5-len2-5,r.y,buf,-1,hintlabelcol);
2129 : }
2130 : }
2131 : }
2132 0 : if ( cv->showvhints && cv->b.sc->vstem!=NULL ) {
2133 0 : GDrawSetDashedLine(pixmap,5,5,cv->height-cv->yoff);
2134 0 : for ( hint = cv->b.sc->vstem; hint!=NULL; hint = hint->next ) {
2135 0 : if ( hint->width<0 ) {
2136 0 : r.x = cv->xoff + rint( (hint->start+hint->width)*cv->scale );
2137 0 : r.width = rint(-hint->width*cv->scale)+1;
2138 : } else {
2139 0 : r.x = cv->xoff + rint(hint->start*cv->scale);
2140 0 : r.width = rint(hint->width*cv->scale)+1;
2141 : }
2142 0 : col = hint->active ? vhintactivecol : vhintcol;
2143 0 : if ( r.x<32767 && r.x+r.width>-32768 ) {
2144 0 : if ( r.x<-32768 ) {
2145 0 : r.width -= (-32768-r.x);
2146 0 : r.x = -32768;
2147 : }
2148 0 : if ( r.x+r.width>32767 )
2149 0 : r.width = 32767-r.x;
2150 0 : for ( hi=hint->where; hi!=NULL; hi=hi->next ) {
2151 0 : r.y = -cv->yoff + cv->height - rint(hi->end*cv->scale);
2152 0 : end = -cv->yoff + cv->height - rint(hi->begin*cv->scale);
2153 0 : if ( end>=0 && r.y<=cv->height ) {
2154 0 : r.height = end-r.y+1;
2155 0 : GDrawFillRect(pixmap,&r,col);
2156 : }
2157 : }
2158 : }
2159 0 : col = (!hint->active && hint->hasconflicts) ? conflicthintcol : col;
2160 0 : if ( r.x>=0 && r.x<=cv->width )
2161 0 : GDrawDrawLine(pixmap,r.x,0,r.x,cv->height,col);
2162 0 : if ( r.x+r.width>=0 && r.x+r.width<=cv->width )
2163 0 : GDrawDrawLine(pixmap,r.x+r.width-1,0,r.x+r.width-1,cv->height,col);
2164 :
2165 0 : r.x = cv->xoff + rint(hint->start*cv->scale);
2166 0 : if ( r.x>-60 && r.x<cv->width+20 ) {
2167 0 : dtos( buf, hint->start);
2168 0 : len = GDrawGetText8Width(pixmap,buf,-1);
2169 0 : r.x += ( hint->width>0 ) ? 3 : -len-3;
2170 0 : GDrawDrawText8(pixmap,r.x,cv->sas+3,buf,-1,hintlabelcol);
2171 : }
2172 0 : r.x = cv->xoff + rint((hint->start+hint->width)*cv->scale);
2173 0 : if ( r.x>-60 && r.x<cv->width+20 ) {
2174 0 : if ( hint->ghost ) {
2175 0 : buf[0] = 'G';
2176 0 : buf[1] = ' ';
2177 0 : dtos(buf+2, hint->width);
2178 : } else
2179 0 : dtos( buf, hint->width);
2180 0 : len = GDrawGetText8Width(pixmap,buf,-1);
2181 0 : r.x += ( hint->width>0 ) ? -len-3 : 3;
2182 0 : GDrawDrawText8(pixmap,r.x,cv->sas+cv->sfh+3,buf,-1,hintlabelcol);
2183 : }
2184 : }
2185 : }
2186 0 : GDrawSetDashedLine(pixmap,0,0,0);
2187 :
2188 0 : for ( md=cv->b.sc->md; md!=NULL; md=md->next )
2189 0 : CVShowMinimumDistance(cv, pixmap,md);
2190 :
2191 0 : if ( cv->showvhints || cv->showhhints ) {
2192 0 : for ( spl=cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL; spl=spl->next ) {
2193 0 : if ( spl->first->prev!=NULL ) for ( sp=spl->first ; ; ) {
2194 0 : if ( cv->showhhints && sp->flexx ) {
2195 : double x,y,end;
2196 0 : x = cv->xoff + rint(sp->me.x*cv->scale);
2197 0 : y = -cv->yoff + cv->height - rint(sp->me.y*cv->scale);
2198 0 : end = cv->xoff + rint(sp->next->to->me.x*cv->scale);
2199 0 : if ( x>-4096 && x<32767 && y>-4096 && y<32767 ) {
2200 0 : GDrawDrawLine(pixmap,x,y,end,y,hflexhintcol);
2201 : }
2202 : }
2203 0 : if ( cv->showvhints && sp->flexy ) {
2204 : double x,y,end;
2205 0 : x = cv->xoff + rint(sp->me.x*cv->scale);
2206 0 : y = -cv->yoff + cv->height - rint(sp->me.y*cv->scale);
2207 0 : end = -cv->yoff + cv->height - rint(sp->next->to->me.y*cv->scale);
2208 0 : if ( x>-4096 && x<32767 && y>-4096 && y<32767 ) {
2209 0 : GDrawDrawLine(pixmap,x,y,x,end,vflexhintcol);
2210 : }
2211 : }
2212 0 : if ( sp->next==NULL ) /* This can happen if we get an internal error inside of RemoveOverlap when the pointlist is not in good shape */
2213 0 : break;
2214 0 : sp = sp->next->to;
2215 0 : if ( sp==spl->first )
2216 0 : break;
2217 0 : }
2218 : }
2219 : }
2220 0 : }
2221 :
2222 0 : static void CVDrawRefName(CharView *cv,GWindow pixmap,RefChar *ref,int fg) {
2223 : int x,y, len;
2224 : GRect size;
2225 :
2226 0 : x = cv->xoff + rint(ref->top.x*cv->scale);
2227 0 : y = -cv->yoff + cv->height - rint(ref->top.y*cv->scale);
2228 0 : y -= 5;
2229 0 : if ( x<-400 || y<-40 || x>cv->width+400 || y>cv->height )
2230 0 : return;
2231 :
2232 0 : GDrawLayoutInit(pixmap,ref->sc->name,-1,cv->small);
2233 0 : GDrawLayoutExtents(pixmap,&size);
2234 0 : GDrawLayoutDraw(pixmap,x-size.width/2,y,fg);
2235 0 : len = size.width;
2236 0 : if ( ref->use_my_metrics )
2237 0 : GDrawDrawImage(pixmap,&GIcon_lock,NULL,x+len+3,y-cv->sas);
2238 : }
2239 :
2240 0 : void DrawAnchorPoint(GWindow pixmap,int x, int y,int selected) {
2241 : GPoint gp[9];
2242 0 : Color col = anchorcol;
2243 :
2244 0 : gp[0].x = x-1; gp[0].y = y-1;
2245 0 : gp[1].x = x; gp[1].y = y-6;
2246 0 : gp[2].x = x+1; gp[2].y = y-1;
2247 0 : gp[3].x = x+6; gp[3].y = y;
2248 0 : gp[4].x = x+1; gp[4].y = y+1;
2249 0 : gp[5].x = x; gp[5].y = y+6;
2250 0 : gp[6].x = x-1; gp[6].y = y+1;
2251 0 : gp[7].x = x-6; gp[7].y = y;
2252 0 : gp[8] = gp[0];
2253 0 : if ( selected )
2254 0 : GDrawDrawPoly(pixmap,gp,9,col);
2255 : else
2256 0 : GDrawFillPoly(pixmap,gp,9,col);
2257 0 : }
2258 :
2259 0 : static void CVDrawAnchorPoints(CharView *cv,GWindow pixmap) {
2260 : int x,y, len, sel;
2261 0 : Color col = anchorcol;
2262 : AnchorPoint *ap;
2263 : char *name, ubuf[50];
2264 : GRect r;
2265 :
2266 0 : if ( cv->b.drawmode!=dm_fore || cv->b.sc->anchor==NULL || !cv->showanchor )
2267 0 : return;
2268 0 : GDrawSetFont(pixmap,cv->normal);
2269 :
2270 0 : for ( sel=0; sel<2; ++sel ) {
2271 0 : for ( ap = cv->b.sc->anchor; ap!=NULL; ap=ap->next ) if ( ap->selected==sel ) {
2272 0 : x = cv->xoff + rint(ap->me.x*cv->scale);
2273 0 : y = -cv->yoff + cv->height - rint(ap->me.y*cv->scale);
2274 0 : if ( x<-400 || y<-40 || x>cv->width+400 || y>cv->height )
2275 0 : continue;
2276 :
2277 0 : DrawAnchorPoint(pixmap,x,y,ap->selected);
2278 0 : ubuf[30]=0;
2279 0 : if ( ap->anchor->type==act_mkmk ) {
2280 0 : cc_strncpy(ubuf,ap->anchor->name,30);
2281 0 : strcat(ubuf," ");
2282 0 : strcat(ubuf,ap->type==at_basemark ? _("Base") : _("Mark") );
2283 0 : name = ubuf;
2284 0 : } else if ( ap->type==at_basechar || ap->type==at_mark || ap->type==at_basemark ) {
2285 0 : name = ap->anchor->name;
2286 0 : } else if ( ap->type==at_centry || ap->type==at_cexit ) {
2287 0 : cc_strncpy(ubuf,ap->anchor->name,30);
2288 0 : strcat(ubuf,ap->type==at_centry ? _("Entry") : _("Exit") );
2289 0 : name = ubuf;
2290 0 : } else if ( ap->type==at_baselig ) {
2291 0 : cc_strncpy(ubuf,ap->anchor->name,30);
2292 0 : sprintf(ubuf+strlen(ubuf),"#%d", ap->lig_index);
2293 0 : name = ubuf;
2294 : } else
2295 0 : name = NULL; /* Should never happen */
2296 :
2297 : GRect size;
2298 0 : GDrawLayoutInit(pixmap,name,-1,NULL);
2299 0 : GDrawLayoutExtents(pixmap,&size);
2300 0 : len = size.width;
2301 :
2302 0 : r.x = x-len/2; r.width = len;
2303 0 : r.y = y+7; r.height = cv->nfh;
2304 0 : GDrawFillRect(pixmap,&r,view_bgcol );
2305 0 : GDrawLayoutDraw(pixmap,x-len/2,y+7+cv->nas,col);
2306 : }
2307 : }
2308 : }
2309 :
2310 0 : static void DrawImageList(CharView *cv,GWindow pixmap,ImageList *backimages) {
2311 : GRect size, temp;
2312 : int x,y;
2313 :
2314 0 : GDrawGetSize(pixmap,&size);
2315 :
2316 0 : while ( backimages!=NULL ) {
2317 0 : struct _GImage *base = backimages->image->list_len==0?
2318 0 : backimages->image->u.image:backimages->image->u.images[0];
2319 :
2320 0 : temp = size;
2321 0 : x = (int) (cv->xoff + rint(backimages->xoff * cv->scale));
2322 0 : y = (int) (-cv->yoff + cv->height - rint(backimages->yoff*cv->scale));
2323 0 : temp.x -= x; temp.y -= y;
2324 0 : temp.width += x; temp.height += y;
2325 :
2326 0 : GDrawDrawImageMagnified(pixmap, backimages->image, &temp,
2327 : x,y,
2328 0 : (int) rint((base->width*backimages->xscale*cv->scale)),
2329 0 : (int) rint((base->height*backimages->yscale*cv->scale)));
2330 0 : backimages = backimages->next;
2331 : }
2332 0 : }
2333 :
2334 0 : static void DrawSelImageList(CharView *cv,GWindow pixmap,ImageList *images) {
2335 0 : while ( images!=NULL ) {
2336 0 : if ( images->selected )
2337 0 : CVDrawBB(cv,pixmap,&images->bb);
2338 0 : images = images->next;
2339 : }
2340 0 : }
2341 :
2342 0 : static void DrawOldState(CharView *cv, GWindow pixmap, Undoes *undo, DRect *clip) {
2343 : RefChar *refs;
2344 :
2345 0 : if ( undo==NULL )
2346 0 : return;
2347 :
2348 0 : CVDrawSplineSet(cv,pixmap,undo->u.state.splines,oldoutlinecol,false,clip);
2349 0 : for ( refs=undo->u.state.refs; refs!=NULL; refs=refs->next )
2350 0 : if ( refs->layers[0].splines!=NULL )
2351 0 : CVDrawSplineSet(cv,pixmap,refs->layers[0].splines,oldoutlinecol,false,clip);
2352 : /* Don't do images... */
2353 : }
2354 :
2355 0 : static void DrawTransOrigin(CharView *cv, GWindow pixmap) {
2356 0 : int x = rint(cv->p.cx*cv->scale) + cv->xoff, y = cv->height-cv->yoff-rint(cv->p.cy*cv->scale);
2357 :
2358 0 : GDrawDrawLine(pixmap,x-4,y,x+4,y,transformorigincol);
2359 0 : GDrawDrawLine(pixmap,x,y-4,x,y+4,transformorigincol);
2360 0 : }
2361 :
2362 0 : static void DrawVLine(CharView *cv,GWindow pixmap,real pos,Color fg, int flags,
2363 : GImage *lock, char *name) {
2364 : char buf[20];
2365 0 : int x = cv->xoff + rint(pos*cv->scale);
2366 0 : DrawLine(cv,pixmap,pos,-32768,pos,32767,fg);
2367 0 : if ( x>-400 && x<cv->width+400 ) {
2368 0 : if ( flags&1 ) {
2369 0 : dtos( buf, pos);
2370 0 : GDrawSetFont(pixmap,cv->small);
2371 0 : GDrawDrawText8(pixmap,x+5,cv->sas+3,buf,-1,metricslabelcol);
2372 0 : if ( lock!=NULL )
2373 0 : GDrawDrawImage(pixmap,lock,NULL,x+5,3+cv->sfh);
2374 : }
2375 0 : if ( name!=NULL )
2376 0 : GDrawDrawText8(pixmap,x+5,cv->sas+cv->sfh*(1+lock!=NULL)+3,name,-1,metricslabelcol);
2377 : }
2378 0 : if ( ItalicConstrained && cv->b.sc->parent->italicangle!=0 ) {
2379 0 : double t = tan(-cv->b.sc->parent->italicangle*3.1415926535897932/180.);
2380 0 : int xoff = rint(8096*t);
2381 0 : DrawLine(cv,pixmap,pos-xoff,-8096,pos+xoff,8096,italiccoordcol);
2382 : }
2383 0 : }
2384 :
2385 0 : static void DrawMMGhosts(CharView *cv,GWindow pixmap,DRect *clip) {
2386 : /* In an MM font, draw any selected alternate versions of the current char */
2387 0 : MMSet *mm = cv->b.sc->parent->mm;
2388 : int j;
2389 : SplineFont *sub;
2390 : SplineChar *sc;
2391 : RefChar *rf;
2392 :
2393 0 : if ( mm==NULL )
2394 0 : return;
2395 0 : for ( j = 0; j<mm->instance_count+1; ++j ) {
2396 0 : if ( j==0 )
2397 0 : sub = mm->normal;
2398 : else
2399 0 : sub = mm->instances[j-1];
2400 0 : sc = NULL;
2401 0 : if ( cv->b.sc->parent!=sub && (cv->mmvisible & (1<<j)) &&
2402 0 : cv->b.sc->orig_pos<sub->glyphcnt )
2403 0 : sc = sub->glyphs[cv->b.sc->orig_pos];
2404 0 : if ( sc!=NULL ) {
2405 0 : for ( rf=sc->layers[ly_fore].refs; rf!=NULL; rf = rf->next )
2406 0 : CVDrawSplineSet(cv,pixmap,rf->layers[0].splines,backoutlinecol,false,clip);
2407 0 : CVDrawSplineSet(cv,pixmap,sc->layers[ly_fore].splines,backoutlinecol,false,clip);
2408 : }
2409 : }
2410 : }
2411 :
2412 0 : static void CVDrawGridRaster(CharView *cv, GWindow pixmap, DRect *clip ) {
2413 0 : if ( cv->showgrids ) {
2414 : /* Draw ppem grid, and the raster for truetype debugging, grid fit */
2415 : GRect pixel;
2416 0 : real ygrid_spacing = (cv->b.sc->parent->ascent+cv->b.sc->parent->descent) / (real) cv->ft_ppemy;
2417 0 : real xgrid_spacing = (cv->b.sc->parent->ascent+cv->b.sc->parent->descent) / (real) cv->ft_ppemx;
2418 : int max,jmax,ii,i,jj,j;
2419 0 : int minx, maxx, miny, maxy, r,or=0;
2420 : Color clut[256];
2421 :
2422 0 : pixel.width = xgrid_spacing*cv->scale+1;
2423 0 : pixel.height = ygrid_spacing*cv->scale+1;
2424 0 : if ( cv->raster!=NULL ) {
2425 0 : if ( cv->raster->num_greys>2 ) {
2426 : int rb, gb, bb, rd, gd, bd;
2427 0 : clut[0] = view_bgcol ;
2428 0 : rb = COLOR_RED(clut[0]); gb = COLOR_GREEN(clut[0]); bb = COLOR_BLUE(clut[0]);
2429 0 : rd = COLOR_RED(rasterdarkcol)-rb;
2430 0 : gd = COLOR_GREEN(rasterdarkcol)-gb;
2431 0 : bd = COLOR_BLUE(rasterdarkcol)-bb;
2432 0 : for ( i=1; i<256; ++i ) {
2433 0 : clut[i] = ( (rb +rd*(i)/0xff)<<16 ) |
2434 0 : ( (gb+gd*(i)/0xff)<<8 ) |
2435 0 : ( (bb+bd*(i)/0xff) );
2436 : }
2437 : }
2438 0 : minx = cv->raster->lb; maxx = minx+cv->raster->cols;
2439 0 : maxy = cv->raster->as; miny = maxy-cv->raster->rows;
2440 0 : if ( cv->oldraster!=NULL ) {
2441 0 : if ( cv->oldraster->lb<minx ) minx = cv->oldraster->lb;
2442 0 : if ( cv->oldraster->lb+cv->oldraster->cols>maxx ) maxx = cv->oldraster->lb+cv->oldraster->cols;
2443 0 : if ( cv->oldraster->as>maxy ) maxy = cv->oldraster->as;
2444 0 : if ( cv->oldraster->as-cv->oldraster->rows<miny ) miny = cv->oldraster->as-cv->oldraster->rows;
2445 : }
2446 0 : for ( ii=maxy; ii>miny; --ii ) {
2447 0 : for ( jj=minx; jj<maxx; ++jj ) {
2448 0 : i = cv->raster->as-ii; j = jj-cv->raster->lb;
2449 0 : if ( i<0 || i>=cv->raster->rows || j<0 || j>=cv->raster->cols )
2450 0 : r = 0;
2451 0 : else if ( cv->raster->num_greys<=2 )
2452 0 : r = cv->raster->bitmap[i*cv->raster->bytes_per_row+(j>>3)] & (1<<(7-(j&7)));
2453 : else
2454 0 : r = cv->raster->bitmap[i*cv->raster->bytes_per_row+j];
2455 0 : if ( cv->oldraster==NULL || cv->oldraster->num_greys!=cv->raster->num_greys)
2456 0 : or = r;
2457 : else {
2458 0 : i = cv->oldraster->as-ii; j = jj-cv->oldraster->lb;
2459 0 : if ( i<0 || i>=cv->oldraster->rows || j<0 || j>=cv->oldraster->cols )
2460 0 : or = 0;
2461 0 : else if ( cv->oldraster->num_greys<=2 )
2462 0 : or = cv->oldraster->bitmap[i*cv->oldraster->bytes_per_row+(j>>3)] & (1<<(7-(j&7)));
2463 : else
2464 0 : or = cv->oldraster->bitmap[i*cv->oldraster->bytes_per_row+j];
2465 : }
2466 0 : if ( r || ( or && cv->showdebugchanges)) {
2467 0 : pixel.x = jj*xgrid_spacing*cv->scale + cv->xoff+1;
2468 0 : pixel.y = cv->height-cv->yoff - rint(ii*ygrid_spacing*cv->scale);
2469 0 : if ( cv->showdebugchanges ) {
2470 0 : if ( cv->raster->num_greys<=2 )
2471 0 : GDrawFillRect(pixmap,&pixel,(r && or) ? rastercol : r ? rasternewcol : rasteroldcol );
2472 : else
2473 0 : GDrawFillRect(pixmap,&pixel,(r-or>-16 && r-or<16) ? clut[r] : (clut[r]&0x00ff00) );
2474 : } else {
2475 0 : if ( cv->raster->num_greys<=2 )
2476 0 : GDrawFillRect(pixmap,&pixel, rastercol );
2477 : else
2478 0 : GDrawFillRect(pixmap,&pixel, clut[r] );
2479 : }
2480 : }
2481 : }
2482 : }
2483 : }
2484 :
2485 0 : for ( i = floor( clip->x/xgrid_spacing ), max = ceil((clip->x+clip->width)/xgrid_spacing);
2486 0 : i<=max; ++i )
2487 0 : DrawLine(cv,pixmap,i*xgrid_spacing,-32768,i*xgrid_spacing,32767,i==0?coordcol:rastergridcol);
2488 0 : for ( i = floor( clip->y/ygrid_spacing ), max = ceil((clip->y+clip->height)/ygrid_spacing);
2489 0 : i<=max; ++i )
2490 0 : DrawLine(cv,pixmap,-32768,i*ygrid_spacing,32767,i*ygrid_spacing,i==0?coordcol:rastergridcol);
2491 0 : if ( xgrid_spacing*cv->scale>=7 && ygrid_spacing*cv->scale>=7) {
2492 0 : for ( i = floor( clip->x/xgrid_spacing ), max = ceil((clip->x+clip->width)/xgrid_spacing);
2493 0 : i<=max; ++i )
2494 0 : for ( j = floor( clip->y/ygrid_spacing ), jmax = ceil((clip->y+clip->height)/ygrid_spacing);
2495 0 : j<=jmax; ++j ) {
2496 0 : int x = (i+.5)*xgrid_spacing*cv->scale + cv->xoff;
2497 0 : int y = cv->height-cv->yoff - rint((j+.5)*ygrid_spacing*cv->scale);
2498 0 : GDrawDrawLine(pixmap,x-2,y,x+2,y,rastergridcol);
2499 0 : GDrawDrawLine(pixmap,x,y-2,x,y+2,rastergridcol);
2500 : }
2501 : }
2502 0 : if ( cv->qg!=NULL ) {
2503 0 : pixel.x = cv->note_x*xgrid_spacing*cv->scale + cv->xoff;
2504 0 : pixel.y = cv->height-cv->yoff - rint(cv->note_y*ygrid_spacing*cv->scale)
2505 0 : - pixel.height;
2506 0 : if ( pixel.height>=20 )
2507 0 : GDrawSetLineWidth(pixmap,3);
2508 0 : else if ( pixel.height>10 )
2509 0 : GDrawSetLineWidth(pixmap,2);
2510 0 : GDrawDrawRect(pixmap,&pixel,deltagridcol);
2511 0 : GDrawSetLineWidth(pixmap,0);
2512 : {
2513 0 : int x = (cv->note_x+.5)*xgrid_spacing*cv->scale + cv->xoff;
2514 0 : int y = cv->height-cv->yoff - rint((cv->note_y+.5)*ygrid_spacing*cv->scale);
2515 0 : GDrawDrawLine(pixmap,x-2,y,x+2,y,deltagridcol);
2516 0 : GDrawDrawLine(pixmap,x,y-2,x,y+2,deltagridcol);
2517 : }
2518 : }
2519 : }
2520 0 : if ( cv->showback[0]&1 ) {
2521 0 : CVDrawSplineSet(cv,pixmap,cv->b.gridfit,gridfitoutlinecol,
2522 0 : cv->showpoints,clip);
2523 : }
2524 0 : }
2525 :
2526 0 : static int APinSC(AnchorPoint *ap,SplineChar *sc) {
2527 : /* Anchor points can be deleted ... */
2528 : AnchorPoint *test;
2529 :
2530 0 : for ( test=sc->anchor; test!=NULL && test!=ap; test = test->next );
2531 0 : return( test==ap );
2532 : }
2533 :
2534 0 : static void DrawAPMatch(CharView *cv,GWindow pixmap,DRect *clip) {
2535 0 : SplineChar *sc = cv->b.sc, *apsc = cv->apsc;
2536 0 : SplineFont *sf = sc->parent;
2537 : real trans[6];
2538 : SplineSet *head, *tail, *temp;
2539 : RefChar *ref;
2540 0 : int layer = CVLayer((CharViewBase *) cv);
2541 :
2542 0 : if ( cv->b.drawmode==dm_grid )
2543 0 : return;
2544 :
2545 : /* The other glyph might have been removed from the font */
2546 : /* Either anchor might have been deleted. Be prepared for that to happen */
2547 0 : if ( (apsc->orig_pos>=sf->glyphcnt || apsc->orig_pos<0) ||
2548 0 : sf->glyphs[apsc->orig_pos]!=apsc ||
2549 0 : !APinSC(cv->apmine,sc) || !APinSC(cv->apmatch,apsc)) {
2550 0 : cv->apmine = cv->apmatch = NULL;
2551 0 : cv->apsc =NULL;
2552 0 : return;
2553 : }
2554 :
2555 : /* Ok this isn't very accurate, but we are going to use the current glyph's*/
2556 : /* coordinate system (because we're showing the current glyph), we should */
2557 : /* always use the base character's coordinates, but that would screw up */
2558 : /* editing of the current glyph if it happened to be the mark */
2559 0 : trans[0] = trans[3] = 1;
2560 0 : trans[1] = trans[2] = 0;
2561 0 : trans[4] = cv->apmine->me.x - cv->apmatch->me.x;
2562 0 : trans[5] = cv->apmine->me.y - cv->apmatch->me.y;
2563 :
2564 0 : head = tail = SplinePointListCopy(apsc->layers[layer].splines);
2565 0 : for ( ref = apsc->layers[layer].refs; ref!=NULL; ref = ref->next ) {
2566 0 : temp = SplinePointListCopy(ref->layers[0].splines);
2567 0 : if ( head!=NULL ) {
2568 0 : for ( ; tail->next!=NULL; tail = tail->next );
2569 0 : tail->next = temp;
2570 : } else
2571 0 : head = tail = temp;
2572 : }
2573 0 : head = SplinePointListTransform(head,trans,tpt_AllPoints);
2574 0 : CVDrawSplineSet(cv,pixmap,head,anchoredoutlinecol,
2575 : false,clip);
2576 0 : SplinePointListsFree(head);
2577 0 : if ( cv->apmine->type==at_mark || cv->apmine->type==at_centry ) {
2578 0 : DrawVLine(cv,pixmap,trans[4],anchoredoutlinecol,false,NULL,NULL);
2579 0 : DrawLine(cv,pixmap,-8096,trans[5],8096,trans[5],anchoredoutlinecol);
2580 : }
2581 : }
2582 :
2583 0 : static void DrawPLine(CharView *cv,GWindow pixmap,int x1, int y1, int x2, int y2,Color col) {
2584 :
2585 0 : if ( x1==x2 || y1==y2 ) {
2586 0 : if ( x1<0 ) x1=0;
2587 0 : else if ( x1>cv->width ) x1 = cv->width;
2588 0 : if ( x2<0 ) x2=0;
2589 0 : else if ( x2>cv->width ) x2 = cv->width;
2590 0 : if ( y1<0 ) y1=0;
2591 0 : else if ( y1>cv->height ) y1 = cv->height;
2592 0 : if ( y2<0 ) y2=0;
2593 0 : else if ( y2>cv->height ) y2 = cv->height;
2594 0 : } else if ( y1<-1000 || y2<-1000 || x1<-1000 || x2<-1000 ||
2595 0 : y1>cv->height+1000 || y2>cv->height+1000 ||
2596 0 : x1>cv->width+1000 || x2>cv->width+1000 )
2597 0 : return;
2598 0 : GDrawDrawLine(pixmap,x1,y1,x2,y2,col);
2599 : }
2600 :
2601 0 : static void FindQuickBounds(SplineSet *ss,BasePoint **bounds) {
2602 : SplinePoint *sp;
2603 :
2604 0 : for ( ; ss!=NULL; ss=ss->next ) {
2605 0 : sp = ss->first;
2606 0 : if ( sp->next==NULL || sp->next->to==sp ) /* Ignore contours with one point. Often tt points for moving references or anchors */
2607 0 : continue;
2608 : for (;;) {
2609 0 : if ( bounds[0]==NULL )
2610 0 : bounds[0] = bounds[1] = bounds[2] = bounds[3] = &sp->me;
2611 : else {
2612 0 : if ( sp->me.x<bounds[0]->x ) bounds[0] = &sp->me;
2613 0 : if ( sp->me.x>bounds[1]->x ) bounds[1] = &sp->me;
2614 0 : if ( sp->me.y<bounds[2]->y ) bounds[2] = &sp->me;
2615 0 : if ( sp->me.y>bounds[3]->y ) bounds[3] = &sp->me;
2616 : }
2617 0 : if ( sp->next==NULL )
2618 0 : break;
2619 0 : sp = sp->next->to;
2620 0 : if ( sp==ss->first )
2621 0 : break;
2622 0 : }
2623 : }
2624 0 : }
2625 :
2626 0 : static void SSFindItalicBounds(SplineSet *ss,double t,SplinePoint **left, SplinePoint **right) {
2627 : SplinePoint *sp;
2628 :
2629 0 : if ( t==0 )
2630 0 : return;
2631 :
2632 0 : for ( ; ss!=NULL; ss=ss->next ) {
2633 0 : sp = ss->first;
2634 0 : if ( sp->next==NULL || sp->next->to==sp ) /* Ignore contours with one point. Often tt points for moving references or anchors */
2635 0 : continue;
2636 : for (;;) {
2637 0 : if ( *left==NULL )
2638 0 : *left = *right = sp;
2639 : else {
2640 0 : double xoff = sp->me.y*t;
2641 0 : if ( sp->me.x-xoff < (*left)->me.x - (*left)->me.y*t ) *left = sp;
2642 0 : if ( sp->me.x-xoff > (*right)->me.x - (*right)->me.y*t ) *right = sp;
2643 : }
2644 0 : if ( sp->next==NULL )
2645 0 : break;
2646 0 : sp = sp->next->to;
2647 0 : if ( sp==ss->first )
2648 0 : break;
2649 0 : }
2650 : }
2651 : }
2652 :
2653 0 : static void CVSideBearings(GWindow pixmap, CharView *cv) {
2654 0 : SplineChar *sc = cv->b.sc;
2655 : RefChar *ref;
2656 : BasePoint *bounds[4];
2657 : int layer,last, first,l;
2658 : int x,y, x2, y2;
2659 : char buf[20];
2660 :
2661 0 : memset(bounds,0,sizeof(bounds));
2662 0 : if ( sc->parent->multilayer ) {
2663 0 : last = sc->layer_cnt-1;
2664 0 : first = ly_fore;
2665 : } else {
2666 0 : first = last = CVLayer( (CharViewBase *) cv);
2667 0 : if ( first==ly_grid )
2668 0 : first = last = ly_fore;
2669 : }
2670 0 : for ( layer = first ; layer<=last; ++layer ) {
2671 0 : FindQuickBounds(sc->layers[layer].splines,bounds);
2672 0 : for ( ref=sc->layers[layer].refs; ref!=NULL; ref=ref->next )
2673 0 : for ( l=0; l<ref->layer_cnt; ++l )
2674 0 : FindQuickBounds(ref->layers[l].splines,bounds);
2675 : }
2676 :
2677 0 : if ( bounds[0]==NULL )
2678 0 : return; /* no points. no side bearings */
2679 :
2680 0 : GDrawSetFont(pixmap,cv->small);
2681 0 : if ( cv->showhmetrics ) {
2682 0 : if ( bounds[0]->x!=0 ) {
2683 0 : x = rint(bounds[0]->x*cv->scale) + cv->xoff;
2684 0 : y = cv->height-cv->yoff-rint(bounds[0]->y*cv->scale);
2685 0 : DrawPLine(cv,pixmap,cv->xoff,y,x,y,metricslabelcol);
2686 : /* arrow heads */
2687 0 : DrawPLine(cv,pixmap,cv->xoff,y,cv->xoff+4,y+4,metricslabelcol);
2688 0 : DrawPLine(cv,pixmap,cv->xoff,y,cv->xoff+4,y-4,metricslabelcol);
2689 0 : DrawPLine(cv,pixmap,x,y,x-4,y-4,metricslabelcol);
2690 0 : DrawPLine(cv,pixmap,x,y,x-4,y+4,metricslabelcol);
2691 0 : dtos( buf, bounds[0]->x);
2692 0 : x = cv->xoff + (x-cv->xoff-GDrawGetText8Width(pixmap,buf,-1))/2;
2693 0 : GDrawDrawText8(pixmap,x,y-4,buf,-1,metricslabelcol);
2694 : }
2695 :
2696 0 : if ( sc->width != bounds[1]->x ) {
2697 0 : x = rint(bounds[1]->x*cv->scale) + cv->xoff;
2698 0 : y = cv->height-cv->yoff-rint(bounds[1]->y*cv->scale);
2699 0 : x2 = rint(sc->width*cv->scale) + cv->xoff;
2700 0 : DrawPLine(cv,pixmap,x,y,x2,y,metricslabelcol);
2701 : /* arrow heads */
2702 0 : DrawPLine(cv,pixmap,x,y,x+4,y+4,metricslabelcol);
2703 0 : DrawPLine(cv,pixmap,x,y,x+4,y-4,metricslabelcol);
2704 0 : DrawPLine(cv,pixmap,x2,y,x2-4,y-4,metricslabelcol);
2705 0 : DrawPLine(cv,pixmap,x2,y,x2-4,y+4,metricslabelcol);
2706 0 : dtos( buf, sc->width-bounds[1]->x);
2707 0 : x = x + (x2-x-GDrawGetText8Width(pixmap,buf,-1))/2;
2708 0 : GDrawDrawText8(pixmap,x,y-4,buf,-1,metricslabelcol);
2709 : }
2710 0 : if ( ItalicConstrained && cv->b.sc->parent->italicangle!=0 ) {
2711 0 : double t = tan(-cv->b.sc->parent->italicangle*3.1415926535897932/180.);
2712 0 : if ( t!=0 ) {
2713 0 : SplinePoint *leftmost=NULL, *rightmost=NULL;
2714 0 : for ( layer=first; layer<=last; ++layer ) {
2715 0 : SSFindItalicBounds(sc->layers[layer].splines,t,&leftmost,&rightmost);
2716 0 : for ( ref=sc->layers[layer].refs; ref!=NULL; ref=ref->next )
2717 0 : for ( l=0; l<ref->layer_cnt; ++l )
2718 0 : SSFindItalicBounds(ref->layers[l].splines,t,&leftmost,&rightmost);
2719 : }
2720 0 : if ( leftmost!=NULL ) {
2721 0 : x = rint(leftmost->me.y*t*cv->scale) + cv->xoff;
2722 0 : x2 = rint(leftmost->me.x*cv->scale) + cv->xoff;
2723 0 : y = cv->height-cv->yoff-rint(leftmost->me.y*cv->scale);
2724 0 : DrawPLine(cv,pixmap,x,y,x2,y,italiccoordcol);
2725 : /* arrow heads */
2726 0 : DrawPLine(cv,pixmap,x,y,x+4,y+4,italiccoordcol);
2727 0 : DrawPLine(cv,pixmap,x,y,x+4,y-4,italiccoordcol);
2728 0 : DrawPLine(cv,pixmap,x2,y,x2-4,y-4,italiccoordcol);
2729 0 : DrawPLine(cv,pixmap,x2,y,x2-4,y+4,italiccoordcol);
2730 0 : dtos( buf, leftmost->me.x-leftmost->me.y*t);
2731 0 : x = x + (x2-x-GDrawGetText8Width(pixmap,buf,-1))/2;
2732 0 : GDrawDrawText8(pixmap,x,y+12,buf,-1,italiccoordcol);
2733 : }
2734 0 : if ( rightmost!=NULL ) {
2735 0 : x = rint(rightmost->me.x*cv->scale) + cv->xoff;
2736 0 : y = cv->height-cv->yoff-rint(rightmost->me.y*cv->scale);
2737 0 : x2 = rint((sc->width + rightmost->me.y*t)*cv->scale) + cv->xoff;
2738 0 : DrawPLine(cv,pixmap,x,y,x2,y,italiccoordcol);
2739 : /* arrow heads */
2740 0 : DrawPLine(cv,pixmap,x,y,x+4,y+4,italiccoordcol);
2741 0 : DrawPLine(cv,pixmap,x,y,x+4,y-4,italiccoordcol);
2742 0 : DrawPLine(cv,pixmap,x2,y,x2-4,y-4,italiccoordcol);
2743 0 : DrawPLine(cv,pixmap,x2,y,x2-4,y+4,italiccoordcol);
2744 0 : dtos( buf, sc->width+rightmost->me.y*t-rightmost->me.x);
2745 0 : x = x + (x2-x-GDrawGetText8Width(pixmap,buf,-1))/2;
2746 0 : GDrawDrawText8(pixmap,x,y+12,buf,-1,italiccoordcol);
2747 : }
2748 : }
2749 : }
2750 : }
2751 :
2752 0 : if ( cv->showvmetrics ) {
2753 0 : x = rint(bounds[2]->x*cv->scale) + cv->xoff;
2754 0 : y = cv->height-cv->yoff-rint(bounds[2]->y*cv->scale);
2755 0 : y2 = cv->height-cv->yoff-rint(-sc->parent->descent*cv->scale);
2756 0 : DrawPLine(cv,pixmap,x,y,x,y2,metricslabelcol);
2757 : /* arrow heads */
2758 0 : DrawPLine(cv,pixmap,x,y,x-4,y-4,metricslabelcol);
2759 0 : DrawPLine(cv,pixmap,x,y,x+4,y-4,metricslabelcol);
2760 0 : DrawPLine(cv,pixmap,x,y2,x+4,y2+4,metricslabelcol);
2761 0 : DrawPLine(cv,pixmap,x,y2,x-4,y2+4,metricslabelcol);
2762 0 : dtos( buf, bounds[2]->y-sc->parent->descent);
2763 0 : y = y + (y-y2-cv->sfh)/2;
2764 0 : GDrawDrawText8(pixmap,x+4,y,buf,-1,metricslabelcol);
2765 :
2766 0 : x = rint(bounds[3]->x*cv->scale) + cv->xoff;
2767 0 : y = cv->height-cv->yoff-rint(bounds[3]->y*cv->scale);
2768 0 : y2 = cv->height-cv->yoff-rint(sc->parent->ascent*cv->scale);
2769 0 : DrawPLine(cv,pixmap,x,y,x,y2,metricslabelcol);
2770 : /* arrow heads */
2771 0 : DrawPLine(cv,pixmap,x,y,x-4,y-4,metricslabelcol);
2772 0 : DrawPLine(cv,pixmap,x,y,x+4,y-4,metricslabelcol);
2773 0 : DrawPLine(cv,pixmap,x,y2,x+4,y2+4,metricslabelcol);
2774 0 : DrawPLine(cv,pixmap,x,y2,x-4,y2+4,metricslabelcol);
2775 0 : dtos( buf, sc->vwidth-bounds[3]->y);
2776 0 : x = x + (x2-x-GDrawGetText8Width(pixmap,buf,-1))/2;
2777 0 : GDrawDrawText8(pixmap,x,y-4,buf,-1,metricslabelcol);
2778 : }
2779 : }
2780 :
2781 0 : static int CVExposeGlyphFill(CharView *cv, GWindow pixmap, GEvent *event, DRect* clip ) {
2782 0 : int layer, cvlayer = CVLayer((CharViewBase *) cv);
2783 0 : int filled = 0;
2784 :
2785 0 : if( shouldShowFilledUsingCairo(cv) ) {
2786 0 : layer = cvlayer;
2787 0 : if ( layer>=0 ) {
2788 0 : CVDrawLayerSplineSet(cv,pixmap,&cv->b.sc->layers[layer],foreoutlinecol,
2789 0 : cv->showpoints, clip, sfm_fill );
2790 0 : filled = 1;
2791 : }
2792 : } else {
2793 0 : if (( cv->showfore || cv->b.drawmode==dm_fore ) && cv->showfilled &&
2794 0 : cv->filled!=NULL ) {
2795 0 : GDrawDrawImage(pixmap, &cv->gi, NULL,
2796 0 : cv->xoff + cv->filled->xmin,
2797 0 : -cv->yoff + cv->height-cv->filled->ymax);
2798 0 : filled = 1;
2799 : }
2800 : }
2801 0 : return(filled);
2802 : }
2803 :
2804 : struct CVExpose_PreTransformSPL_ud
2805 : {
2806 : int dopoints;
2807 : CharView *cv;
2808 : GWindow pixmap;
2809 : Color fg;
2810 : DRect* clip;
2811 : enum outlinesfm_flags strokeFillMode;
2812 : };
2813 :
2814 :
2815 0 : static void CVExpose_PreTransformSPL_fe( SplinePointList *spl, struct CVExpose_PreTransformSPL_ud* d )
2816 : {
2817 0 : CVDrawSplineSetSpecialized( d->cv, d->pixmap, spl,
2818 : d->fg, d->dopoints, d->clip, d->strokeFillMode,
2819 : DraggingComparisonAlphaChannelOverride );
2820 0 : }
2821 :
2822 0 : static void CVExposeReferences( CharView *cv, GWindow pixmap, SplineChar* sc, int layer, DRect* clip )
2823 : {
2824 0 : RefChar *rf = 0;
2825 0 : int rlayer = 0;
2826 :
2827 0 : for ( rf = sc->layers[layer].refs; rf!=NULL; rf = rf->next )
2828 : {
2829 0 : if ( cv->showrefnames )
2830 0 : CVDrawRefName(cv,pixmap,rf,0);
2831 0 : enum outlinesfm_flags refsfm = sfm_stroke;
2832 0 : if( shouldShowFilledUsingCairo(cv) ) {
2833 0 : refsfm = sfm_fill;
2834 : }
2835 :
2836 0 : for ( rlayer=0; rlayer<rf->layer_cnt; ++rlayer )
2837 0 : CVDrawSplineSetSpecialized(cv,pixmap,rf->layers[rlayer].splines,foreoutlinecol,-1,clip, refsfm, 0);
2838 0 : if ( rf->selected && cv->b.layerheads[cv->b.drawmode]==&sc->layers[layer])
2839 0 : CVDrawBB(cv,pixmap,&rf->bb);
2840 : }
2841 0 : }
2842 :
2843 :
2844 0 : static void CVExpose(CharView *cv, GWindow pixmap, GEvent *event ) {
2845 0 : SplineFont *sf = cv->b.sc->parent;
2846 : RefChar *rf;
2847 : GRect old;
2848 : DRect clip;
2849 : char buf[20];
2850 : PST *pst;
2851 0 : int i, layer, rlayer, cvlayer = CVLayer((CharViewBase *) cv);
2852 0 : enum outlinesfm_flags strokeFillMode = sfm_stroke;
2853 0 : int GlyphHasBeenFilled = 0;
2854 :
2855 0 : GDrawPushClip(pixmap,&event->u.expose.rect,&old);
2856 :
2857 0 : if( shouldShowFilledUsingCairo(cv) ) {
2858 0 : strokeFillMode = sfm_fill;
2859 : }
2860 :
2861 0 : clip.width = event->u.expose.rect.width/cv->scale;
2862 0 : clip.height = event->u.expose.rect.height/cv->scale;
2863 0 : clip.x = (event->u.expose.rect.x-cv->xoff)/cv->scale;
2864 0 : clip.y = (cv->height-event->u.expose.rect.y-event->u.expose.rect.height-cv->yoff)/cv->scale;
2865 :
2866 0 : GDrawSetFont(pixmap,cv->small);
2867 0 : GDrawSetLineWidth(pixmap,0);
2868 :
2869 0 : if ( !cv->show_ft_results && cv->dv==NULL ) {
2870 :
2871 0 : if ( cv->backimgs==NULL && !(GDrawHasCairo(cv->v)&gc_buildpath))
2872 0 : cv->backimgs = GDrawCreatePixmap(GDrawGetDisplayOfWindow(cv->v),cv->width,cv->height);
2873 0 : if ( GDrawHasCairo(cv->v)&gc_buildpath ) {
2874 0 : for ( layer = ly_back; layer<cv->b.sc->layer_cnt; ++layer ) if ( cv->b.sc->layers[layer].images!=NULL ) {
2875 0 : if (( sf->multilayer && ((( cv->showback[0]&1 || cvlayer==layer) && layer==ly_back ) ||
2876 0 : ((cv->showfore || cvlayer==layer) && layer>ly_back)) ) ||
2877 0 : ( !sf->multilayer && (((cv->showfore && cvlayer==layer) && layer==ly_fore) ||
2878 0 : (((cv->showback[layer>>5]&(1<<(layer&31))) || cvlayer==layer) && layer!=ly_fore))) ) {
2879 : /* This really should be after the grids, but then it would completely*/
2880 : /* hide them. */
2881 0 : DrawImageList(cv,pixmap,cv->b.sc->layers[layer].images);
2882 : }
2883 : }
2884 0 : cv->back_img_out_of_date = false;
2885 0 : if ( cv->showhhints || cv->showvhints || cv->showdhints || cv->showblues || cv->showfamilyblues)
2886 0 : CVShowHints(cv,pixmap);
2887 0 : } else if ( cv->back_img_out_of_date ) {
2888 0 : GDrawFillRect(cv->backimgs,NULL,view_bgcol);
2889 0 : if ( cv->showhhints || cv->showvhints || cv->showdhints || cv->showblues || cv->showfamilyblues)
2890 0 : CVShowHints(cv,cv->backimgs);
2891 0 : for ( layer = ly_back; layer<cv->b.sc->layer_cnt; ++layer ) if ( cv->b.sc->layers[layer].images!=NULL ) {
2892 0 : if (( sf->multilayer && ((( cv->showback[0]&1 || cvlayer==layer) && layer==ly_back ) ||
2893 0 : ((cv->showfore || cvlayer==layer) && layer>ly_back)) ) ||
2894 0 : ( !sf->multilayer && (((cv->showfore && cvlayer==layer) && layer==ly_fore) ||
2895 0 : (((cv->showback[layer>>5]&(1<<(layer&31))) || cvlayer==layer) && layer!=ly_fore))) ) {
2896 : /* This really should be after the grids, but then it would completely*/
2897 : /* hide them. */
2898 0 : if ( cv->back_img_out_of_date )
2899 0 : DrawImageList(cv,cv->backimgs,cv->b.sc->layers[layer].images);
2900 : }
2901 : }
2902 0 : cv->back_img_out_of_date = false;
2903 : }
2904 0 : if ( cv->backimgs!=NULL ) {
2905 : GRect r;
2906 0 : r.x = r.y = 0; r.width = cv->width; r.height = cv->height;
2907 0 : GDrawDrawPixmap(pixmap,cv->backimgs,&r,0,0);
2908 0 : } else if ( !(GDrawHasCairo(cv->v)&gc_buildpath) &&
2909 0 : ( cv->showhhints || cv->showvhints || cv->showdhints || cv->showblues || cv->showfamilyblues)) {
2910 : /* if we've got bg images (and we're showing them) then the hints live in */
2911 : /* the bg image pixmap (else they get overwritten by the pixmap) */
2912 0 : CVShowHints(cv,pixmap);
2913 : }
2914 0 : if ( cv->showgrids || cv->b.drawmode==dm_grid ) {
2915 0 : CVDrawSplineSet(cv,pixmap,cv->b.fv->sf->grid.splines,guideoutlinecol,
2916 0 : cv->showpoints && cv->b.drawmode==dm_grid,&clip);
2917 : }
2918 0 : if ( cv->showhmetrics ) {
2919 0 : Color lbcolor = (!cv->inactive && cv->lbearingsel) ? lbearingselcol : coordcol;
2920 0 : DrawVLine(cv,pixmap,0,lbcolor,false,NULL,NULL);
2921 0 : DrawLine(cv,pixmap,-8096,0,8096,0,coordcol);
2922 0 : DrawLine(cv,pixmap,-8096,sf->ascent,8096,sf->ascent,coordcol);
2923 0 : DrawLine(cv,pixmap,-8096,-sf->descent,8096,-sf->descent,coordcol);
2924 : }
2925 0 : if ( cv->showvmetrics ) {
2926 0 : DrawLine(cv,pixmap,(sf->ascent+sf->descent)/2,-8096,(sf->ascent+sf->descent)/2,8096,coordcol);
2927 : /*DrawLine(cv,pixmap,-8096,sf->vertical_origin,8096,sf->vertical_origin,coordcol);*/
2928 : }
2929 :
2930 0 : DrawSelImageList(cv,pixmap,cv->b.layerheads[cv->b.drawmode]->images);
2931 :
2932 : /* Wrong order, I know. But it is useful to have the background */
2933 : /* visible on top of the fill... */
2934 0 : GlyphHasBeenFilled = CVExposeGlyphFill(cv, pixmap, event, &clip );
2935 : } else {
2936 : /* Draw FreeType Results */
2937 0 : CVDrawGridRaster(cv,pixmap,&clip);
2938 : }
2939 :
2940 0 : if ( cv->b.layerheads[cv->b.drawmode]->undoes!=NULL &&
2941 0 : cv->b.layerheads[cv->b.drawmode]->undoes->undotype==ut_tstate )
2942 0 : DrawOldState(cv,pixmap,cv->b.layerheads[cv->b.drawmode]->undoes, &clip);
2943 :
2944 0 : if ( cv->showfore )
2945 0 : cv->showback[0] |= (1<<ly_fore);
2946 : else
2947 0 : cv->showback[0] &= ~(1<<ly_fore);
2948 :
2949 0 : for ( layer=ly_back; layer<cv->b.sc->layer_cnt; ++layer ) if ( layer!=cvlayer ) {
2950 0 : if ( cv->showback[layer>>5]&(1<<(layer&31)) ) {
2951 : /* Used to draw the image list here, but that's too slow. Optimization*/
2952 : /* is to draw to pixmap, dump pixmap a bit earlier */
2953 : /* Then when we moved the fill image around, we had to deal with the */
2954 : /* images before the fill... */
2955 0 : int activelayer = CVLayer(&cv->b);
2956 :
2957 0 : enum outlinesfm_flags strokeFillMode = sfm_stroke;
2958 0 : if( cv->inPreviewMode )
2959 0 : strokeFillMode = sfm_nothing;
2960 0 : if( layer == activelayer && layer >= ly_back )
2961 0 : strokeFillMode = sfm_fill;
2962 :
2963 0 : CVDrawLayerSplineSet(cv,pixmap,&cv->b.sc->layers[layer],
2964 0 : !sf->multilayer || layer==ly_back ? backoutlinecol : foreoutlinecol,
2965 : false,&clip,strokeFillMode);
2966 0 : for ( rf=cv->b.sc->layers[layer].refs; rf!=NULL; rf = rf->next ) {
2967 0 : if ( /* cv->b.drawmode==dm_back &&*/ cv->showrefnames )
2968 0 : CVDrawRefName(cv,pixmap,rf,0);
2969 0 : for ( rlayer=0; rlayer<rf->layer_cnt; ++rlayer )
2970 0 : CVDrawSplineSet(cv,pixmap,rf->layers[rlayer].splines, backoutlinecol,false,&clip);
2971 0 : if ( rf->selected && cv->b.layerheads[cv->b.drawmode]==&cv->b.sc->layers[layer])
2972 0 : CVDrawBB(cv,pixmap,&rf->bb);
2973 : }
2974 : }
2975 : }
2976 0 : if ( cv->mmvisible!=0 )
2977 0 : DrawMMGhosts(cv,pixmap,&clip);
2978 0 : if ( cv->template1!=NULL )
2979 0 : CVDrawTemplates(cv,pixmap,cv->template1,&clip);
2980 0 : if ( cv->template2!=NULL )
2981 0 : CVDrawTemplates(cv,pixmap,cv->template2,&clip);
2982 :
2983 : /* Draw the active layer last so its splines are on top. */
2984 : /* Note that we don't check whether the layer is visible or not, we always*/
2985 : /* draw the current layer -- unless they've turned on grid fit. Then they*/
2986 : /* might want to hide the active layer. */
2987 0 : layer = cvlayer;
2988 :
2989 :
2990 : /*
2991 : * If we have a pretransform_spl and the user wants to see it then show it to them
2992 : */
2993 0 : if( cv->p.pretransform_spl )
2994 : {
2995 : struct CVExpose_PreTransformSPL_ud d;
2996 0 : d.dopoints = 1;
2997 0 : d.cv = cv;
2998 0 : d.pixmap = pixmap;
2999 0 : d.fg = DraggingComparisonOutlineColor;
3000 0 : d.clip = &clip;
3001 0 : d.strokeFillMode = sfm_stroke_trans;
3002 0 : g_list_foreach( cv->p.pretransform_spl, (GFunc)CVExpose_PreTransformSPL_fe, &d );
3003 : }
3004 :
3005 : /* The call to CVExposeGlyphFill() above will have rendered a filled glyph already. */
3006 : /* We draw the outline only at this stage so as to have it layered */
3007 : /* over the control points if they are currently visible. */
3008 : /* CVDrawLayerSplineSet() will draw both the control points, and the font outline over those */
3009 : /* NB:
3010 : * Drawing the stroked outline may also use the color
3011 : * clippathcol for some splines, so we can't really avoid a
3012 : * restroke unless we are sure
3013 : * FOR-ALL(splines):spl->is_clip_path==0 */
3014 0 : if( shouldShowFilledUsingCairo(cv) ) {
3015 0 : strokeFillMode = sfm_stroke;
3016 : }
3017 0 : if( GlyphHasBeenFilled ) {
3018 0 : strokeFillMode = sfm_stroke_trans;
3019 : }
3020 :
3021 0 : if ( layer<0 ) /* Guide lines are special */
3022 0 : CVDrawLayerSplineSet( cv,pixmap,cv->b.layerheads[cv->b.drawmode],foreoutlinecol,
3023 0 : cv->showpoints ,&clip, strokeFillMode );
3024 0 : else if ( (cv->showback[layer>>5]&(1<<(layer&31))) ||
3025 0 : (!cv->show_ft_results && cv->dv==NULL ))
3026 : {
3027 0 : CVExposeReferences( cv, pixmap, cv->b.sc, layer, &clip );
3028 : }
3029 0 : if ( layer>=0 )
3030 : {
3031 0 : if( cv->dv && !(cv->showback[layer>>5]&(1<<(layer&31))))
3032 : {
3033 : // MIQ 2013 feb: issue/168
3034 : // turn off the glyph outline if we are in debug mode and
3035 : // the layer is not visible
3036 : }
3037 : else
3038 : {
3039 0 : CVDrawLayerSplineSet( cv,pixmap,&cv->b.sc->layers[layer],foreoutlinecol,
3040 0 : cv->showpoints ,&clip, strokeFillMode );
3041 :
3042 :
3043 0 : int showpoints = 0;
3044 0 : enum outlinesfm_flags sm = sfm_stroke;
3045 0 : if( cv->inPreviewMode ) {
3046 0 : sm = sfm_fill;
3047 : }
3048 :
3049 0 : int ridx = cv->additionalCharsToShowActiveIndex+1;
3050 : // TRACE("expose(b) additionalCharsToShowActiveIndex:%d\n", cv->additionalCharsToShowActiveIndex );
3051 0 : if( cv->additionalCharsToShow[ ridx ] )
3052 : {
3053 0 : int i = 1;
3054 0 : int originalxoff = cv->xoff;
3055 0 : int offset = cv->scale * cv->b.sc->width;
3056 0 : for( i=ridx; i < additionalCharsToShowLimit; i++ )
3057 : {
3058 : // TRACE("expose(right) loop:%d\n", i );
3059 0 : SplineChar* xc = cv->additionalCharsToShow[i];
3060 0 : if( !xc )
3061 0 : break;
3062 :
3063 0 : cv->xoff += offset;
3064 0 : CVExposeReferences( cv, pixmap, xc, layer, &clip );
3065 0 : CVDrawLayerSplineSet( cv, pixmap, &xc->layers[layer], foreoutlinecol,
3066 : showpoints ,&clip, sm );
3067 0 : offset = cv->scale * xc->width;
3068 : }
3069 0 : cv->xoff = originalxoff;
3070 : }
3071 :
3072 :
3073 :
3074 0 : if( cv->additionalCharsToShowActiveIndex > 0 )
3075 : {
3076 0 : int i = 1;
3077 0 : int originalxoff = cv->xoff;
3078 0 : int offset = 0;
3079 :
3080 0 : for( i=cv->additionalCharsToShowActiveIndex-1; i >= 0; i-- )
3081 : {
3082 : // TRACE("expose(left) loop:%d\n", i );
3083 0 : SplineChar* xc = cv->additionalCharsToShow[i];
3084 0 : if( !xc )
3085 0 : break;
3086 :
3087 0 : offset = cv->scale * xc->width;
3088 0 : cv->xoff -= offset;
3089 0 : CVExposeReferences( cv, pixmap, xc, layer, &clip );
3090 0 : CVDrawLayerSplineSet( cv, pixmap, &xc->layers[layer], foreoutlinecol,
3091 : showpoints ,&clip, sm );
3092 : }
3093 0 : cv->xoff = originalxoff;
3094 : }
3095 :
3096 : // TRACE("expose(e) ridx:%d\n", ridx );
3097 :
3098 : }
3099 : }
3100 :
3101 :
3102 0 : if ( cv->freehand.current_trace )
3103 0 : CVDrawSplineSet( cv,pixmap,cv->freehand.current_trace,tracecol,
3104 : false,&clip);
3105 :
3106 0 : if ( cv->showhmetrics && (cv->b.container==NULL || cv->b.container->funcs->type==cvc_mathkern) ) {
3107 0 : RefChar *lock = HasUseMyMetrics(cv->b.sc,cvlayer);
3108 0 : if ( lock!=NULL ) cv->b.sc->width = lock->sc->width;
3109 0 : DrawVLine(cv,pixmap,cv->b.sc->width,(!cv->inactive && cv->widthsel)?widthselcol:widthcol,true,
3110 : lock!=NULL ? &GIcon_lock : NULL, NULL);
3111 0 : if ( cv->b.sc->italic_correction!=TEX_UNDEF && cv->b.sc->italic_correction!=0 ) {
3112 0 : GDrawSetDashedLine(pixmap,2,2,0);
3113 0 : DrawVLine(cv,pixmap,cv->b.sc->width+cv->b.sc->italic_correction,(!cv->inactive && cv->icsel)?widthselcol:widthcol,
3114 : /* GT: Italic Correction */
3115 : false, NULL,_("ItalicCor."));
3116 0 : GDrawSetDashedLine(pixmap,0,0,0);
3117 : }
3118 : }
3119 0 : if ( cv->showhmetrics && cv->b.container==NULL ) {
3120 0 : for ( pst=cv->b.sc->possub; pst!=NULL && pst->type!=pst_lcaret; pst=pst->next );
3121 0 : if ( pst!=NULL ) {
3122 0 : for ( i=0; i<pst->u.lcaret.cnt; ++i )
3123 0 : DrawVLine(cv,pixmap,pst->u.lcaret.carets[i],lcaretcol,true,NULL,_("Lig.Caret"));
3124 : }
3125 0 : if ( cv->show_ft_results || cv->dv!=NULL )
3126 0 : DrawVLine(cv,pixmap,cv->b.ft_gridfitwidth,widthgridfitcol,true,NULL,NULL);
3127 0 : if ( cv->b.sc->top_accent_horiz!=TEX_UNDEF )
3128 0 : DrawVLine(cv,pixmap,cv->b.sc->top_accent_horiz,(!cv->inactive && cv->tah_sel)?widthselcol:anchorcol,true,
3129 : NULL,_("TopAccent"));
3130 : }
3131 0 : if ( cv->showvmetrics ) {
3132 0 : int len, y = -cv->yoff + cv->height - rint((/*sf->vertical_origin*/-cv->b.sc->vwidth)*cv->scale);
3133 0 : DrawLine(cv,pixmap,-32768,/*sf->vertical_origin*/-cv->b.sc->vwidth,
3134 0 : 32767,/*sf->vertical_origin*/-cv->b.sc->vwidth,
3135 0 : (!cv->inactive && cv->vwidthsel)?widthselcol:widthcol);
3136 0 : if ( y>-40 && y<cv->height+40 ) {
3137 0 : dtos( buf, cv->b.sc->vwidth);
3138 0 : GDrawSetFont(pixmap,cv->small);
3139 0 : len = GDrawGetText8Width(pixmap,buf,-1);
3140 0 : GDrawDrawText8(pixmap,cv->width-len-5,y,buf,-1,metricslabelcol);
3141 : }
3142 : }
3143 0 : if ( cv->showsidebearings && cv->showfore &&
3144 0 : (cv->showvmetrics || cv->showhmetrics))
3145 0 : CVSideBearings(pixmap,cv);
3146 :
3147 0 : if ((( cv->active_tool >= cvt_scale && cv->active_tool <= cvt_perspective ) ||
3148 0 : cv->active_shape!=NULL ) &&
3149 : cv->p.pressed )
3150 0 : DrawTransOrigin(cv,pixmap);
3151 0 : if ( cv->dv==NULL || (cv->showback[ly_fore>>5]&(1<<(ly_fore&31))) )
3152 0 : CVDrawAnchorPoints(cv,pixmap);
3153 0 : if ( cv->apmine!=NULL )
3154 0 : DrawAPMatch(cv,pixmap,&clip);
3155 :
3156 0 : if ( cv->p.rubberbanding || cv->p.rubberlining ) {
3157 0 : if ( cv->p.rubberbanding )
3158 0 : CVDrawRubberRect(pixmap,cv);
3159 0 : if ( cv->p.rubberlining )
3160 0 : CVDrawRubberLine(pixmap,cv);
3161 : }
3162 0 : CVRulerExpose(pixmap,cv);
3163 :
3164 0 : GDrawPopClip(pixmap,&old);
3165 0 : }
3166 :
3167 6159 : static void SC_UpdateAll(SplineChar *sc) {
3168 : CharView *cv;
3169 : struct splinecharlist *dlist;
3170 : MetricsView *mv;
3171 : FontView *fv;
3172 :
3173 6159 : for ( cv=(CharView *) (sc->views); cv!=NULL; cv=(CharView *) (cv->b.next) )
3174 0 : GDrawRequestExpose(cv->v,NULL,false);
3175 8747 : for ( dlist=sc->dependents; dlist!=NULL; dlist=dlist->next )
3176 2588 : SCUpdateAll(dlist->sc);
3177 6159 : if ( sc->parent!=NULL ) {
3178 12318 : for ( fv = (FontView *) (sc->parent->fv); fv!=NULL; fv=(FontView *) (fv->b.nextsame) )
3179 6159 : FVRegenChar(fv,sc);
3180 6159 : for ( mv = sc->parent->metrics; mv!=NULL; mv=mv->next )
3181 0 : MVRegenChar(mv,sc);
3182 : }
3183 6159 : }
3184 :
3185 2684 : static void SC_OutOfDateBackground(SplineChar *sc) {
3186 : CharView *cv;
3187 :
3188 2684 : for ( cv=(CharView *) (sc->views); cv!=NULL; cv=(CharView *) (cv->b.next) )
3189 0 : cv->back_img_out_of_date = true;
3190 2684 : }
3191 :
3192 : /* CVRegenFill() regenerates data used to show or not show paths as filled */
3193 : /* This is not static so that it can be called from the layers palette */
3194 0 : void CVRegenFill(CharView *cv) {
3195 0 : BDFCharFree(cv->filled);
3196 0 : cv->filled = NULL;
3197 0 : if ( cv->showfilled && !shouldShowFilledUsingCairo(cv) ) {
3198 : extern int use_freetype_to_rasterize_fv;
3199 0 : int layer = CVLayer((CharViewBase *) cv);
3200 0 : int size = cv->scale*(cv->b.fv->sf->ascent+cv->b.fv->sf->descent);
3201 0 : int clut_len= 2;
3202 :
3203 0 : if ( layer==ly_grid ) layer=ly_fore; /* otherwise crashes when using guides layer! */
3204 :
3205 : /* Generally I don't think there's much point in doing an anti-aliased*/
3206 : /* fill. But on the "M" (and "W") glyph of extravigant caps, ft won't*/
3207 : /* do a mono fill */
3208 0 : if ( use_freetype_to_rasterize_fv && hasFreeType()) {
3209 0 : int depth = 1;
3210 0 : if( use_freetype_with_aa_fill_cv ) {
3211 0 : depth = 4;
3212 0 : clut_len = 16;
3213 : }
3214 0 : cv->filled = SplineCharFreeTypeRasterizeNoHints(cv->b.sc,layer,
3215 : size,72, depth);
3216 0 : if ( cv->filled==NULL && size<2000 ) {
3217 : /* There are some glyphs which freetype won't rasterize in */
3218 : /* mono mode, but will in grey scale. Don't ask me why */
3219 0 : cv->filled = SplineCharFreeTypeRasterizeNoHints(cv->b.sc,
3220 : layer, size, 72, 4);
3221 0 : clut_len = 16;
3222 : }
3223 : }
3224 0 : if ( cv->filled==NULL )
3225 0 : cv->filled = SplineCharRasterize(cv->b.sc,layer,size+.1);
3226 0 : if ( cv->filled==NULL )
3227 0 : return;
3228 0 : cv->gi.u.image->image_type = clut_len==2 ? it_mono : it_index;
3229 0 : cv->gi.u.image->data = cv->filled->bitmap;
3230 0 : cv->gi.u.image->bytes_per_line = cv->filled->bytes_per_line;
3231 0 : cv->gi.u.image->width = cv->filled->xmax-cv->filled->xmin+1;
3232 0 : cv->gi.u.image->height = cv->filled->ymax-cv->filled->ymin+1;
3233 0 : if ( clut_len!=cv->gi.u.image->clut->clut_len ) {
3234 0 : GClut *clut = cv->gi.u.image->clut;
3235 : int i;
3236 0 : Color bg = view_bgcol;
3237 0 : for ( i=0; i<clut_len; ++i ) {
3238 : int r,g,b;
3239 0 : r = ((bg>>16)&0xff)*(clut_len-1-i) + ((fillcol>>16)&0xff)*i;
3240 0 : g = ((bg>>8 )&0xff)*(clut_len-1-i) + ((fillcol>>8 )&0xff)*i;
3241 0 : b = ((bg )&0xff)*(clut_len-1-i) + ((fillcol )&0xff)*i;
3242 0 : clut->clut[i] = COLOR_CREATE(r/(clut_len-1),g/(clut_len-1),b/(clut_len-1));
3243 : }
3244 0 : clut->clut_len = clut_len;
3245 : }
3246 0 : GDrawRequestExpose(cv->v,NULL,false);
3247 : }
3248 : }
3249 :
3250 :
3251 0 : static void FVRedrawAllCharViewsSF(SplineFont *sf)
3252 : {
3253 : int i;
3254 : CharView *cv;
3255 :
3256 0 : for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL )
3257 0 : for ( cv = (CharView *) (sf->glyphs[i]->views); cv!=NULL; cv=(CharView *) (cv->b.next) )
3258 0 : GDrawRequestExpose(cv->v,NULL,false);
3259 0 : }
3260 :
3261 0 : void FVRedrawAllCharViews(FontView *fv)
3262 : {
3263 0 : FVRedrawAllCharViewsSF( fv->b.sf );
3264 0 : }
3265 :
3266 895 : static void SCRegenFills(SplineChar *sc) {
3267 : struct splinecharlist *dlist;
3268 : CharView *cv;
3269 :
3270 895 : for ( cv = (CharView *) (sc->views); cv!=NULL; cv=(CharView *) (cv->b.next) )
3271 0 : CVRegenFill(cv);
3272 895 : for ( dlist=sc->dependents; dlist!=NULL; dlist=dlist->next )
3273 0 : SCRegenFills(dlist->sc);
3274 895 : }
3275 :
3276 895 : static void SCRegenDependents(SplineChar *sc, int layer) {
3277 : struct splinecharlist *dlist;
3278 : FontView *fv;
3279 : int first, last;
3280 :
3281 895 : first = last = layer;
3282 895 : if ( layer==ly_all ) {
3283 895 : first = 0; last = sc->layer_cnt-1;
3284 : }
3285 2685 : for ( layer = first; layer<=last; ++layer ) {
3286 3580 : for ( fv = (FontView *) (sc->parent->fv); fv!=NULL; fv=(FontView *) (fv->b.nextsame) ) {
3287 1790 : if ( fv->sv!=NULL && layer<=ly_fore ) {
3288 0 : SCReinstanciateRef(&fv->sv->sd.sc_srch,sc,layer);
3289 0 : SCReinstanciateRef(&fv->sv->sd.sc_rpl,sc,layer);
3290 : }
3291 : }
3292 :
3293 1790 : for ( dlist=sc->dependents; dlist!=NULL; dlist=dlist->next ) {
3294 0 : SCReinstanciateRef(dlist->sc,sc,layer);
3295 0 : SCRegenDependents(dlist->sc,layer);
3296 : }
3297 : }
3298 895 : }
3299 :
3300 0 : static void CVUpdateInfo(CharView *cv, GEvent *event) {
3301 :
3302 0 : cv->info_within = true;
3303 0 : cv->e.x = event->u.mouse.x; cv->e.y = event->u.mouse.y;
3304 0 : cv->info.x = (event->u.mouse.x-cv->xoff)/cv->scale;
3305 0 : cv->info.y = (cv->height-event->u.mouse.y-cv->yoff)/cv->scale;
3306 0 : CVInfoDraw(cv,cv->gw);
3307 0 : }
3308 :
3309 0 : static void CVNewScale(CharView *cv) {
3310 : GEvent e;
3311 :
3312 0 : CVRegenFill(cv);
3313 0 : cv->back_img_out_of_date = true;
3314 :
3315 0 : GScrollBarSetBounds(cv->vsb,-20000*cv->scale,8000*cv->scale,cv->height);
3316 0 : GScrollBarSetBounds(cv->hsb,-8000*cv->scale,32000*cv->scale,cv->width);
3317 0 : GScrollBarSetPos(cv->vsb,cv->yoff-cv->height);
3318 0 : GScrollBarSetPos(cv->hsb,-cv->xoff);
3319 :
3320 0 : GDrawRequestExpose(cv->v,NULL,false);
3321 0 : if ( cv->showrulers )
3322 0 : GDrawRequestExpose(cv->gw,NULL,false);
3323 0 : GDrawGetPointerPosition(cv->v,&e);
3324 0 : CVUpdateInfo(cv,&e);
3325 0 : }
3326 :
3327 0 : static void _CVFit(CharView *cv,DBounds *b, int integral) {
3328 : real left, right, top, bottom, hsc, wsc;
3329 : extern int palettes_docked;
3330 0 : int offset = palettes_docked ? 90 : 0;
3331 0 : int em = cv->b.sc->parent->ascent + cv->b.sc->parent->descent;
3332 0 : int hsmall = true;
3333 :
3334 0 : if ( offset>cv->width ) offset = 0;
3335 :
3336 0 : bottom = b->miny;
3337 0 : top = b->maxy;
3338 0 : left = b->minx;
3339 0 : right = b->maxx;
3340 :
3341 0 : if ( top<bottom ) IError("Bottom bigger than top!");
3342 0 : if ( right<left ) IError("Left bigger than right!");
3343 0 : top -= bottom;
3344 0 : right -= left;
3345 0 : if ( top==0 ) top = em;
3346 0 : if ( right==0 ) right = em;
3347 0 : wsc = (cv->width-offset) / right;
3348 0 : hsc = cv->height / top;
3349 0 : if ( wsc<hsc ) { hsc = wsc; hsmall = false ; }
3350 :
3351 0 : cv->scale = hsc;
3352 0 : if ( integral ) {
3353 0 : if ( cv->scale > 1.0 ) {
3354 0 : cv->scale = floor(cv->scale);
3355 : } else {
3356 0 : cv->scale = 1/ceil(1/cv->scale);
3357 : }
3358 : } else {
3359 0 : if ( cv->scale > 1.0 ) {
3360 0 : cv->scale = floor(2*cv->scale)/2;
3361 : } else {
3362 0 : cv->scale = 2/ceil(2/cv->scale);
3363 : }
3364 : }
3365 :
3366 : /* Center glyph horizontally */
3367 0 : cv->xoff = ( (cv->width-offset) - (right*cv->scale) )/2 + offset - b->minx*cv->scale;
3368 0 : if ( hsmall )
3369 0 : cv->yoff = -bottom*cv->scale;
3370 : else
3371 0 : cv->yoff = -(bottom+top/2)*cv->scale + cv->height/2;
3372 :
3373 0 : CVNewScale(cv);
3374 0 : }
3375 :
3376 0 : static void CVFit(CharView *cv) {
3377 : DBounds b;
3378 : double center;
3379 :
3380 0 : SplineCharFindBounds(cv->b.sc,&b);
3381 0 : if ( b.miny==0 && b.maxy==0 ) {
3382 0 : b.maxy =cv->b.sc->parent->ascent;
3383 0 : b.miny = -cv->b.sc->parent->descent;
3384 : }
3385 : /* FF used to normalize bounding boxes making maxx positive. But this */
3386 : /* may result into an incorrect positioning for combining marks, which */
3387 : /* usually have both bearings negative. So keep negative values as they are. */
3388 : /* As for the Y axis, we only ensure the minimum value doesn't exceed zero, */
3389 : /* so that the baseline is always visible. */
3390 :
3391 0 : if ( b.miny>0 ) b.miny = 0;
3392 :
3393 : /* Now give some extra space around the interesting stuff */
3394 0 : center = (b.maxx+b.minx)/2;
3395 0 : b.minx = center - (center - b.minx)*1.2;
3396 0 : b.maxx = center + (b.maxx - center)*1.2;
3397 0 : center = (b.maxy+b.miny)/2;
3398 0 : b.miny = center - (center - b.miny)*1.2;
3399 0 : b.maxy = center + (b.maxy - center)*1.2;
3400 :
3401 0 : _CVFit(cv,&b,true);
3402 0 : }
3403 :
3404 0 : static void CVUnlinkView(CharView *cv ) {
3405 : CharView *test;
3406 :
3407 0 : if ( cv->b.sc->views == (CharViewBase *) cv ) {
3408 0 : cv->b.sc->views = cv->b.next;
3409 : } else {
3410 0 : for ( test=(CharView *) (cv->b.sc->views);
3411 0 : test->b.next!=(CharViewBase *) cv && test->b.next!=NULL;
3412 0 : test=(CharView *) (test->b.next) );
3413 0 : if ( test->b.next==(CharViewBase *) cv )
3414 0 : test->b.next = cv->b.next;
3415 : }
3416 0 : }
3417 :
3418 0 : static GWindow CharIcon(CharView *cv, FontView *fv) {
3419 0 : SplineChar *sc = cv->b.sc;
3420 : BDFFont *bdf, *bdf2;
3421 : BDFChar *bdfc;
3422 0 : GWindow icon = cv->icon;
3423 : GRect r;
3424 :
3425 0 : r.x = r.y = 0; r.width = r.height = fv->cbw-1;
3426 0 : if ( icon == NULL )
3427 0 : cv->icon = icon = GDrawCreatePixmap(NULL,r.width,r.width);
3428 0 : GDrawFillRect(icon,&r,0x0); /* for some reason icons seem to be color reversed by my defn */
3429 :
3430 0 : bdf = NULL; bdfc = NULL;
3431 0 : if ( sc->layers[ly_fore].refs!=NULL || sc->layers[ly_fore].splines!=NULL ) {
3432 0 : bdf = fv->show;
3433 0 : if ( sc->orig_pos>=bdf->glyphcnt || bdf->glyphs[sc->orig_pos]==NULL )
3434 0 : bdf = fv->filled;
3435 0 : if ( sc->orig_pos>=bdf->glyphcnt || bdf->glyphs[sc->orig_pos]==NULL ) {
3436 0 : bdf2 = NULL; bdfc = NULL;
3437 0 : for ( bdf=fv->b.sf->bitmaps; bdf!=NULL && bdf->pixelsize<24 ; bdf=bdf->next )
3438 0 : bdf2 = bdf;
3439 0 : if ( bdf2!=NULL && bdf!=NULL ) {
3440 0 : if ( 24-bdf2->pixelsize < bdf->pixelsize-24 )
3441 0 : bdf = bdf2;
3442 0 : } else if ( bdf==NULL )
3443 0 : bdf = bdf2;
3444 : }
3445 0 : if ( bdf!=NULL && sc->orig_pos<bdf->glyphcnt )
3446 0 : bdfc = bdf->glyphs[sc->orig_pos];
3447 : }
3448 :
3449 0 : if ( bdfc!=NULL ) {
3450 : GClut clut;
3451 : struct _GImage base;
3452 : GImage gi;
3453 : /* if not empty, use the font's own shape, otherwise use a standard */
3454 : /* font */
3455 0 : memset(&gi,'\0',sizeof(gi));
3456 0 : memset(&base,'\0',sizeof(base));
3457 0 : memset(&clut,'\0',sizeof(clut));
3458 0 : gi.u.image = &base;
3459 0 : base.trans = -1;
3460 0 : base.clut = &clut;
3461 0 : if ( bdfc->byte_data ) { int i;
3462 0 : base.image_type = it_index;
3463 0 : clut.clut_len = bdf->clut->clut_len;
3464 0 : for ( i=0; i<clut.clut_len; ++i ) {
3465 0 : int v = 255-i*255/(clut.clut_len-1);
3466 0 : clut.clut[i] = COLOR_CREATE(v,v,v);
3467 : }
3468 0 : clut.trans_index = -1;
3469 : } else {
3470 0 : base.image_type = it_mono;
3471 0 : clut.clut_len = 2;
3472 0 : clut.clut[1] = 0xffffff;
3473 : }
3474 0 : base.data = bdfc->bitmap;
3475 0 : base.bytes_per_line = bdfc->bytes_per_line;
3476 0 : base.width = bdfc->xmax-bdfc->xmin+1;
3477 0 : base.height = bdfc->ymax-bdfc->ymin+1;
3478 0 : GDrawDrawImage(icon,&gi,NULL,(r.width-base.width)/2,(r.height-base.height)/2);
3479 0 : } else if ( sc->unicodeenc!=-1 ) {
3480 : FontRequest rq;
3481 : GFont *font;
3482 : unichar_t text[2];
3483 : int as, ds, ld, width;
3484 :
3485 0 : memset(&rq,0,sizeof(rq));
3486 0 : rq.utf8_family_name = SERIF_UI_FAMILIES;
3487 0 : rq.point_size = 24;
3488 0 : rq.weight = 400;
3489 0 : font = GDrawInstanciateFont(NULL,&rq);
3490 0 : GDrawSetFont(icon,font);
3491 0 : text[0] = sc->unicodeenc; text[1] = 0;
3492 0 : GDrawWindowFontMetrics(icon,font,&as,&ds,&ld);
3493 0 : width = GDrawGetTextWidth(icon,text,1);
3494 0 : GDrawDrawText(icon,(r.width-width)/2,(r.height-as-ds)/2+as,text,1,0xffffff);
3495 : }
3496 0 : return( icon );
3497 : }
3498 :
3499 0 : static int CVCurEnc(CharView *cv)
3500 : {
3501 0 : if ( cv->map_of_enc == ((FontView *) (cv->b.fv))->b.map && cv->enc!=-1 )
3502 0 : return( cv->enc );
3503 :
3504 0 : return( ((FontView *) (cv->b.fv))->b.map->backmap[cv->b.sc->orig_pos] );
3505 : }
3506 :
3507 0 : static char *CVMakeTitles(CharView *cv,char *buf,size_t len) {
3508 : char *title;
3509 0 : SplineChar *sc = cv->b.sc;
3510 0 : SplineFont *sf = sc->parent;
3511 : char *uniname;
3512 : size_t used;
3513 :
3514 : /* GT: This is the title for a window showing an outline character */
3515 : /* GT: It will look something like: */
3516 : /* GT: exclam at 33 from Arial */
3517 : /* GT: $1 is the name of the glyph */
3518 : /* GT: $2 is the glyph's encoding */
3519 : /* GT: $3 is the font name */
3520 : /* GT: $4 is the changed flag ('*' for the changed items)*/
3521 0 : used = snprintf(buf,len,_("%1$.80s at %2$d from %3$.90s%4$s"),
3522 : sc->name, CVCurEnc(cv), sf->fontname,
3523 0 : sc->changed ? "*" : "");
3524 0 : title = copy(buf);
3525 :
3526 0 : if (used < len) {
3527 : /* Enhance 'buf' description with Nameslist.txt unicode name definition */
3528 0 : if ( (uniname=unicode_name(sc->unicodeenc))!=NULL ) {
3529 0 : used += snprintf(buf+used, len-used, " %s", uniname);
3530 0 : free(uniname);
3531 : }
3532 : }
3533 :
3534 0 : if (used < len && ( cv->show_ft_results || cv->dv )) {
3535 0 : snprintf(buf+used, len-used, " (%gpt, %ddpi)", (double) cv->ft_pointsizey, cv->ft_dpi );
3536 : }
3537 :
3538 0 : return( title );
3539 : }
3540 :
3541 3750 : static void SC_RefreshTitles(SplineChar *sc) {
3542 : /* Called if the user changes the unicode encoding or the character name */
3543 : CharView *cv;
3544 : char buf[300], *title;
3545 :
3546 3750 : if ( (CharView *) (sc->views)==NULL )
3547 7500 : return;
3548 0 : for ( cv = (CharView *) (sc->views); cv!=NULL; cv=(CharView *) (cv->b.next) ) {
3549 0 : title = CVMakeTitles(cv,buf,sizeof(buf));
3550 : /* Could be different if one window is debugging and one is not */
3551 0 : GDrawSetWindowTitles8(cv->gw,buf,title);
3552 0 : free(title);
3553 : }
3554 : }
3555 :
3556 0 : static void CVChangeTabsVisibility(CharView *cv,int makevisible) {
3557 : GRect gsize, pos, sbsize;
3558 :
3559 0 : if ( cv->tabs==NULL || GGadgetIsVisible(cv->tabs)==makevisible )
3560 0 : return;
3561 0 : GGadgetGetSize(cv->tabs,&gsize);
3562 0 : GGadgetGetSize(cv->vsb,&sbsize);
3563 0 : if ( makevisible ) {
3564 0 : cv->mbh += gsize.height;
3565 0 : cv->height -= gsize.height;
3566 0 : GGadgetMove(cv->vsb,sbsize.x,sbsize.y+gsize.height);
3567 0 : GGadgetResize(cv->vsb,sbsize.width,sbsize.height-gsize.height);
3568 0 : GGadgetMoveAddToY( cv->charselector, gsize.height );
3569 0 : GGadgetMoveAddToY( cv->charselectorNext, gsize.height );
3570 0 : GGadgetMoveAddToY( cv->charselectorPrev, gsize.height );
3571 : } else {
3572 0 : cv->mbh -= gsize.height;
3573 0 : cv->height += gsize.height;
3574 0 : GGadgetMove(cv->vsb,sbsize.x,sbsize.y-gsize.height);
3575 0 : GGadgetResize(cv->vsb,sbsize.width,sbsize.height+gsize.height);
3576 0 : GGadgetMoveAddToY( cv->charselector, -1*gsize.height );
3577 0 : GGadgetMoveAddToY( cv->charselectorNext, -1*gsize.height );
3578 0 : GGadgetMoveAddToY( cv->charselectorPrev, -1*gsize.height );
3579 : }
3580 0 : GGadgetSetVisible(cv->tabs,makevisible);
3581 0 : cv->back_img_out_of_date = true;
3582 0 : pos.x = 0; pos.y = cv->mbh+cv->charselectorh+cv->infoh;
3583 0 : pos.width = cv->width; pos.height = cv->height;
3584 0 : if ( cv->showrulers ) {
3585 0 : pos.x += cv->rulerh;
3586 0 : pos.y += cv->rulerh;
3587 : }
3588 0 : GDrawMoveResize(cv->v,pos.x,pos.y,pos.width,pos.height);
3589 0 : GDrawSync(NULL);
3590 0 : GDrawRequestExpose(cv->v,NULL,false);
3591 0 : GDrawRequestExpose(cv->gw,NULL,false);
3592 : }
3593 :
3594 0 : static void CVCheckPoints(CharView *cv) {
3595 0 : if ( !SCPointsNumberedProperly(cv->b.sc,CVLayer((CharViewBase *) cv)) && cv->b.sc->ttf_instrs_len!=0 ) {
3596 : char *buts[3];
3597 : int answer;
3598 0 : buts[0] = _("_Yes");
3599 0 : buts[1] = _("_No");
3600 0 : buts[2] = NULL;
3601 0 : 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);
3602 0 : if ( answer==0 ) {
3603 0 : free(cv->b.sc->ttf_instrs); cv->b.sc->ttf_instrs = NULL;
3604 0 : cv->b.sc->ttf_instrs_len = 0;
3605 : }
3606 : }
3607 0 : }
3608 :
3609 0 : static void CVChangeSC_storeTab( CharView *cv, int tabnumber )
3610 : {
3611 : TRACE("CVChangeSC_storeTab() %d\n", tabnumber );
3612 0 : if( tabnumber < charview_cvtabssz )
3613 : {
3614 0 : CharViewTab* t = &cv->cvtabs[tabnumber];
3615 0 : strncpy( t->charselected,
3616 0 : GGadgetGetTitle8(cv->charselector),
3617 : charviewtab_charselectedsz );
3618 : }
3619 0 : }
3620 :
3621 0 : static void CVChangeSC_fetchTab( CharView *cv, int tabnumber )
3622 : {
3623 0 : if( tabnumber < charview_cvtabssz )
3624 : {
3625 0 : CharViewTab* t = &cv->cvtabs[tabnumber];
3626 0 : GGadgetSetTitle8(cv->charselector, t->charselected );
3627 : }
3628 0 : }
3629 :
3630 0 : static void CVSetCharSelectorValueFromSC( CharView *cv, SplineChar *sc )
3631 : {
3632 0 : const char* title = Wordlist_getSCName( sc );
3633 0 : GGadgetSetTitle8(cv->charselector, title);
3634 0 : }
3635 :
3636 :
3637 0 : void CVChangeSC( CharView *cv, SplineChar *sc )
3638 : {
3639 : char *title;
3640 : char buf[300];
3641 : extern int updateflex;
3642 : int i;
3643 0 : int old_layer = CVLayer((CharViewBase *) cv), blayer;
3644 0 : int was_fitted = cv->dv==NULL && cv->b.gridfit!=NULL;
3645 :
3646 0 : if ( old_layer>=sc->layer_cnt )
3647 0 : old_layer = ly_fore; /* Can happen in type3 fonts where each glyph has a different layer cnt */
3648 :
3649 0 : memset( cv->additionalCharsToShow, 0, sizeof(SplineChar*) * additionalCharsToShowLimit );
3650 0 : cv->additionalCharsToShowActiveIndex = 0;
3651 0 : cv->additionalCharsToShow[0] = sc;
3652 :
3653 0 : CVDebugFree(cv->dv);
3654 :
3655 0 : if ( cv->expandedge != ee_none ) {
3656 0 : GDrawSetCursor(cv->v,ct_mypointer);
3657 0 : cv->expandedge = ee_none;
3658 : }
3659 :
3660 0 : SplinePointListsFree(cv->b.gridfit); cv->b.gridfit = NULL;
3661 0 : FreeType_FreeRaster(cv->oldraster); cv->oldraster = NULL;
3662 0 : FreeType_FreeRaster(cv->raster); cv->raster = NULL;
3663 :
3664 0 : SCLigCaretCheck(sc,false);
3665 :
3666 0 : CVUnlinkView(cv);
3667 0 : cv->p.nextcp = cv->p.prevcp = cv->widthsel = cv->vwidthsel = false;
3668 0 : if ( (CharView *) (sc->views)==NULL && updateflex )
3669 0 : SplineCharIsFlexible(sc,old_layer!=ly_grid ? old_layer : ly_fore );
3670 0 : cv->b.sc = sc;
3671 0 : cv->b.next = sc->views;
3672 0 : sc->views = &cv->b;
3673 0 : cv->enc = ( ((FontView *) (cv->b.fv))->b.map->backmap[cv->b.sc->orig_pos] );
3674 0 : cv->b.layerheads[dm_fore] = &sc->layers[ly_fore];
3675 0 : blayer = old_layer;
3676 0 : if ( old_layer==ly_grid || old_layer==ly_fore ||
3677 0 : sc->parent->multilayer || old_layer>=sc->layer_cnt )
3678 0 : blayer = ly_back;
3679 0 : cv->b.layerheads[dm_back] = &sc->layers[blayer];
3680 0 : cv->b.layerheads[dm_grid] = &sc->parent->grid;
3681 0 : cv->p.sp = cv->lastselpt = NULL;
3682 0 : cv->p.spiro = cv->lastselcp = NULL;
3683 0 : cv->apmine = cv->apmatch = NULL; cv->apsc = NULL;
3684 0 : cv->template1 = cv->template2 = NULL;
3685 : #if HANYANG
3686 : if ( cv->b.sc->parent->rules!=NULL && cv->b.sc->compositionunit )
3687 : Disp_DefaultTemplate(cv);
3688 : #endif
3689 0 : if ( cv->b.layerheads[cv->b.drawmode]->order2 )
3690 0 : CVCheckPoints(cv);
3691 0 : if ( cv->showpointnumbers || cv->show_ft_results )
3692 0 : SCNumberPoints(sc,old_layer);
3693 0 : if ( cv->show_ft_results )
3694 0 : CVGridFitChar(cv);
3695 :
3696 0 : CVNewScale(cv);
3697 :
3698 0 : CharIcon(cv,(FontView *) (cv->b.fv));
3699 0 : title = CVMakeTitles(cv,buf,sizeof(buf));
3700 0 : GDrawSetWindowTitles8(cv->gw,buf,title);
3701 0 : CVInfoDraw(cv,cv->gw);
3702 0 : free(title);
3703 0 : _CVPaletteActivate(cv,true);
3704 :
3705 0 : if ( cv->tabs!=NULL ) {
3706 0 : for ( i=0; i<cv->former_cnt; ++i )
3707 0 : if ( strcmp(cv->former_names[i],sc->name)==0 )
3708 0 : break;
3709 0 : if ( i!=cv->former_cnt && cv->showtabs )
3710 : {
3711 0 : CVChangeSC_storeTab( cv, cv->oldtabnum );
3712 0 : CVChangeSC_fetchTab( cv, i );
3713 0 : cv->oldtabnum = i;
3714 0 : GTabSetSetSel(cv->tabs,i);
3715 : }
3716 : else
3717 : {
3718 : // Only need to store here, as we are about to make a new tab.
3719 0 : CVChangeSC_storeTab( cv, cv->oldtabnum );
3720 0 : cv->oldtabnum = 0;
3721 : // have to shuffle the cvtabs along to be in sync with cv->tabs
3722 : {
3723 0 : int i = 0;
3724 0 : for( i=charview_cvtabssz-1; i > 0; i-- )
3725 : {
3726 0 : cv->cvtabs[i] = cv->cvtabs[i-1];
3727 : }
3728 : }
3729 0 : CVSetCharSelectorValueFromSC( cv, sc );
3730 :
3731 :
3732 :
3733 0 : if ( cv->former_cnt==FORMER_MAX )
3734 0 : free(cv->former_names[FORMER_MAX-1]);
3735 0 : for ( i=cv->former_cnt<FORMER_MAX?cv->former_cnt-1:FORMER_MAX-2; i>=0; --i )
3736 0 : cv->former_names[i+1] = cv->former_names[i];
3737 0 : cv->former_names[0] = copy(sc->name);
3738 0 : if ( cv->former_cnt<FORMER_MAX )
3739 0 : ++cv->former_cnt;
3740 0 : for ( i=0; i<cv->former_cnt; ++i )
3741 : {
3742 0 : if( i < charview_cvtabssz )
3743 : {
3744 0 : CharViewTab* t = &cv->cvtabs[i];
3745 0 : GTabSetChangeTabName(cv->tabs, t->charselected, i);
3746 : }
3747 : }
3748 :
3749 0 : GTabSetRemetric(cv->tabs);
3750 0 : GTabSetSetSel(cv->tabs,0); /* This does a redraw */
3751 0 : if ( !GGadgetIsVisible(cv->tabs) && cv->showtabs )
3752 0 : CVChangeTabsVisibility(cv,true);
3753 : }
3754 : }
3755 0 : if( !strcmp(GGadgetGetTitle8(cv->charselector),""))
3756 0 : CVSetCharSelectorValueFromSC( cv, sc );
3757 :
3758 0 : if ( sc->inspiro && !hasspiro() && !sc->parent->complained_about_spiros ) {
3759 0 : sc->parent->complained_about_spiros = true;
3760 : #ifdef _NO_LIBSPIRO
3761 : 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."));
3762 : #else
3763 0 : 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."));
3764 : #endif
3765 : }
3766 :
3767 0 : if ( was_fitted )
3768 0 : CVGridFitChar(cv);
3769 :
3770 : // Force any extra chars to be setup and drawn
3771 : GEvent e;
3772 0 : e.type=et_controlevent;
3773 0 : e.u.control.subtype = et_textchanged;
3774 0 : e.u.control.u.tf_changed.from_pulldown = 0;
3775 0 : CV_OnCharSelectorTextChanged( cv->charselector, &e );
3776 0 : }
3777 :
3778 0 : static void CVChangeChar(CharView *cv, int i )
3779 : {
3780 : SplineChar *sc;
3781 0 : SplineFont *sf = cv->b.sc->parent;
3782 0 : EncMap *map = ((FontView *) (cv->b.fv))->b.map;
3783 0 : int gid = i<0 || i>= map->enccount ? -2 : map->map[i];
3784 :
3785 0 : if ( sf->cidmaster!=NULL && !map->enc->is_compact ) {
3786 0 : SplineFont *cidmaster = sf->cidmaster;
3787 : int k;
3788 0 : for ( k=0; k<cidmaster->subfontcnt; ++k ) {
3789 0 : SplineFont *sf = cidmaster->subfonts[k];
3790 0 : if ( i<sf->glyphcnt && sf->glyphs[i]!=NULL )
3791 0 : break;
3792 : }
3793 0 : if ( k!=cidmaster->subfontcnt ) {
3794 0 : if ( cidmaster->subfonts[k] != sf ) {
3795 0 : sf = cidmaster->subfonts[k];
3796 0 : gid = ( i>=sf->glyphcnt ) ? -2 : i;
3797 : /* can't create a new glyph this way */
3798 : }
3799 : }
3800 : }
3801 0 : if ( gid == -2 )
3802 0 : return;
3803 0 : if ( gid==-1 || (sc = sf->glyphs[gid])==NULL ) {
3804 0 : sc = SFMakeChar(sf,map,i);
3805 0 : sc->inspiro = cv->b.sc->inspiro && hasspiro();
3806 : }
3807 :
3808 0 : if ( sc==NULL || (cv->b.sc == sc && cv->enc==i ))
3809 0 : return;
3810 0 : cv->map_of_enc = map;
3811 0 : cv->enc = i;
3812 0 : CVChangeSC(cv,sc);
3813 : }
3814 :
3815 : /*
3816 : * Unused
3817 : static void CVSwitchToTab(CharView *cv,int tnum ) {
3818 : if( tnum >= cv->former_cnt )
3819 : return;
3820 :
3821 : SplineFont *sf = cv->b.fv->sf;
3822 : char* n = cv->former_names[tnum];
3823 : int unienc = UniFromName(n,sf->uni_interp,cv->b.fv->map->enc);
3824 : CVChangeChar(cv,unienc);
3825 : }
3826 :
3827 : static void CVMenuShowTab(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
3828 : CharView *cv = (CharView *) GDrawGetUserData(gw);
3829 : CVSwitchToTab(cv,mi->mid);
3830 : }
3831 : */
3832 :
3833 0 : static int CVChangeToFormer( GGadget *g, GEvent *e) {
3834 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_radiochanged ) {
3835 0 : CharView *cv = GDrawGetUserData(GGadgetGetWindow(g));
3836 0 : int new_aspect = GTabSetGetSel(g);
3837 0 : SplineFont *sf = cv->b.sc->parent;
3838 : int gid;
3839 :
3840 0 : for ( gid=sf->glyphcnt-1; gid>=0; --gid )
3841 0 : if ( sf->glyphs[gid]!=NULL &&
3842 0 : strcmp(sf->glyphs[gid]->name,cv->former_names[new_aspect])==0 )
3843 0 : break;
3844 0 : if ( gid<0 ) {
3845 : /* They changed the name? See if we can get a unicode value from it */
3846 0 : int unienc = UniFromName(cv->former_names[new_aspect],sf->uni_interp,cv->b.fv->map->enc);
3847 0 : if ( unienc>=0 ) {
3848 0 : gid = SFFindGID(sf,unienc,cv->former_names[new_aspect]);
3849 0 : if ( gid>=0 ) {
3850 0 : free(cv->former_names[new_aspect]);
3851 0 : cv->former_names[new_aspect] = copy(sf->glyphs[gid]->name);
3852 : }
3853 : }
3854 : }
3855 0 : if ( gid<0 )
3856 0 : return( true );
3857 0 : CVChangeSC(cv,sf->glyphs[gid]);
3858 0 : cv->enc = ((FontView *) (cv->b.fv))->b.map->backmap[cv->b.sc->orig_pos];
3859 : }
3860 0 : return( true );
3861 : }
3862 :
3863 0 : static void CVFakeMove(CharView *cv, GEvent *event) {
3864 : GEvent e;
3865 :
3866 0 : memset(&e,0,sizeof(e));
3867 0 : e.type = et_mousemove;
3868 0 : e.w = cv->v;
3869 0 : if ( event->w!=cv->v ) {
3870 : GPoint p;
3871 0 : p.x = event->u.chr.x; p.y = event->u.chr.y;
3872 0 : GDrawTranslateCoordinates(event->w,cv->v,&p);
3873 0 : event->u.chr.x = p.x; event->u.chr.y = p.y;
3874 : }
3875 0 : e.u.mouse.state = TrueCharState(event);
3876 0 : e.u.mouse.x = event->u.chr.x;
3877 0 : e.u.mouse.y = event->u.chr.y;
3878 0 : e.u.mouse.device = NULL;
3879 0 : CVMouseMove(cv,&e);
3880 0 : }
3881 :
3882 0 : static void CVDoFindInFontView(CharView *cv) {
3883 0 : FVChangeChar((FontView *) (cv->b.fv),CVCurEnc(cv));
3884 0 : GDrawSetVisible(((FontView *) (cv->b.fv))->gw,true);
3885 0 : GDrawRaise(((FontView *) (cv->b.fv))->gw);
3886 0 : }
3887 :
3888 : static uint16 HaveModifiers = 0;
3889 : static uint16 PressingTilde = 0;
3890 : static uint16 PrevCharEventWasCharUpOnControl = 0;
3891 :
3892 :
3893 0 : static void CVCharUp(CharView *cv, GEvent *event ) {
3894 :
3895 0 : if ( !event->u.chr.autorepeat && !HaveModifiers && event->u.chr.keysym==' ' ) {
3896 0 : update_spacebar_hand_tool(cv);
3897 : }
3898 :
3899 0 : int oldactiveModifierControl = cv->activeModifierControl;
3900 0 : int oldactiveModifierAlt = cv->activeModifierAlt;
3901 0 : cv->activeModifierControl &= ~( event->u.chr.keysym == GK_Control_L || event->u.chr.keysym == GK_Control_R
3902 0 : || event->u.chr.keysym == GK_Meta_L || event->u.chr.keysym == GK_Meta_R );
3903 0 : cv->activeModifierAlt &= ~( event->u.chr.keysym == GK_Alt_L || event->u.chr.keysym == GK_Alt_R
3904 0 : || event->u.chr.keysym == XK_Mode_switch );
3905 : // helps with keys on the mac
3906 0 : if( (event->u.chr.state&ksm_meta) )
3907 0 : cv->activeModifierAlt = 0;
3908 0 : if( oldactiveModifierControl != cv->activeModifierControl
3909 0 : || oldactiveModifierAlt != cv->activeModifierAlt )
3910 : {
3911 0 : CVInfoDraw(cv,cv->gw);
3912 : }
3913 :
3914 :
3915 :
3916 : // TRACE("CVCharUp() ag:%d key:%d\n", cv_auto_goto, event->u.chr.keysym );
3917 0 : if( !cv_auto_goto )
3918 : {
3919 0 : bool isImmediateKeyTogglePreview = isImmediateKey( cv->gw, "TogglePreview", event ) != NULL;
3920 0 : if( isImmediateKeyTogglePreview ) {
3921 0 : PressingTilde = 1;
3922 : }
3923 :
3924 0 : if( PrevCharEventWasCharUpOnControl && isImmediateKeyTogglePreview )
3925 : {
3926 0 : HaveModifiers = 0;
3927 0 : PrevCharEventWasCharUpOnControl = 0;
3928 0 : return;
3929 : }
3930 0 : PrevCharEventWasCharUpOnControl = 0;
3931 :
3932 0 : if( !event->u.chr.autorepeat
3933 0 : && (event->u.chr.keysym == GK_Control_L
3934 0 : || event->u.chr.keysym == GK_Control_R ))
3935 : {
3936 0 : PrevCharEventWasCharUpOnControl = 1;
3937 0 : if( !PressingTilde ) {
3938 0 : HaveModifiers = 0;
3939 : }
3940 : }
3941 :
3942 0 : if ( !event->u.chr.autorepeat && !HaveModifiers && isImmediateKeyTogglePreview ) {
3943 0 : PressingTilde = 0;
3944 0 : CVPreviewModeSet( cv->gw, false );
3945 0 : return;
3946 : }
3947 :
3948 0 : if ( !event->u.chr.autorepeat && isImmediateKeyTogglePreview ) {
3949 0 : PressingTilde = 0;
3950 : }
3951 0 : if ( event->u.chr.autorepeat && HaveModifiers && isImmediateKeyTogglePreview ) {
3952 0 : return;
3953 : }
3954 : }
3955 :
3956 :
3957 0 : if( event->u.chr.keysym == XK_Escape )
3958 : {
3959 : TRACE("escape char.......!\n");
3960 0 : GGadget *active = GWindowGetFocusGadgetOfWindow(cv->gw);
3961 0 : if( active == cv->charselector )
3962 : {
3963 : TRACE("was on charselector\n");
3964 0 : GWidgetIndicateFocusGadget( cv->hsb );
3965 : }
3966 0 : else if ( cv->charselector != NULL )
3967 : {
3968 : TRACE("was on NOT charselector\n");
3969 0 : GWidgetIndicateFocusGadget( cv->charselector );
3970 : }
3971 : }
3972 :
3973 :
3974 : #if _ModKeysAutoRepeat
3975 : /* Under cygwin these keys auto repeat, they don't under normal X */
3976 : if ( event->u.chr.keysym == GK_Shift_L || event->u.chr.keysym == GK_Shift_R ||
3977 : event->u.chr.keysym == GK_Control_L || event->u.chr.keysym == GK_Control_R ||
3978 : event->u.chr.keysym == GK_Meta_L || event->u.chr.keysym == GK_Meta_R ||
3979 : event->u.chr.keysym == GK_Alt_L || event->u.chr.keysym == GK_Alt_R ||
3980 : event->u.chr.keysym == GK_Super_L || event->u.chr.keysym == GK_Super_R ||
3981 : event->u.chr.keysym == GK_Hyper_L || event->u.chr.keysym == GK_Hyper_R ) {
3982 : if ( cv->autorpt!=NULL ) {
3983 : GDrawCancelTimer(cv->autorpt);
3984 : CVToolsSetCursor(cv,cv->oldstate,NULL);
3985 : }
3986 : cv->keysym = event->u.chr.keysym;
3987 : cv->oldkeyx = event->u.chr.x;
3988 : cv->oldkeyy = event->u.chr.y;
3989 : cv->oldkeyw = event->w;
3990 : cv->oldstate = TrueCharState(event);
3991 : cv->autorpt = GDrawRequestTimer(cv->v,100,0,NULL);
3992 : } else {
3993 : if ( cv->autorpt!=NULL ) {
3994 : GDrawCancelTimer(cv->autorpt); cv->autorpt=NULL;
3995 : CVToolsSetCursor(cv,cv->oldstate,NULL);
3996 : }
3997 : CVToolsSetCursor(cv,TrueCharState(event),NULL);
3998 : }
3999 : #else
4000 0 : CVToolsSetCursor(cv,TrueCharState(event),NULL);
4001 0 : if ( event->u.chr.keysym == GK_Shift_L || event->u.chr.keysym == GK_Shift_R ||
4002 0 : event->u.chr.keysym == GK_Alt_L || event->u.chr.keysym == GK_Alt_R ||
4003 0 : event->u.chr.keysym == GK_Meta_L || event->u.chr.keysym == GK_Meta_R )
4004 0 : CVFakeMove(cv, event);
4005 : #endif
4006 : }
4007 :
4008 0 : void CVInfoDrawText(CharView *cv, GWindow pixmap ) {
4009 : GRect r;
4010 0 : Color bg = GDrawGetDefaultBackground(GDrawGetDisplayOfWindow(pixmap));
4011 0 : Color fg = GDrawGetDefaultForeground(GDrawGetDisplayOfWindow(pixmap));
4012 0 : const int buffersz = 150;
4013 0 : char buffer[buffersz+1];
4014 0 : int ybase = cv->mbh+cv->charselectorh+(cv->infoh-cv->sfh)/2+cv->sas;
4015 : real xdiff, ydiff;
4016 : SplinePoint *sp, dummy;
4017 : spiro_cp *cp;
4018 :
4019 0 : GDrawSetFont(pixmap,cv->small);
4020 0 : r.x = RPT_DATA; r.width = SPT_BASE-RPT_DATA;
4021 0 : r.y = cv->mbh+cv->charselectorh; r.height = cv->infoh-1;
4022 0 : GDrawFillRect(pixmap,&r,bg);
4023 0 : r.x = SPT_DATA; r.width = SOF_BASE-SPT_DATA;
4024 0 : GDrawFillRect(pixmap,&r,bg);
4025 0 : r.x = SOF_DATA; r.width = SDS_BASE-SOF_DATA;
4026 0 : GDrawFillRect(pixmap,&r,bg);
4027 0 : r.x = SDS_DATA; r.width = SAN_BASE-SDS_DATA;
4028 0 : GDrawFillRect(pixmap,&r,bg);
4029 0 : r.x = SAN_DATA; r.width = MAG_BASE-SAN_DATA;
4030 0 : GDrawFillRect(pixmap,&r,bg);
4031 0 : r.x = MAG_DATA; r.width = LAYER_DATA-MAG_DATA;
4032 0 : GDrawFillRect(pixmap,&r,bg);
4033 0 : r.x = LAYER_DATA; r.width = CODERANGE_DATA-LAYER_DATA;
4034 0 : GDrawFillRect(pixmap,&r,bg);
4035 0 : r.x = CODERANGE_DATA; r.width = FLAGS_DATA-CODERANGE_DATA;
4036 0 : GDrawFillRect(pixmap,&r,bg);
4037 0 : r.x = FLAGS_DATA; r.width = 200;
4038 0 : GDrawFillRect(pixmap,&r,bg);
4039 :
4040 0 : if ( cv->info_within ) {
4041 0 : if ( cv->info.x>=1000 || cv->info.x<=-1000 || cv->info.y>=1000 || cv->info.y<=-1000 )
4042 0 : sprintf(buffer,"%d%s%d", (int) cv->info.x, coord_sep, (int) cv->info.y );
4043 : else
4044 0 : sprintf(buffer,"%.4g%s%.4g", (double) cv->info.x, coord_sep, (double) cv->info.y );
4045 0 : buffer[11] = '\0';
4046 0 : GDrawDrawText8(pixmap,RPT_DATA,ybase,buffer,-1,fg);
4047 : }
4048 0 : if ( cv->scale>=.25 )
4049 0 : sprintf( buffer, "%d%%", (int) (100*cv->scale));
4050 : else
4051 0 : sprintf( buffer, "%.3g%%", (double) (100*cv->scale));
4052 0 : GDrawDrawText8(pixmap,MAG_DATA,ybase,buffer,-1,fg);
4053 :
4054 0 : const int layernamesz = 100;
4055 0 : char layername[layernamesz+1];
4056 0 : strncpy(layername,_("Guide"),layernamesz);
4057 0 : if(cv->b.drawmode!=dm_grid) {
4058 0 : int idx = CVLayer((CharViewBase *) cv);
4059 0 : if(idx >= 0 && idx < cv->b.sc->parent->layer_cnt) {
4060 0 : strncpy(layername,cv->b.sc->parent->layers[idx].name,layernamesz);
4061 : }
4062 : }
4063 0 : snprintf( buffer, buffersz, _("Active Layer: %s (%s)"),
4064 0 : layername,
4065 : /* GT: Guide layer, make it short */
4066 0 : ( cv->b.drawmode==dm_grid ? _("Guide") :
4067 : /* GT: Background, make it short */
4068 0 : cv->b.layerheads[cv->b.drawmode]->background ? _("Back") :
4069 : /* GT: Foreground, make it short */
4070 : _("Fore") )
4071 : );
4072 0 : GDrawDrawText8(pixmap,LAYER_DATA,ybase,buffer,-1,fg);
4073 0 : GDrawDrawText8(pixmap,LAYER_DATA,ybase,buffer,-1,fg);
4074 :
4075 0 : if ( cv->coderange==cr_none )
4076 : {
4077 0 : snprintf( buffer, buffersz, _("Modes: "));
4078 0 : if( CVShouldInterpolateCPsOnMotion(cv) )
4079 0 : strcat( buffer, "Interpolate" );
4080 0 : GDrawDrawText8(pixmap,FLAGS_DATA,ybase,buffer,-1,fg);
4081 : }
4082 :
4083 :
4084 0 : if ( cv->coderange!=cr_none ) {
4085 0 : GDrawDrawText8(pixmap,CODERANGE_DATA,ybase,
4086 0 : cv->coderange==cr_fpgm ? _("'fpgm'") :
4087 0 : cv->coderange==cr_prep ? _("'prep'") : _("Glyph"),
4088 : -1,fg);
4089 0 : GDrawDrawText8(pixmap,CODERANGE_DATA+40,ybase,
4090 0 : FreeTypeStringVersion(), -1,fg);
4091 : }
4092 0 : sp = NULL; cp = NULL;
4093 0 : if ( cv->b.sc->inspiro && hasspiro())
4094 0 : cp = cv->p.spiro!=NULL ? cv->p.spiro : cv->lastselcp;
4095 : else
4096 0 : sp = cv->p.sp!=NULL ? cv->p.sp : cv->lastselpt;
4097 0 : if ( sp==NULL && cp==NULL )
4098 0 : if ( cv->active_tool==cvt_rect || cv->active_tool==cvt_elipse ||
4099 0 : cv->active_tool==cvt_poly || cv->active_tool==cvt_star ||
4100 0 : cv->active_tool==cvt_scale || cv->active_tool==cvt_skew ||
4101 0 : cv->active_tool==cvt_rotate || cv->active_tool==cvt_flip ) {
4102 0 : dummy.me.x = cv->p.cx; dummy.me.y = cv->p.cy;
4103 0 : sp = &dummy;
4104 : }
4105 0 : if ( sp || cp ) {
4106 : real selx, sely;
4107 0 : if ( sp ) {
4108 0 : if ( cv->pressed && sp==cv->p.sp ) {
4109 0 : selx = cv->p.constrain.x;
4110 0 : sely = cv->p.constrain.y;
4111 : } else {
4112 0 : selx = sp->me.x;
4113 0 : sely = sp->me.y;
4114 : }
4115 : } else {
4116 0 : selx = cp->x;
4117 0 : sely = cp->y;
4118 : }
4119 0 : xdiff=cv->info.x-selx;
4120 0 : ydiff = cv->info.y-sely;
4121 :
4122 0 : if ( selx>=1000 || selx<=-1000 || sely>=1000 || sely<=-1000 )
4123 0 : sprintf(buffer,"%d%s%d", (int) selx, coord_sep, (int) sely );
4124 : else
4125 0 : sprintf(buffer,"%.4g%s%.4g", (double) selx, coord_sep, (double) sely );
4126 0 : buffer[11] = '\0';
4127 0 : GDrawDrawText8(pixmap,SPT_DATA,ybase,buffer,-1,fg);
4128 0 : } else if ( cv->widthsel && cv->info_within ) {
4129 0 : xdiff = cv->info.x-cv->p.cx;
4130 0 : ydiff = 0;
4131 0 : } else if ( cv->p.rubberbanding && cv->info_within ) {
4132 0 : xdiff=cv->info.x-cv->p.cx;
4133 0 : ydiff = cv->info.y-cv->p.cy;
4134 : } else
4135 0 : return;
4136 0 : if ( !cv->info_within )
4137 0 : return;
4138 :
4139 0 : if ( cv->active_tool==cvt_scale ) {
4140 0 : xdiff = 100.0 + (cv->info.x-cv->p.cx)/(4*cv->scale);
4141 0 : ydiff = 100.0 + (cv->info.y-cv->p.cy)/(4*cv->scale);
4142 0 : if ( xdiff>=100 || xdiff<=-100 || ydiff>=100 || ydiff<=-100 )
4143 0 : sprintf(buffer,"%d%%%s%d%%", (int) xdiff, coord_sep, (int) ydiff );
4144 : else
4145 0 : sprintf(buffer,"%.3g%%%s%.3g%%", (double) xdiff, coord_sep, (double) ydiff );
4146 0 : } else if ( xdiff>=1000 || xdiff<=-1000 || ydiff>=1000 || ydiff<=-1000 )
4147 0 : sprintf(buffer,"%d%s%d", (int) xdiff, coord_sep, (int) ydiff );
4148 : else
4149 0 : sprintf(buffer,"%.4g%s%.4g", (double) xdiff, coord_sep, (double) ydiff );
4150 0 : buffer[11] = '\0';
4151 0 : GDrawDrawText8(pixmap,SOF_DATA,ybase,buffer,-1,fg);
4152 :
4153 0 : sprintf( buffer, "%.1f", sqrt(xdiff*xdiff+ydiff*ydiff));
4154 0 : GDrawDrawText8(pixmap,SDS_DATA,ybase,buffer,-1,fg);
4155 :
4156 : /* Utf-8 for degree sign */
4157 0 : sprintf( buffer, "%d\302\260", (int) rint(180*atan2(ydiff,xdiff)/3.1415926535897932));
4158 0 : GDrawDrawText8(pixmap,SAN_DATA,ybase,buffer,-1,fg);
4159 : }
4160 :
4161 0 : static void CVInfoDrawRulers(CharView *cv, GWindow pixmap ) {
4162 0 : int rstart = cv->mbh+cv->charselectorh+cv->infoh;
4163 0 : GDrawSetXORMode(pixmap);
4164 0 : GDrawSetXORBase(pixmap,GDrawGetDefaultBackground(NULL));
4165 0 : GDrawSetLineWidth(pixmap,0);
4166 0 : if ( cv->olde.x!=-1 ) {
4167 0 : GDrawDrawLine(pixmap,cv->olde.x+cv->rulerh,rstart,cv->olde.x+cv->rulerh,rstart+cv->rulerh,0xff0000);
4168 0 : GDrawDrawLine(pixmap,0,cv->olde.y+rstart+cv->rulerh,cv->rulerh,cv->olde.y+rstart+cv->rulerh,0xff0000);
4169 : }
4170 0 : GDrawDrawLine(pixmap,cv->e.x+cv->rulerh,rstart,cv->e.x+cv->rulerh,rstart+cv->rulerh,0xff0000);
4171 0 : GDrawDrawLine(pixmap,0,cv->e.y+rstart+cv->rulerh,cv->rulerh,cv->e.y+rstart+cv->rulerh,0xff0000);
4172 0 : cv->olde = cv->e;
4173 0 : GDrawSetCopyMode(pixmap);
4174 0 : }
4175 :
4176 0 : void CVInfoDraw(CharView *cv, GWindow pixmap ) {
4177 0 : CVInfoDrawText(cv,pixmap);
4178 0 : if ( cv->showrulers )
4179 0 : CVInfoDrawRulers(cv,pixmap);
4180 0 : }
4181 :
4182 0 : static void CVCrossing(CharView *cv, GEvent *event ) {
4183 0 : CVToolsSetCursor(cv,event->u.mouse.state,event->u.mouse.device);
4184 0 : cv->info_within = event->u.crossing.entered;
4185 0 : cv->info.x = (event->u.crossing.x-cv->xoff)/cv->scale;
4186 0 : cv->info.y = (cv->height-event->u.crossing.y-cv->yoff)/cv->scale;
4187 0 : CVInfoDraw(cv,cv->gw);
4188 0 : CPEndInfo(cv);
4189 0 : }
4190 :
4191 0 : static int CheckSpiroPoint(FindSel *fs, spiro_cp *cp, SplineSet *spl,int index) {
4192 :
4193 0 : if ( fs->xl<=cp->x && fs->xh>=cp->x &&
4194 0 : fs->yl<=cp->y && fs->yh >= cp->y ) {
4195 0 : fs->p->spiro = cp;
4196 0 : fs->p->spline = NULL;
4197 0 : fs->p->anysel = true;
4198 0 : fs->p->spl = spl;
4199 0 : fs->p->spiro_index = index;
4200 0 : return( true );
4201 : }
4202 0 : return( false );
4203 : }
4204 :
4205 0 : static int CheckPoint(FindSel *fs, SplinePoint *sp, SplineSet *spl) {
4206 :
4207 0 : if ( fs->xl<=sp->me.x && fs->xh>=sp->me.x &&
4208 0 : fs->yl<=sp->me.y && fs->yh >= sp->me.y ) {
4209 0 : fs->p->sp = sp;
4210 0 : fs->p->spline = NULL;
4211 0 : fs->p->anysel = true;
4212 0 : fs->p->spl = spl;
4213 0 : if ( !fs->seek_controls )
4214 0 : return( true );
4215 : }
4216 0 : if ( (sp->selected && fs->select_controls)
4217 0 : || fs->all_controls
4218 0 : || fs->alwaysshowcontrolpoints )
4219 : {
4220 0 : int seln=false, selp=false;
4221 0 : if ( fs->c_xl<=sp->nextcp.x && fs->c_xh>=sp->nextcp.x &&
4222 0 : fs->c_yl<=sp->nextcp.y && fs->c_yh >= sp->nextcp.y )
4223 0 : seln = true;
4224 0 : if ( fs->c_xl<=sp->prevcp.x && fs->c_xh>=sp->prevcp.x &&
4225 0 : fs->c_yl<=sp->prevcp.y && fs->c_yh >= sp->prevcp.y )
4226 0 : selp = true;
4227 0 : if ( seln && selp ) {
4228 : /* Select the one with a spline attached. */
4229 0 : if ( sp->prev!=NULL && sp->next==NULL )
4230 0 : seln = false;
4231 : }
4232 0 : if ( seln ) {
4233 0 : fs->p->sp = sp;
4234 0 : fs->p->spline = NULL;
4235 0 : fs->p->spl = spl;
4236 0 : fs->p->nextcp = true;
4237 0 : fs->p->anysel = true;
4238 0 : fs->p->cp = sp->nextcp;
4239 0 : if ( sp->nonextcp && (sp->pointtype==pt_curve || sp->pointtype==pt_hvcurve)) {
4240 0 : fs->p->cp.x = sp->me.x + (sp->me.x-sp->prevcp.x);
4241 0 : fs->p->cp.y = sp->me.y + (sp->me.y-sp->prevcp.y);
4242 : }
4243 0 : sp->selected = true;
4244 0 : sp->nextcpselected = true;
4245 0 : return( true );
4246 0 : } else if ( selp ) {
4247 0 : fs->p->sp = sp;
4248 0 : fs->p->spline = NULL;
4249 0 : fs->p->spl = spl;
4250 0 : fs->p->prevcp = true;
4251 0 : fs->p->anysel = true;
4252 0 : fs->p->cp = sp->prevcp;
4253 0 : if ( sp->noprevcp && (sp->pointtype==pt_curve || sp->pointtype==pt_hvcurve)) {
4254 0 : fs->p->cp.x = sp->me.x + (sp->me.x-sp->nextcp.x);
4255 0 : fs->p->cp.y = sp->me.y + (sp->me.y-sp->nextcp.y);
4256 : }
4257 0 : sp->selected = true;
4258 0 : sp->prevcpselected = true;
4259 0 : return( true );
4260 : }
4261 : }
4262 0 : return( false );
4263 : }
4264 :
4265 0 : static int CheckSpline(FindSel *fs, Spline *spline, SplineSet *spl) {
4266 :
4267 : /* Anything else is better than a spline */
4268 0 : if ( fs->p->anysel )
4269 0 : return( false );
4270 :
4271 0 : if ( NearSpline(fs,spline)) {
4272 0 : fs->p->spline = spline;
4273 0 : fs->p->spl = spl;
4274 0 : fs->p->anysel = true;
4275 0 : fs->p->spiro_index = SplineT2SpiroIndex(spline,fs->p->t,spl);
4276 0 : return( false /*true*/ ); /* Check if there's a point where we are first */
4277 : /* if there is use it, if not (because anysel is true) we'll fall back */
4278 : /* here */
4279 : }
4280 :
4281 0 : return( false );
4282 : }
4283 :
4284 0 : static int InImage( FindSel *fs, ImageList *img) {
4285 : int x,y;
4286 :
4287 0 : x = floor((fs->p->cx-img->xoff)/img->xscale);
4288 0 : y = floor((img->yoff-fs->p->cy)/img->yscale);
4289 0 : if ( x<0 || y<0 || x>=GImageGetWidth(img->image) || y>=GImageGetHeight(img->image))
4290 0 : return ( false );
4291 0 : if ( GImageGetPixelRGBA(img->image,x,y)<0x80000000 ) /* Transparent(ish) */
4292 0 : return( false );
4293 :
4294 0 : return( true );
4295 : }
4296 :
4297 0 : static int InSplineSet( FindSel *fs, SplinePointList *set,int inspiro) {
4298 : SplinePointList *spl;
4299 : Spline *spline, *first;
4300 : int i;
4301 :
4302 0 : for ( spl = set; spl!=NULL; spl = spl->next ) {
4303 0 : if ( inspiro ) {
4304 0 : for ( i=0; i<spl->spiro_cnt-1; ++i )
4305 0 : if ( CheckSpiroPoint(fs,&spl->spiros[i],spl,i))
4306 0 : return( true );
4307 0 : first = NULL;
4308 0 : for ( spline = spl->first->next; spline!=NULL && spline!=first; spline=spline->to->next ) {
4309 0 : if ( CheckSpline(fs,spline,spl), fs->p->anysel )
4310 0 : return( true );
4311 0 : if ( first==NULL ) first = spline;
4312 : }
4313 : } else {
4314 0 : if ( CheckPoint(fs,spl->first,spl) && ( !fs->seek_controls || fs->p->nextcp || fs->p->prevcp )) {
4315 0 : return( true );
4316 : }
4317 0 : first = NULL;
4318 0 : for ( spline = spl->first->next; spline!=NULL && spline!=first; spline=spline->to->next ) {
4319 0 : if ( (CheckPoint(fs,spline->to,spl) && ( !fs->seek_controls || fs->p->nextcp || fs->p->prevcp )) ||
4320 0 : ( CheckSpline(fs,spline,spl) && !fs->seek_controls )) {
4321 0 : return( true );
4322 : }
4323 0 : if ( first==NULL ) first = spline;
4324 : }
4325 : }
4326 : }
4327 0 : return( fs->p->anysel );
4328 : }
4329 :
4330 0 : static int NearSplineSetPoints( FindSel *fs, SplinePointList *set,int inspiro) {
4331 : SplinePointList *spl;
4332 : Spline *spline, *first;
4333 : int i;
4334 :
4335 0 : for ( spl = set; spl!=NULL; spl = spl->next ) {
4336 0 : if ( inspiro ) {
4337 0 : for ( i=0; i<spl->spiro_cnt; ++i )
4338 0 : if ( CheckSpiroPoint(fs,&spl->spiros[i],spl,i))
4339 0 : return( true );
4340 : } else {
4341 0 : if ( CheckPoint(fs,spl->first,spl)) {
4342 0 : return( true );
4343 : }
4344 0 : first = NULL;
4345 0 : for ( spline = spl->first->next; spline!=NULL && spline!=first; spline=spline->to->next ) {
4346 0 : if ( CheckPoint(fs,spline->to,spl) ) {
4347 0 : return( true );
4348 : }
4349 0 : if ( first==NULL ) first = spline;
4350 : }
4351 : }
4352 : }
4353 0 : return( fs->p->anysel );
4354 : }
4355 :
4356 0 : static int16 MouseToCX( CharView *cv, int16 mx )
4357 : {
4358 0 : return( mx - cv->xoff ) / cv->scale;
4359 : }
4360 :
4361 :
4362 0 : static void SetFS( FindSel *fs, PressedOn *p, CharView *cv, GEvent *event) {
4363 : extern int snaptoint;
4364 :
4365 0 : memset(p,'\0',sizeof(PressedOn));
4366 0 : p->pressed = true;
4367 :
4368 0 : memset(fs,'\0',sizeof(*fs));
4369 0 : fs->p = p;
4370 0 : fs->e = event;
4371 0 : p->x = event->u.mouse.x;
4372 0 : p->y = event->u.mouse.y;
4373 0 : p->cx = (event->u.mouse.x-cv->xoff)/cv->scale;
4374 0 : p->cy = (cv->height-event->u.mouse.y-cv->yoff)/cv->scale;
4375 :
4376 0 : fs->fudge = (cv->active_tool==cvt_ruler ? snapdistancemeasuretool : snapdistance)/cv->scale;
4377 :
4378 : /* If they have really large control points then expand
4379 : * the selection range to allow them to still click on the
4380 : * very edge of the control point to select it.
4381 : */
4382 0 : if( prefs_cvEditHandleSize > prefs_cvEditHandleSize_default )
4383 : {
4384 0 : float delta = (prefs_cvEditHandleSize - prefs_cvEditHandleSize_default) / cv->scale;
4385 0 : delta *= 1.5;
4386 0 : fs->fudge += delta;
4387 : }
4388 :
4389 0 : fs->c_xl = fs->xl = p->cx - fs->fudge;
4390 0 : fs->c_xh = fs->xh = p->cx + fs->fudge;
4391 0 : fs->c_yl = fs->yl = p->cy - fs->fudge;
4392 0 : fs->c_yh = fs->yh = p->cy + fs->fudge;
4393 0 : if ( snaptoint ) {
4394 0 : p->cx = rint(p->cx);
4395 0 : p->cy = rint(p->cy);
4396 0 : if ( fs->xl>p->cx - fs->fudge )
4397 0 : fs->xl = p->cx - fs->fudge;
4398 0 : if ( fs->xh < p->cx + fs->fudge )
4399 0 : fs->xh = p->cx + fs->fudge;
4400 0 : if ( fs->yl>p->cy - fs->fudge )
4401 0 : fs->yl = p->cy - fs->fudge;
4402 0 : if ( fs->yh < p->cy + fs->fudge )
4403 0 : fs->yh = p->cy + fs->fudge;
4404 : }
4405 0 : }
4406 :
4407 0 : int CVMouseAtSpline(CharView *cv,GEvent *event) {
4408 : FindSel fs;
4409 0 : int pressed = cv->p.pressed;
4410 :
4411 0 : SetFS(&fs,&cv->p,cv,event);
4412 0 : cv->p.pressed = pressed;
4413 0 : return( InSplineSet(&fs,cv->b.layerheads[cv->b.drawmode]->splines,cv->b.sc->inspiro && hasspiro()));
4414 : }
4415 :
4416 0 : static GEvent *CVConstrainedMouseDown(CharView *cv,GEvent *event, GEvent *fake) {
4417 : SplinePoint *base;
4418 : spiro_cp *basecp;
4419 : int basex, basey, dx, dy;
4420 : double basetruex, basetruey;
4421 : int sign;
4422 :
4423 0 : if ( !CVAnySelPoint(cv,&base,&basecp))
4424 0 : return( event );
4425 :
4426 0 : if ( base!=NULL ) {
4427 0 : basetruex = base->me.x;
4428 0 : basetruey = base->me.y;
4429 : } else {
4430 0 : basetruex = basecp->x;
4431 0 : basetruey = basecp->y;
4432 : }
4433 0 : basex = cv->xoff + rint(basetruex*cv->scale);
4434 0 : basey = -cv->yoff + cv->height - rint(basetruey*cv->scale);
4435 :
4436 0 : dx= event->u.mouse.x-basex, dy = event->u.mouse.y-basey;
4437 0 : sign = dx*dy<0?-1:1;
4438 :
4439 0 : fake->u.mouse = event->u.mouse;
4440 0 : if ( dx<0 ) dx = -dx; if ( dy<0 ) dy = -dy;
4441 0 : if ( dy >= 2*dx ) {
4442 0 : cv->p.x = fake->u.mouse.x = basex;
4443 0 : cv->p.cx = basetruex ;
4444 0 : if ( !(event->u.mouse.state&ksm_meta) &&
4445 0 : ItalicConstrained && cv->b.sc->parent->italicangle!=0 ) {
4446 0 : double off = tan(cv->b.sc->parent->italicangle*3.1415926535897932/180)*
4447 0 : (cv->p.cy-basetruey);
4448 0 : double aoff = off<0 ? -off : off;
4449 0 : if ( dx>=aoff*cv->scale/2 && (event->u.mouse.x-basex<0)!=(off<0) ) {
4450 0 : cv->p.cx -= off;
4451 0 : cv->p.x = fake->u.mouse.x = cv->xoff + rint(cv->p.cx*cv->scale);
4452 : }
4453 : }
4454 0 : } else if ( dx >= 2*dy ) {
4455 0 : fake->u.mouse.y = basey;
4456 0 : cv->p.cy = basetruey;
4457 0 : } else if ( dx > dy ) {
4458 0 : fake->u.mouse.x = basex + sign * (event->u.mouse.y-cv->p.y);
4459 0 : cv->p.cx = basetruex - sign * (cv->p.cy-basetruey);
4460 : } else {
4461 0 : fake->u.mouse.y = basey + sign * (event->u.mouse.x-cv->p.x);
4462 0 : cv->p.cy = basetruey - sign * (cv->p.cx-basetruex);
4463 : }
4464 :
4465 0 : return( fake );
4466 : }
4467 :
4468 0 : static void CVSetConstrainPoint(CharView *cv, GEvent *event) {
4469 : SplineSet *sel;
4470 :
4471 0 : if ( (sel = CVAnySelPointList(cv))!=NULL ) {
4472 0 : if ( sel->first->selected ) cv->p.constrain = sel->first->me;
4473 0 : else cv->p.constrain = sel->last->me;
4474 0 : } else if ( cv->p.sp!=NULL ) {
4475 0 : cv->p.constrain = cv->p.sp->me;
4476 : } else {
4477 0 : cv->p.constrain.x = cv->info.x;
4478 0 : cv->p.constrain.y = cv->info.y;
4479 : }
4480 0 : }
4481 :
4482 0 : static void CVDoSnaps(CharView *cv, FindSel *fs) {
4483 0 : PressedOn *p = fs->p;
4484 :
4485 0 : if ( cv->b.drawmode!=dm_grid && cv->b.layerheads[dm_grid]->splines!=NULL ) {
4486 : PressedOn temp;
4487 0 : int oldseek = fs->seek_controls;
4488 0 : temp = *p;
4489 0 : fs->p = &temp;
4490 0 : fs->seek_controls = false;
4491 0 : if ( InSplineSet( fs, cv->b.layerheads[dm_grid]->splines,cv->b.sc->inspiro && hasspiro())) {
4492 0 : if ( temp.spline!=NULL ) {
4493 0 : p->cx = ((temp.spline->splines[0].a*temp.t+
4494 0 : temp.spline->splines[0].b)*temp.t+
4495 0 : temp.spline->splines[0].c)*temp.t+
4496 0 : temp.spline->splines[0].d;
4497 0 : p->cy = ((temp.spline->splines[1].a*temp.t+
4498 0 : temp.spline->splines[1].b)*temp.t+
4499 0 : temp.spline->splines[1].c)*temp.t+
4500 0 : temp.spline->splines[1].d;
4501 0 : } else if ( temp.sp!=NULL ) {
4502 0 : p->cx = temp.sp->me.x;
4503 0 : p->cy = temp.sp->me.y;
4504 : }
4505 : }
4506 0 : fs->p = p;
4507 0 : fs->seek_controls = oldseek;
4508 : }
4509 0 : if ( p->cx>-fs->fudge && p->cx<fs->fudge )
4510 0 : p->cx = 0;
4511 0 : else if ( p->cx>cv->b.sc->width-fs->fudge && p->cx<cv->b.sc->width+fs->fudge &&
4512 0 : !cv->widthsel)
4513 0 : p->cx = cv->b.sc->width;
4514 0 : else if ( cv->widthsel && p!=&cv->p &&
4515 0 : p->cx>cv->oldwidth-fs->fudge && p->cx<cv->oldwidth+fs->fudge )
4516 0 : p->cx = cv->oldwidth;
4517 0 : if ( p->cy>-fs->fudge && p->cy<fs->fudge )
4518 0 : p->cy = 0;
4519 0 : }
4520 :
4521 0 : static int _CVTestSelectFromEvent(CharView *cv,FindSel *fs) {
4522 : PressedOn temp;
4523 : ImageList *img;
4524 : int found;
4525 :
4526 0 : found = InSplineSet(fs,cv->b.layerheads[cv->b.drawmode]->splines,cv->b.sc->inspiro && hasspiro());
4527 :
4528 0 : if ( !found ) {
4529 : RefChar *rf;
4530 0 : temp = cv->p;
4531 0 : fs->p = &temp;
4532 0 : fs->seek_controls = false;
4533 0 : for ( rf=cv->b.layerheads[cv->b.drawmode]->refs; rf!=NULL; rf = rf->next ) {
4534 0 : if ( InSplineSet(fs,rf->layers[0].splines,cv->b.sc->inspiro && hasspiro())) {
4535 0 : cv->p.ref = rf;
4536 0 : cv->p.anysel = true;
4537 0 : break;
4538 : }
4539 : }
4540 0 : if ( cv->b.drawmode==dm_fore && ( cv->showanchor && !cv->p.anysel )) {
4541 0 : AnchorPoint *ap, *found=NULL;
4542 : /* I do this pecular search because: */
4543 : /* 1) I expect there to be lots of times we get multiple */
4544 : /* anchors at the same location */
4545 : /* 2) The anchor points are drawn so that the bottommost */
4546 : /* is displayed */
4547 0 : for ( ap=cv->b.sc->anchor; ap!=NULL; ap=ap->next )
4548 0 : if ( fs->xl<=ap->me.x && fs->xh>=ap->me.x &&
4549 0 : fs->yl<=ap->me.y && fs->yh >= ap->me.y )
4550 0 : found = ap;
4551 0 : if ( found!=NULL ) {
4552 0 : cv->p.ap = found;
4553 0 : cv->p.anysel = true;
4554 : }
4555 : }
4556 0 : for ( img = cv->b.layerheads[cv->b.drawmode]->images; img!=NULL; img=img->next ) {
4557 0 : if ( InImage(fs,img)) {
4558 0 : cv->p.img = img;
4559 0 : cv->p.anysel = true;
4560 0 : break;
4561 : }
4562 : }
4563 : }
4564 0 : return( cv->p.anysel );
4565 : }
4566 :
4567 0 : int CVTestSelectFromEvent(CharView *cv,GEvent *event) {
4568 : FindSel fs;
4569 :
4570 0 : SetFS(&fs,&cv->p,cv,event);
4571 0 : return( _CVTestSelectFromEvent(cv,&fs));
4572 : }
4573 :
4574 : /**
4575 : * A cache for the selected spline point or spiro control point
4576 : */
4577 : typedef struct lastselectedpoint
4578 : {
4579 : SplinePoint *lastselpt;
4580 : spiro_cp *lastselcp;
4581 : } lastSelectedPoint;
4582 :
4583 :
4584 0 : void CVFreePreTransformSPL( CharView* cv )
4585 : {
4586 0 : if( cv->p.pretransform_spl )
4587 : {
4588 0 : g_list_foreach( cv->p.pretransform_spl, (GFunc)SplinePointListFree, NULL );
4589 0 : g_list_free( cv->p.pretransform_spl );
4590 : }
4591 0 : cv->p.pretransform_spl = 0;
4592 0 : }
4593 :
4594 0 : static void CVMaybeCreateDraggingComparisonOutline( CharView* cv )
4595 : {
4596 0 : if( !prefs_create_dragging_comparison_outline )
4597 0 : return;
4598 0 : if( !cv )
4599 0 : return;
4600 0 : if( cv->p.pretransform_spl )
4601 0 : CVFreePreTransformSPL( cv );
4602 :
4603 0 : Layer* l = cv->b.layerheads[cv->b.drawmode];
4604 0 : if( !l || !l->splines )
4605 0 : return;
4606 :
4607 0 : SplinePointList* spl = l->splines;
4608 0 : for( ; spl; spl = spl->next )
4609 : {
4610 0 : int anySel = 0;
4611 0 : SPLFirstVisitPoints( spl->first, isAnyControlPointSelectedVisitor, &anySel );
4612 0 : if( anySel || (cv->b.sc->inspiro && hasspiro()))
4613 : {
4614 0 : cv->p.pretransform_spl = g_list_append( cv->p.pretransform_spl,
4615 0 : SplinePointListCopy(spl) );
4616 : }
4617 : }
4618 :
4619 : }
4620 :
4621 :
4622 0 : static void CVSwitchActiveSC( CharView *cv, SplineChar* sc, int idx )
4623 : {
4624 0 : int i=0;
4625 0 : FontViewBase *fv = cv->b.fv;
4626 : char buf[300];
4627 :
4628 : TRACE("CVSwitchActiveSC() idx:%d active:%d\n", idx, cv->additionalCharsToShowActiveIndex );
4629 0 : if( !sc )
4630 : {
4631 0 : sc = cv->additionalCharsToShow[i];
4632 0 : if( !sc )
4633 0 : return;
4634 : }
4635 : else
4636 : {
4637 : // test for setting something twice
4638 0 : if( !idx && cv->additionalCharsToShowActiveIndex == idx )
4639 : {
4640 0 : if( cv->additionalCharsToShow[i] == sc )
4641 0 : return;
4642 : }
4643 : }
4644 :
4645 0 : cv->changedActiveGlyph = 1;
4646 : TRACE("CVSwitchActiveSC(b) activeidx:%d newidx:%d\n", cv->additionalCharsToShowActiveIndex, idx );
4647 0 : for( i=0; i < additionalCharsToShowLimit; i++ )
4648 0 : if( cv->additionalCharsToShow[i] )
4649 : TRACE("CVSwitchActiveSC(b) toshow.. i:%d char:%s\n", i, cv->additionalCharsToShow[i]
4650 : ? cv->additionalCharsToShow[i]->name : "N/A" );
4651 :
4652 :
4653 : //
4654 : // Work out how far we should scroll the panel to keep
4655 : // the display from jumping around. First look right then
4656 : // check left.
4657 0 : int scroll_offset = 0;
4658 0 : if( idx > cv->additionalCharsToShowActiveIndex )
4659 : {
4660 0 : SplineChar* xc = 0;
4661 0 : int i = 0;
4662 0 : scroll_offset = cv->b.sc->width;
4663 0 : int ridx = cv->additionalCharsToShowActiveIndex+1;
4664 0 : for( i=ridx; i < idx; i++ )
4665 : {
4666 0 : if((xc = cv->additionalCharsToShow[i]))
4667 0 : scroll_offset += xc->width;
4668 : }
4669 : }
4670 0 : if( idx < cv->additionalCharsToShowActiveIndex )
4671 : {
4672 0 : SplineChar* xc = 0;
4673 0 : int i = 0;
4674 0 : scroll_offset = 0;
4675 0 : int ridx = cv->additionalCharsToShowActiveIndex-1;
4676 0 : for( i=ridx; i >= idx; i-- )
4677 : {
4678 0 : if((xc = cv->additionalCharsToShow[i]))
4679 0 : scroll_offset -= xc->width;
4680 : }
4681 : }
4682 :
4683 :
4684 :
4685 :
4686 :
4687 0 : CVUnlinkView( cv );
4688 0 : cv->b.sc = sc;
4689 0 : cv->b.next = sc->views;
4690 0 : cv->b.layerheads[dm_fore] = &sc->layers[ly_fore];
4691 0 : cv->b.layerheads[dm_back] = &sc->layers[ly_back];
4692 0 : cv->b.layerheads[dm_grid] = &fv->sf->grid;
4693 0 : if ( !sc->parent->multilayer && fv->active_layer!=ly_fore ) {
4694 0 : cv->b.layerheads[dm_back] = &sc->layers[fv->active_layer];
4695 0 : cv->b.drawmode = dm_back;
4696 : }
4697 0 : CharIcon(cv,(FontView *) (cv->b.fv));
4698 0 : char* title = CVMakeTitles(cv,buf,sizeof(buf));
4699 0 : GDrawSetWindowTitles8(cv->gw,buf,title);
4700 0 : CVInfoDraw(cv,cv->gw);
4701 0 : free(title);
4702 0 : _CVPaletteActivate(cv,true);
4703 :
4704 : TRACE("CVSwitchActiveSC() idx:%d\n", idx );
4705 :
4706 0 : cv->additionalCharsToShowActiveIndex = idx;
4707 :
4708 : // update the select[i]on in the input text to reflect
4709 : // the users currently selected char.
4710 : {
4711 0 : SplineFont* sf = cv->b.sc->parent;
4712 0 : EncMap *map = ((FontView *) (cv->b.fv))->b.map;
4713 0 : unichar_t *srctxt = GGadgetGetTitle( cv->charselector );
4714 0 : int endsWithSlash = u_endswith( srctxt, c_to_u("/"));
4715 :
4716 0 : unichar_t* p = 0;
4717 0 : p = Wordlist_selectionClear( sf, map, srctxt );
4718 0 : p = Wordlist_selectionAdd( sf, map, p, idx );
4719 0 : if( endsWithSlash )
4720 0 : uc_strcat( p, "/" );
4721 :
4722 : // only update when the selection has changed.
4723 : // updating this string is a non reversable operation if the
4724 : // user is part way through typing some text.
4725 0 : if( !Wordlist_selectionsEqual( srctxt, p ))
4726 : {
4727 0 : GGadgetSetTitle( cv->charselector, p );
4728 : }
4729 : }
4730 :
4731 :
4732 0 : cv->b.next = sc->views;
4733 0 : sc->views = &cv->b;
4734 :
4735 : // Move the scrollbar so that it appears the selection
4736 : // box has moved rather than all the characters.
4737 0 : if( scroll_offset )
4738 0 : CVHScrollSetPos( cv, cv->xoff + scroll_offset * cv->scale );
4739 :
4740 : // if ( CVClearSel(cv))
4741 : // SCUpdateAll(cv->b.sc);
4742 :
4743 : }
4744 :
4745 0 : static void CVMouseDown(CharView *cv, GEvent *event ) {
4746 : FindSel fs;
4747 : GEvent fake;
4748 : lastSelectedPoint lastSel;
4749 0 : memset( &lastSel, 0, sizeof(lastSelectedPoint));
4750 :
4751 0 : if ( event->u.mouse.button==2 && event->u.mouse.device!=NULL &&
4752 0 : strcmp(event->u.mouse.device,"stylus")==0 )
4753 0 : return; /* I treat this more like a modifier key change than a button press */
4754 :
4755 0 : if ( cv->expandedge != ee_none )
4756 0 : GDrawSetCursor(cv->v,ct_mypointer);
4757 0 : if ( event->u.mouse.button==3 )
4758 : {
4759 : /* context menu */
4760 0 : CVToolsPopup(cv,event);
4761 0 : return;
4762 : }
4763 :
4764 : TRACE("tool:%d pointer:%d ctl:%d alt:%d\n",
4765 : cv->showing_tool,
4766 : (cv->showing_tool == cvt_pointer),
4767 : cv->activeModifierControl, cv->activeModifierAlt );
4768 :
4769 0 : int8 override_showing_tool = cvt_none;
4770 0 : int8 old_showing_tool = cv->showing_tool;
4771 0 : if( cv->showing_tool == cvt_pointer
4772 0 : && cv->activeModifierControl
4773 0 : && cv->activeModifierAlt )
4774 : {
4775 : FindSel fs;
4776 0 : SetFS(&fs,&cv->p,cv,event);
4777 0 : int found = InSplineSet( &fs, cv->b.layerheads[cv->b.drawmode]->splines,
4778 0 : cv->b.sc->inspiro && hasspiro());
4779 : TRACE("in spline set:%d cv->p.sp:%p\n", found, cv->p.sp );
4780 :
4781 : //
4782 : // Only overwrite to create a point if the user has clicked a spline.
4783 : //
4784 0 : if( found && !cv->p.sp )
4785 0 : override_showing_tool = cvt_curve;
4786 : }
4787 :
4788 0 : if( cv->charselector && cv->charselector == GWindowGetFocusGadgetOfWindow(cv->gw))
4789 0 : GWindowClearFocusGadgetOfWindow(cv->gw);
4790 :
4791 0 : update_spacebar_hand_tool(cv);
4792 :
4793 0 : CVToolsSetCursor(cv,event->u.mouse.state|(1<<(7+event->u.mouse.button)), event->u.mouse.device );
4794 0 : if( override_showing_tool != cvt_none )
4795 0 : cv->showing_tool = override_showing_tool;
4796 0 : cv->active_tool = cv->showing_tool;
4797 0 : cv->needsrasterize = false;
4798 0 : cv->recentchange = false;
4799 :
4800 :
4801 0 : SetFS(&fs,&cv->p,cv,event);
4802 0 : if ( event->u.mouse.state&ksm_shift )
4803 0 : event = CVConstrainedMouseDown(cv,event,&fake);
4804 :
4805 0 : if ( cv->active_tool == cvt_pointer ) {
4806 0 : fs.select_controls = true;
4807 0 : if ( event->u.mouse.state&ksm_meta ) {
4808 0 : fs.seek_controls = true;
4809 : /* Allow more slop looking for control points if they asked for them */
4810 0 : fs.c_xl -= fs.fudge; fs.c_xh += fs.fudge;
4811 0 : fs.c_yl -= fs.fudge; fs.c_yh += fs.fudge;
4812 : }
4813 0 : if ( cv->showpointnumbers && cv->b.layerheads[cv->b.drawmode]->order2 )
4814 0 : fs.all_controls = true;
4815 0 : fs.alwaysshowcontrolpoints = cv->alwaysshowcontrolpoints;
4816 0 : lastSel.lastselpt = cv->lastselpt;
4817 0 : lastSel.lastselcp = cv->lastselcp;
4818 0 : cv->lastselpt = NULL;
4819 0 : cv->lastselcp = NULL;
4820 0 : _CVTestSelectFromEvent(cv,&fs);
4821 0 : fs.p = &cv->p;
4822 :
4823 : // TRACE("cvmousedown cv->xoff:%d\n", cv->xoff );
4824 : // TRACE("cvmousedown x:%d y:%d\n", event->u.mouse.x, event->u.mouse.y );
4825 :
4826 0 : if( !cv->p.anysel && cv->b.drawmode != dm_grid )
4827 : {
4828 : // If we are in left-right arrow cursor mode to move
4829 : // those bearings then don't even think about changing
4830 : // the char right now.
4831 0 : if( !CVNearRBearingLine( cv, cv->p.cx, fs.fudge )
4832 0 : && !CVNearLBearingLine( cv, cv->p.cx, fs.fudge ))
4833 : {
4834 0 : int i=0;
4835 0 : FindSel fsadjusted = fs;
4836 0 : fsadjusted.c_xl -= 2*fsadjusted.fudge;
4837 0 : fsadjusted.c_xh += 2*fsadjusted.fudge;
4838 0 : fsadjusted.xl -= 2*fsadjusted.fudge;
4839 0 : fsadjusted.xh += 2*fsadjusted.fudge;
4840 0 : SplineChar* xc = 0;
4841 0 : int xcidx = -1;
4842 0 : int borderFudge = 20;
4843 :
4844 : {
4845 0 : int offset = cv->b.sc->width;
4846 0 : int cumulativeLeftSideBearing = 0;
4847 : // TRACE("first offset:%d original cx:%f \n", offset, fsadjusted.p->cx );
4848 0 : int ridx = cv->additionalCharsToShowActiveIndex+1;
4849 0 : for( i=ridx; i < additionalCharsToShowLimit; i++ )
4850 : {
4851 0 : if( i == cv->additionalCharsToShowActiveIndex )
4852 0 : continue;
4853 0 : xc = cv->additionalCharsToShow[i];
4854 0 : if( !xc )
4855 0 : break;
4856 0 : int OffsetForDoingCharNextToActive = 0;
4857 0 : if( i == ridx )
4858 : {
4859 0 : OffsetForDoingCharNextToActive = borderFudge;
4860 : }
4861 :
4862 :
4863 0 : cumulativeLeftSideBearing += offset;
4864 : /* TRACE("1 adj. x:%f %f\n",fsadjusted.xl,fsadjusted.xh); */
4865 : /* TRACE("1 adj.cx:%f %f\n",fsadjusted.c_xl,fsadjusted.c_xh); */
4866 : /* TRACE("1 p. cx:%f %f\n",fsadjusted.p->cx,fsadjusted.p->cy ); */
4867 : /* fsadjusted.c_xl -= offset; */
4868 : /* fsadjusted.c_xh -= offset; */
4869 : /* fsadjusted.xl -= offset; */
4870 : /* fsadjusted.xh -= offset; */
4871 : /* TRACE("2 adj. x:%f %f\n",fsadjusted.xl,fsadjusted.xh); */
4872 : /* TRACE("2 adj.cx:%f %f\n",fsadjusted.c_xl,fsadjusted.c_xh); */
4873 : /* TRACE("2 p. cx:%f %f\n",fsadjusted.p->cx,fsadjusted.p->cy ); */
4874 : /* int found = InSplineSet( &fsadjusted, */
4875 : /* xc->layers[cv->b.drawmode-1].splines, */
4876 : /* xc->inspiro && hasspiro()); */
4877 : TRACE("A:%d\n", cumulativeLeftSideBearing );
4878 : TRACE("B:%f\n", fsadjusted.p->cx );
4879 : TRACE("C:%d\n", cumulativeLeftSideBearing+xc->width );
4880 0 : int found = IS_IN_ORDER3(
4881 : cumulativeLeftSideBearing + OffsetForDoingCharNextToActive,
4882 : fsadjusted.p->cx,
4883 : cumulativeLeftSideBearing+xc->width );
4884 : TRACE("CVMOUSEDOWN i:%d found:%d\n", i, found );
4885 0 : if( found )
4886 : {
4887 : TRACE("FOUND FOUND FOUND FOUND FOUND FOUND FOUND \n");
4888 :
4889 0 : xcidx = i;
4890 : // CVChangeSC(cv,xc);
4891 0 : break;
4892 : }
4893 :
4894 0 : offset = xc->width;
4895 : }
4896 : }
4897 :
4898 0 : fsadjusted = fs;
4899 0 : fsadjusted.c_xl -= 2*fsadjusted.fudge;
4900 0 : fsadjusted.c_xh += 2*fsadjusted.fudge;
4901 0 : fsadjusted.xl -= 2*fsadjusted.fudge;
4902 0 : fsadjusted.xh += 2*fsadjusted.fudge;
4903 :
4904 0 : if( !xc && cv->additionalCharsToShowActiveIndex > 0 )
4905 : {
4906 0 : xc = cv->additionalCharsToShow[cv->additionalCharsToShowActiveIndex-1];
4907 0 : int offset = xc->width;
4908 0 : int cumulativeLeftSideBearing = 0;
4909 : // TRACE("first offset:%d original cx:%f \n", offset, fsadjusted.p->cx );
4910 0 : int lidx = cv->additionalCharsToShowActiveIndex-1;
4911 0 : for( i=lidx; i>=0; i-- )
4912 : {
4913 0 : if( i == cv->additionalCharsToShowActiveIndex )
4914 0 : continue;
4915 0 : xc = cv->additionalCharsToShow[i];
4916 0 : if( !xc )
4917 0 : break;
4918 0 : cumulativeLeftSideBearing -= xc->width;
4919 0 : int OffsetForDoingCharNextToActive = 0;
4920 0 : if( i == lidx )
4921 : {
4922 0 : OffsetForDoingCharNextToActive = borderFudge;
4923 : }
4924 :
4925 : /* TRACE("1 adj. x:%f %f\n",fsadjusted.xl,fsadjusted.xh); */
4926 : /* TRACE("1 adj.cx:%f %f\n",fsadjusted.c_xl,fsadjusted.c_xh); */
4927 : /* TRACE("1 p. cx:%f %f\n",fsadjusted.p->cx,fsadjusted.p->cy ); */
4928 : /* fsadjusted.c_xl += offset; */
4929 : /* fsadjusted.c_xh += offset; */
4930 : /* fsadjusted.xl += offset; */
4931 : /* fsadjusted.xh += offset; */
4932 : /* TRACE("2 adj. x:%f %f\n",fsadjusted.xl,fsadjusted.xh); */
4933 : /* TRACE("2 adj.cx:%f %f\n",fsadjusted.c_xl,fsadjusted.c_xh); */
4934 : /* TRACE("2 p. cx:%f %f\n",fsadjusted.p->cx,fsadjusted.p->cy ); */
4935 : /* int found = InSplineSet( &fsadjusted, */
4936 : /* xc->layers[cv->b.drawmode-1].splines, */
4937 : /* xc->inspiro && hasspiro()); */
4938 : TRACE("A:%d\n", cumulativeLeftSideBearing );
4939 : TRACE("B:%f\n", fsadjusted.p->cx );
4940 : TRACE("C:%d\n", cumulativeLeftSideBearing+xc->width );
4941 0 : int found = IS_IN_ORDER3(
4942 : cumulativeLeftSideBearing,
4943 : fsadjusted.p->cx,
4944 : cumulativeLeftSideBearing + xc->width - OffsetForDoingCharNextToActive );
4945 :
4946 : TRACE("cvmousedown i:%d found:%d\n", i, found );
4947 0 : if( found )
4948 : {
4949 : TRACE("FOUND FOUND FOUND FOUND FOUND FOUND FOUND i:%d\n", i);
4950 0 : xcidx = i;
4951 0 : break;
4952 : }
4953 :
4954 0 : offset = xc->width;
4955 : }
4956 : }
4957 :
4958 : TRACE("have xc:%p xcidx:%d\n", xc, xcidx );
4959 : TRACE(" idx:%d active:%d\n", xcidx, cv->additionalCharsToShowActiveIndex );
4960 0 : if( xc && xcidx >= 0 )
4961 : {
4962 0 : CVSwitchActiveSC( cv, xc, xcidx );
4963 0 : GDrawRequestExpose(cv->v,NULL,false);
4964 0 : return;
4965 : }
4966 : }
4967 : }
4968 :
4969 :
4970 :
4971 0 : } else if ( cv->active_tool == cvt_curve || cv->active_tool == cvt_corner ||
4972 0 : cv->active_tool == cvt_tangent || cv->active_tool == cvt_hvcurve ||
4973 0 : cv->active_tool == cvt_pen || cv->active_tool == cvt_ruler )
4974 : {
4975 : /* Snap to points and splines */
4976 0 : InSplineSet(&fs,cv->b.layerheads[cv->b.drawmode]->splines,cv->b.sc->inspiro && hasspiro());
4977 0 : if ( fs.p->sp==NULL && fs.p->spline==NULL )
4978 0 : CVDoSnaps(cv,&fs);
4979 : } else {
4980 : /* Just snap to points */
4981 0 : NearSplineSetPoints(&fs,cv->b.layerheads[cv->b.drawmode]->splines,cv->b.sc->inspiro && hasspiro());
4982 0 : if ( fs.p->sp==NULL && fs.p->spline==NULL )
4983 0 : CVDoSnaps(cv,&fs);
4984 : }
4985 :
4986 0 : cv->e.x = event->u.mouse.x; cv->e.y = event->u.mouse.y;
4987 0 : if ( cv->p.sp!=NULL ) {
4988 : BasePoint *p;
4989 0 : if ( cv->p.nextcp )
4990 0 : p = &cv->p.sp->nextcp;
4991 0 : else if ( cv->p.prevcp )
4992 0 : p = &cv->p.sp->prevcp;
4993 : else
4994 0 : p = &cv->p.sp->me;
4995 0 : cv->info.x = p->x;
4996 0 : cv->info.y = p->y;
4997 0 : cv->p.cx = p->x; cv->p.cy = p->y;
4998 0 : } else if ( cv->p.spiro!=NULL ) {
4999 0 : cv->info.x = cv->p.spiro->x;
5000 0 : cv->info.y = cv->p.spiro->y;
5001 0 : cv->p.cx = cv->p.spiro->x; cv->p.cy = cv->p.spiro->y;
5002 : } else {
5003 0 : cv->info.x = cv->p.cx;
5004 0 : cv->info.y = cv->p.cy;
5005 : }
5006 0 : cv->info_within = true;
5007 0 : CVInfoDraw(cv,cv->gw);
5008 0 : CVSetConstrainPoint(cv,event);
5009 :
5010 0 : int selectionChanged = 0;
5011 0 : switch ( cv->active_tool ) {
5012 : case cvt_pointer:
5013 0 : CVMouseDownPointer(cv, &fs, event);
5014 0 : CVMaybeCreateDraggingComparisonOutline( cv );
5015 0 : if( lastSel.lastselpt != fs.p->sp || lastSel.lastselcp != fs.p->spiro ) {
5016 : #define BASEPOINT_IS_EMPTY(p) ( p.x == (real)0.0 && p.y == (real)0.0 )
5017 : // If we are in a collab session, we might like to preserve here
5018 : // so that we can send a change of selected points to other members
5019 : // of the group
5020 0 : if( collabclient_inSession( &cv->b ) )
5021 : {
5022 0 : if( BASEPOINT_IS_EMPTY( fs.p->cp ) )
5023 : {
5024 : //
5025 : // Do not send clicks on bezier control points.
5026 : //
5027 : TRACE("skipping!\n");
5028 : }
5029 : else
5030 : {
5031 0 : CVPreserveState(&cv->b);
5032 0 : selectionChanged = 1;
5033 : }
5034 : }
5035 : }
5036 0 : cv->lastselpt = fs.p->sp;
5037 0 : cv->lastselcp = fs.p->spiro;
5038 : if( selectionChanged ) {
5039 : // collabclient_sendRedo( &cv->b );
5040 : }
5041 0 : break;
5042 : case cvt_magnify: case cvt_minify:
5043 : //When scroll zooming, the old showing tool is the normal pointer.
5044 0 : old_showing_tool = cv->active_tool;
5045 0 : break;
5046 : case cvt_hand:
5047 0 : CVMouseDownHand(cv);
5048 0 : break;
5049 : case cvt_freehand:
5050 0 : CVMouseDownFreeHand(cv,event);
5051 0 : break;
5052 : case cvt_curve: case cvt_corner: case cvt_tangent: case cvt_pen:
5053 : case cvt_hvcurve:
5054 0 : CVMouseDownPoint(cv,event);
5055 0 : break;
5056 : case cvt_ruler:
5057 0 : CVMouseDownRuler(cv,event);
5058 0 : break;
5059 : case cvt_rotate: case cvt_flip: case cvt_scale: case cvt_skew:
5060 : case cvt_3d_rotate: case cvt_perspective:
5061 0 : CVMouseDownTransform(cv);
5062 0 : break;
5063 : case cvt_knife:
5064 0 : CVMouseDownKnife(cv);
5065 0 : break;
5066 : case cvt_rect: case cvt_elipse: case cvt_poly: case cvt_star:
5067 0 : CVMouseDownShape(cv,event);
5068 0 : break;
5069 : }
5070 0 : cv->showing_tool = old_showing_tool;
5071 : }
5072 :
5073 4402 : static void _SCHintsChanged(SplineChar *sc) {
5074 : struct splinecharlist *dlist;
5075 :
5076 4402 : if ( !sc->changedsincelasthinted ) {
5077 2082 : sc->changedsincelasthinted = true;
5078 2082 : FVMarkHintsOutOfDate(sc);
5079 : }
5080 :
5081 5208 : for ( dlist=sc->dependents; dlist!=NULL; dlist=dlist->next )
5082 806 : _SCHintsChanged(dlist->sc);
5083 4402 : }
5084 :
5085 3230 : static void SC_HintsChanged(SplineChar *sc) {
5086 : struct splinecharlist *dlist;
5087 3230 : int was = sc->changedsincelasthinted;
5088 :
5089 3230 : if ( sc->parent->onlybitmaps || sc->parent->multilayer || sc->parent->strokedfont )
5090 3230 : return;
5091 3230 : sc->changedsincelasthinted = false; /* We just applied a hinting change */
5092 3230 : if ( !sc->changed ) {
5093 2152 : sc->changed = true;
5094 2152 : FVToggleCharChanged(sc);
5095 2152 : SCRefreshTitles(sc);
5096 2152 : if ( !sc->parent->changed ) {
5097 8 : sc->parent->changed = true;
5098 8 : FVSetTitles(sc->parent);
5099 : }
5100 : }
5101 5932 : for ( dlist=sc->dependents; dlist!=NULL; dlist=dlist->next )
5102 2702 : _SCHintsChanged(dlist->sc);
5103 3230 : if ( was ) {
5104 : FontView *fvs;
5105 50 : for ( fvs = (FontView *) (sc->parent->fv); fvs!=NULL; fvs=(FontView *) (fvs->b.nextsame) )
5106 25 : GDrawRequestExpose(fvs->v,NULL,false);
5107 : }
5108 : }
5109 :
5110 0 : void CVSetCharChanged(CharView *cv,int changed) {
5111 0 : SplineFont *sf = cv->b.fv->sf;
5112 0 : SplineChar *sc = cv->b.sc;
5113 0 : int oldchanged = sf->changed;
5114 : /* A changed argument of 2 means the outline didn't change, but something */
5115 : /* else (width, anchorpoint) did */
5116 0 : int cvlayer = CVLayer((CharViewBase *) cv);
5117 :
5118 0 : if ( changed )
5119 0 : SFSetModTime(sf);
5120 0 : if ( cv->b.drawmode==dm_grid ) {
5121 0 : if ( changed ) {
5122 0 : sf->changed = true;
5123 0 : if ( sf->cidmaster!=NULL )
5124 0 : sf->cidmaster->changed = true;
5125 : }
5126 : } else {
5127 0 : if ( cv->b.drawmode==dm_fore && changed==1 ) {
5128 0 : sf->onlybitmaps = false;
5129 : }
5130 0 : SCTickValidationState(cv->b.sc,cvlayer);
5131 0 : if ( (sc->changed==0) != (changed==0) ) {
5132 0 : sc->changed = (changed!=0);
5133 0 : FVToggleCharChanged(sc);
5134 0 : SCRefreshTitles(sc);
5135 0 : if ( changed ) {
5136 0 : sf->changed = true;
5137 0 : if ( sf->cidmaster!=NULL )
5138 0 : sf->cidmaster->changed = true;
5139 : }
5140 : }
5141 0 : if ( changed==1 ) {
5142 0 : instrcheck(sc,cvlayer);
5143 : /*SCDeGridFit(sc);*/
5144 0 : if ( sc->parent->onlybitmaps )
5145 : /* Do nothing */;
5146 0 : else if ( sc->parent->multilayer || sc->parent->strokedfont || sc->layers[cvlayer].order2 )
5147 0 : sc->changed_since_search = true;
5148 0 : else if ( cv->b.drawmode==dm_fore ) {
5149 0 : sc->changed_since_search = true;
5150 0 : _SCHintsChanged(cv->b.sc);
5151 : }
5152 0 : sc->changed_since_autosave = true;
5153 0 : sf->changed_since_autosave = true;
5154 0 : sf->changed_since_xuidchanged = true;
5155 0 : if ( sf->cidmaster!=NULL ) {
5156 0 : sf->cidmaster->changed_since_autosave = true;
5157 0 : sf->cidmaster->changed_since_xuidchanged = true;
5158 : }
5159 : }
5160 0 : if ( cv->b.drawmode!=dm_grid ) {
5161 0 : cv->needsrasterize = true;
5162 : }
5163 : }
5164 0 : cv->recentchange = true;
5165 0 : if ( !oldchanged )
5166 0 : FVSetTitles(sf);
5167 0 : }
5168 :
5169 0 : void SCClearSelPt(SplineChar *sc) {
5170 : CharView *cv;
5171 :
5172 0 : for ( cv=(CharView *) (sc->views); cv!=NULL; cv=(CharView *) (cv->b.next) ) {
5173 0 : cv->lastselpt = cv->p.sp = NULL;
5174 0 : cv->p.spiro = cv->lastselcp = NULL;
5175 : }
5176 0 : }
5177 :
5178 895 : static void _SC_CharChangedUpdate(SplineChar *sc,int layer,int changed) {
5179 895 : SplineFont *sf = sc->parent;
5180 : extern int updateflex;
5181 : /* layer might be ly_none or ly_all */
5182 :
5183 895 : if ( layer>=sc->layer_cnt ) {
5184 0 : IError( "Bad layer in _SC_CharChangedUpdate");
5185 0 : layer = ly_fore;
5186 : }
5187 895 : if ( layer>=0 && !sc->layers[layer].background )
5188 895 : TTFPointMatches(sc,layer,true);
5189 895 : if ( changed != -1 ) {
5190 895 : sc->changed_since_autosave = true;
5191 895 : SFSetModTime(sf);
5192 895 : if ( (sc->changed==0) != (changed==0) ) {
5193 704 : sc->changed = (changed!=0);
5194 704 : if ( changed && layer>=ly_fore && (sc->layers[layer].splines!=NULL || sc->layers[layer].refs!=NULL))
5195 693 : sc->parent->onlybitmaps = false;
5196 704 : FVToggleCharChanged(sc);
5197 704 : SCRefreshTitles(sc);
5198 : }
5199 895 : if ( !sf->changed ) {
5200 14 : sf->changed = true;
5201 14 : if ( sf->cidmaster )
5202 0 : sf->cidmaster->changed = true;
5203 14 : FVSetTitles(sf);
5204 : }
5205 895 : if ( changed && layer>=0 && !sc->layers[layer].background && sc->layers[layer].order2 ) {
5206 0 : instrcheck(sc,layer);
5207 0 : SCReGridFit(sc,layer);
5208 : }
5209 895 : if ( !sc->parent->onlybitmaps && !sc->parent->multilayer &&
5210 894 : changed==1 && !sc->parent->strokedfont &&
5211 894 : layer>=0 &&
5212 1788 : !sc->layers[layer].background && !sc->layers[layer].order2 )
5213 894 : _SCHintsChanged(sc);
5214 895 : sc->changed_since_search = true;
5215 895 : sf->changed = true;
5216 895 : sf->changed_since_autosave = true;
5217 895 : sf->changed_since_xuidchanged = true;
5218 895 : if ( layer>=0 )
5219 895 : SCTickValidationState(sc,layer);
5220 : }
5221 895 : if ( sf->cidmaster!=NULL )
5222 0 : sf->cidmaster->changed = sf->cidmaster->changed_since_autosave =
5223 0 : sf->cidmaster->changed_since_xuidchanged = true;
5224 895 : SCRegenDependents(sc,ly_all); /* All chars linked to this one need to get the new splines */
5225 895 : if ( updateflex && (CharView *) (sc->views)!=NULL && layer>=ly_fore )
5226 0 : SplineCharIsFlexible(sc,layer);
5227 895 : SCUpdateAll(sc);
5228 895 : SCLayersChange(sc);
5229 895 : SCRegenFills(sc);
5230 895 : }
5231 :
5232 895 : static void SC_CharChangedUpdate(SplineChar *sc,int layer) {
5233 895 : _SC_CharChangedUpdate(sc,layer,true);
5234 895 : }
5235 :
5236 0 : static void _CV_CharChangedUpdate(CharView *cv,int changed) {
5237 : extern int updateflex;
5238 : FontView *fv;
5239 0 : int cvlayer = CVLayer((CharViewBase *) cv);
5240 :
5241 0 : CVSetCharChanged(cv,changed);
5242 0 : CVLayerChange(cv);
5243 0 : if ( cv->needsrasterize ) {
5244 0 : TTFPointMatches(cv->b.sc,cvlayer,true); /* Must precede regen dependents, as this can change references */
5245 0 : SCRegenDependents(cv->b.sc,cvlayer); /* All chars linked to this one need to get the new splines */
5246 0 : if ( cv->b.layerheads[cv->b.drawmode]->order2 )
5247 0 : SCReGridFit(cv->b.sc,cvlayer);
5248 0 : if ( updateflex && cvlayer!=ly_grid && !cv->b.layerheads[cv->b.drawmode]->background )
5249 0 : SplineCharIsFlexible(cv->b.sc,cvlayer);
5250 0 : SCUpdateAll(cv->b.sc);
5251 0 : SCRegenFills(cv->b.sc);
5252 0 : for ( fv = (FontView *) (cv->b.sc->parent->fv); fv!=NULL; fv=(FontView *) (fv->b.nextsame) )
5253 0 : FVRegenChar(fv,cv->b.sc);
5254 0 : cv->needsrasterize = false;
5255 0 : } else if ( cv->b.drawmode!=dm_grid ) {
5256 : /* If we changed the background then only views of this character */
5257 : /* need to know about it. No dependents needed, but why write */
5258 : /* another routine for a rare case... */
5259 0 : SCUpdateAll(cv->b.sc);
5260 : } else /* if ( cv->b.drawmode==dm_grid )*/ {
5261 : /* If we changed the grid then any character needs to know it */
5262 0 : FVRedrawAllCharViewsSF(cv->b.sc->parent);
5263 : }
5264 0 : cv->recentchange = false;
5265 0 : cv->p.sp = NULL; /* Might have been deleted */
5266 0 : }
5267 :
5268 0 : static void CV_CharChangedUpdate(CharView *cv) {
5269 0 : _CV_CharChangedUpdate(cv,true);
5270 0 : }
5271 :
5272 0 : static void CVMouseMove(CharView *cv, GEvent *event ) {
5273 : real cx, cy;
5274 : PressedOn p;
5275 : FindSel fs;
5276 : GEvent fake;
5277 0 : int stop_motion = false;
5278 0 : int has_spiro = hasspiro();
5279 :
5280 : /* Debug wacom !!!! */
5281 : /* TRACE( "dev=%s (%d,%d) 0x%x\n", event->u.mouse.device!=NULL?event->u.mouse.device:"<None>", */
5282 : /* event->u.mouse.x, event->u.mouse.y, event->u.mouse.state); */
5283 :
5284 0 : if ( event->u.mouse.device!=NULL )
5285 0 : CVToolsSetCursor(cv,event->u.mouse.state,event->u.mouse.device);
5286 :
5287 0 : if ( !cv->p.pressed ) {
5288 0 : CVUpdateInfo(cv, event);
5289 0 : if ( cv->showing_tool==cvt_pointer ) {
5290 0 : CVCheckResizeCursors(cv);
5291 0 : if ( cv->dv!=NULL )
5292 0 : CVDebugPointPopup(cv);
5293 0 : } else if ( cv->showing_tool == cvt_ruler )
5294 0 : CVMouseMoveRuler(cv,event);
5295 0 : return;
5296 : }
5297 :
5298 0 : GDrawRequestExpose(cv->v,NULL,false); /* TBD, hack to clear ruler */
5299 :
5300 0 : SetFS(&fs,&p,cv,event);
5301 0 : if ( cv->active_tool == cvt_freehand )
5302 : /* freehand does it's own kind of constraining */;
5303 0 : else if ( (event->u.mouse.state&ksm_shift) && !cv->p.rubberbanding ) {
5304 : /* Constrained */
5305 :
5306 0 : fake.u.mouse = event->u.mouse;
5307 0 : if ( ((event->u.mouse.state&ksm_meta) ||
5308 0 : (!cv->cntrldown && (event->u.mouse.state&ksm_control))) &&
5309 0 : (cv->p.nextcp || cv->p.prevcp)) {
5310 0 : real dot = (cv->p.cp.x-cv->p.constrain.x)*(p.cx-cv->p.constrain.x) +
5311 0 : (cv->p.cp.y-cv->p.constrain.y)*(p.cy-cv->p.constrain.y);
5312 0 : real len = (cv->p.cp.x-cv->p.constrain.x)*(cv->p.cp.x-cv->p.constrain.x)+
5313 0 : (cv->p.cp.y-cv->p.constrain.y)*(cv->p.cp.y-cv->p.constrain.y);
5314 0 : if ( len!=0 ) {
5315 0 : dot /= len;
5316 : /* constrain control point to same angle with respect to base point*/
5317 0 : if ( dot<0 ) dot = 0;
5318 0 : p.cx = cv->p.constrain.x + dot*(cv->p.cp.x-cv->p.constrain.x);
5319 0 : p.cy = cv->p.constrain.y + dot*(cv->p.cp.y-cv->p.constrain.y);
5320 0 : p.x = fake.u.mouse.x = cv->xoff + rint(p.cx*cv->scale);
5321 0 : p.y = fake.u.mouse.y = -cv->yoff + cv->height - rint(p.cy*cv->scale);
5322 : }
5323 : } else {
5324 : /* Constrain mouse to hor/vert/45 from base point */
5325 0 : int basex = cv->active_tool!=cvt_hand ? cv->xoff + rint(cv->p.constrain.x*cv->scale) : cv->p.x;
5326 0 : int basey = cv->active_tool!=cvt_hand ?-cv->yoff + cv->height - rint(cv->p.constrain.y*cv->scale) : cv->p.y;
5327 0 : int dx= event->u.mouse.x-basex, dy = event->u.mouse.y-basey;
5328 0 : int sign = dx*dy<0?-1:1;
5329 0 : double aspect = 1.0;
5330 :
5331 0 : if ( dx<0 ) dx = -dx; if ( dy<0 ) dy = -dy;
5332 0 : if ( cv->p.img!=NULL && cv->p.img->bb.minx!=cv->p.img->bb.maxx )
5333 0 : aspect = (cv->p.img->bb.maxy - cv->p.img->bb.miny) / (cv->p.img->bb.maxx - cv->p.img->bb.minx);
5334 0 : else if ( cv->p.ref!=NULL && cv->p.ref->bb.minx!=cv->p.ref->bb.maxx )
5335 0 : aspect = (cv->p.ref->bb.maxy - cv->p.ref->bb.miny) / (cv->p.ref->bb.maxx - cv->p.ref->bb.minx);
5336 0 : if ( dy >= 2*dx ) {
5337 0 : p.x = fake.u.mouse.x = basex;
5338 0 : p.cx = cv->p.constrain.x;
5339 0 : if ( ItalicConstrained && cv->b.sc->parent->italicangle!=0 ) {
5340 0 : double off = tan(cv->b.sc->parent->italicangle*3.1415926535897932/180)*
5341 0 : (p.cy-cv->p.constrain.y);
5342 0 : double aoff = off<0 ? -off : off;
5343 0 : if ( dx>=aoff*cv->scale/2 && (event->u.mouse.x-basex<0)!=(off<0) ) {
5344 0 : p.cx -= off;
5345 0 : p.x = fake.u.mouse.x = cv->xoff + rint(p.cx*cv->scale);
5346 : }
5347 : }
5348 0 : } else if ( dx >= 2*dy ) {
5349 0 : p.y = fake.u.mouse.y = basey;
5350 0 : p.cy = cv->p.constrain.y;
5351 0 : } else if ( dx > dy ) {
5352 0 : p.x = fake.u.mouse.x = basex + sign * (event->u.mouse.y-basey)/aspect;
5353 0 : p.cx = cv->p.constrain.x - sign * (p.cy-cv->p.constrain.y)/aspect;
5354 : } else {
5355 0 : p.y = fake.u.mouse.y = basey + sign * (event->u.mouse.x-basex)*aspect;
5356 0 : p.cy = cv->p.constrain.y - sign * (p.cx-cv->p.constrain.x)*aspect;
5357 : }
5358 : }
5359 0 : event = &fake;
5360 : }
5361 :
5362 : /* If we've changed the character (recentchange is true) we want to */
5363 : /* snap to the original location, otherwise we'll keep snapping to the */
5364 : /* current point as it moves across the screen (jerkily) */
5365 0 : if ( cv->active_tool == cvt_hand || cv->active_tool == cvt_freehand )
5366 : /* Don't snap to points */;
5367 0 : else if ( !cv->joinvalid ||
5368 0 : ((!cv->b.sc->inspiro || has_spiro) && !CheckPoint(&fs,&cv->joinpos,NULL)) ||
5369 0 : ( cv->b.sc->inspiro && has_spiro && !CheckSpiroPoint(&fs,&cv->joincp,NULL,0))) {
5370 : SplinePointList *spl;
5371 0 : spl = cv->b.layerheads[cv->b.drawmode]->splines;
5372 0 : if ( cv->recentchange && cv->active_tool==cvt_pointer &&
5373 0 : cv->b.layerheads[cv->b.drawmode]->undoes!=NULL &&
5374 0 : (cv->b.layerheads[cv->b.drawmode]->undoes->undotype==ut_state ||
5375 0 : cv->b.layerheads[cv->b.drawmode]->undoes->undotype==ut_tstate ))
5376 0 : spl = cv->b.layerheads[cv->b.drawmode]->undoes->u.state.splines;
5377 0 : if ( cv->active_tool != cvt_knife && cv->active_tool != cvt_ruler ) {
5378 0 : if ( cv->active_tool == cvt_pointer && ( cv->p.nextcp || cv->p.prevcp ))
5379 0 : fs.select_controls = true;
5380 0 : NearSplineSetPoints(&fs,spl,cv->b.sc->inspiro && has_spiro);
5381 : } else
5382 0 : InSplineSet(&fs,spl,cv->b.sc->inspiro && has_spiro);
5383 : }
5384 : /* p.sp and cv->p.sp may correspond to different undo states, thus being */
5385 : /* different objects even while describing essentially the same point. */
5386 : /* So compare point coordinates rather than the points themselves */
5387 0 : if ( (cv->p.nextcp || cv->p.prevcp) && p.nextcp &&
5388 0 : p.sp!=NULL && cv->p.sp != NULL &&
5389 0 : p.sp->me.x == cv->p.sp->me.x && p.sp->me.y == cv->p.sp->me.y ) {
5390 : /* If either control point selected, then snap to it or its brother */
5391 : /* when close */
5392 0 : p.cx = p.sp->nextcp.x;
5393 0 : p.cy = p.sp->nextcp.y;
5394 0 : } else if (( cv->p.nextcp || cv->p.prevcp) && p.prevcp &&
5395 0 : p.sp!=NULL && cv->p.sp != NULL &&
5396 0 : p.sp->me.x == cv->p.sp->me.x && p.sp->me.y == cv->p.sp->me.y ) {
5397 0 : p.cx = p.sp->prevcp.x;
5398 0 : p.cy = p.sp->prevcp.y;
5399 0 : } else if ( p.sp!=NULL && p.sp!=cv->active_sp ) { /* Snap to points */
5400 0 : p.cx = p.sp->me.x;
5401 0 : p.cy = p.sp->me.y;
5402 0 : } else if ( p.spiro!=NULL && p.spiro!=cv->active_cp ) {
5403 0 : p.cx = p.spiro->x;
5404 0 : p.cy = p.spiro->y;
5405 : } else {
5406 0 : CVDoSnaps(cv,&fs);
5407 : }
5408 0 : cx = (p.cx -cv->p.cx) / cv->scale;
5409 0 : cy = (p.cy - cv->p.cy) / cv->scale;
5410 0 : if ( cx<0 ) cx = -cx;
5411 0 : if ( cy<0 ) cy = -cy;
5412 :
5413 : /* If they haven't moved far from the start point, then snap to it */
5414 0 : if ( cx+cy < 4 ) {
5415 0 : p.x = cv->p.x; p.y = cv->p.y;
5416 : }
5417 :
5418 0 : cv->info.x = p.cx; cv->info.y = p.cy;
5419 0 : cv->info_sp = p.sp;
5420 0 : cv->info_spline = p.spline;
5421 0 : cv->info_t = p.t;
5422 0 : cv->e.x = event->u.mouse.x; cv->e.y = event->u.mouse.y;
5423 0 : CVInfoDraw(cv,cv->gw);
5424 :
5425 0 : switch ( cv->active_tool ) {
5426 : case cvt_pointer:
5427 0 : stop_motion = CVMouseMovePointer(cv,event);
5428 0 : break;
5429 : case cvt_magnify: case cvt_minify:
5430 0 : if ( !cv->p.rubberbanding ) {
5431 0 : cv->p.ex = cv->p.cx;
5432 0 : cv->p.ey = cv->p.cy;
5433 : }
5434 0 : if ( cv->p.rubberbanding )
5435 0 : CVDrawRubberRect(cv->v,cv);
5436 0 : cv->p.ex = cv->info.x;
5437 0 : cv->p.ey = cv->info.y;
5438 0 : cv->p.rubberbanding = true;
5439 0 : CVDrawRubberRect(cv->v,cv);
5440 0 : break;
5441 : case cvt_hand:
5442 0 : CVMouseMoveHand(cv,event);
5443 0 : break;
5444 : case cvt_freehand:
5445 0 : CVMouseMoveFreeHand(cv,event);
5446 0 : break;
5447 : case cvt_curve: case cvt_corner: case cvt_tangent: case cvt_hvcurve:
5448 0 : CVMouseMovePoint(cv,&p);
5449 0 : break;
5450 : case cvt_pen:
5451 0 : CVMouseMovePen(cv,&p,event);
5452 0 : break;
5453 : case cvt_ruler:
5454 0 : CVMouseMoveRuler(cv,event);
5455 0 : break;
5456 : case cvt_rotate: case cvt_flip: case cvt_scale: case cvt_skew:
5457 : case cvt_3d_rotate: case cvt_perspective:
5458 0 : CVMouseMoveTransform(cv);
5459 0 : break;
5460 : case cvt_knife:
5461 0 : CVMouseMoveKnife(cv,&p);
5462 0 : break;
5463 : case cvt_rect: case cvt_elipse: case cvt_poly: case cvt_star:
5464 0 : CVMouseMoveShape(cv);
5465 0 : break;
5466 : }
5467 0 : if ( stop_motion ) {
5468 0 : event->type = et_mouseup;
5469 0 : CVMouseUp(cv,event);
5470 : }
5471 : }
5472 :
5473 0 : static void CVMagnify(CharView *cv, real midx, real midy, int bigger, int LockPosition) {
5474 : static float scales[] = { 1, 2, 3, 4, 6, 8, 11, 16, 23, 32, 45, 64, 90, 128, 181, 256, 512, 1024, 0 };
5475 : float oldscale;
5476 : int i, j;
5477 :
5478 0 : oldscale = cv->scale;
5479 :
5480 0 : if ( bigger!=0 ) {
5481 0 : if ( cv->scale>=1 ) {
5482 0 : for ( i=0; scales[i]!=0 && cv->scale>scales[i]; ++i );
5483 0 : if ( scales[i]==0 ) i=j= i-1;
5484 0 : else if ( RealNear(scales[i],cv->scale) ) j=i;
5485 0 : else if ( i!=0 && RealNear(scales[i-1],cv->scale) ) j= --i; /* Round errors! */
5486 0 : else j = i-1;
5487 0 : } else { real sinv = 1/cv->scale; int t;
5488 0 : for ( i=0; scales[i]!=0 && sinv>scales[i]; ++i );
5489 0 : if ( scales[i]==0 ) i=j= i-1;
5490 0 : else if ( RealNear(scales[i],sinv) ) j=i;
5491 0 : else if ( i!=0 && RealNear(scales[i-1],sinv) ) j= --i; /* Round errors! */
5492 0 : else j = i-1;
5493 0 : t = j;
5494 0 : j = -i; i = -t;
5495 : }
5496 0 : if ( bigger==1 ) {
5497 0 : if ( i==j ) ++i;
5498 0 : if ( i>0 && scales[i]==0 ) --i;
5499 0 : if ( i>=0 )
5500 0 : cv->scale = scales[i];
5501 : else
5502 0 : cv->scale = 1/scales[-i];
5503 : } else {
5504 0 : if ( i==j ) --j;
5505 0 : if ( j<0 && scales[-j]==0 ) ++j;
5506 0 : if ( j>=0 )
5507 0 : cv->scale = scales[j];
5508 : else
5509 0 : cv->scale = 1/scales[-j];
5510 : }
5511 : }
5512 :
5513 0 : if (LockPosition) {
5514 0 : float mousex = rint(midx * oldscale + cv->xoff);
5515 0 : float mousey = rint(midy * oldscale + cv->yoff - cv->height);
5516 0 : cv->xoff = mousex - midx*cv->scale;
5517 0 : cv->yoff = mousey - midy*cv->scale + cv->height;
5518 : }
5519 : else {
5520 0 : cv->xoff = -(rint(midx*cv->scale) - cv->width/2);
5521 0 : cv->yoff = -(rint(midy*cv->scale) - cv->height/2);
5522 : }
5523 :
5524 0 : CVNewScale(cv);
5525 0 : }
5526 :
5527 0 : static void CVMouseUp(CharView *cv, GEvent *event ) {
5528 :
5529 0 : CVMouseMove(cv,event);
5530 0 : if ( cv->pressed!=NULL ) {
5531 0 : GDrawCancelTimer(cv->pressed);
5532 0 : cv->pressed = NULL;
5533 : }
5534 0 : cv->p.pressed = false;
5535 0 : CVFreePreTransformSPL( cv );
5536 0 : update_spacebar_hand_tool(cv);
5537 :
5538 0 : if ( cv->p.rubberbanding ) {
5539 0 : CVDrawRubberRect(cv->v,cv);
5540 0 : cv->p.rubberbanding = false;
5541 0 : } else if ( cv->p.rubberlining ) {
5542 0 : CVDrawRubberLine(cv->v,cv);
5543 0 : cv->p.rubberlining = false;
5544 : }
5545 :
5546 : // This is needed to allow characters to the left of the
5547 : // active one to be picked with the mouse,
5548 : // but outright it does mess with keyboard input changing BCP
5549 : // so we only do it for mouse up to the left of the left side
5550 : // bearing, because that click can not currently activate any BCP
5551 0 : if ( cv->active_tool == cvt_pointer &&
5552 0 : MouseToCX( cv, event->u.mouse.x ) < -2 )
5553 : {
5554 : // Since we allow clicking anywhere now, instead of having
5555 : // to check if you clicked on a spline of a prev char,
5556 : // then we don't need this. It also causes an issue with the arrow
5557 : // keys moving a BCP on a spline left of the lbearing line.
5558 : // (comment included just in case this click on spline feature is desired in the future)
5559 : /* FindSel fs; */
5560 : /* SetFS(&fs,&cv->p,cv,event); */
5561 : /* _CVTestSelectFromEvent(cv,&fs); */
5562 : /* fs.p = &cv->p; */
5563 : }
5564 :
5565 :
5566 0 : switch ( cv->active_tool ) {
5567 : case cvt_pointer:
5568 0 : CVMouseUpPointer(cv);
5569 0 : break;
5570 : case cvt_ruler:
5571 0 : CVMouseUpRuler(cv,event);
5572 0 : break;
5573 : case cvt_hand:
5574 0 : CVMouseUpHand(cv);
5575 0 : break;
5576 : case cvt_freehand:
5577 0 : CVMouseUpFreeHand(cv,event);
5578 0 : break;
5579 : case cvt_curve: case cvt_corner: case cvt_tangent: case cvt_hvcurve:
5580 : case cvt_pen:
5581 0 : CVMouseUpPoint(cv,event);
5582 0 : CVGridHandlePossibleFitChar( cv );
5583 0 : break;
5584 : case cvt_magnify: case cvt_minify:
5585 0 : if ( cv->p.x>=event->u.mouse.x-6 && cv->p.x<=event->u.mouse.x+6 &&
5586 0 : cv->p.y>=event->u.mouse.y-6 && cv->p.y<=event->u.mouse.y+6 ) {
5587 : real cx, cy;
5588 0 : cx = (event->u.mouse.x-cv->xoff)/cv->scale;
5589 0 : cy = (cv->height-event->u.mouse.y-cv->yoff)/cv->scale ;
5590 0 : CVMagnify(cv,cx,cy,cv->active_tool==cvt_minify?-1:1,event->u.mouse.button>3);
5591 : } else {
5592 : DBounds b;
5593 0 : double oldscale = cv->scale;
5594 0 : if ( cv->p.cx>cv->info.x ) {
5595 0 : b.minx = cv->info.x;
5596 0 : b.maxx = cv->p.cx;
5597 : } else {
5598 0 : b.minx = cv->p.cx;
5599 0 : b.maxx = cv->info.x;
5600 : }
5601 0 : if ( cv->p.cy>cv->info.y ) {
5602 0 : b.miny = cv->info.y;
5603 0 : b.maxy = cv->p.cy;
5604 : } else {
5605 0 : b.miny = cv->p.cy;
5606 0 : b.maxy = cv->info.y;
5607 : }
5608 0 : _CVFit(cv,&b,false);
5609 0 : if ( oldscale==cv->scale ) {
5610 0 : cv->scale += .5;
5611 0 : CVNewScale(cv);
5612 : }
5613 : }
5614 0 : break;
5615 : case cvt_rotate: case cvt_flip: case cvt_scale: case cvt_skew:
5616 : case cvt_3d_rotate: case cvt_perspective:
5617 0 : CVMouseUpTransform(cv);
5618 0 : break;
5619 : case cvt_knife:
5620 0 : CVMouseUpKnife(cv,event);
5621 0 : break;
5622 : case cvt_rect: case cvt_elipse: case cvt_poly: case cvt_star:
5623 0 : CVMouseUpShape(cv);
5624 0 : CVGridHandlePossibleFitChar( cv );
5625 0 : break;
5626 : }
5627 0 : cv->active_tool = cvt_none;
5628 0 : 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 */
5629 : /* CharChangedUpdate is a rather blunt tool. When moving anchor points with */
5630 : /* the mouse we need finer control than it provides */
5631 : /* If recentchange is set then change should also be set, don't think we */
5632 : /* need the full form of this call */
5633 0 : if ( cv->needsrasterize || cv->recentchange )
5634 0 : _CV_CharChangedUpdate(cv,2);
5635 :
5636 0 : dlist_foreach( &cv->pointInfoDialogs, (dlist_foreach_func_type)PIChangePoint );
5637 0 : collabclient_sendRedo( &cv->b );
5638 0 : }
5639 :
5640 0 : static void CVTimer(CharView *cv,GEvent *event) {
5641 :
5642 0 : if ( event->u.timer.timer==cv->pressed ) {
5643 : GEvent e;
5644 0 : GDrawGetPointerPosition(cv->v,&e);
5645 0 : if ( e.u.mouse.x<0 || e.u.mouse.y<0 ||
5646 0 : e.u.mouse.x>=cv->width || e.u.mouse.y >= cv->height ) {
5647 0 : real dx = 0, dy = 0;
5648 0 : if ( e.u.mouse.x<0 )
5649 0 : dx = cv->width/8;
5650 0 : else if ( e.u.mouse.x>=cv->width )
5651 0 : dx = -cv->width/8;
5652 0 : if ( e.u.mouse.y<0 )
5653 0 : dy = -cv->height/8;
5654 0 : else if ( e.u.mouse.y>=cv->height )
5655 0 : dy = cv->height/8;
5656 0 : cv->xoff += dx; cv->yoff += dy;
5657 0 : cv->back_img_out_of_date = true;
5658 0 : if ( dy!=0 )
5659 0 : GScrollBarSetPos(cv->vsb,cv->yoff-cv->height);
5660 0 : if ( dx!=0 )
5661 0 : GScrollBarSetPos(cv->hsb,-cv->xoff);
5662 0 : GDrawRequestExpose(cv->v,NULL,false);
5663 : }
5664 : #if _ModKeysAutoRepeat
5665 : /* Under cygwin the modifier keys auto repeat, they don't under normal X */
5666 : } else if ( cv->autorpt==event->u.timer.timer ) {
5667 : cv->autorpt = NULL;
5668 : CVToolsSetCursor(cv,cv->oldstate,NULL);
5669 : if ( cv->keysym == GK_Shift_L || cv->keysym == GK_Shift_R ||
5670 : cv->keysym == GK_Alt_L || cv->keysym == GK_Alt_R ||
5671 : cv->keysym == GK_Meta_L || cv->keysym == GK_Meta_R ) {
5672 : GEvent e;
5673 : e.w = cv->oldkeyw;
5674 : e.u.chr.keysym = cv->keysym;
5675 : e.u.chr.x = cv->oldkeyx;
5676 : e.u.chr.y = cv->oldkeyy;
5677 : CVFakeMove(cv,&e);
5678 : }
5679 : #endif
5680 : }
5681 0 : }
5682 :
5683 0 : static void CVDrop(CharView *cv,GEvent *event) {
5684 : /* We should get a list of character names. Add each as a RefChar */
5685 : int32 len;
5686 0 : int ch, first = true;
5687 : char *start, *pt, *cnames;
5688 : SplineChar *rsc;
5689 : RefChar *new;
5690 0 : int layer = CVLayer((CharViewBase *) cv);
5691 :
5692 0 : if ( cv->b.drawmode==dm_grid ) {
5693 0 : ff_post_error(_("Not Guides"),_("References may not be dragged into the guidelines layer"));
5694 0 : return;
5695 : }
5696 0 : if ( !GDrawSelectionHasType(cv->gw,sn_drag_and_drop,"STRING"))
5697 0 : return;
5698 0 : cnames = GDrawRequestSelection(cv->gw,sn_drag_and_drop,"STRING",&len);
5699 0 : if ( cnames==NULL )
5700 0 : return;
5701 :
5702 0 : start = cnames;
5703 0 : while ( *start ) {
5704 0 : while ( *start==' ' ) ++start;
5705 0 : if ( *start=='\0' )
5706 0 : break;
5707 0 : for ( pt=start; *pt && *pt!=' '; ++pt );
5708 0 : ch = *pt; *pt = '\0';
5709 0 : if ( (rsc=SFGetChar(cv->b.sc->parent,-1,start))!=NULL && rsc!=cv->b.sc ) {
5710 0 : if ( first ) {
5711 0 : CVPreserveState(&cv->b);
5712 0 : first =false;
5713 : }
5714 0 : new = RefCharCreate();
5715 0 : new->transform[0] = new->transform[3] = 1.0;
5716 0 : new->layers[0].splines = NULL;
5717 0 : new->sc = rsc;
5718 0 : new->next = cv->b.sc->layers[layer].refs;
5719 0 : cv->b.sc->layers[layer].refs = new;
5720 0 : SCReinstanciateRefChar(cv->b.sc,new,layer);
5721 0 : SCMakeDependent(cv->b.sc,rsc);
5722 : }
5723 0 : *pt = ch;
5724 0 : start = pt;
5725 : }
5726 :
5727 0 : free(cnames);
5728 0 : CVCharChangedUpdate(&cv->b);
5729 : }
5730 :
5731 0 : static int v_e_h(GWindow gw, GEvent *event) {
5732 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
5733 :
5734 0 : GGadgetPopupExternalEvent(event);
5735 0 : if (( event->type==et_mouseup || event->type==et_mousedown ) &&
5736 0 : (event->u.mouse.button>=4 && event->u.mouse.button<=7 ) ) {
5737 0 : if ( !(event->u.mouse.state&(ksm_control)) ) /* bind control to magnify/minify */
5738 : {
5739 0 : int ish = event->u.mouse.button>5;
5740 0 : if ( event->u.mouse.state&ksm_shift ) ish = !ish;
5741 0 : if ( ish ) /* bind shift to vertical scrolling */
5742 0 : return( GGadgetDispatchEvent(cv->hsb,event));
5743 : else
5744 0 : return( GGadgetDispatchEvent(cv->vsb,event));
5745 : }
5746 : }
5747 :
5748 0 : switch ( event->type ) {
5749 : case et_expose:
5750 0 : GDrawSetLineWidth(gw,0);
5751 0 : CVExpose(cv,gw,event);
5752 0 : break;
5753 : case et_crossing:
5754 0 : CVCrossing(cv,event);
5755 0 : break;
5756 : case et_mousedown:
5757 0 : CVPaletteActivate(cv);
5758 0 : if ( cv->gic!=NULL )
5759 0 : GDrawSetGIC(gw,cv->gic,0,20);
5760 0 : if ( cv->inactive )
5761 0 : (cv->b.container->funcs->activateMe)(cv->b.container,&cv->b);
5762 0 : CVMouseDown(cv,event);
5763 0 : break;
5764 : case et_mousemove:
5765 0 : if ( cv->p.pressed || cv->spacebar_hold)
5766 0 : GDrawSkipMouseMoveEvents(cv->v,event);
5767 0 : CVMouseMove(cv,event);
5768 0 : break;
5769 : case et_mouseup:
5770 0 : CVMouseUp(cv,event);
5771 0 : break;
5772 : case et_char:
5773 0 : if ( cv->b.container!=NULL )
5774 0 : (cv->b.container->funcs->charEvent)(cv->b.container,event);
5775 : else
5776 0 : CVChar(cv,event);
5777 0 : break;
5778 : case et_charup:
5779 0 : CVCharUp(cv,event);
5780 0 : break;
5781 : case et_timer:
5782 0 : CVTimer(cv,event);
5783 0 : break;
5784 : case et_drop:
5785 0 : CVDrop(cv,event);
5786 0 : break;
5787 : case et_focus:
5788 0 : if ( event->u.focus.gained_focus ) {
5789 0 : if ( cv->gic!=NULL )
5790 0 : GDrawSetGIC(gw,cv->gic,0,20);
5791 : }
5792 0 : break;
5793 : }
5794 0 : return( true );
5795 : }
5796 :
5797 0 : static void CVDrawNum(CharView *UNUSED(cv),GWindow pixmap,int x, int y, char *format,real val, int align) {
5798 : char buffer[40];
5799 : int len;
5800 :
5801 0 : if ( val==0 ) val=0; /* avoid -0 */
5802 0 : sprintf(buffer,format,(double)val); /* formats are given as for doubles */
5803 0 : if ( align!=0 ) {
5804 0 : len = GDrawGetText8Width(pixmap,buffer,-1);
5805 0 : if ( align==1 )
5806 0 : x-=len/2;
5807 : else
5808 0 : x-=len;
5809 : }
5810 0 : GDrawDrawText8(pixmap,x,y,buffer,-1,GDrawGetDefaultForeground(NULL));
5811 0 : }
5812 :
5813 0 : static void CVDrawVNum(CharView *cv,GWindow pixmap,int x, int y, char *format,real val, int align) {
5814 : char buffer[40], *pt;
5815 : int len;
5816 :
5817 0 : if ( val==0 ) val=0; /* avoid -0 */
5818 0 : sprintf(buffer,format,(double)val); /* formats are given as for doubles */
5819 0 : if ( align!=0 ) {
5820 0 : len = strlen(buffer)*cv->sfh;
5821 0 : if ( align==1 )
5822 0 : y-=len/2;
5823 : else
5824 0 : y-=len;
5825 : }
5826 0 : for ( pt=buffer; *pt; ++pt ) {
5827 0 : GDrawDrawText8(pixmap,x,y,pt,1,GDrawGetDefaultForeground(NULL));
5828 0 : y += cv->sdh;
5829 : }
5830 0 : }
5831 :
5832 :
5833 0 : static void CVExposeRulers(CharView *cv, GWindow pixmap ) {
5834 : real xmin, xmax, ymin, ymax;
5835 : real onehundred, pos;
5836 : real units, littleunits;
5837 0 : int ybase = cv->mbh+cv->charselectorh+cv->infoh;
5838 : int x,y;
5839 : GRect rect;
5840 0 : Color def_fg = GDrawGetDefaultForeground(NULL);
5841 :
5842 0 : xmin = -cv->xoff/cv->scale;
5843 0 : xmax = (cv->width-cv->xoff)/cv->scale;
5844 0 : ymin = -cv->yoff/cv->scale;
5845 0 : ymax = (cv->height-cv->yoff)/cv->scale;
5846 0 : onehundred = 100/cv->scale;
5847 :
5848 0 : if ( onehundred<5 ) {
5849 0 : units = 1; littleunits=0;
5850 0 : } else if ( onehundred<10 ) {
5851 0 : units = 5; littleunits=1;
5852 0 : } else if ( onehundred<50 ) {
5853 0 : units = 10; littleunits=2;
5854 0 : } else if ( onehundred<100 ) {
5855 0 : units = 25; littleunits=5;
5856 0 : } else if ( onehundred<500/2 ) {
5857 0 : units = 100; littleunits=20;
5858 0 : } else if ( onehundred<1000/2 ) {
5859 : // The next numbers (1000 and up) take more space to display, so Frank has adjusted the thresholds.
5860 0 : units = 250; littleunits=50;
5861 0 : } else if ( onehundred<5000/2 ) {
5862 0 : units = 1000; littleunits=200;
5863 0 : } else if ( onehundred<10000/2 ) {
5864 0 : units = 2500; littleunits=500;
5865 0 : } else if ( onehundred<50000/2 ) {
5866 0 : units = 10000; littleunits=2000;
5867 : } else {
5868 0 : for ( units=1 ; units<onehundred*2; units *= 10 );
5869 0 : units/=10; littleunits = units/5;
5870 : }
5871 :
5872 0 : rect.x = 0; rect.width = cv->width+cv->rulerh; rect.y = ybase; rect.height = cv->rulerh;
5873 0 : GDrawFillRect(pixmap,&rect,GDrawGetDefaultBackground(NULL));
5874 0 : rect.y = ybase; rect.height = cv->height+cv->rulerh; rect.x = 0; rect.width = cv->rulerh;
5875 0 : GDrawFillRect(pixmap,&rect,GDrawGetDefaultBackground(NULL));
5876 0 : GDrawSetLineWidth(pixmap,0);
5877 0 : GDrawDrawLine(pixmap,cv->rulerh,cv->mbh+cv->charselectorh+cv->infoh+cv->rulerh-1,8096,cv->mbh+cv->charselectorh+cv->infoh+cv->rulerh-1,def_fg);
5878 0 : GDrawDrawLine(pixmap,cv->rulerh-1,cv->mbh+cv->charselectorh+cv->infoh+cv->rulerh,cv->rulerh-1,8096,def_fg);
5879 :
5880 0 : GDrawSetFont(pixmap,cv->small);
5881 0 : if ( xmax-xmin<1 && cv->width>100 ) {
5882 0 : CVDrawNum(cv,pixmap,cv->rulerh,ybase+cv->sas,"%.3f",xmin,0);
5883 0 : CVDrawNum(cv,pixmap,cv->rulerh+cv->width,ybase+cv->sas,"%.3f",xmax,2);
5884 : }
5885 0 : if ( ymax-ymin<1 && cv->height>100 ) {
5886 0 : CVDrawVNum(cv,pixmap,1,ybase+cv->rulerh+cv->height+cv->sas,"%.3f",ymin,0);
5887 0 : CVDrawVNum(cv,pixmap,1,ybase+cv->rulerh+cv->sas,"%.3f",ymax,2);
5888 : }
5889 0 : if ( fabs(xmin/units) < 1e5 && fabs(ymin/units)<1e5 && fabs(xmax/units)<1e5 && fabs(ymax/units)<1e5 ) {
5890 0 : if ( littleunits!=0 ) {
5891 0 : for ( pos=littleunits*ceil(xmin/littleunits); pos<xmax; pos += littleunits ) {
5892 0 : x = cv->xoff + rint(pos*cv->scale);
5893 0 : GDrawDrawLine(pixmap,x+cv->rulerh,ybase+cv->rulerh-4,x+cv->rulerh,ybase+cv->rulerh, def_fg);
5894 : }
5895 0 : for ( pos=littleunits*ceil(ymin/littleunits); pos<ymax; pos += littleunits ) {
5896 0 : y = -cv->yoff + cv->height - rint(pos*cv->scale);
5897 0 : GDrawDrawLine(pixmap,cv->rulerh-4,ybase+cv->rulerh+y,cv->rulerh,ybase+cv->rulerh+y, def_fg);
5898 : }
5899 : }
5900 0 : for ( pos=units*ceil(xmin/units); pos<xmax; pos += units ) {
5901 0 : x = cv->xoff + rint(pos*cv->scale);
5902 0 : GDrawDrawLine(pixmap,x+cv->rulerh,ybase,x+cv->rulerh,ybase+cv->rulerh, rulerbigtickcol);
5903 0 : CVDrawNum(cv,pixmap,x+cv->rulerh+15,ybase+cv->sas,"%g",pos,1);
5904 : }
5905 0 : for ( pos=units*ceil(ymin/units); pos<ymax; pos += units ) {
5906 0 : y = -cv->yoff + cv->height - rint(pos*cv->scale);
5907 0 : GDrawDrawLine(pixmap,0,ybase+cv->rulerh+y,cv->rulerh,ybase+cv->rulerh+y, rulerbigtickcol);
5908 0 : CVDrawVNum(cv,pixmap,1,y+ybase+cv->rulerh+cv->sas+20,"%g",pos,1);
5909 : }
5910 : }
5911 0 : }
5912 :
5913 0 : static void InfoExpose(CharView *cv, GWindow pixmap, GEvent *expose) {
5914 : GRect old1, old2;
5915 0 : Color def_fg = GDrawGetDefaultForeground(NULL);
5916 :
5917 0 : if ( expose->u.expose.rect.y + expose->u.expose.rect.height < cv->mbh ||
5918 0 : (!cv->showrulers && expose->u.expose.rect.y >= cv->mbh+cv->charselectorh+cv->infoh ))
5919 0 : return;
5920 :
5921 0 : GDrawPushClip(pixmap,&expose->u.expose.rect,&old1);
5922 0 : GDrawSetLineWidth(pixmap,0);
5923 0 : if ( expose->u.expose.rect.y< cv->mbh+cv->charselectorh+cv->infoh ) {
5924 0 : GDrawPushClip(pixmap,&expose->u.expose.rect,&old2);
5925 :
5926 0 : GDrawDrawLine(pixmap,0,cv->mbh+cv->charselectorh+cv->infoh-1,8096,cv->mbh+cv->charselectorh+cv->infoh-1,def_fg);
5927 0 : GDrawDrawImage(pixmap,&GIcon_rightpointer,NULL,RPT_BASE,cv->mbh+cv->charselectorh+2);
5928 0 : GDrawDrawImage(pixmap,&GIcon_selectedpoint,NULL,SPT_BASE,cv->mbh+cv->charselectorh+2);
5929 0 : GDrawDrawImage(pixmap,&GIcon_sel2ptr,NULL,SOF_BASE,cv->mbh+cv->charselectorh+2);
5930 0 : GDrawDrawImage(pixmap,&GIcon_distance,NULL,SDS_BASE,cv->mbh+cv->charselectorh+2);
5931 0 : GDrawDrawImage(pixmap,&GIcon_angle,NULL,SAN_BASE,cv->mbh+cv->charselectorh+2);
5932 0 : GDrawDrawImage(pixmap,&GIcon_mag,NULL,MAG_BASE,cv->mbh+cv->charselectorh+2);
5933 0 : CVInfoDrawText(cv,pixmap);
5934 0 : GDrawPopClip(pixmap,&old2);
5935 : }
5936 0 : if ( cv->showrulers ) {
5937 0 : CVExposeRulers(cv,pixmap);
5938 0 : cv->olde.x = -1;
5939 0 : CVInfoDrawRulers(cv,pixmap);
5940 : }
5941 0 : GDrawPopClip(pixmap,&old1);
5942 : }
5943 :
5944 0 : void CVResize(CharView *cv ) {
5945 0 : int sbsize = GDrawPointsToPixels(cv->gw,_GScrollBar_Width);
5946 : GRect size;
5947 0 : GDrawGetSize(cv->gw,&size);
5948 : {
5949 0 : int newwidth = size.width-sbsize,
5950 0 : newheight = size.height-sbsize - cv->mbh-cv->charselectorh-cv->infoh;
5951 0 : int sbwidth = newwidth, sbheight = newheight;
5952 :
5953 0 : if ( cv->dv!=NULL ) {
5954 0 : newwidth -= cv->dv->dwidth;
5955 0 : sbwidth -= cv->dv->dwidth;
5956 : }
5957 0 : if ( newwidth<30 || newheight<50 ) {
5958 0 : if ( newwidth<30 )
5959 0 : newwidth = 30+sbsize+(cv->dv!=NULL ? cv->dv->dwidth : 0);
5960 0 : if ( newheight<50 )
5961 0 : newheight = 50+sbsize+cv->mbh+cv->charselectorh+cv->infoh;
5962 0 : GDrawResize(cv->gw,newwidth,newheight);
5963 0 : return;
5964 : }
5965 :
5966 0 : if ( cv->dv!=NULL ) {
5967 0 : int dvheight = size.height-(cv->mbh+cv->charselectorh+cv->infoh);
5968 0 : GDrawMove(cv->dv->dv,size.width-cv->dv->dwidth,cv->mbh+cv->charselectorh+cv->infoh);
5969 0 : GDrawResize(cv->dv->dv,cv->dv->dwidth,dvheight);
5970 0 : GDrawResize(cv->dv->ii.v,cv->dv->dwidth-sbsize,dvheight-cv->dv->toph);
5971 0 : GGadgetResize(cv->dv->ii.vsb,sbsize,dvheight-cv->dv->toph);
5972 0 : cv->dv->ii.vheight = dvheight-cv->dv->toph;
5973 0 : GDrawRequestExpose(cv->dv->dv,NULL,false);
5974 0 : GDrawRequestExpose(cv->dv->ii.v,NULL,false);
5975 0 : GScrollBarSetBounds(cv->dv->ii.vsb,0,cv->dv->ii.lheight+1,
5976 0 : cv->dv->ii.vheight/cv->dv->ii.fh);
5977 : }
5978 :
5979 0 : if (cv->charselector != NULL && cv->charselectorPrev != NULL && cv->charselectorNext != NULL) {
5980 : GRect charselector_size;
5981 : GRect charselectorNext_size;
5982 : GRect charselectorPrev_size;
5983 0 : GGadgetGetSize(cv->charselector, &charselector_size);
5984 0 : GGadgetGetSize(cv->charselectorPrev, &charselectorPrev_size);
5985 0 : GGadgetGetSize(cv->charselectorNext, &charselectorNext_size);
5986 0 : int new_charselector_width = newwidth + sbsize - ( 4 * charselector_size.x ) - charselectorNext_size.width - charselectorPrev_size.width;
5987 0 : int new_charselectorPrev_x = newwidth + sbsize - ( 2 * charselector_size.x ) - charselectorNext_size.width - charselectorPrev_size.width;
5988 0 : int new_charselectorNext_x = newwidth + sbsize - ( 1 * charselector_size.x ) - charselectorNext_size.width;
5989 0 : GGadgetResize(cv->charselector, new_charselector_width, charselector_size.height);
5990 0 : GGadgetMove(cv->charselectorPrev, new_charselectorPrev_x, charselectorPrev_size.y);
5991 0 : GGadgetMove(cv->charselectorNext, new_charselectorNext_x, charselectorNext_size.y);
5992 0 : charselector_size.x = 0; charselector_size.y = cv->mbh; charselector_size.width = newwidth + sbsize; charselector_size.height = cv->charselectorh;
5993 0 : GDrawRequestExpose(cv->gw, &charselector_size, false);
5994 : }
5995 :
5996 0 : if ( cv->showrulers ) {
5997 0 : newheight -= cv->rulerh;
5998 0 : newwidth -= cv->rulerh;
5999 : }
6000 :
6001 0 : if ( newwidth == cv->width && newheight == cv->height )
6002 0 : return;
6003 0 : if ( cv->backimgs!=NULL )
6004 0 : GDrawDestroyWindow(cv->backimgs);
6005 0 : cv->backimgs = NULL;
6006 :
6007 : /* MenuBar takes care of itself */
6008 0 : GDrawResize(cv->v,newwidth,newheight);
6009 0 : GGadgetMove(cv->vsb,sbwidth, cv->mbh+cv->charselectorh+cv->infoh);
6010 0 : GGadgetResize(cv->vsb,sbsize,sbheight);
6011 0 : GGadgetMove(cv->hsb,0,size.height-sbsize);
6012 0 : GGadgetResize(cv->hsb,sbwidth,sbsize);
6013 0 : cv->width = newwidth; cv->height = newheight;
6014 0 : /*CVFit(cv);*/ CVNewScale(cv);
6015 0 : CVPalettesRaise(cv);
6016 0 : if ( cv->b.container == NULL && ( cv_width!=size.width || cv_height!=size.height )) {
6017 0 : cv_width = size.width;
6018 0 : cv_height = size.height;
6019 0 : SavePrefs(true);
6020 : }
6021 : }
6022 : }
6023 :
6024 0 : static void CVHScrollSetPos( CharView *cv, int newpos )
6025 : {
6026 : TRACE("CVHScrollSetPos(1) cvxoff:%f newpos:%d\n", cv->xoff, newpos );
6027 0 : if ( newpos<-(32000*cv->scale-cv->width) )
6028 0 : newpos = -(32000*cv->scale-cv->width);
6029 0 : if ( newpos>8000*cv->scale ) newpos = 8000*cv->scale;
6030 : TRACE("CVHScrollSetPos(2) cvxoff:%f newpos:%d\n", cv->xoff, newpos );
6031 0 : if ( newpos!=cv->xoff ) {
6032 0 : int diff = newpos-cv->xoff;
6033 0 : cv->xoff = newpos;
6034 0 : cv->back_img_out_of_date = true;
6035 0 : GScrollBarSetPos(cv->hsb,-newpos);
6036 0 : GDrawScroll(cv->v,NULL,diff,0);
6037 0 : if (( cv->showhhints && cv->b.sc->hstem!=NULL ) || cv->showblues || cv->showvmetrics ) {
6038 : GRect r;
6039 0 : r.y = 0; r.height = cv->height;
6040 0 : r.width = 6*cv->sfh+10;
6041 0 : if ( diff>0 )
6042 0 : r.x = cv->width-r.width;
6043 : else
6044 0 : r.x = cv->width+diff-r.width;
6045 0 : GDrawRequestExpose(cv->v,&r,false);
6046 : }
6047 0 : if ( cv->showrulers ) {
6048 : GRect r;
6049 0 : r.y = cv->infoh+cv->mbh+cv->charselectorh; r.height = cv->rulerh; r.x = 0; r.width = cv->rulerh+cv->width;
6050 0 : GDrawRequestExpose(cv->gw,&r,false);
6051 : }
6052 : }
6053 0 : }
6054 :
6055 0 : static void CVHScroll(CharView *cv, struct sbevent *sb) {
6056 0 : int newpos = cv->xoff;
6057 :
6058 0 : switch( sb->type ) {
6059 : case et_sb_top:
6060 0 : newpos = 0;
6061 0 : break;
6062 : case et_sb_uppage:
6063 0 : newpos += 9*cv->width/10;
6064 0 : break;
6065 : case et_sb_up:
6066 0 : newpos += cv->width/15;
6067 0 : break;
6068 : case et_sb_down:
6069 0 : newpos -= cv->width/15;
6070 0 : break;
6071 : case et_sb_downpage:
6072 0 : newpos -= 9*cv->width/10;
6073 0 : break;
6074 : case et_sb_bottom:
6075 0 : newpos = 0;
6076 0 : break;
6077 : case et_sb_thumb:
6078 : case et_sb_thumbrelease:
6079 0 : newpos = -sb->pos;
6080 0 : break;
6081 : case et_sb_halfup:
6082 0 : newpos += cv->width/30;
6083 0 : break;
6084 : case et_sb_halfdown:
6085 0 : newpos -= cv->width/30;
6086 0 : break;
6087 : }
6088 :
6089 0 : CVHScrollSetPos( cv, newpos );
6090 0 : }
6091 :
6092 0 : static void CVVScroll(CharView *cv, struct sbevent *sb) {
6093 0 : int newpos = cv->yoff;
6094 :
6095 0 : switch( sb->type ) {
6096 : case et_sb_top:
6097 0 : newpos = 0;
6098 0 : break;
6099 : case et_sb_uppage:
6100 0 : newpos -= 9*cv->height/10;
6101 0 : break;
6102 : case et_sb_up:
6103 0 : newpos -= cv->height/15;
6104 0 : break;
6105 : case et_sb_down:
6106 0 : newpos += cv->height/15;
6107 0 : break;
6108 : case et_sb_downpage:
6109 0 : newpos += 9*cv->height/10;
6110 0 : break;
6111 : case et_sb_bottom:
6112 0 : newpos = 0;
6113 0 : break;
6114 : case et_sb_thumb:
6115 : case et_sb_thumbrelease:
6116 0 : newpos = sb->pos+cv->height;
6117 0 : break;
6118 : case et_sb_halfup:
6119 0 : newpos -= cv->height/30;
6120 0 : break;
6121 : case et_sb_halfdown:
6122 0 : newpos += cv->height/30;
6123 0 : break;
6124 : }
6125 0 : if ( newpos<-(20000*cv->scale-cv->height) )
6126 0 : newpos = -(20000*cv->scale-cv->height);
6127 0 : if ( newpos>8000*cv->scale ) newpos = 8000*cv->scale;
6128 0 : if ( newpos!=cv->yoff ) {
6129 0 : int diff = newpos-cv->yoff;
6130 0 : cv->yoff = newpos;
6131 0 : cv->back_img_out_of_date = true;
6132 0 : GScrollBarSetPos(cv->vsb,newpos-cv->height);
6133 0 : GDrawScroll(cv->v,NULL,0,diff);
6134 0 : if (( cv->showvhints && cv->b.sc->vstem!=NULL) || cv->showhmetrics ) {
6135 : GRect r;
6136 0 : RefChar *lock = HasUseMyMetrics(cv->b.sc,CVLayer((CharViewBase *) cv));
6137 0 : r.x = 0; r.width = cv->width;
6138 0 : r.height = 2*cv->sfh+6;
6139 0 : if ( lock!=NULL )
6140 0 : r.height = cv->sfh+3+GImageGetHeight(&GIcon_lock);
6141 0 : if ( diff>0 )
6142 0 : r.y = 0;
6143 : else
6144 0 : r.y = -diff;
6145 0 : GDrawRequestExpose(cv->v,&r,false);
6146 : }
6147 0 : if ( cv->showrulers ) {
6148 : GRect r;
6149 0 : r.x = 0; r.width = cv->rulerh; r.y = cv->infoh+cv->charselectorh+cv->mbh; r.height = cv->rulerh+cv->height;
6150 0 : GDrawRequestExpose(cv->gw,&r,false);
6151 : }
6152 : }
6153 0 : }
6154 :
6155 0 : void LogoExpose(GWindow pixmap,GEvent *event, GRect *r,enum drawmode dm) {
6156 0 : int sbsize = GDrawPointsToPixels(pixmap,_GScrollBar_Width);
6157 : GRect old;
6158 :
6159 0 : r->width = r->height = sbsize;
6160 0 : if ( event->u.expose.rect.x+event->u.expose.rect.width >= r->x &&
6161 0 : event->u.expose.rect.y+event->u.expose.rect.height >= r->y ) {
6162 : /* Put something into the little box where the two scroll bars meet */
6163 : int xoff, yoff;
6164 0 : GImage *which = (dm==dm_fore) ? &GIcon_FontForgeLogo :
6165 0 : (dm==dm_back) ? &GIcon_FontForgeBack :
6166 : &GIcon_FontForgeGuide;
6167 0 : struct _GImage *base = which->u.image;
6168 0 : xoff = (sbsize-base->width);
6169 0 : yoff = (sbsize-base->height);
6170 0 : GDrawPushClip(pixmap,r,&old);
6171 0 : GDrawDrawImage(pixmap,which,NULL,
6172 0 : r->x+(xoff-xoff/2),r->y+(yoff-yoff/2));
6173 0 : GDrawPopClip(pixmap,&old);
6174 : /*GDrawDrawLine(pixmap,r->x+sbsize-1,r->y,r->x+sbsize-1,r->y+sbsize,0x000000);*/
6175 : }
6176 0 : }
6177 :
6178 0 : static void CVLogoExpose(CharView *cv,GWindow pixmap,GEvent *event) {
6179 0 : int rh = cv->showrulers ? cv->rulerh : 0;
6180 : GRect r;
6181 :
6182 0 : r.x = cv->width+rh;
6183 0 : r.y = cv->height+cv->mbh+cv->charselectorh+cv->infoh+rh;
6184 0 : LogoExpose(pixmap,event,&r,cv->b.drawmode==dm_grid? dm_grid :
6185 0 : cv->b.layerheads[cv->b.drawmode]->background ? dm_back : dm_fore );
6186 0 : }
6187 :
6188 0 : static void CVDrawGuideLine(CharView *cv,int guide_pos) {
6189 0 : GWindow pixmap = cv->v;
6190 :
6191 0 : if ( guide_pos<0 )
6192 0 : return;
6193 0 : GDrawSetDashedLine(pixmap,2,2,0);
6194 0 : GDrawSetLineWidth(pixmap,0);
6195 0 : GDrawSetXORMode(pixmap);
6196 0 : GDrawSetXORBase(pixmap,GDrawGetDefaultBackground(NULL));
6197 0 : if ( cv->ruler_pressedv ) {
6198 0 : GDrawDrawLine(pixmap,guide_pos,0,guide_pos,cv->height,0x000000);
6199 : } else {
6200 0 : GDrawDrawLine(pixmap,0,guide_pos,cv->width,guide_pos,0x000000);
6201 : }
6202 0 : GDrawSetCopyMode(pixmap);
6203 0 : GDrawSetDashedLine(pixmap,0,0,0);
6204 : }
6205 :
6206 0 : static void CVAddGuide(CharView *cv,int is_v,int guide_pos) {
6207 : SplinePoint *sp1, *sp2;
6208 : SplineSet *ss;
6209 0 : SplineFont *sf = cv->b.sc->parent;
6210 0 : int emsize = sf->ascent+sf->descent;
6211 :
6212 0 : if ( is_v ) {
6213 : /* Create a vertical guide line */
6214 0 : double x = (guide_pos-cv->xoff)/cv->scale;
6215 0 : sp1 = SplinePointCreate(x,sf->ascent+emsize/2);
6216 0 : sp2 = SplinePointCreate(x,-sf->descent-emsize/2);
6217 : } else {
6218 0 : double y = (cv->height-guide_pos-cv->yoff)/cv->scale;
6219 0 : sp1 = SplinePointCreate(-emsize,y);
6220 0 : sp2 = SplinePointCreate(2*emsize,y);
6221 : }
6222 0 : SplineMake(sp1,sp2,sf->grid.order2);
6223 0 : ss = chunkalloc(sizeof(SplineSet));
6224 0 : ss->first = sp1; ss->last = sp2;
6225 0 : ss->next = sf->grid.splines;
6226 0 : sf->grid.splines = ss;
6227 0 : ss->contour_name = gwwv_ask_string(_("Name this contour"),NULL,
6228 0 : _("Name this guideline or cancel to create it without a name"));
6229 0 : if ( ss->contour_name!=NULL && *ss->contour_name=='\0' ) {
6230 0 : free(ss->contour_name);
6231 0 : ss->contour_name = NULL;
6232 : }
6233 :
6234 0 : FVRedrawAllCharViewsSF(sf);
6235 0 : if ( !sf->changed ) {
6236 0 : sf->changed = true;
6237 0 : FVSetTitles(sf);
6238 : }
6239 0 : }
6240 :
6241 : static CharView* ActiveCharView = 0;
6242 :
6243 0 : static int cv_e_h(GWindow gw, GEvent *event) {
6244 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
6245 :
6246 0 : if (( event->type==et_mouseup || event->type==et_mousedown ) &&
6247 0 : (event->u.mouse.button>=4 && event->u.mouse.button<=7) ) {
6248 0 : int ish = event->u.mouse.button>5;
6249 0 : if ( event->u.mouse.state&ksm_shift ) ish = !ish;
6250 0 : if ( ish ) /* bind shift to vertical scrolling */
6251 0 : return( GGadgetDispatchEvent(cv->hsb,event));
6252 : else
6253 0 : return( GGadgetDispatchEvent(cv->vsb,event));
6254 : }
6255 :
6256 0 : switch ( event->type ) {
6257 : case et_selclear:
6258 0 : ClipboardClear();
6259 0 : break;
6260 : case et_expose:
6261 0 : GDrawSetLineWidth(gw,0);
6262 0 : InfoExpose(cv,gw,event);
6263 0 : CVLogoExpose(cv,gw,event);
6264 0 : break;
6265 : case et_char:
6266 0 : if ( cv->b.container!=NULL )
6267 0 : (cv->b.container->funcs->charEvent)(cv->b.container,event);
6268 : else
6269 0 : CVChar(cv,event);
6270 0 : break;
6271 : case et_charup:
6272 0 : CVCharUp(cv,event);
6273 0 : break;
6274 : case et_resize:
6275 0 : if ( event->u.resize.sized )
6276 0 : CVResize(cv);
6277 0 : break;
6278 : case et_controlevent:
6279 0 : switch ( event->u.control.subtype ) {
6280 : case et_scrollbarchange:
6281 0 : if ( event->u.control.g == cv->hsb )
6282 0 : CVHScroll(cv,&event->u.control.u.sb);
6283 : else
6284 0 : CVVScroll(cv,&event->u.control.u.sb);
6285 0 : break;
6286 : }
6287 0 : break;
6288 : case et_map:
6289 0 : if ( event->u.map.is_visible )
6290 0 : CVPaletteActivate(cv);
6291 : else
6292 0 : CVPalettesHideIfMine(cv);
6293 0 : break;
6294 : case et_destroy:
6295 0 : CVUnlinkView(cv);
6296 0 : CVPalettesHideIfMine(cv);
6297 0 : if ( cv->backimgs!=NULL ) {
6298 0 : GDrawDestroyWindow(cv->backimgs);
6299 0 : cv->backimgs = NULL;
6300 : }
6301 0 : if ( cv->icon!=NULL ) {
6302 0 : GDrawDestroyWindow(cv->icon);
6303 0 : cv->icon = NULL;
6304 : }
6305 0 : CharViewFree(cv);
6306 0 : break;
6307 : case et_close:
6308 0 : dlist_foreach( &cv->pointInfoDialogs, PI_Destroy );
6309 0 : GDrawDestroyWindow(gw);
6310 0 : break;
6311 : case et_mouseup: case et_mousedown:
6312 0 : GGadgetEndPopup();
6313 0 : CVPaletteActivate(cv);
6314 0 : if ( cv->inactive )
6315 0 : (cv->b.container->funcs->activateMe)(cv->b.container,&cv->b);
6316 0 : if ( cv->showrulers ) {
6317 0 : 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;
6318 0 : int is_v = event->u.mouse.x<cv->rulerh;
6319 0 : if ( cv->gwgic!=NULL && event->type==et_mousedown)
6320 0 : GDrawSetGIC(gw,cv->gwgic,0,20);
6321 0 : if ( event->type == et_mousedown ) {
6322 0 : if ( is_h && is_v )
6323 : /* Ambiguous, ignore */;
6324 0 : else if ( is_h ) {
6325 0 : cv->ruler_pressed = true;
6326 0 : cv->ruler_pressedv = false;
6327 0 : GDrawSetCursor(cv->v,ct_updown);
6328 0 : GDrawSetCursor(cv->gw,ct_updown);
6329 0 : } else if ( is_v ) {
6330 0 : cv->ruler_pressed = true;
6331 0 : cv->ruler_pressedv = true;
6332 0 : GDrawSetCursor(cv->v,ct_leftright);
6333 0 : GDrawSetCursor(cv->gw,ct_leftright);
6334 : }
6335 0 : cv->guide_pos = -1;
6336 0 : } else if ( event->type==et_mouseup && cv->ruler_pressed ) {
6337 0 : CVDrawGuideLine(cv,cv->guide_pos);
6338 0 : cv->guide_pos = -1;
6339 0 : cv->showing_tool = cvt_none;
6340 0 : 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 */
6341 0 : GDrawSetCursor(cv->gw,ct_mypointer);
6342 0 : cv->ruler_pressed = false;
6343 0 : if ( is_h || is_v )
6344 : /* Do Nothing */;
6345 0 : else if ( cv->ruler_pressedv )
6346 0 : CVAddGuide(cv,true,event->u.mouse.x-cv->rulerh);
6347 : else
6348 0 : CVAddGuide(cv,false,event->u.mouse.y-(cv->mbh+cv->charselectorh+cv->infoh+cv->rulerh));
6349 : }
6350 : }
6351 0 : break;
6352 : case et_mousemove:
6353 0 : if ( cv->ruler_pressed ) {
6354 0 : CVDrawGuideLine(cv,cv->guide_pos);
6355 0 : cv->e.x = event->u.mouse.x - cv->rulerh;
6356 0 : cv->e.y = event->u.mouse.y-(cv->mbh+cv->charselectorh+cv->infoh+cv->rulerh);
6357 0 : cv->info.x = (cv->e.x-cv->xoff)/cv->scale;
6358 0 : cv->info.y = (cv->height-cv->e.y-cv->yoff)/cv->scale;
6359 0 : if ( cv->ruler_pressedv )
6360 0 : cv->guide_pos = cv->e.x;
6361 : else
6362 0 : cv->guide_pos = cv->e.y;
6363 0 : CVDrawGuideLine(cv,cv->guide_pos);
6364 0 : CVInfoDraw(cv,cv->gw);
6365 : }
6366 0 : else if ( event->u.mouse.y > cv->mbh )
6367 : {
6368 0 : if( GGadgetContainsEventLocation( cv->charselectorPrev, event ))
6369 : {
6370 0 : GGadgetPreparePopup(cv->gw,c_to_u("Show the previous word in the current word list\n"
6371 : "Select the menu File / Load Word List... to load a wordlist."));
6372 : }
6373 0 : else if( GGadgetContainsEventLocation( cv->charselectorNext, event ))
6374 : {
6375 0 : GGadgetPreparePopup(cv->gw,c_to_u("Show the next word in the current word list\n"
6376 : "Select the menu File / Load Word List... to load a wordlist."));
6377 : }
6378 0 : else if( GGadgetContainsEventLocation( cv->charselector, event ))
6379 : {
6380 0 : GGadgetPreparePopup(cv->gw,c_to_u("This is a word list that you can step through to quickly see your glyphs in context\n"
6381 : "Select the menu File / Load Word List... to load a wordlist."));
6382 : }
6383 : else
6384 : {
6385 0 : int enc = CVCurEnc(cv);
6386 0 : SCPreparePopup(cv->gw,cv->b.sc,cv->b.fv->map->remap,enc,
6387 0 : UniFromEnc(enc,cv->b.fv->map->enc));
6388 : }
6389 : }
6390 0 : break;
6391 : case et_drop:
6392 0 : CVDrop(cv,event);
6393 0 : break;
6394 : case et_focus:
6395 0 : if ( event->u.focus.gained_focus ) {
6396 0 : ActiveCharView = cv;
6397 0 : if ( cv->gic!=NULL )
6398 0 : GDrawSetGIC(gw,cv->gic,0,20);
6399 : }
6400 0 : break;
6401 : }
6402 0 : return( true );
6403 : }
6404 :
6405 0 : CharView* CharViewFindActive()
6406 : {
6407 0 : return ActiveCharView;
6408 : }
6409 :
6410 :
6411 : #define MID_Fit 2001
6412 : #define MID_ZoomIn 2002
6413 : #define MID_ZoomOut 2003
6414 : #define MID_HidePoints 2004
6415 : #define MID_HideControlPoints 2005
6416 : #define MID_Fill 2006
6417 : #define MID_Next 2007
6418 : #define MID_Prev 2008
6419 : #define MID_HideRulers 2009
6420 : #define MID_Preview 2010
6421 : #define MID_DraggingComparisonOutline 2011
6422 : #define MID_NextDef 2012
6423 : #define MID_PrevDef 2013
6424 : #define MID_DisplayCompositions 2014
6425 : #define MID_MarkExtrema 2015
6426 : #define MID_Goto 2016
6427 : #define MID_FindInFontView 2017
6428 : #define MID_KernPairs 2018
6429 : #define MID_AnchorPairs 2019
6430 : #define MID_ShowGridFit 2020
6431 : #define MID_PtsNone 2021
6432 : #define MID_PtsTrue 2022
6433 : #define MID_PtsPost 2023
6434 : #define MID_PtsSVG 2024
6435 : #define MID_Ligatures 2025
6436 : #define MID_Former 2026
6437 : #define MID_MarkPointsOfInflection 2027
6438 : #define MID_ShowCPInfo 2028
6439 : #define MID_ShowTabs 2029
6440 : #define MID_AnchorGlyph 2030
6441 : #define MID_AnchorControl 2031
6442 : #define MID_ShowSideBearings 2032
6443 : #define MID_Bigger 2033
6444 : #define MID_Smaller 2034
6445 : #define MID_GridFitAA 2035
6446 : #define MID_GridFitOff 2036
6447 : #define MID_ShowHHints 2037
6448 : #define MID_ShowVHints 2038
6449 : #define MID_ShowDHints 2039
6450 : #define MID_ShowBlueValues 2040
6451 : #define MID_ShowFamilyBlues 2041
6452 : #define MID_ShowAnchors 2042
6453 : #define MID_ShowHMetrics 2043
6454 : #define MID_ShowVMetrics 2044
6455 : #define MID_ShowRefNames 2045
6456 : #define MID_ShowAlmostHV 2046
6457 : #define MID_ShowAlmostHVCurves 2047
6458 : #define MID_DefineAlmost 2048
6459 : #define MID_SnapOutlines 2049
6460 : #define MID_ShowDebugChanges 2050
6461 : #define MID_Cut 2101
6462 : #define MID_Copy 2102
6463 : #define MID_Paste 2103
6464 : #define MID_Clear 2104
6465 : #define MID_Merge 2105
6466 : #define MID_SelAll 2106
6467 : #define MID_CopyRef 2107
6468 : #define MID_UnlinkRef 2108
6469 : #define MID_Undo 2109
6470 : #define MID_Redo 2110
6471 : #define MID_CopyWidth 2111
6472 : #define MID_RemoveUndoes 2112
6473 : #define MID_CopyFgToBg 2115
6474 : #define MID_NextPt 2116
6475 : #define MID_PrevPt 2117
6476 : #define MID_FirstPt 2118
6477 : #define MID_NextCP 2119
6478 : #define MID_PrevCP 2120
6479 : #define MID_SelNone 2121
6480 : #define MID_SelectWidth 2122
6481 : #define MID_SelectVWidth 2123
6482 : #define MID_CopyLBearing 2124
6483 : #define MID_CopyRBearing 2125
6484 : #define MID_CopyVWidth 2126
6485 : #define MID_Join 2127
6486 : #define MID_CopyGridFit 2128
6487 : /*#define MID_Elide 2129*/
6488 : #define MID_SelectAllPoints 2130
6489 : #define MID_SelectAnchors 2131
6490 : #define MID_FirstPtNextCont 2132
6491 : #define MID_Contours 2133
6492 : #define MID_SelectHM 2134
6493 : #define MID_SelInvert 2136
6494 : #define MID_CopyBgToFg 2137
6495 : #define MID_SelPointAt 2138
6496 : #define MID_CopyLookupData 2139
6497 : #define MID_SelectOpenContours 2140
6498 : #define MID_MergeToLine 2141
6499 : #define MID_Clockwise 2201
6500 : #define MID_Counter 2202
6501 : #define MID_GetInfo 2203
6502 : #define MID_Correct 2204
6503 : #define MID_AvailBitmaps 2210
6504 : #define MID_RegenBitmaps 2211
6505 : #define MID_Stroke 2205
6506 : #define MID_RmOverlap 2206
6507 : #define MID_Simplify 2207
6508 : #define MID_BuildAccent 2208
6509 : #define MID_Autotrace 2212
6510 : #define MID_Round 2213
6511 : #define MID_Embolden 2217
6512 : #define MID_Condense 2218
6513 : #define MID_Average 2219
6514 : #define MID_SpacePts 2220
6515 : #define MID_SpaceRegion 2221
6516 : #define MID_MakeParallel 2222
6517 : #define MID_ShowDependentRefs 2223
6518 : #define MID_AddExtrema 2224
6519 : #define MID_CleanupGlyph 2225
6520 : #define MID_TilePath 2226
6521 : #define MID_BuildComposite 2227
6522 : #define MID_Exclude 2228
6523 : #define MID_Intersection 2229
6524 : #define MID_FindInter 2230
6525 : #define MID_Styles 2231
6526 : #define MID_SimplifyMore 2232
6527 : #define MID_First 2233
6528 : #define MID_Earlier 2234
6529 : #define MID_Later 2235
6530 : #define MID_Last 2236
6531 : #define MID_CharInfo 2240
6532 : #define MID_ShowDependentSubs 2241
6533 : #define MID_CanonicalStart 2242
6534 : #define MID_CanonicalContours 2243
6535 : #define MID_RemoveBitmaps 2244
6536 : #define MID_RoundToCluster 2245
6537 : #define MID_Align 2246
6538 : #define MID_FontInfo 2247
6539 : #define MID_FindProblems 2248
6540 : #define MID_InsertText 2249
6541 : #define MID_Italic 2250
6542 : #define MID_ChangeXHeight 2251
6543 : #define MID_ChangeGlyph 2252
6544 : #define MID_CheckSelf 2253
6545 : #define MID_GlyphSelfIntersects 2254
6546 : #define MID_ReverseDir 2255
6547 : #define MID_Corner 2301
6548 : #define MID_Tangent 2302
6549 : #define MID_Curve 2303
6550 : #define MID_MakeFirst 2304
6551 : #define MID_MakeLine 2305
6552 : #define MID_CenterCP 2306
6553 : #define MID_ImplicitPt 2307
6554 : #define MID_NoImplicitPt 2308
6555 : #define MID_InsertPtOnSplineAt 2309
6556 : #define MID_AddAnchor 2310
6557 : #define MID_HVCurve 2311
6558 : #define MID_SpiroG4 2312
6559 : #define MID_SpiroG2 2313
6560 : #define MID_SpiroCorner 2314
6561 : #define MID_SpiroLeft 2315
6562 : #define MID_SpiroRight 2316
6563 : #define MID_SpiroMakeFirst 2317
6564 : #define MID_NamePoint 2318
6565 : #define MID_NameContour 2319
6566 : #define MID_AcceptableExtrema 2320
6567 : #define MID_MakeArc 2321
6568 : #define MID_ClipPath 2322
6569 :
6570 : #define MID_AutoHint 2400
6571 : #define MID_ClearHStem 2401
6572 : #define MID_ClearVStem 2402
6573 : #define MID_ClearDStem 2403
6574 : #define MID_AddHHint 2404
6575 : #define MID_AddVHint 2405
6576 : #define MID_AddDHint 2406
6577 : #define MID_ReviewHints 2407
6578 : #define MID_CreateHHint 2408
6579 : #define MID_CreateVHint 2409
6580 : #define MID_MinimumDistance 2410
6581 : #define MID_AutoInstr 2411
6582 : #define MID_ClearInstr 2412
6583 : #define MID_EditInstructions 2413
6584 : #define MID_Debug 2414
6585 : #define MID_HintSubsPt 2415
6586 : #define MID_AutoCounter 2416
6587 : #define MID_DontAutoHint 2417
6588 : #define MID_Deltas 2418
6589 : #define MID_Tools 2501
6590 : #define MID_Layers 2502
6591 : #define MID_DockPalettes 2503
6592 : #define MID_Center 2600
6593 : #define MID_SetWidth 2601
6594 : #define MID_SetLBearing 2602
6595 : #define MID_SetRBearing 2603
6596 : #define MID_Thirds 2604
6597 : #define MID_RemoveKerns 2605
6598 : #define MID_SetVWidth 2606
6599 : #define MID_RemoveVKerns 2607
6600 : #define MID_KPCloseup 2608
6601 : #define MID_AnchorsAway 2609
6602 : #define MID_SetBearings 2610
6603 : #define MID_OpenBitmap 2700
6604 : #define MID_Revert 2702
6605 : #define MID_Recent 2703
6606 : #define MID_RevertGlyph 2707
6607 : #define MID_Open 2708
6608 : #define MID_New 2709
6609 : #define MID_Close 2710
6610 : #define MID_Quit 2711
6611 : #define MID_CloseTab 2712
6612 : #define MID_GenerateTTC 2713
6613 : #define MID_VKernClass 2715
6614 : #define MID_VKernFromHKern 2716
6615 :
6616 : #define MID_ShowGridFitLiveUpdate 2720
6617 :
6618 : #define MID_MMReblend 2800
6619 : #define MID_MMAll 2821
6620 : #define MID_MMNone 2822
6621 :
6622 : #define MID_PtsPos 2823
6623 :
6624 : #define MID_Warnings 3000
6625 :
6626 0 : static void CVMenuClose(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6627 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
6628 0 : if ( cv->b.container )
6629 0 : (cv->b.container->funcs->doClose)(cv->b.container);
6630 : else
6631 0 : GDrawDestroyWindow(gw);
6632 0 : }
6633 :
6634 0 : static void CVMenuCloseTab(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6635 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
6636 : int pos, i;
6637 :
6638 0 : if ( cv->b.container || cv->tabs==NULL || cv->former_cnt<=1 )
6639 0 : return;
6640 0 : pos = GTabSetGetSel(cv->tabs);
6641 0 : free(cv->former_names[pos]);
6642 0 : for ( i=pos+1; i<cv->former_cnt; ++i )
6643 0 : cv->former_names[i-1] = cv->former_names[i];
6644 0 : --cv->former_cnt;
6645 0 : GTabSetRemoveTabByPos(cv->tabs,pos); /* This should send an event that the selection has changed */
6646 0 : GTabSetRemetric(cv->tabs);
6647 : }
6648 :
6649 0 : static void CVMenuOpen(GWindow gw, struct gmenuitem *mi, GEvent *g) {
6650 0 : CharView *d = (CharView*)GDrawGetUserData(gw);
6651 0 : FontView *fv = NULL;
6652 0 : if (d) {
6653 0 : fv = (FontView*)d->b.fv;
6654 : }
6655 0 : _FVMenuOpen(fv);
6656 0 : }
6657 :
6658 0 : static void CVMenuOpenBitmap(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6659 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
6660 0 : if ( cv->b.fv->sf->bitmaps==NULL )
6661 0 : return;
6662 0 : BitmapViewCreatePick(CVCurEnc(cv),(FontView *) (cv->b.fv));
6663 : }
6664 :
6665 0 : static void CVMenuOpenMetrics(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6666 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
6667 0 : MetricsViewCreate((FontView *) (cv->b.fv),cv->b.sc,NULL);
6668 0 : }
6669 :
6670 0 : static void CVMenuSave(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6671 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
6672 0 : _FVMenuSave((FontView *) (cv->b.fv));
6673 0 : }
6674 :
6675 0 : static void CVMenuSaveAs(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6676 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
6677 0 : _FVMenuSaveAs((FontView *) (cv->b.fv));
6678 0 : }
6679 :
6680 0 : static void CVMenuGenerate(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6681 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
6682 0 : FontViewBase *fv = cv->b.fv;
6683 0 : SFGenerateFont(cv->b.sc->parent,CVLayer((CharViewBase *) cv),false,fv->normal==NULL?fv->map:fv->normal);
6684 0 : }
6685 :
6686 0 : static void CVMenuGenerateFamily(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6687 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
6688 0 : _FVMenuGenerate((FontView *) (cv->b.fv),gf_macfamily);
6689 0 : }
6690 :
6691 0 : static void CVMenuGenerateTTC(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6692 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
6693 0 : _FVMenuGenerate((FontView *) (cv->b.fv),gf_ttc);
6694 0 : }
6695 :
6696 0 : static void CVMenuExport(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6697 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
6698 0 : CVExport(cv);
6699 0 : }
6700 :
6701 0 : static void CVInkscapeAdjust(CharView *cv) {
6702 : /* Inkscape considers different coordinates useful. That is to say, */
6703 : /* Inkscape views the world as a blank sheet of paper and often */
6704 : /* put things outside the [0,1000] range (especially in Y) that */
6705 : /* FF uses. So after doing a Paste, or Import or something similar */
6706 : /* check and see if the image is completely out of view, and if so */
6707 : /* then adjust the view field */
6708 : DBounds b;
6709 0 : int layer = CVLayer((CharViewBase *) cv);
6710 :
6711 0 : if (layer != ly_grid) SplineCharLayerQuickBounds(cv->b.sc,layer,&b);
6712 : else {
6713 0 : b.minx = b.miny = 1e10;
6714 0 : b.maxx = b.maxy = -1e10;
6715 0 : SplineSetQuickBounds(cv->b.sc->parent->grid.splines,&b);
6716 : }
6717 :
6718 0 : b.minx *= cv->scale; b.maxx *= cv->scale;
6719 0 : b.miny *= cv->scale; b.maxy *= cv->scale;
6720 :
6721 0 : if ( b.minx + cv->xoff < 0 || b.miny + cv->yoff < 0 ||
6722 0 : b.maxx + cv->xoff > cv->width || b.maxy + cv->yoff > cv->height )
6723 0 : CVFit(cv);
6724 0 : }
6725 :
6726 0 : static void CVMenuImport(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6727 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
6728 0 : CVImport(cv);
6729 0 : CVInkscapeAdjust(cv);
6730 0 : }
6731 :
6732 0 : static void CVMenuRevert(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6733 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
6734 0 : FVDelay((FontView *) (cv->b.fv),(void (*)(FontView *)) FVRevert);
6735 : /* The revert command can potentially */
6736 : /* destroy our window (if the char weren't in the */
6737 : /* old font). If that happens before the menu finishes */
6738 : /* we get a crash. So delay till after the menu completes */
6739 0 : }
6740 :
6741 0 : static void CVMenuRevertGlyph(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6742 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
6743 : SplineChar *sc, temp;
6744 : Undoes **undoes;
6745 : int layer, lc;
6746 : CharView *cvs;
6747 0 : int mylayer = CVLayer((CharViewBase *) cv);
6748 :
6749 0 : if ( cv->b.sc->parent->filename==NULL || cv->b.sc->namechanged || cv->b.sc->parent->mm!=NULL )
6750 0 : return;
6751 0 : if ( cv->b.sc->parent->sfd_version<2 )
6752 0 : ff_post_error(_("Old sfd file"),_("This font comes from an old format sfd file. Not all aspects of it can be reverted successfully."));
6753 :
6754 0 : sc = SFDReadOneChar(cv->b.sc->parent,cv->b.sc->name);
6755 0 : if ( sc==NULL ) {
6756 0 : ff_post_error(_("Can't Find Glyph"),_("The glyph, %.80s, can't be found in the sfd file"),cv->b.sc->name);
6757 0 : cv->b.sc->namechanged = true;
6758 : } else {
6759 0 : SCPreserveState(cv->b.sc,true);
6760 0 : SCPreserveBackground(cv->b.sc);
6761 0 : temp = *cv->b.sc;
6762 0 : cv->b.sc->dependents = NULL;
6763 0 : lc = cv->b.sc->layer_cnt;
6764 0 : undoes = malloc(lc*sizeof(Undoes *));
6765 0 : for ( layer=0; layer<lc; ++layer ) {
6766 0 : undoes[layer] = cv->b.sc->layers[layer].undoes;
6767 0 : cv->b.sc->layers[layer].undoes = NULL;
6768 : }
6769 0 : SplineCharFreeContents(cv->b.sc);
6770 0 : *cv->b.sc = *sc;
6771 0 : chunkfree(sc,sizeof(SplineChar));
6772 0 : cv->b.sc->parent = temp.parent;
6773 0 : cv->b.sc->dependents = temp.dependents;
6774 0 : for ( layer = 0; layer<lc && layer<cv->b.sc->layer_cnt; ++layer )
6775 0 : cv->b.sc->layers[layer].undoes = undoes[layer];
6776 0 : for ( ; layer<lc; ++layer )
6777 0 : UndoesFree(undoes[layer]);
6778 0 : free(undoes);
6779 0 : cv->b.sc->views = temp.views;
6780 : /* cv->b.sc->changed = temp.changed; */
6781 0 : for ( cvs=(CharView *) (cv->b.sc->views); cvs!=NULL; cvs=(CharView *) (cvs->b.next) ) {
6782 0 : cvs->b.layerheads[dm_back] = &cv->b.sc->layers[ly_back];
6783 0 : cvs->b.layerheads[dm_fore] = &cv->b.sc->layers[ly_fore];
6784 0 : if ( cv->b.sc->parent->multilayer ) {
6785 0 : if ( mylayer!=ly_back )
6786 0 : cvs->b.layerheads[dm_fore] = &cv->b.sc->layers[mylayer];
6787 : } else {
6788 0 : if ( mylayer!=ly_fore )
6789 0 : cvs->b.layerheads[dm_back] = &cv->b.sc->layers[mylayer];
6790 : }
6791 : }
6792 0 : RevertedGlyphReferenceFixup(cv->b.sc, temp.parent);
6793 0 : _CV_CharChangedUpdate(cv,false);
6794 : }
6795 : }
6796 :
6797 0 : static void CVAddWordList(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e))
6798 : {
6799 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
6800 0 : WordlistLoadToGTextInfo( cv->charselector, &cv->charselectoridx );
6801 0 : }
6802 :
6803 0 : static void CVMenuPrint(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6804 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
6805 :
6806 0 : PrintFFDlg(NULL,cv->b.sc,NULL);
6807 0 : }
6808 :
6809 : #if !defined(_NO_PYTHON)
6810 0 : static void CVMenuExecute(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6811 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
6812 0 : ScriptDlg((FontView *) (cv->b.fv),cv);
6813 0 : }
6814 : #endif /* !_NO_PYTHON */
6815 :
6816 0 : static void fllistcheck(GWindow gw, struct gmenuitem *mi,GEvent *UNUSED(e)) {
6817 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
6818 : FontView *fvs;
6819 :
6820 0 : for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
6821 0 : switch ( mi->mid ) {
6822 : case MID_Open: case MID_New:
6823 0 : mi->ti.disabled = cv->b.container!=NULL && !(cv->b.container->funcs->canOpen)(cv->b.container);
6824 0 : break;
6825 : case MID_GenerateTTC:
6826 0 : for ( fvs=fv_list; fvs!=NULL; fvs=(FontView *) (fvs->b.next) ) {
6827 0 : if ( fvs!=(FontView *) cv->b.fv )
6828 0 : break;
6829 : }
6830 0 : mi->ti.disabled = fvs==NULL || cv->b.container!=NULL;
6831 0 : break;
6832 : case MID_Revert:
6833 0 : mi->ti.disabled = cv->b.fv->sf->origname==NULL || cv->b.fv->sf->new || cv->b.container;
6834 0 : break;
6835 : case MID_RevertGlyph:
6836 0 : mi->ti.disabled = cv->b.fv->sf->filename==NULL ||
6837 0 : cv->b.fv->sf->sfd_version<2 ||
6838 0 : cv->b.sc->namechanged ||
6839 0 : cv->b.fv->sf->mm!=NULL ||
6840 0 : cv->b.container;
6841 0 : break;
6842 : case MID_Recent:
6843 0 : mi->ti.disabled = !RecentFilesAny() ||
6844 0 : (cv->b.container!=NULL && !(cv->b.container->funcs->canOpen)(cv->b.container));
6845 0 : break;
6846 : case MID_Close: case MID_Quit:
6847 0 : mi->ti.disabled = false;
6848 0 : break;
6849 : case MID_CloseTab:
6850 0 : mi->ti.disabled = cv->tabs==NULL || cv->former_cnt<=1;
6851 0 : break;
6852 : default:
6853 0 : mi->ti.disabled = cv->b.container!=NULL;
6854 0 : break;
6855 : }
6856 : }
6857 0 : }
6858 :
6859 0 : static void CVMenuFontInfo(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6860 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
6861 0 : FontInfo(cv->b.sc->parent,CVLayer((CharViewBase *) cv),-1,false);
6862 0 : }
6863 :
6864 0 : static void CVMenuFindProblems(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6865 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
6866 0 : FindProblems(NULL,cv,NULL);
6867 0 : }
6868 :
6869 0 : static void CVMenuEmbolden(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6870 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
6871 0 : EmboldenDlg(NULL,cv);
6872 0 : }
6873 :
6874 0 : static void CVMenuItalic(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6875 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
6876 0 : ItalicDlg(NULL,cv);
6877 0 : }
6878 :
6879 0 : static void CVMenuOblique(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6880 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
6881 0 : ObliqueDlg(NULL,cv);
6882 0 : }
6883 :
6884 0 : static void CVMenuCondense(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6885 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
6886 0 : CondenseExtendDlg(NULL,cv);
6887 0 : }
6888 :
6889 0 : static void CVMenuChangeXHeight(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6890 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
6891 0 : ChangeXHeightDlg(NULL,cv);
6892 0 : }
6893 :
6894 0 : static void CVMenuChangeGlyph(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6895 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
6896 0 : GlyphChangeDlg(NULL,cv,gc_generic);
6897 0 : }
6898 :
6899 0 : static void CVMenuInline(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6900 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
6901 0 : OutlineDlg(NULL,cv,NULL,true);
6902 0 : }
6903 :
6904 0 : static void CVMenuOutline(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6905 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
6906 0 : OutlineDlg(NULL,cv,NULL,false);
6907 0 : }
6908 :
6909 0 : static void CVMenuShadow(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6910 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
6911 0 : ShadowDlg(NULL,cv,NULL,false);
6912 0 : }
6913 :
6914 0 : static void CVMenuWireframe(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6915 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
6916 0 : ShadowDlg(NULL,cv,NULL,true);
6917 0 : }
6918 :
6919 0 : static void _CVMenuScale(CharView *cv, int mid) {
6920 0 : if ( mid == MID_Fit ) {
6921 0 : CVFit(cv);
6922 : } else {
6923 : BasePoint c;
6924 0 : c.x = (cv->width/2-cv->xoff)/cv->scale;
6925 0 : c.y = (cv->height/2-cv->yoff)/cv->scale;
6926 0 : if ( CVAnySel(cv,NULL,NULL,NULL,NULL))
6927 0 : CVFindCenter(cv,&c,false);
6928 0 : CVMagnify(cv,c.x,c.y, mid==MID_ZoomOut?-1:1,0);
6929 : }
6930 0 : }
6931 :
6932 0 : static void CVMenuScale(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
6933 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
6934 0 : _CVMenuScale(cv,mi->mid);
6935 0 : }
6936 :
6937 0 : static void CVMenuShowHide(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6938 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
6939 0 : CVShows.showpoints = cv->showpoints = !cv->showpoints;
6940 0 : GDrawRequestExpose(cv->v,NULL,false);
6941 0 : }
6942 :
6943 0 : static void CVMenuShowHideControlPoints(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6944 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
6945 0 : CVShows.alwaysshowcontrolpoints = cv->alwaysshowcontrolpoints = !cv->alwaysshowcontrolpoints;
6946 0 : GDrawRequestExpose(cv->v,NULL,false);
6947 0 : }
6948 :
6949 0 : static void CVMenuNumberPoints(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
6950 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
6951 :
6952 0 : switch ( mi->mid ) {
6953 : case MID_PtsNone:
6954 0 : cv->showpointnumbers = 0;
6955 0 : break;
6956 : case MID_PtsTrue:
6957 0 : cv->showpointnumbers = 1;
6958 0 : CVCheckPoints(cv);
6959 0 : break;
6960 : case MID_PtsPost:
6961 0 : cv->showpointnumbers = 1;
6962 0 : cv->b.sc->numberpointsbackards = true;
6963 0 : break;
6964 : case MID_PtsSVG:
6965 0 : cv->showpointnumbers = 1;
6966 0 : cv->b.sc->numberpointsbackards = false;
6967 0 : break;
6968 : case MID_PtsPos:
6969 0 : cv->showpointnumbers = 2;
6970 0 : break;
6971 : }
6972 0 : SCNumberPoints(cv->b.sc,CVLayer((CharViewBase *) cv));
6973 0 : SCUpdateAll(cv->b.sc);
6974 0 : }
6975 :
6976 0 : static void CVMenuMarkExtrema(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6977 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
6978 :
6979 0 : CVShows.markextrema = cv->markextrema = !cv->markextrema;
6980 0 : SavePrefs(true);
6981 0 : GDrawRequestExpose(cv->v,NULL,false);
6982 0 : }
6983 :
6984 0 : static void CVMenuMarkPointsOfInflection(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6985 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
6986 :
6987 0 : CVShows.markpoi = cv->markpoi = !cv->markpoi;
6988 0 : SavePrefs(true);
6989 0 : GDrawRequestExpose(cv->v,NULL,false);
6990 0 : }
6991 :
6992 0 : static void CVMenuShowAlmostHV(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
6993 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
6994 :
6995 0 : CVShows.showalmosthvlines = cv->showalmosthvlines = !cv->showalmosthvlines;
6996 0 : SavePrefs(true);
6997 0 : GDrawRequestExpose(cv->v,NULL,false);
6998 0 : }
6999 :
7000 0 : static void CVMenuShowAlmostHVCurves(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
7001 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
7002 :
7003 0 : CVShows.showalmosthvcurves = cv->showalmosthvcurves = !cv->showalmosthvcurves;
7004 0 : SavePrefs(true);
7005 0 : GDrawRequestExpose(cv->v,NULL,false);
7006 0 : }
7007 :
7008 0 : static void CVMenuDefineAlmost(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
7009 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
7010 : char buf[20], *end;
7011 : int val;
7012 : char *ret;
7013 :
7014 0 : sprintf(buf,"%d",cv->hvoffset );
7015 :
7016 0 : ret = gwwv_ask_string(_("Define \"Almost Horizontal\""),buf,
7017 0 : _("A line is \"almost\" horizontal (or vertical)\nif the coordinates are within this many em-units"));
7018 0 : if ( ret==NULL )
7019 0 : return;
7020 0 : val = strtol(ret,&end,10);
7021 0 : if ( val>100 || val<=0 || *end!='\0' ) {
7022 0 : free(ret);
7023 0 : ff_post_error(_("Bad number"),_("Bad number"));
7024 : } else {
7025 0 : free(ret);
7026 0 : CVShows.hvoffset = cv->hvoffset = val;
7027 0 : SavePrefs(true);
7028 0 : GDrawRequestExpose(cv->v,NULL,false);
7029 : }
7030 : }
7031 :
7032 0 : static void CVMenuShowCPInfo(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
7033 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
7034 :
7035 0 : CVShows.showcpinfo = cv->showcpinfo = !cv->showcpinfo;
7036 0 : SavePrefs(true);
7037 : /* Nothing to update, only show this stuff in the user is moving a cp */
7038 : /* which s/he is currently not, s/he is manipulating the menu */
7039 0 : }
7040 :
7041 0 : static void CVMenuShowTabs(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
7042 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
7043 :
7044 0 : CVShows.showtabs = cv->showtabs = !cv->showtabs;
7045 0 : CVChangeTabsVisibility(cv,cv->showtabs);
7046 0 : SavePrefs(true);
7047 0 : }
7048 :
7049 0 : static void CVMenuShowSideBearings(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
7050 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
7051 :
7052 0 : CVShows.showsidebearings = cv->showsidebearings = !cv->showsidebearings;
7053 0 : SavePrefs(true);
7054 0 : GDrawRequestExpose(cv->v,NULL,false);
7055 0 : }
7056 :
7057 0 : static void CVMenuShowRefNames(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
7058 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
7059 :
7060 0 : CVShows.showrefnames = cv->showrefnames = !cv->showrefnames;
7061 0 : SavePrefs(true);
7062 0 : GDrawRequestExpose(cv->v,NULL,false);
7063 0 : }
7064 :
7065 0 : static void CVMenuSnapOutlines(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
7066 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
7067 :
7068 0 : CVShows.snapoutlines = cv->snapoutlines = !cv->snapoutlines;
7069 0 : SavePrefs(true);
7070 0 : GDrawRequestExpose(cv->v,NULL,false);
7071 0 : }
7072 :
7073 0 : static void CVMenuShowHints(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
7074 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
7075 :
7076 0 : switch ( mi->mid ) {
7077 : case MID_ShowHHints:
7078 0 : CVShows.showhhints = cv->showhhints = !cv->showhhints;
7079 0 : cv->back_img_out_of_date = true; /* only this cv */
7080 0 : break;
7081 : case MID_ShowVHints:
7082 0 : CVShows.showvhints = cv->showvhints = !cv->showvhints;
7083 0 : cv->back_img_out_of_date = true; /* only this cv */
7084 0 : break;
7085 : case MID_ShowDHints:
7086 0 : CVShows.showdhints = cv->showdhints = !cv->showdhints;
7087 0 : cv->back_img_out_of_date = true; /* only this cv */
7088 0 : break;
7089 : case MID_ShowBlueValues:
7090 0 : CVShows.showblues = cv->showblues = !cv->showblues;
7091 0 : cv->back_img_out_of_date = true; /* only this cv */
7092 0 : break;
7093 : case MID_ShowFamilyBlues:
7094 0 : CVShows.showfamilyblues = cv->showfamilyblues = !cv->showfamilyblues;
7095 0 : cv->back_img_out_of_date = true; /* only this cv */
7096 0 : break;
7097 : case MID_ShowAnchors:
7098 0 : CVShows.showanchor = cv->showanchor = !cv->showanchor;
7099 0 : break;
7100 : case MID_ShowHMetrics:
7101 0 : CVShows.showhmetrics = cv->showhmetrics = !cv->showhmetrics;
7102 0 : break;
7103 : case MID_ShowVMetrics:
7104 0 : CVShows.showvmetrics = cv->showvmetrics = !cv->showvmetrics;
7105 0 : break;
7106 : case MID_ShowDebugChanges:
7107 0 : CVShows.showdebugchanges = cv->showdebugchanges = !cv->showdebugchanges;
7108 0 : break;
7109 : default:
7110 0 : IError("Unexpected call to CVMenuShowHints");
7111 0 : break;
7112 : }
7113 0 : SavePrefs(true);
7114 0 : GDrawRequestExpose(cv->v,NULL,false);
7115 : /* !!!! In this interim version we should request an expose on cvlayers */
7116 : /* but that's private to cvpalettes, and later we won't need to */
7117 0 : }
7118 :
7119 0 : static void _CVMenuShowHideRulers(CharView *cv) {
7120 : GRect pos;
7121 :
7122 0 : CVShows.showrulers = cv->showrulers = !cv->showrulers;
7123 0 : pos.y = cv->mbh+cv->charselectorh+cv->infoh;
7124 0 : pos.x = 0;
7125 0 : if ( cv->showrulers ) {
7126 0 : cv->height -= cv->rulerh;
7127 0 : cv->width -= cv->rulerh;
7128 0 : pos.y += cv->rulerh;
7129 0 : pos.x += cv->rulerh;
7130 : } else {
7131 0 : cv->height += cv->rulerh;
7132 0 : cv->width += cv->rulerh;
7133 : }
7134 0 : cv->back_img_out_of_date = true;
7135 0 : pos.width = cv->width; pos.height = cv->height;
7136 0 : GDrawMoveResize(cv->v,pos.x,pos.y,pos.width,pos.height);
7137 0 : GDrawSync(NULL);
7138 0 : GDrawRequestExpose(cv->v,NULL,false);
7139 0 : SavePrefs(true);
7140 0 : }
7141 :
7142 0 : static void CVMenuShowHideRulers(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
7143 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
7144 0 : _CVMenuShowHideRulers(cv);
7145 0 : }
7146 :
7147 0 : static void CVMenuFill(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
7148 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
7149 :
7150 0 : CVShows.showfilled = cv->showfilled = !cv->showfilled;
7151 0 : CVRegenFill(cv);
7152 0 : GDrawRequestExpose(cv->v,NULL,false);
7153 0 : }
7154 :
7155 0 : static struct cvshows* cvshowsCopyTo( struct cvshows* dst, CharView* src )
7156 : {
7157 0 : dst->showfore = src->showfore;
7158 0 : dst->showgrids = src->showgrids;
7159 0 : dst->showhhints = src->showhhints;
7160 0 : dst->showvhints = src->showvhints;
7161 0 : dst->showdhints = src->showdhints;
7162 0 : dst->showpoints = src->showpoints;
7163 0 : dst->alwaysshowcontrolpoints = src->alwaysshowcontrolpoints;
7164 0 : dst->showfilled = src->showfilled;
7165 0 : dst->showrulers = src->showrulers;
7166 0 : dst->showrounds = src->showrounds;
7167 0 : dst->showmdx = src->showmdx;
7168 0 : dst->showmdy = src->showmdy;
7169 0 : dst->showhmetrics = src->showhmetrics;
7170 0 : dst->showvmetrics = src->showvmetrics;
7171 0 : dst->markextrema = src->markextrema;
7172 0 : dst->markpoi = src->markpoi;
7173 0 : dst->showblues = src->showblues;
7174 0 : dst->showfamilyblues = src->showfamilyblues;
7175 0 : dst->showanchor = src->showanchor;
7176 0 : dst->showcpinfo = src->showcpinfo;
7177 0 : dst->showtabs = src->showtabs;
7178 0 : dst->showsidebearings = src->showsidebearings;
7179 0 : dst->showrefnames = src->showrefnames;
7180 0 : dst->snapoutlines = src->snapoutlines;
7181 0 : dst->showalmosthvlines = src->showalmosthvlines;
7182 0 : dst->showalmosthvcurves = src->showalmosthvcurves;
7183 0 : dst->hvoffset = src->hvoffset;
7184 0 : dst->checkselfintersects = src->checkselfintersects;
7185 0 : dst->showdebugchanges = src->showdebugchanges;
7186 0 : return dst;
7187 : }
7188 :
7189 0 : static CharView* cvshowsCopyFrom( CharView* dst, struct cvshows* src )
7190 : {
7191 0 : dst->showfore = src->showfore;
7192 0 : dst->showgrids = src->showgrids;
7193 0 : dst->showhhints = src->showhhints;
7194 0 : dst->showvhints = src->showvhints;
7195 0 : dst->showdhints = src->showdhints;
7196 0 : dst->showpoints = src->showpoints;
7197 0 : dst->alwaysshowcontrolpoints = src->alwaysshowcontrolpoints;
7198 0 : dst->showfilled = src->showfilled;
7199 0 : dst->showrulers = src->showrulers;
7200 0 : dst->showrounds = src->showrounds;
7201 0 : dst->showmdx = src->showmdx;
7202 0 : dst->showmdy = src->showmdy;
7203 0 : dst->showhmetrics = src->showhmetrics;
7204 0 : dst->showvmetrics = src->showvmetrics;
7205 0 : dst->markextrema = src->markextrema;
7206 0 : dst->markpoi = src->markpoi;
7207 0 : dst->showblues = src->showblues;
7208 0 : dst->showfamilyblues = src->showfamilyblues;
7209 0 : dst->showanchor = src->showanchor;
7210 0 : dst->showcpinfo = src->showcpinfo;
7211 0 : dst->showtabs = src->showtabs;
7212 0 : dst->showsidebearings = src->showsidebearings;
7213 0 : dst->showrefnames = src->showrefnames;
7214 0 : dst->snapoutlines = src->snapoutlines;
7215 0 : dst->showalmosthvlines = src->showalmosthvlines;
7216 0 : dst->showalmosthvcurves = src->showalmosthvcurves;
7217 0 : dst->hvoffset = src->hvoffset;
7218 0 : dst->checkselfintersects = src->checkselfintersects;
7219 0 : dst->showdebugchanges = src->showdebugchanges;
7220 0 : return dst;
7221 : }
7222 :
7223 0 : static void CVPreviewModeSet(GWindow gw, int checked ) {
7224 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
7225 0 : if( checked == cv->inPreviewMode )
7226 0 : return;
7227 :
7228 0 : cv->inPreviewMode = checked;
7229 0 : if( checked ) {
7230 0 : cvshowsCopyTo( &CVShowsPrevewToggleSavedState, cv );
7231 0 : cv->showfore = 1;
7232 0 : cv->showgrids = 0;
7233 0 : cv->showhhints = 0;
7234 0 : cv->showvhints = 0;
7235 0 : cv->showdhints = 0;
7236 0 : cv->showpoints = 0;
7237 0 : cv->alwaysshowcontrolpoints = 0;
7238 0 : cv->showfilled = 1;
7239 0 : cv->showrounds = 0;
7240 0 : cv->showanchor = 0;
7241 0 : cv->showrefnames = 0;
7242 0 : cv->showhmetrics = 0;
7243 0 : cv->showvmetrics = 0;
7244 : } else {
7245 0 : cvshowsCopyFrom( cv, &CVShowsPrevewToggleSavedState );
7246 : }
7247 0 : CVRegenFill(cv);
7248 0 : GDrawRequestExpose(cv->v,NULL,false);
7249 : }
7250 :
7251 0 : static void CVMenuPreview(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
7252 0 : int checked = mi->ti.checked;
7253 :
7254 : #if 0
7255 : // This has the effect of breaking the button since cv_auto_goto and HaveModifiers tend to be false.
7256 : // The purpose of these checks is unclear.
7257 : if( !cv_auto_goto ) {
7258 : if( !HaveModifiers )
7259 : return;
7260 : }
7261 : #endif // 0
7262 :
7263 0 : CVPreviewModeSet(gw, checked);
7264 0 : }
7265 :
7266 0 : static void CVMenuDraggingComparisonOutline(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e))
7267 : {
7268 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
7269 :
7270 0 : int checked = mi->ti.checked;
7271 0 : CVFreePreTransformSPL( cv );
7272 0 : prefs_create_dragging_comparison_outline = checked;
7273 0 : SavePrefs(true);
7274 0 : }
7275 :
7276 :
7277 0 : static void CVMenuShowGridFit(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
7278 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
7279 :
7280 0 : if ( !hasFreeType() || cv->dv!=NULL )
7281 0 : return;
7282 0 : cv->show_ft_results_live_update = 0;
7283 0 : CVFtPpemDlg(cv,false);
7284 : }
7285 :
7286 0 : static void CVMenuShowGridFitLiveUpdate(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
7287 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
7288 :
7289 0 : if ( !hasFreeType() || cv->dv!=NULL )
7290 0 : return;
7291 0 : cv->show_ft_results_live_update = 1;
7292 0 : CVFtPpemDlg(cv,false);
7293 : }
7294 :
7295 0 : static void CVMenuChangePointSize(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
7296 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
7297 :
7298 0 : if ( !hasFreeType() || cv->dv!=NULL || !cv->show_ft_results )
7299 0 : return;
7300 :
7301 0 : if ( mi->mid==MID_GridFitOff ) {
7302 0 : cv->show_ft_results = false;
7303 0 : cv->show_ft_results_live_update = false;
7304 :
7305 0 : SplinePointListsFree(cv->b.gridfit); cv->b.gridfit = NULL;
7306 0 : FreeType_FreeRaster(cv->raster); cv->raster = NULL;
7307 0 : GDrawRequestExpose(cv->v,NULL,false);
7308 : } else {
7309 0 : if ( mi->mid==MID_Bigger ) {
7310 0 : ++cv->ft_pointsizex;
7311 0 : ++cv->ft_pointsizey;
7312 0 : } else if ( mi->mid==MID_Smaller ) {
7313 0 : if ( cv->ft_pointsizex>1 )
7314 0 : --cv->ft_pointsizex;
7315 0 : if ( cv->ft_pointsizey>1 )
7316 0 : --cv->ft_pointsizey;
7317 : }
7318 :
7319 0 : if ( mi->mid==MID_GridFitAA )
7320 0 : cv->ft_depth = cv->ft_depth==8 ? 1 : 8;
7321 0 : cv->ft_ppemx = rint(cv->ft_pointsizex*cv->ft_dpi/72.0);
7322 0 : cv->ft_ppemy = rint(cv->ft_pointsizey*cv->ft_dpi/72.0);
7323 0 : CVGridFitChar(cv);
7324 : }
7325 0 : SCRefreshTitles(cv->b.sc);
7326 : }
7327 :
7328 0 : static void CVMenuEditInstrs(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
7329 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
7330 0 : SCEditInstructions(cv->b.sc);
7331 0 : }
7332 :
7333 0 : static void CVMenuDebug(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
7334 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
7335 :
7336 0 : if ( !hasFreeTypeDebugger())
7337 0 : return;
7338 0 : CVFtPpemDlg(cv,true);
7339 : }
7340 :
7341 0 : static void CVMenuDeltas(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
7342 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
7343 :
7344 0 : if ( !hasFreeTypeDebugger())
7345 0 : return;
7346 0 : DeltaSuggestionDlg(NULL,cv);
7347 : }
7348 :
7349 0 : static void CVMenuClearInstrs(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
7350 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
7351 :
7352 0 : if ( cv->b.sc->ttf_instrs_len!=0 ) {
7353 0 : free(cv->b.sc->ttf_instrs);
7354 0 : cv->b.sc->ttf_instrs = NULL;
7355 0 : cv->b.sc->ttf_instrs_len = 0;
7356 0 : cv->b.sc->instructions_out_of_date = false;
7357 0 : SCCharChangedUpdate(cv->b.sc,ly_none);
7358 0 : SCMarkInstrDlgAsChanged(cv->b.sc);
7359 0 : cv->b.sc->complained_about_ptnums = false; /* Should be after CharChanged */
7360 : }
7361 0 : }
7362 :
7363 0 : static void CVMenuKernPairs(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
7364 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
7365 0 : SFShowKernPairs(cv->b.sc->parent,cv->b.sc,NULL,CVLayer((CharViewBase *) cv));
7366 0 : }
7367 :
7368 0 : static void CVMenuLigatures(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
7369 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
7370 0 : SFShowLigatures(cv->b.fv->sf,cv->b.sc);
7371 0 : }
7372 :
7373 0 : static void CVMenuAnchorPairs(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
7374 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
7375 0 : SFShowKernPairs(cv->b.sc->parent,cv->b.sc,(AnchorClass *) (-1),CVLayer((CharViewBase *) cv));
7376 0 : }
7377 :
7378 0 : static void CVMenuAPDetach(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
7379 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
7380 0 : cv->apmine = cv->apmatch = NULL;
7381 0 : cv->apsc = NULL;
7382 0 : GDrawRequestExpose(cv->v,NULL,false);
7383 0 : }
7384 :
7385 0 : static void CVMenuAPAttachSC(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
7386 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
7387 : enum anchor_type type;
7388 : AnchorPoint *ap;
7389 : AnchorClass *ac;
7390 :
7391 0 : ap = mi->ti.userdata;
7392 0 : if ( ap==NULL )
7393 0 : for ( ap = cv->b.sc->anchor; ap!=NULL && !ap->selected; ap=ap->next );
7394 0 : if ( ap==NULL )
7395 0 : ap = cv->b.sc->anchor;
7396 0 : if ( ap==NULL )
7397 0 : return;
7398 0 : type = ap->type;
7399 0 : cv->apmine = ap;
7400 0 : ac = ap->anchor;
7401 0 : cv->apsc = mi->ti.userdata;
7402 0 : for ( ap = cv->apsc->anchor; ap!=NULL ; ap=ap->next ) {
7403 0 : if ( ap->anchor==ac &&
7404 0 : ((type==at_centry && ap->type==at_cexit) ||
7405 0 : (type==at_cexit && ap->type==at_centry) ||
7406 0 : (type==at_mark && ap->type!=at_mark) ||
7407 0 : ((type==at_basechar || type==at_baselig || type==at_basemark) && ap->type==at_mark)) )
7408 : break;
7409 : }
7410 0 : cv->apmatch = ap;
7411 0 : GDrawRequestExpose(cv->v,NULL,false);
7412 : }
7413 :
7414 0 : static SplineChar **GlyphsMatchingAP(SplineFont *sf, AnchorPoint *ap) {
7415 : SplineChar *sc;
7416 0 : AnchorClass *ac = ap->anchor;
7417 0 : enum anchor_type type = ap->type;
7418 : int i, k, gcnt;
7419 : SplineChar **glyphs;
7420 :
7421 0 : glyphs = NULL;
7422 0 : for ( k=0; k<2; ++k ) {
7423 0 : gcnt = 0;
7424 0 : for ( i=0; i<sf->glyphcnt; ++i ) if ( (sc=sf->glyphs[i])!=NULL ) {
7425 0 : for ( ap = sc->anchor; ap!=NULL; ap=ap->next ) {
7426 0 : if ( ap->anchor == ac &&
7427 0 : ((type==at_centry && ap->type==at_cexit) ||
7428 0 : (type==at_cexit && ap->type==at_centry) ||
7429 0 : (type==at_mark && ap->type!=at_mark) ||
7430 0 : ((type==at_basechar || type==at_baselig || type==at_basemark) && ap->type==at_mark)) )
7431 : break;
7432 : }
7433 0 : if ( ap!=NULL ) {
7434 0 : if ( k )
7435 0 : glyphs[gcnt] = sc;
7436 0 : ++gcnt;
7437 : }
7438 : }
7439 0 : if ( !k ) {
7440 0 : if ( gcnt==0 )
7441 0 : return( NULL );
7442 0 : glyphs = malloc((gcnt+1)*sizeof(SplineChar *));
7443 : } else
7444 0 : glyphs[gcnt] = NULL;
7445 : }
7446 0 : return( glyphs );
7447 : }
7448 :
7449 0 : static void _CVMenuChangeChar(CharView *cv, int mid) {
7450 0 : SplineFont *sf = cv->b.sc->parent;
7451 0 : int pos = -1;
7452 : int gid;
7453 0 : EncMap *map = cv->b.fv->map;
7454 0 : Encoding *enc = map->enc;
7455 :
7456 0 : if ( cv->b.container!=NULL ) {
7457 0 : if ( cv->b.container->funcs->doNavigate!=NULL && mid != MID_Former)
7458 0 : (cv->b.container->funcs->doNavigate)(cv->b.container,
7459 : mid==MID_Next ? nt_next :
7460 : mid==MID_Prev ? nt_prev :
7461 : mid==MID_NextDef ? nt_next :
7462 : /* mid==MID_PrevDef ?*/ nt_prev);
7463 0 : return;
7464 : }
7465 :
7466 0 : int curenc = CVCurEnc(cv);
7467 :
7468 0 : if( cv->charselector )
7469 : {
7470 0 : char* txt = GGadgetGetTitle8( cv->charselector );
7471 0 : if( txt && strlen(txt) > 1 )
7472 : {
7473 0 : int offset = 1;
7474 0 : if ( mid == MID_Prev )
7475 0 : offset = -1;
7476 :
7477 0 : unichar_t *txtu = GGadgetGetTitle( cv->charselector );
7478 0 : unichar_t* r = Wordlist_advanceSelectedCharsBy( cv->b.sc->parent,
7479 0 : ((FontView *) (cv->b.fv))->b.map,
7480 : txtu, offset );
7481 0 : free( txtu );
7482 :
7483 0 : GGadgetSetTitle( cv->charselector, r );
7484 : // Force any extra chars to be setup and drawn
7485 : GEvent e;
7486 0 : e.type=et_controlevent;
7487 0 : e.u.control.subtype = et_textchanged;
7488 0 : e.u.control.u.tf_changed.from_pulldown = 0;
7489 0 : CV_OnCharSelectorTextChanged( cv->charselector, &e );
7490 0 : return;
7491 : }
7492 : }
7493 :
7494 0 : if ( mid == MID_Next ) {
7495 0 : pos = curenc+1;
7496 0 : } else if ( mid == MID_Prev ) {
7497 0 : pos = curenc-1;
7498 0 : } else if ( mid == MID_NextDef ) {
7499 0 : for ( pos = CVCurEnc(cv)+1; pos<map->enccount &&
7500 0 : ((gid=map->map[pos])==-1 || !SCWorthOutputting(sf->glyphs[gid])); ++pos );
7501 0 : if ( pos>=map->enccount ) {
7502 0 : if ( enc->is_tradchinese ) {
7503 0 : if ( strstrmatch(enc->enc_name,"hkscs")!=NULL ) {
7504 0 : if ( CVCurEnc(cv)<0x8140 )
7505 0 : pos = 0x8140;
7506 : } else {
7507 0 : if ( CVCurEnc(cv)<0xa140 )
7508 0 : pos = 0xa140;
7509 : }
7510 0 : } else if ( CVCurEnc(cv)<0x8431 && strstrmatch(enc->enc_name,"johab")!=NULL )
7511 0 : pos = 0x8431;
7512 0 : else if ( CVCurEnc(cv)<0xa1a1 && strstrmatch(enc->iconv_name?enc->iconv_name:enc->enc_name,"EUC")!=NULL )
7513 0 : pos = 0xa1a1;
7514 0 : else if ( CVCurEnc(cv)<0x8140 && strstrmatch(enc->enc_name,"sjis")!=NULL )
7515 0 : pos = 0x8140;
7516 0 : else if ( CVCurEnc(cv)<0xe040 && strstrmatch(enc->enc_name,"sjis")!=NULL )
7517 0 : pos = 0xe040;
7518 0 : if ( pos>=map->enccount )
7519 0 : return;
7520 : }
7521 0 : } else if ( mid == MID_PrevDef ) {
7522 0 : for ( pos = CVCurEnc(cv)-1; pos>=0 &&
7523 0 : ((gid=map->map[pos])==-1 || !SCWorthOutputting(sf->glyphs[gid])); --pos );
7524 0 : if ( pos<0 )
7525 0 : return;
7526 0 : } else if ( mid == MID_Former ) {
7527 0 : if ( cv->former_cnt<=1 )
7528 0 : return;
7529 0 : for ( gid=sf->glyphcnt-1; gid>=0; --gid )
7530 0 : if ( sf->glyphs[gid]!=NULL &&
7531 0 : strcmp(sf->glyphs[gid]->name,cv->former_names[1])==0 )
7532 0 : break;
7533 0 : if ( gid<0 )
7534 0 : return;
7535 0 : pos = map->backmap[gid];
7536 : }
7537 : /* Werner doesn't think it should wrap */
7538 0 : if ( pos<0 ) /* pos = map->enccount-1; */
7539 0 : return;
7540 0 : else if ( pos>= map->enccount ) /* pos = 0; */
7541 0 : return;
7542 :
7543 0 : if ( pos>=0 && pos<map->enccount )
7544 0 : CVChangeChar(cv,pos);
7545 : }
7546 :
7547 :
7548 0 : static void CVMenuChangeChar(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
7549 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
7550 0 : _CVMenuChangeChar(cv,mi->mid);
7551 0 : }
7552 :
7553 0 : static int CVMoveToNextInWordList(GGadget *g, GEvent *e)
7554 : {
7555 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
7556 0 : CharView *cv = GDrawGetUserData(GGadgetGetWindow(g));
7557 0 : CVMoveInWordListByOffset( cv, 1 );
7558 : }
7559 0 : return 1;
7560 : }
7561 0 : static int CVMoveToPrevInWordList(GGadget *g, GEvent *e)
7562 : {
7563 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
7564 0 : CharView *cv = GDrawGetUserData(GGadgetGetWindow(g));
7565 0 : CVMoveInWordListByOffset( cv, -1 );
7566 : }
7567 0 : return 1;
7568 : }
7569 :
7570 : /**
7571 : * If the prev/next BCP is selected than add those to the hash table
7572 : * at "ret".
7573 : */
7574 0 : static void getSelectedControlPointsVisitor(SplinePoint* splfirst, Spline* s, SplinePoint* sp, void* udata )
7575 : {
7576 0 : GHashTable* ret = (GHashTable*)udata;
7577 0 : if( sp->nextcpselected )
7578 0 : g_hash_table_insert( ret, sp, 0 );
7579 0 : if( sp->prevcpselected )
7580 0 : g_hash_table_insert( ret, sp, 0 );
7581 0 : }
7582 0 : static void getAllControlPointsVisitor(SplinePoint* splfirst, Spline* s, SplinePoint* sp, void* udata )
7583 : {
7584 0 : GHashTable* ret = (GHashTable*)udata;
7585 0 : g_hash_table_insert( ret, sp, 0 );
7586 0 : g_hash_table_insert( ret, sp, 0 );
7587 0 : }
7588 0 : static void isAnyControlPointSelectedVisitor(SplinePoint* splfirst, Spline* s, SplinePoint* sp, void* udata )
7589 : {
7590 0 : int* ret = (int*)udata;
7591 0 : if( sp->selected )
7592 0 : (*ret) = 1;
7593 0 : }
7594 :
7595 :
7596 : /**
7597 : * Get a hash table with all the selected BCP in it.
7598 : *
7599 : * The caller must call g_hash_table_destroy() on the return value.
7600 : */
7601 0 : static GHashTable* getSelectedControlPoints( CharView *cv, PressedOn *p )
7602 : {
7603 0 : Layer* l = cv->b.layerheads[cv->b.drawmode];
7604 0 : if( !l || !l->splines )
7605 0 : return 0;
7606 :
7607 0 : GHashTable* ret = g_hash_table_new( g_direct_hash, g_direct_equal );
7608 0 : SplinePointList* spl = l->splines;
7609 0 : for( ; spl; spl = spl->next )
7610 : {
7611 0 : SPLFirstVisitPoints( spl->first, getSelectedControlPointsVisitor, ret );
7612 : }
7613 :
7614 0 : return ret;
7615 : }
7616 0 : static GHashTable* getAllControlPoints( CharView *cv, PressedOn *p )
7617 : {
7618 0 : Layer* l = cv->b.layerheads[cv->b.drawmode];
7619 0 : if( !l || !l->splines )
7620 0 : return 0;
7621 :
7622 0 : GHashTable* ret = g_hash_table_new( g_direct_hash, g_direct_equal );
7623 0 : SplinePointList* spl = l->splines;
7624 0 : for( ; spl; spl = spl->next )
7625 : {
7626 0 : SPLFirstVisitPoints( spl->first, getAllControlPointsVisitor, ret );
7627 : }
7628 0 : return ret;
7629 : }
7630 :
7631 0 : void FE_touchControlPoint( void* key,
7632 : void* value,
7633 : SplinePoint* sp,
7634 : BasePoint *which,
7635 : bool isnext,
7636 : void* udata )
7637 : {
7638 : TRACE("FE_touchControlPoint() which:%p\n", which );
7639 0 : SPTouchControl( sp, which, (int)(intptr_t)udata );
7640 0 : }
7641 :
7642 0 : void FE_unselectBCP( void* key,
7643 : void* value,
7644 : SplinePoint* sp,
7645 : BasePoint *which,
7646 : bool isnext,
7647 : void* udata )
7648 : {
7649 0 : sp->nextcpselected = 0;
7650 0 : sp->prevcpselected = 0;
7651 0 : }
7652 :
7653 0 : void FE_adjustBCPByDelta( void* key,
7654 : void* value,
7655 : SplinePoint* sp,
7656 : BasePoint *which,
7657 : bool isnext,
7658 : void* udata )
7659 : {
7660 0 : FE_adjustBCPByDeltaData* data = (FE_adjustBCPByDeltaData*)udata;
7661 0 : CharView *cv = data->cv;
7662 :
7663 : TRACE("FE_adjustBCPByDelta %p %d\n", which, isnext );
7664 : BasePoint to;
7665 0 : to.x = which->x + data->dx;
7666 0 : to.y = which->y + data->dy;
7667 0 : SPAdjustControl(sp,which,&to,cv->b.layerheads[cv->b.drawmode]->order2);
7668 0 : CVSetCharChanged(cv,true);
7669 0 : }
7670 :
7671 0 : void FE_adjustBCPByDeltaWhilePreservingBCPAngle( void* key,
7672 : void* value,
7673 : SplinePoint* sp,
7674 : BasePoint *which,
7675 : bool isnext,
7676 : void* udata )
7677 : {
7678 0 : FE_adjustBCPByDeltaData* data = (FE_adjustBCPByDeltaData*)udata;
7679 0 : CharView *cv = data->cv;
7680 :
7681 : // TRACE("FE_adjustBCPByDeltaWhilePreservingBCPAngle which:%p data:%p isnext:%d\n", which, data, isnext );
7682 : // TRACE("FE_adjustBCPByDeltaWhilePreservingBCPAngle delta %f %f\n", data->dx, data->dy );
7683 : BasePoint to;
7684 0 : to.x = which->x + data->dx;
7685 0 : to.y = which->y + data->dy;
7686 :
7687 : // work out near and far BCP for this movement
7688 0 : BasePoint* near = &sp->nextcp;
7689 0 : BasePoint* far = &sp->prevcp;
7690 0 : if( !isnext )
7691 : {
7692 0 : near = &sp->prevcp;
7693 0 : far = &sp->nextcp;
7694 : }
7695 :
7696 0 : real dx = near->x - far->x;
7697 0 : if( !fabs(dx) )
7698 : {
7699 : // flatline protection
7700 0 : to.x = which->x + data->dx;
7701 0 : to.y = which->y + data->dy;
7702 : }
7703 : else
7704 : {
7705 : // we have a workable gradient
7706 0 : real m = (near->y - far->y) / dx;
7707 :
7708 : // should we lean to x or y for the change?
7709 : // all this is based on m = y2-y1/x2-x1
7710 : // we use m from near and far and extrapolate to the new location
7711 : // based on either x or y and calculate the other ordinate from the
7712 : // gradiant function above.
7713 0 : if( fabs(m) < 1.0 )
7714 : {
7715 0 : real datadx = data->dx;
7716 0 : if( data->keyboarddx && !datadx )
7717 : {
7718 0 : datadx = data->dy;
7719 0 : if( m < 0 )
7720 0 : datadx *= -1;
7721 : }
7722 :
7723 0 : real dx = near->x - far->x;
7724 0 : real m = (near->y - far->y) / dx;
7725 0 : to.x = which->x + datadx;
7726 0 : to.y = m * (to.x - near->x) + near->y;
7727 : }
7728 : else
7729 : {
7730 0 : real datady = data->dy;
7731 0 : if( data->keyboarddx && !datady )
7732 : {
7733 0 : datady = data->dx;
7734 0 : if( m < 0 )
7735 0 : datady *= -1;
7736 : }
7737 0 : real dx = near->x - far->x;
7738 0 : real m = (near->y - far->y) / dx;
7739 0 : to.y = which->y + datady;
7740 0 : to.x = (to.y - near->y + m*near->x) / m;
7741 : }
7742 : }
7743 :
7744 : // move the point and update
7745 0 : SPAdjustControl(sp,which,&to,cv->b.layerheads[cv->b.drawmode]->order2);
7746 0 : CVSetCharChanged(cv,true);
7747 0 : }
7748 :
7749 : /**
7750 : * Container for arguments to FE_visitSelectedControlPoints.
7751 : */
7752 : typedef struct visitSelectedControlPoints_CallbackDataS
7753 : {
7754 : int count; // number of times visitor is called.
7755 : int sel;
7756 : visitSelectedControlPointsVisitor func; // Visitor function to delegate to
7757 : gpointer udata; // user data to use when calling above func()
7758 :
7759 : } visitSelectedControlPoints_CallbackData;
7760 :
7761 : /**
7762 : * Visitor function: calls a delegate visitor function for any prev
7763 : * and next BCP which are selected for each spline point. This is a
7764 : * handy visitor when your BCP handling code for the most part doesn't
7765 : * care if it will operate on the next or prev BCP, ie your visitor
7766 : * simply wants to visit all the selected BCP.
7767 : */
7768 0 : static void FE_visitSelectedControlPoints( gpointer key,
7769 : gpointer value,
7770 : gpointer udata )
7771 : {
7772 0 : visitSelectedControlPoints_CallbackData* d = (visitSelectedControlPoints_CallbackData*)udata;
7773 0 : SplinePoint* sp = (SplinePoint*)key;
7774 :
7775 0 : d->count++;
7776 0 : if( sp->nextcpselected )
7777 : {
7778 0 : BasePoint *which = &sp->nextcp;
7779 0 : d->func( key, value, sp, which, true, d->udata );
7780 : }
7781 0 : if( sp->prevcpselected )
7782 : {
7783 0 : BasePoint *which = &sp->prevcp;
7784 0 : d->func( key, value, sp, which, false, d->udata );
7785 : }
7786 0 : }
7787 0 : static void FE_visitAllControlPoints( gpointer key,
7788 : gpointer value,
7789 : gpointer udata )
7790 : {
7791 0 : visitSelectedControlPoints_CallbackData* d = (visitSelectedControlPoints_CallbackData*)udata;
7792 0 : SplinePoint* sp = (SplinePoint*)key;
7793 :
7794 0 : d->count++;
7795 : {
7796 0 : BasePoint *which = &sp->nextcp;
7797 0 : d->func( key, value, sp, which, true, d->udata );
7798 : }
7799 : {
7800 0 : BasePoint *which = &sp->prevcp;
7801 0 : d->func( key, value, sp, which, false, d->udata );
7802 : }
7803 0 : }
7804 0 : static void FE_visitAdjacentToSelectedControlPoints( gpointer key,
7805 : gpointer value,
7806 : gpointer udata )
7807 : {
7808 0 : visitSelectedControlPoints_CallbackData* d = (visitSelectedControlPoints_CallbackData*)udata;
7809 0 : SplinePoint* sp = (SplinePoint*)key;
7810 :
7811 0 : if( sp->selected )
7812 0 : return;
7813 :
7814 0 : d->count++;
7815 0 : if( sp->prev && sp->prev->from && sp->prev->from->selected )
7816 : {
7817 0 : d->func( key, value, sp, &sp->nextcp, true, d->udata );
7818 0 : d->func( key, value, sp, &sp->prevcp, true, d->udata );
7819 : }
7820 0 : if( sp->next && sp->next->to && sp->next->to->selected )
7821 : {
7822 0 : d->func( key, value, sp, &sp->nextcp, true, d->udata );
7823 0 : d->func( key, value, sp, &sp->prevcp, true, d->udata );
7824 : }
7825 : }
7826 :
7827 0 : void visitSelectedControlPoints( GHashTable *col, visitSelectedControlPointsVisitor f, gpointer udata )
7828 : {
7829 : visitSelectedControlPoints_CallbackData d;
7830 0 : d.func = f;
7831 0 : d.udata = udata;
7832 0 : d.count = 0;
7833 0 : g_hash_table_foreach( col, FE_visitSelectedControlPoints, &d );
7834 0 : }
7835 :
7836 0 : void visitAllControlPoints( GHashTable *col, visitSelectedControlPointsVisitor f, gpointer udata )
7837 : {
7838 : visitSelectedControlPoints_CallbackData d;
7839 0 : d.func = f;
7840 0 : d.udata = udata;
7841 0 : d.count = 0;
7842 0 : g_hash_table_foreach( col, FE_visitAllControlPoints, &d );
7843 0 : }
7844 0 : static void visitAdjacentToSelectedControlPoints( GHashTable *col, visitSelectedControlPointsVisitor f, gpointer udata )
7845 : {
7846 : visitSelectedControlPoints_CallbackData d;
7847 0 : d.func = f;
7848 0 : d.udata = udata;
7849 0 : d.count = 0;
7850 0 : g_hash_table_foreach( col, FE_visitAdjacentToSelectedControlPoints, &d );
7851 0 : }
7852 :
7853 0 : void CVFindAndVisitSelectedControlPoints( CharView *cv, bool preserveState,
7854 : visitSelectedControlPointsVisitor f, void* udata )
7855 : {
7856 : // TRACE("CVFindAndVisitSelectedControlPoints(top) cv->p.sp:%p\n", cv->p.sp );
7857 0 : GHashTable* col = getSelectedControlPoints( cv, &cv->p );
7858 0 : if(!col)
7859 0 : return;
7860 :
7861 0 : if( g_hash_table_size( col ) )
7862 : {
7863 0 : if( preserveState )
7864 0 : CVPreserveState(&cv->b);
7865 0 : visitSelectedControlPoints( col, f, udata );
7866 : }
7867 0 : g_hash_table_destroy(col);
7868 : }
7869 :
7870 0 : void CVVisitAllControlPoints( CharView *cv, bool preserveState,
7871 : visitSelectedControlPointsVisitor f, void* udata )
7872 : {
7873 : TRACE("CVVisitAllControlPoints(top) cv->p.spl:%p cv->p.sp:%p\n", cv->p.spl, cv->p.sp );
7874 0 : if( !cv->p.spl || !cv->p.sp )
7875 0 : return;
7876 :
7877 0 : GHashTable* col = getAllControlPoints( cv, &cv->p );
7878 0 : if( g_hash_table_size( col ) )
7879 : {
7880 0 : if( preserveState )
7881 0 : CVPreserveState(&cv->b);
7882 0 : visitAllControlPoints( col, f, udata );
7883 : }
7884 0 : g_hash_table_destroy(col);
7885 : }
7886 :
7887 0 : void CVVisitAdjacentToSelectedControlPoints( CharView *cv, bool preserveState,
7888 : visitSelectedControlPointsVisitor f, void* udata )
7889 : {
7890 : // TRACE("CVVisitAdjacentToSelectedControlPoints(top) cv->p.sp:%p\n", cv->p.sp );
7891 0 : if( !cv->p.spl || !cv->p.sp )
7892 0 : return;
7893 :
7894 0 : GHashTable* col = getAllControlPoints( cv, &cv->p );
7895 0 : if( !col )
7896 0 : return;
7897 :
7898 0 : if( g_hash_table_size( col ) )
7899 : {
7900 0 : if( preserveState )
7901 0 : CVPreserveState(&cv->b);
7902 0 : visitAdjacentToSelectedControlPoints( col, f, udata );
7903 : }
7904 0 : g_hash_table_destroy(col);
7905 : }
7906 :
7907 :
7908 :
7909 0 : void CVChar(CharView *cv, GEvent *event ) {
7910 : extern float arrowAmount, arrowAccelFactor;
7911 : extern int navigation_mask;
7912 :
7913 0 : if( !cv_auto_goto )
7914 : {
7915 0 : if( event->u.chr.keysym == GK_Control_L
7916 0 : || event->u.chr.keysym == GK_Control_R )
7917 : {
7918 0 : HaveModifiers = 1;
7919 : }
7920 0 : bool isImmediateKeyTogglePreview = isImmediateKey( cv->gw, "TogglePreview", event ) != NULL;
7921 :
7922 0 : if( !HaveModifiers && isImmediateKeyTogglePreview ) {
7923 0 : PressingTilde = 1;
7924 0 : CVPreviewModeSet( cv->gw, true );
7925 0 : return;
7926 : }
7927 : }
7928 :
7929 : /* TRACE("GK_Control_L:%d\n", ( event->u.chr.keysym == GK_Control_L )); */
7930 : /* TRACE("GK_Meta_L:%d\n", ( event->u.chr.keysym == GK_Meta_L )); */
7931 :
7932 0 : int oldactiveModifierControl = cv->activeModifierControl;
7933 0 : int oldactiveModifierAlt = cv->activeModifierAlt;
7934 0 : cv->activeModifierControl |= ( event->u.chr.keysym == GK_Control_L || event->u.chr.keysym == GK_Control_R
7935 0 : || event->u.chr.keysym == GK_Meta_L || event->u.chr.keysym == GK_Meta_R );
7936 0 : cv->activeModifierAlt |= ( event->u.chr.keysym == GK_Alt_L || event->u.chr.keysym == GK_Alt_R
7937 0 : || event->u.chr.keysym == XK_Mode_switch );
7938 :
7939 0 : if( oldactiveModifierControl != cv->activeModifierControl
7940 0 : || oldactiveModifierAlt != cv->activeModifierAlt )
7941 : {
7942 0 : CVInfoDraw(cv,cv->gw);
7943 : }
7944 :
7945 :
7946 : #if _ModKeysAutoRepeat
7947 : /* Under cygwin these keys auto repeat, they don't under normal X */
7948 : if ( cv->autorpt!=NULL ) {
7949 : GDrawCancelTimer(cv->autorpt); cv->autorpt = NULL;
7950 : if ( cv->keysym == event->u.chr.keysym ) /* It's an autorepeat, ignore it */
7951 : return;
7952 : CVToolsSetCursor(cv,cv->oldstate,NULL);
7953 : }
7954 : #endif
7955 :
7956 : #if MyMemory
7957 : if ( event->u.chr.keysym == GK_F2 ) {
7958 : fprintf( stderr, "Malloc debug on\n" );
7959 : __malloc_debug(5);
7960 : } else if ( event->u.chr.keysym == GK_F3 ) {
7961 : fprintf( stderr, "Malloc debug off\n" );
7962 : __malloc_debug(0);
7963 : }
7964 : #endif
7965 :
7966 0 : if ( !HaveModifiers && event->u.chr.keysym==' ' && cv->spacebar_hold==0 ) {
7967 0 : cv->p.x = event->u.mouse.x;
7968 0 : cv->p.y = event->u.mouse.y;
7969 0 : update_spacebar_hand_tool(cv);
7970 : }
7971 :
7972 0 : CVPaletteActivate(cv);
7973 0 : CVToolsSetCursor(cv,TrueCharState(event),NULL);
7974 :
7975 :
7976 : /* The window check is to prevent infinite loops since DVChar can */
7977 : /* call CVChar too */
7978 0 : if ( cv->dv!=NULL && (event->w==cv->gw || event->w==cv->v) && DVChar(cv->dv,event))
7979 : {
7980 : /* All Done */;
7981 : }
7982 0 : else if ( event->u.chr.keysym=='s' &&
7983 0 : (event->u.chr.state&ksm_control) &&
7984 0 : (event->u.chr.state&ksm_meta) )
7985 0 : MenuSaveAll(NULL,NULL,NULL);
7986 0 : else if ( event->u.chr.keysym=='q' &&
7987 0 : (event->u.chr.state&ksm_control) &&
7988 0 : (event->u.chr.state&ksm_meta) )
7989 0 : MenuExit(NULL,NULL,NULL);
7990 0 : else if ( event->u.chr.keysym == GK_Shift_L || event->u.chr.keysym == GK_Shift_R ||
7991 0 : event->u.chr.keysym == GK_Alt_L || event->u.chr.keysym == GK_Alt_R ||
7992 0 : event->u.chr.keysym == GK_Meta_L || event->u.chr.keysym == GK_Meta_R ) {
7993 0 : CVFakeMove(cv, event);
7994 0 : } else if (( event->u.chr.keysym == GK_Tab || event->u.chr.keysym == GK_BackTab) &&
7995 0 : (event->u.chr.state&ksm_control) && cv->showtabs && cv->former_cnt>1 ) {
7996 0 : GGadgetDispatchEvent(cv->tabs,event);
7997 0 : } else if ( (event->u.chr.state&ksm_meta) &&
7998 0 : !(event->u.chr.state&(ksm_control|ksm_shift)) &&
7999 0 : event->u.chr.chars[0]!='\0' ) {
8000 0 : CVPaletteMnemonicCheck(event);
8001 0 : } else if ( !(event->u.chr.state&(ksm_control|ksm_meta)) &&
8002 0 : event->u.chr.keysym == GK_BackSpace ) {
8003 : /* Menu does delete */
8004 0 : CVClear(cv->gw,NULL,NULL);
8005 0 : } else if ( event->u.chr.keysym == GK_Help ) {
8006 0 : MenuHelp(NULL,NULL,NULL); /* Menu does F1 */
8007 0 : } else if ( event->u.chr.keysym=='<' && (event->u.chr.state&ksm_control) ) {
8008 : /* European keyboards do not need shift to get < */
8009 0 : CVDoFindInFontView(cv);
8010 0 : } else if ( (event->u.chr.keysym=='[' || event->u.chr.keysym==']') &&
8011 0 : (event->u.chr.state&ksm_control) ) {
8012 : /* European keyboards need a funky modifier to get [] */
8013 0 : _CVMenuChangeChar(cv,event->u.chr.keysym=='[' ? MID_Prev : MID_Next );
8014 0 : } else if ( (event->u.chr.keysym=='{' || event->u.chr.keysym=='}') &&
8015 0 : (event->u.chr.state&ksm_control) ) {
8016 : /* European keyboards need a funky modifier to get {} */
8017 0 : _CVMenuChangeChar(cv,event->u.chr.keysym=='{' ? MID_PrevDef : MID_NextDef );
8018 0 : } else if ( event->u.chr.keysym=='\\' && (event->u.chr.state&ksm_control) ) {
8019 : /* European keyboards need a funky modifier to get \ */
8020 0 : CVDoTransform(cv,cvt_none);
8021 0 : } else if ( (event->u.chr.keysym=='F' || event->u.chr.keysym=='B') &&
8022 0 : !(event->u.chr.state&(ksm_control|ksm_meta)) ) {
8023 0 : CVLSelectLayer(cv, event->u.chr.keysym=='F' ? 1 : 0);
8024 0 : } else if ( (event->u.chr.state&ksm_control) && (event->u.chr.keysym=='-' || event->u.chr.keysym==0xffad/*XK_KP_Subtract*/) ){
8025 0 : _CVMenuScale(cv, MID_ZoomOut);
8026 0 : } else if ( (event->u.chr.state&ksm_control) && (event->u.chr.keysym=='=' || event->u.chr.keysym==0xffab/*XK_KP_Add*/) ){
8027 0 : _CVMenuScale(cv, MID_ZoomIn);
8028 : }
8029 0 : else if ( event->u.chr.keysym == GK_Left ||
8030 0 : event->u.chr.keysym == GK_Up ||
8031 0 : event->u.chr.keysym == GK_Right ||
8032 0 : event->u.chr.keysym == GK_Down ||
8033 0 : event->u.chr.keysym == GK_KP_Left ||
8034 0 : event->u.chr.keysym == GK_KP_Up ||
8035 0 : event->u.chr.keysym == GK_KP_Right ||
8036 0 : event->u.chr.keysym == GK_KP_Down )
8037 0 : {
8038 : TRACE("key left/right/up/down...\n");
8039 :
8040 0 : GGadget *active = GWindowGetFocusGadgetOfWindow(cv->gw);
8041 0 : if( active == cv->charselector )
8042 : {
8043 0 : if ( event->u.chr.keysym == GK_Left ||event->u.chr.keysym == GK_Right )
8044 : {
8045 : TRACE("left/right on the charselector!\n");
8046 : }
8047 0 : int dir = ( event->u.chr.keysym == GK_Up || event->u.chr.keysym==GK_KP_Up ) ? -1 : 1;
8048 0 : Wordlist_MoveByOffset( cv->charselector, &cv->charselectoridx, dir );
8049 :
8050 0 : return;
8051 : }
8052 :
8053 :
8054 0 : real dx=0, dy=0; int anya;
8055 0 : switch ( event->u.chr.keysym ) {
8056 : case GK_Left: case GK_KP_Left:
8057 0 : dx = -1;
8058 0 : break;
8059 : case GK_Right: case GK_KP_Right:
8060 0 : dx = 1;
8061 0 : break;
8062 : case GK_Up: case GK_KP_Up:
8063 0 : dy = 1;
8064 0 : break;
8065 : case GK_Down: case GK_KP_Down:
8066 0 : dy = -1;
8067 0 : break;
8068 : }
8069 0 : if ( event->u.chr.state & (ksm_control|ksm_capslock) ) {
8070 : struct sbevent sb;
8071 0 : sb.type = dy>0 || dx<0 ? et_sb_halfup : et_sb_halfdown;
8072 0 : if ( dx==0 )
8073 0 : CVVScroll(cv,&sb);
8074 : else
8075 0 : CVHScroll(cv,&sb);
8076 : }
8077 : else
8078 : {
8079 : // TRACE("cvchar( moving points? ) shift:%d\n", ( event->u.chr.state & (ksm_shift) ));
8080 : FE_adjustBCPByDeltaData d;
8081 0 : memset( &d, 0, sizeof(FE_adjustBCPByDeltaData));
8082 0 : visitSelectedControlPointsVisitor func = FE_adjustBCPByDelta;
8083 0 : if ( event->u.chr.state & ksm_meta )
8084 : {
8085 : // move the bcp 1 unit in the direction it already has
8086 0 : func = FE_adjustBCPByDeltaWhilePreservingBCPAngle;
8087 : // allow that func to work it's magic on any gradient
8088 0 : d.keyboarddx = 1;
8089 : }
8090 : /* if ( event->u.chr.state & (ksm_shift) ) */
8091 : /* dx -= dy*tan((cv->b.sc->parent->italicangle)*(3.1415926535897932/180) ); */
8092 0 : if ( event->u.chr.state & (ksm_shift) )
8093 : {
8094 0 : dx *= arrowAccelFactor; dy *= arrowAccelFactor;
8095 : }
8096 :
8097 0 : if (( cv->p.sp!=NULL || cv->lastselpt!=NULL ) &&
8098 0 : (cv->p.nextcp || cv->p.prevcp) )
8099 0 : {
8100 : // This code moves 1 or more BCP
8101 :
8102 0 : SplinePoint *old = cv->p.sp;
8103 0 : d.cv = cv;
8104 0 : d.dx = dx * arrowAmount;
8105 0 : d.dy = dy * arrowAmount;
8106 0 : CVFindAndVisitSelectedControlPoints( cv, true,
8107 : func, &d );
8108 0 : cv->p.sp = old;
8109 0 : SCUpdateAll(cv->b.sc);
8110 :
8111 : }
8112 0 : else if ( CVAnySel(cv,NULL,NULL,NULL,&anya) || cv->widthsel || cv->vwidthsel )
8113 : {
8114 0 : CVPreserveState(&cv->b);
8115 0 : CVMoveSelection(cv,dx*arrowAmount,dy*arrowAmount, event->u.chr.state);
8116 0 : if ( cv->widthsel )
8117 0 : SCSynchronizeWidth(cv->b.sc,cv->b.sc->width,cv->b.sc->width-dx,NULL);
8118 0 : _CV_CharChangedUpdate(cv,2);
8119 0 : CVInfoDraw(cv,cv->gw);
8120 : }
8121 0 : CVGridHandlePossibleFitChar( cv );
8122 : }
8123 0 : } else if ( event->u.chr.keysym == GK_Page_Up ||
8124 0 : event->u.chr.keysym == GK_KP_Page_Up ||
8125 0 : event->u.chr.keysym == GK_Prior ||
8126 0 : event->u.chr.keysym == GK_Page_Down ||
8127 0 : event->u.chr.keysym == GK_KP_Page_Down ||
8128 0 : event->u.chr.keysym == GK_Next ) {
8129 : /* Um... how do we scroll horizontally??? */
8130 : struct sbevent sb;
8131 0 : sb.type = et_sb_uppage;
8132 0 : if ( event->u.chr.keysym == GK_Page_Down ||
8133 0 : event->u.chr.keysym == GK_KP_Page_Down ||
8134 0 : event->u.chr.keysym == GK_Next )
8135 0 : sb.type = et_sb_downpage;
8136 0 : CVVScroll(cv,&sb);
8137 0 : } else if ( event->u.chr.keysym == GK_Home ) {
8138 0 : CVFit(cv);
8139 0 : } else if ( event->u.chr.keysym==' ' && cv->spacebar_hold ){
8140 0 : } else if ( (event->u.chr.state&((GMenuMask()|navigation_mask)&~(ksm_shift|ksm_capslock)))==navigation_mask &&
8141 0 : event->type == et_char &&
8142 0 : event->u.chr.keysym!=0 &&
8143 0 : (event->u.chr.keysym<GK_Special /*|| event->u.chr.keysym>=0x10000*/)) {
8144 0 : SplineFont *sf = cv->b.sc->parent;
8145 : int i;
8146 0 : EncMap *map = cv->b.fv->map;
8147 : extern int cv_auto_goto;
8148 0 : if ( cv_auto_goto ) {
8149 0 : i = SFFindSlot(sf,map,event->u.chr.keysym,NULL);
8150 0 : if ( i!=-1 )
8151 0 : CVChangeChar(cv,i);
8152 : }
8153 : }
8154 : }
8155 :
8156 0 : void CVShowPoint(CharView *cv, BasePoint *me) {
8157 : int x, y;
8158 0 : int fudge = 30;
8159 :
8160 0 : if ( cv->width<60 )
8161 0 : fudge = cv->width/3;
8162 0 : if ( cv->height<60 && fudge>cv->height/3 )
8163 0 : fudge = cv->height/3;
8164 :
8165 : /* Make sure the point is visible and has some context around it */
8166 0 : x = cv->xoff + rint(me->x*cv->scale);
8167 0 : y = -cv->yoff + cv->height - rint(me->y*cv->scale);
8168 0 : if ( x<fudge || y<fudge || x>cv->width-fudge || y>cv->height-fudge )
8169 0 : CVMagnify(cv,me->x,me->y,0,0);
8170 0 : }
8171 :
8172 0 : static void CVSelectContours(CharView *cv) {
8173 : SplineSet *spl;
8174 : SplinePoint *sp;
8175 : int sel;
8176 : int i;
8177 :
8178 0 : for ( spl=cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL; spl=spl->next ) {
8179 0 : sel = false;
8180 0 : if ( cv->b.sc->inspiro && hasspiro()) {
8181 0 : for ( i=0; i<spl->spiro_cnt-1; ++i ) {
8182 0 : if ( SPIRO_SELECTED(&spl->spiros[i]) ) {
8183 0 : sel = true;
8184 0 : break;
8185 : }
8186 : }
8187 0 : if ( sel ) {
8188 0 : for ( i=0; i<spl->spiro_cnt-1; ++i )
8189 0 : SPIRO_SELECT(&spl->spiros[i]);
8190 : }
8191 : } else {
8192 0 : for ( sp=spl->first ; ; ) {
8193 0 : if ( sp->selected ) {
8194 0 : sel = true;
8195 0 : break;
8196 : }
8197 0 : if ( sp->next==NULL )
8198 0 : break;
8199 0 : sp = sp->next->to;
8200 0 : if ( sp==spl->first )
8201 0 : break;
8202 0 : }
8203 0 : if ( sel ) {
8204 0 : for ( sp=spl->first ; ; ) {
8205 0 : sp->selected = true;
8206 0 : if ( sp->next==NULL )
8207 0 : break;
8208 0 : sp = sp->next->to;
8209 0 : if ( sp==spl->first )
8210 0 : break;
8211 0 : }
8212 : }
8213 : }
8214 : }
8215 0 : SCUpdateAll(cv->b.sc);
8216 0 : }
8217 :
8218 0 : static void CVMenuSelectContours(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8219 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
8220 0 : CVSelectContours(cv);
8221 0 : }
8222 :
8223 0 : static void CVMenuSelectPointAt(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8224 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
8225 0 : CVSelectPointAt(cv);
8226 0 : }
8227 :
8228 0 : static void CVNextPrevSpiroPt(CharView *cv, struct gmenuitem *mi) {
8229 : RefChar *r; ImageList *il;
8230 : SplineSet *spl, *ss;
8231 : SplinePoint *junk;
8232 : int x, y;
8233 0 : spiro_cp *selcp = NULL, *other;
8234 : int index;
8235 :
8236 0 : if ( mi->mid == MID_FirstPt ) {
8237 0 : if ( cv->b.layerheads[cv->b.drawmode]->splines==NULL )
8238 0 : return;
8239 0 : CVClearSel(cv);
8240 0 : other = &cv->b.layerheads[cv->b.drawmode]->splines->spiros[0];
8241 : } else {
8242 0 : if ( !CVOneThingSel(cv,&junk,&spl,&r,&il,NULL,&selcp) || spl==NULL )
8243 0 : return;
8244 0 : other = selcp;
8245 0 : if ( spl==NULL )
8246 0 : return;
8247 0 : index = selcp - spl->spiros;
8248 0 : if ( mi->mid == MID_NextPt ) {
8249 0 : if ( index!=spl->spiro_cnt-2 )
8250 0 : other = &spl->spiros[index+1];
8251 : else {
8252 0 : if ( spl->next == NULL )
8253 0 : spl = cv->b.layerheads[cv->b.drawmode]->splines;
8254 : else
8255 0 : spl = spl->next;
8256 0 : other = &spl->spiros[0];
8257 : }
8258 0 : } else if ( mi->mid == MID_PrevPt ) {
8259 0 : if ( index!=0 ) {
8260 0 : other = &spl->spiros[index-1];
8261 : } else {
8262 0 : if ( spl==cv->b.layerheads[cv->b.drawmode]->splines ) {
8263 0 : for ( ss = cv->b.layerheads[cv->b.drawmode]->splines; ss->next!=NULL; ss=ss->next );
8264 : } else {
8265 0 : for ( ss = cv->b.layerheads[cv->b.drawmode]->splines; ss->next!=spl; ss=ss->next );
8266 : }
8267 0 : spl = ss;
8268 0 : other = &ss->spiros[ss->spiro_cnt-2];
8269 : }
8270 0 : } else if ( mi->mid == MID_FirstPtNextCont ) {
8271 0 : if ( spl->next!=NULL )
8272 0 : other = &spl->next->spiros[0];
8273 : else
8274 0 : other = NULL;
8275 : }
8276 : }
8277 0 : if ( selcp!=NULL )
8278 0 : SPIRO_DESELECT(selcp);
8279 0 : if ( other!=NULL )
8280 0 : SPIRO_SELECT(other);
8281 0 : cv->p.sp = NULL;
8282 0 : cv->lastselpt = NULL;
8283 0 : cv->lastselcp = other;
8284 :
8285 : /* Make sure the point is visible and has some context around it */
8286 0 : if ( other!=NULL ) {
8287 0 : x = cv->xoff + rint(other->x*cv->scale);
8288 0 : y = -cv->yoff + cv->height - rint(other->y*cv->scale);
8289 0 : if ( x<40 || y<40 || x>cv->width-40 || y>cv->height-40 )
8290 0 : CVMagnify(cv,other->x,other->y,0,0);
8291 : }
8292 :
8293 0 : CVInfoDraw(cv,cv->gw);
8294 0 : SCUpdateAll(cv->b.sc);
8295 : }
8296 :
8297 0 : static void CVNextPrevPt(CharView *cv, struct gmenuitem *mi) {
8298 0 : SplinePoint *selpt=NULL, *other;
8299 : RefChar *r; ImageList *il;
8300 : SplineSet *spl, *ss;
8301 : int x, y;
8302 : spiro_cp *junk;
8303 :
8304 0 : if ( cv->b.sc->inspiro && hasspiro()) {
8305 0 : CVNextPrevSpiroPt(cv,mi);
8306 0 : return;
8307 : }
8308 :
8309 0 : if ( mi->mid == MID_FirstPt ) {
8310 0 : if ( cv->b.layerheads[cv->b.drawmode]->splines==NULL )
8311 0 : return;
8312 0 : other = (cv->b.layerheads[cv->b.drawmode]->splines)->first;
8313 0 : CVClearSel(cv);
8314 : } else {
8315 0 : if ( !CVOneThingSel(cv,&selpt,&spl,&r,&il,NULL,&junk) || spl==NULL )
8316 0 : return;
8317 0 : other = selpt;
8318 0 : if ( spl==NULL )
8319 0 : return;
8320 0 : else if ( mi->mid == MID_NextPt ) {
8321 0 : if ( other->next!=NULL && other->next->to!=spl->first )
8322 0 : other = other->next->to;
8323 : else {
8324 0 : if ( spl->next == NULL )
8325 0 : spl = cv->b.layerheads[cv->b.drawmode]->splines;
8326 : else
8327 0 : spl = spl->next;
8328 0 : other = spl->first;
8329 : }
8330 0 : } else if ( mi->mid == MID_PrevPt ) {
8331 0 : if ( other!=spl->first ) {
8332 0 : other = other->prev->from;
8333 : } else {
8334 0 : if ( spl==cv->b.layerheads[cv->b.drawmode]->splines ) {
8335 0 : for ( ss = cv->b.layerheads[cv->b.drawmode]->splines; ss->next!=NULL; ss=ss->next );
8336 : } else {
8337 0 : for ( ss = cv->b.layerheads[cv->b.drawmode]->splines; ss->next!=spl; ss=ss->next );
8338 : }
8339 0 : spl = ss;
8340 0 : other = ss->last;
8341 0 : if ( spl->last==spl->first && spl->last->prev!=NULL )
8342 0 : other = other->prev->from;
8343 : }
8344 0 : } else if ( mi->mid == MID_FirstPtNextCont ) {
8345 0 : if ( spl->next!=NULL )
8346 0 : other = spl->next->first;
8347 : else
8348 0 : other = NULL;
8349 : }
8350 : }
8351 0 : if ( selpt!=NULL )
8352 0 : selpt->selected = false;
8353 0 : if ( other!=NULL )
8354 0 : other->selected = true;
8355 0 : cv->p.sp = NULL;
8356 0 : cv->lastselpt = other;
8357 0 : cv->p.spiro = cv->lastselcp = NULL;
8358 :
8359 : /* Make sure the point is visible and has some context around it */
8360 0 : if ( other!=NULL ) {
8361 0 : x = cv->xoff + rint(other->me.x*cv->scale);
8362 0 : y = -cv->yoff + cv->height - rint(other->me.y*cv->scale);
8363 0 : if ( x<40 || y<40 || x>cv->width-40 || y>cv->height-40 )
8364 0 : CVMagnify(cv,other->me.x,other->me.y,0,0);
8365 : }
8366 :
8367 0 : CVInfoDraw(cv,cv->gw);
8368 0 : SCUpdateAll(cv->b.sc);
8369 : }
8370 :
8371 0 : static void CVMenuNextPrevPt(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
8372 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
8373 0 : CVNextPrevPt(cv, mi);
8374 0 : }
8375 :
8376 0 : static void CVNextPrevCPt(CharView *cv, struct gmenuitem *mi) {
8377 0 : SplinePoint *selpt=NULL;
8378 : RefChar *r; ImageList *il;
8379 : SplineSet *spl;
8380 : spiro_cp *junk;
8381 :
8382 0 : if ( !CVOneThingSel(cv,&selpt,&spl,&r,&il,NULL,&junk))
8383 0 : return;
8384 0 : if ( selpt==NULL )
8385 0 : return;
8386 0 : cv->p.nextcp = mi->mid==MID_NextCP;
8387 0 : cv->p.prevcp = mi->mid==MID_PrevCP;
8388 0 : SCUpdateAll(cv->b.sc);
8389 : }
8390 :
8391 0 : static void CVMenuNextPrevCPt(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
8392 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
8393 0 : CVNextPrevCPt(cv, mi);
8394 0 : }
8395 :
8396 0 : static void CVMenuGotoChar(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8397 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
8398 : int pos;
8399 :
8400 0 : if ( cv->b.container ) {
8401 0 : (cv->b.container->funcs->doNavigate)(cv->b.container,nt_goto);
8402 0 : return;
8403 : }
8404 :
8405 0 : pos = GotoChar(cv->b.fv->sf,cv->b.fv->map,NULL);
8406 0 : if ( pos!=-1 )
8407 0 : CVChangeChar(cv,pos);
8408 : }
8409 :
8410 0 : static void CVMenuFindInFontView(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8411 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
8412 0 : CVDoFindInFontView(cv);
8413 0 : }
8414 :
8415 0 : static void CVMenuPalettesDock(GWindow UNUSED(gw), struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8416 0 : PalettesChangeDocking();
8417 0 : }
8418 :
8419 0 : static void CVMenuPaletteShow(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
8420 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
8421 0 : CVPaletteSetVisible(cv, mi->mid==MID_Tools, !CVPaletteIsVisible(cv, mi->mid==MID_Tools));
8422 0 : }
8423 :
8424 0 : static void cv_pllistcheck(CharView *cv, struct gmenuitem *mi) {
8425 : extern int palettes_docked;
8426 :
8427 0 : for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
8428 0 : switch ( mi->mid ) {
8429 : case MID_Tools:
8430 0 : mi->ti.checked = CVPaletteIsVisible(cv,1);
8431 0 : break;
8432 : case MID_Layers:
8433 0 : mi->ti.checked = CVPaletteIsVisible(cv,0);
8434 0 : break;
8435 : case MID_DockPalettes:
8436 0 : mi->ti.checked = palettes_docked;
8437 0 : break;
8438 : }
8439 : }
8440 0 : }
8441 :
8442 0 : static void pllistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
8443 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
8444 0 : cv_pllistcheck(cv, mi);
8445 0 : }
8446 :
8447 : /*
8448 : * Unused
8449 : static void tablistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
8450 : GDrawGetUserData(gw);
8451 : }
8452 : */
8453 :
8454 0 : static void CVUndo(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8455 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
8456 :
8457 0 : Undoes *undo = cv->b.layerheads[cv->b.drawmode]->undoes;
8458 :
8459 : // TRACE("CVUndo() undo:%p u->next:%p\n", undo, ( undo ? undo->next : 0 ) );
8460 0 : if( undo )
8461 : {
8462 0 : if ( collabclient_inSession( &cv->b ) ) {
8463 0 : collabclient_performLocalUndo( &cv->b );
8464 0 : cv->lastselpt = NULL;
8465 0 : _CVCharChangedUpdate(&cv->b,1);
8466 0 : return;
8467 : }
8468 : }
8469 :
8470 0 : CVDoUndo(&cv->b);
8471 0 : cv->lastselpt = NULL;
8472 : }
8473 :
8474 0 : static void CVRedo(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8475 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
8476 :
8477 0 : Undoes *undo = cv->b.layerheads[cv->b.drawmode]->redoes;
8478 0 : if ( undo ) {
8479 0 : if ( collabclient_inSession(&cv->b) ) {
8480 : TRACE("in-session (redo)!\n");
8481 0 : collabclient_performLocalRedo( &cv->b );
8482 0 : cv->lastselpt = NULL;
8483 0 : _CVCharChangedUpdate(&cv->b,1);
8484 0 : return;
8485 : }
8486 : }
8487 :
8488 0 : CVDoRedo(&cv->b);
8489 0 : cv->lastselpt = NULL;
8490 : }
8491 :
8492 0 : static void _CVCopy(CharView *cv) {
8493 0 : int desel = false, anya;
8494 :
8495 : /* If nothing is selected, copy everything. Do that by temporarily selecting everything */
8496 0 : if ( !CVAnySel(cv,NULL,NULL,NULL,&anya))
8497 0 : if ( !(desel = CVSetSel(cv,-1)))
8498 0 : return;
8499 0 : CopySelected(&cv->b,cv->showanchor);
8500 0 : if ( desel )
8501 0 : CVClearSel(cv);
8502 : }
8503 :
8504 0 : static void CVCopy(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8505 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
8506 0 : _CVCopy(cv);
8507 0 : }
8508 :
8509 0 : static void CVCopyLookupData(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8510 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
8511 0 : SCCopyLookupData(cv->b.sc);
8512 0 : }
8513 :
8514 0 : static void CVCopyRef(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8515 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
8516 0 : CopyReference(cv->b.sc);
8517 0 : }
8518 :
8519 0 : static void CVMenuCopyGridFit(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8520 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
8521 0 : CVCopyGridFit(&cv->b);
8522 0 : }
8523 :
8524 0 : static void CVCopyWidth(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
8525 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
8526 0 : if ( mi->mid==MID_CopyVWidth && !cv->b.sc->parent->hasvmetrics )
8527 0 : return;
8528 0 : CopyWidth(&cv->b,mi->mid==MID_CopyWidth?ut_width:
8529 0 : mi->mid==MID_CopyVWidth?ut_vwidth:
8530 0 : mi->mid==MID_CopyLBearing?ut_lbearing:
8531 : ut_rbearing);
8532 : }
8533 :
8534 0 : static void CVDoClear(CharView *cv) {
8535 : ImageList *prev, *imgs, *next;
8536 : RefChar *refs, *rnext;
8537 0 : int layer = CVLayer((CharViewBase *) cv);
8538 : int anyimages;
8539 :
8540 0 : CVPreserveState(&cv->b);
8541 0 : if ( cv->b.drawmode==dm_fore )
8542 0 : SCRemoveSelectedMinimumDistances(cv->b.sc,2);
8543 0 : cv->b.layerheads[cv->b.drawmode]->splines = SplinePointListRemoveSelected(cv->b.sc,
8544 0 : cv->b.layerheads[cv->b.drawmode]->splines);
8545 0 : for ( refs=cv->b.layerheads[cv->b.drawmode]->refs; refs!=NULL; refs = rnext ) {
8546 0 : rnext = refs->next;
8547 0 : if ( refs->selected )
8548 0 : SCRemoveDependent(cv->b.sc,refs,layer);
8549 : }
8550 0 : if ( cv->b.drawmode==dm_fore ) {
8551 0 : AnchorPoint *ap, *aprev=NULL, *anext;
8552 0 : if ( cv->showanchor ) for ( ap=cv->b.sc->anchor; ap!=NULL; ap=anext ) {
8553 0 : anext = ap->next;
8554 0 : if ( ap->selected ) {
8555 0 : if ( aprev!=NULL )
8556 0 : aprev->next = anext;
8557 : else
8558 0 : cv->b.sc->anchor = anext;
8559 0 : ap->next = NULL;
8560 0 : AnchorPointsFree(ap);
8561 : } else
8562 0 : aprev = ap;
8563 : }
8564 : }
8565 0 : anyimages = false;
8566 0 : for ( prev = NULL, imgs=cv->b.layerheads[cv->b.drawmode]->images; imgs!=NULL; imgs = next ) {
8567 0 : next = imgs->next;
8568 0 : if ( !imgs->selected )
8569 0 : prev = imgs;
8570 : else {
8571 0 : if ( prev==NULL )
8572 0 : cv->b.layerheads[cv->b.drawmode]->images = next;
8573 : else
8574 0 : prev->next = next;
8575 0 : chunkfree(imgs,sizeof(ImageList));
8576 : /* garbage collection of images????!!!! */
8577 0 : anyimages = true;
8578 : }
8579 : }
8580 0 : if ( anyimages )
8581 0 : SCOutOfDateBackground(cv->b.sc);
8582 0 : if ( cv->lastselpt!=NULL || cv->p.sp!=NULL || cv->p.spiro!=NULL || cv->lastselcp!=NULL ) {
8583 0 : cv->lastselpt = NULL; cv->p.sp = NULL;
8584 0 : cv->p.spiro = cv->lastselcp = NULL;
8585 0 : CVInfoDraw(cv,cv->gw);
8586 : }
8587 0 : }
8588 :
8589 0 : static void CVClear(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8590 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
8591 : int anyanchor;
8592 :
8593 0 : if ( !CVAnySel(cv,NULL,NULL,NULL,&anyanchor))
8594 0 : return;
8595 0 : CVDoClear(cv);
8596 0 : CVGridHandlePossibleFitChar( cv );
8597 0 : CVCharChangedUpdate(&cv->b);
8598 : }
8599 :
8600 0 : static void CVClearBackground(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8601 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
8602 0 : SCClearBackground(cv->b.sc);
8603 0 : }
8604 :
8605 0 : static void _CVPaste(CharView *cv) {
8606 0 : enum undotype ut = CopyUndoType();
8607 0 : 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;
8608 0 : if ( ut!=ut_lbearing ) /* The lbearing code does this itself */
8609 0 : CVPreserveStateHints(&cv->b);
8610 0 : if ( ut!=ut_width && ut!=ut_vwidth && ut!=ut_lbearing && ut!=ut_rbearing && ut!=ut_possub )
8611 0 : CVClearSel(cv);
8612 0 : PasteToCV(&cv->b);
8613 0 : cv->lastselpt = NULL;
8614 0 : CVCharChangedUpdate(&cv->b);
8615 0 : if ( was_empty && (cv->b.sc->hstem != NULL || cv->b.sc->vstem!=NULL ))
8616 0 : cv->b.sc->changedsincelasthinted = false;
8617 0 : }
8618 :
8619 0 : static void CVPaste(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8620 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
8621 0 : _CVPaste(cv);
8622 0 : CVInkscapeAdjust(cv);
8623 0 : }
8624 :
8625 0 : static void _CVMerge(CharView *cv, int elide) {
8626 0 : int anyp = 0;
8627 :
8628 0 : if ( !CVAnySel(cv,&anyp,NULL,NULL,NULL) || !anyp)
8629 0 : return;
8630 0 : CVPreserveState(&cv->b);
8631 0 : SplineCharMerge(cv->b.sc,&cv->b.layerheads[cv->b.drawmode]->splines,!elide);
8632 0 : SCClearSelPt(cv->b.sc);
8633 0 : CVCharChangedUpdate(&cv->b);
8634 : }
8635 :
8636 0 : void CVMerge(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8637 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
8638 0 : _CVMerge(cv,false);
8639 0 : }
8640 :
8641 0 : static void _CVMergeToLine(CharView *cv, int elide) {
8642 0 : int anyp = 0;
8643 :
8644 0 : if ( !CVAnySel(cv,&anyp,NULL,NULL,NULL) || !anyp)
8645 0 : return;
8646 0 : CVPreserveState(&cv->b);
8647 0 : SplineCharMerge(cv->b.sc,&cv->b.layerheads[cv->b.drawmode]->splines,!elide);
8648 :
8649 : // Select the other side of the new curve
8650 0 : GList_Glib* gl = CVGetSelectedPoints( cv );
8651 0 : if( g_list_first(gl) )
8652 0 : SPSelectPrevPoint( (SplinePoint*)g_list_first(gl)->data, 1 );
8653 0 : g_list_free( gl );
8654 :
8655 : // And make the curve between the two active points a line
8656 0 : _CVMenuMakeLine( (CharViewBase*) cv, 0, 0 );
8657 0 : SCClearSelPt(cv->b.sc);
8658 0 : CVCharChangedUpdate(&cv->b);
8659 : }
8660 :
8661 0 : void CVMergeToLine(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8662 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
8663 0 : _CVMergeToLine(cv,false);
8664 :
8665 0 : }
8666 :
8667 0 : static void _CVJoin(CharView *cv) {
8668 0 : int anyp = 0, changed;
8669 : extern float joinsnap;
8670 :
8671 0 : CVAnySel(cv,&anyp,NULL,NULL,NULL);
8672 0 : CVPreserveState(&cv->b);
8673 0 : cv->b.layerheads[cv->b.drawmode]->splines = SplineSetJoin(cv->b.layerheads[cv->b.drawmode]->splines,!anyp,joinsnap/cv->scale,&changed);
8674 0 : if ( changed )
8675 0 : CVCharChangedUpdate(&cv->b);
8676 0 : }
8677 :
8678 0 : static void CVJoin(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8679 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
8680 0 : _CVJoin(cv);
8681 0 : }
8682 :
8683 0 : static void _CVCut(CharView *cv) {
8684 : int anya;
8685 :
8686 0 : if ( !CVAnySel(cv,NULL,NULL,NULL,&anya))
8687 0 : return;
8688 0 : _CVCopy(cv);
8689 0 : CVDoClear(cv);
8690 0 : CVCharChangedUpdate(&cv->b);
8691 : }
8692 :
8693 0 : static void CVCut(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8694 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
8695 0 : _CVCut(cv);
8696 0 : }
8697 :
8698 0 : static void CVCopyFgBg(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8699 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
8700 :
8701 0 : if ( cv->b.sc->layers[ly_fore].splines==NULL )
8702 0 : return;
8703 0 : SCCopyLayerToLayer(cv->b.sc,ly_fore,ly_back,false);
8704 : }
8705 :
8706 0 : static void CVMenuCopyL2L(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8707 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
8708 0 : CVCopyLayerToLayer(cv);
8709 0 : }
8710 :
8711 0 : static void CVMenuCompareL2L(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8712 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
8713 0 : CVCompareLayerToLayer(cv);
8714 0 : }
8715 :
8716 0 : static void CVSelectAll(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
8717 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
8718 0 : int mask = -1;
8719 :
8720 0 : if ( mi->mid==MID_SelectAllPoints )
8721 0 : mask = 1;
8722 0 : else if ( mi->mid==MID_SelectAnchors )
8723 0 : mask = 2;
8724 0 : else if ( mi->mid==MID_SelAll ) {
8725 0 : mask = 1;
8726 0 : if (cv->b.drawmode==dm_fore) mask+=2;
8727 : /* TODO! Should we also check if this is the right foreground layer? */
8728 : }
8729 :
8730 0 : if ( CVSetSel(cv,mask))
8731 0 : SCUpdateAll(cv->b.sc);
8732 0 : }
8733 :
8734 0 : static void CVSelectOpenContours(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8735 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
8736 : SplineSet *ss;
8737 : int i;
8738 : SplinePoint *sp;
8739 0 : int changed = CVClearSel(cv);
8740 :
8741 0 : for ( ss=cv->b.layerheads[cv->b.drawmode]->splines; ss!=NULL; ss=ss->next ) {
8742 0 : if ( ss->first->prev==NULL ) {
8743 0 : changed = true;
8744 0 : if ( cv->b.sc->inspiro && hasspiro()) {
8745 0 : for ( i=0; i<ss->spiro_cnt; ++i )
8746 0 : SPIRO_SELECT(&ss->spiros[i]);
8747 : } else {
8748 0 : for ( sp=ss->first ;; ) {
8749 0 : sp->selected = true;
8750 0 : if ( sp->next==NULL )
8751 0 : break;
8752 0 : sp = sp->next->to;
8753 0 : }
8754 : }
8755 : }
8756 : }
8757 0 : if ( changed )
8758 0 : SCUpdateAll(cv->b.sc);
8759 0 : }
8760 :
8761 0 : static void CVSelectNone(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8762 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
8763 0 : if ( CVClearSel(cv))
8764 0 : SCUpdateAll(cv->b.sc);
8765 0 : }
8766 :
8767 0 : static void CVSelectInvert(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8768 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
8769 0 : CVInvertSel(cv);
8770 0 : SCUpdateAll(cv->b.sc);
8771 0 : }
8772 :
8773 0 : static void CVSelectWidth(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8774 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
8775 0 : if ( HasUseMyMetrics(cv->b.sc,CVLayer((CharViewBase *) cv))!=NULL )
8776 0 : return;
8777 0 : cv->widthsel = !cv->widthsel;
8778 0 : cv->oldwidth = cv->b.sc->width;
8779 0 : SCUpdateAll(cv->b.sc);
8780 : }
8781 :
8782 0 : static void CVSelectVWidth(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8783 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
8784 0 : if ( !cv->showvmetrics || !cv->b.sc->parent->hasvmetrics )
8785 0 : return;
8786 0 : if ( HasUseMyMetrics(cv->b.sc,CVLayer((CharViewBase *) cv))!=NULL )
8787 0 : return;
8788 0 : cv->vwidthsel = !cv->widthsel;
8789 0 : cv->oldvwidth = cv->b.sc->vwidth;
8790 0 : SCUpdateAll(cv->b.sc);
8791 : }
8792 :
8793 0 : static void CVSelectHM(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8794 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
8795 : SplinePoint *sp; SplineSet *spl; RefChar *r; ImageList *im;
8796 : spiro_cp *junk;
8797 0 : int exactlyone = CVOneThingSel(cv,&sp,&spl,&r,&im,NULL,&junk);
8798 :
8799 0 : if ( !exactlyone || sp==NULL || sp->hintmask == NULL || spl==NULL )
8800 0 : return;
8801 0 : while ( sp!=NULL ) {
8802 0 : if ( sp->prev==NULL )
8803 0 : break;
8804 0 : sp = sp->prev->from;
8805 0 : if ( sp == spl->first )
8806 0 : break;
8807 0 : if ( sp->hintmask!=NULL )
8808 0 : goto done;
8809 0 : sp->selected = true;
8810 : }
8811 0 : for ( spl = spl->next; spl!=NULL; spl = spl->next ) {
8812 0 : for ( sp=spl->first; sp!=NULL; ) {
8813 0 : if ( sp->hintmask!=NULL )
8814 0 : goto done;
8815 0 : sp->selected = true;
8816 0 : if ( sp->prev==NULL )
8817 0 : break;
8818 0 : sp = sp->prev->from;
8819 0 : if ( sp == spl->first )
8820 0 : break;
8821 : }
8822 : }
8823 : done:
8824 0 : SCUpdateAll(cv->b.sc);
8825 : }
8826 :
8827 0 : static void _CVUnlinkRef(CharView *cv) {
8828 0 : int anyrefs=0;
8829 : RefChar *rf, *next;
8830 :
8831 0 : if ( cv->b.layerheads[cv->b.drawmode]->refs!=NULL ) {
8832 0 : CVPreserveState(&cv->b);
8833 0 : for ( rf=cv->b.layerheads[cv->b.drawmode]->refs; rf!=NULL && !anyrefs; rf=rf->next )
8834 0 : if ( rf->selected ) anyrefs = true;
8835 0 : for ( rf=cv->b.layerheads[cv->b.drawmode]->refs; rf!=NULL ; rf=next ) {
8836 0 : next = rf->next;
8837 0 : if ( rf->selected || !anyrefs) {
8838 0 : SCRefToSplines(cv->b.sc,rf,CVLayer((CharViewBase *) cv));
8839 : }
8840 : }
8841 0 : CVSetCharChanged(cv,true);
8842 0 : SCUpdateAll(cv->b.sc);
8843 : /* Don't need to update dependancies, their splines won't have changed*/
8844 : }
8845 0 : }
8846 :
8847 0 : static void CVUnlinkRef(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
8848 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
8849 0 : _CVUnlinkRef(cv);
8850 0 : }
8851 :
8852 : typedef struct getValueDialogData
8853 : {
8854 : int done;
8855 : int cancelled;
8856 : CharView *cv;
8857 : GWindow gw;
8858 : char* ret;
8859 : GTextInfo label;
8860 : } GetValueDialogData;
8861 :
8862 0 : static int getValueDialogData_e_h(GWindow gw, GEvent *event) {
8863 0 : if ( event->type==et_close ) {
8864 0 : GetValueDialogData *hd = GDrawGetUserData(gw);
8865 0 : hd->done = true;
8866 0 : } else if ( event->type == et_char ) {
8867 0 : return( false );
8868 0 : } else if ( event->type == et_map ) {
8869 : /* Above palettes */
8870 0 : GDrawRaise(gw);
8871 : }
8872 0 : return( true );
8873 : }
8874 :
8875 0 : static int getValueFromUser_OK(GGadget *g, GEvent *e)
8876 : {
8877 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
8878 0 : GetValueDialogData *hd = GDrawGetUserData(GGadgetGetWindow(g));
8879 0 : strcpy( hd->ret, u_to_c(hd->label.text));
8880 0 : strcpy( hd->ret, GGadgetGetTitle8(GWidgetGetControl(hd->gw,CID_getValueFromUser)));
8881 0 : hd->done = true;
8882 : }
8883 0 : return( true );
8884 : }
8885 :
8886 0 : static int getValueFromUser_Cancel(GGadget *g, GEvent *e) {
8887 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
8888 0 : GetValueDialogData *hd = GDrawGetUserData(GGadgetGetWindow(g));
8889 0 : hd->cancelled = true;
8890 0 : hd->done = true;
8891 : }
8892 0 : return( true );
8893 : }
8894 :
8895 0 : static char* getValueFromUser( CharView *cv, const char* windowTitle, const char* msg, const char* defaultValue )
8896 : {
8897 0 : const int retsz = 4096;
8898 : static char ret[4097];
8899 : static GetValueDialogData DATA;
8900 : GRect pos;
8901 : GWindow gw;
8902 : GWindowAttrs wattrs;
8903 : GGadgetCreateData gcd[9], *harray1[4], *harray2[9], *barray[7], *varray[5][2], boxes[5];
8904 : GTextInfo label[9];
8905 :
8906 0 : DATA.cancelled = false;
8907 0 : DATA.done = false;
8908 0 : DATA.cv = cv;
8909 0 : DATA.ret = ret;
8910 0 : ret[0] = '\0';
8911 :
8912 0 : if ( DATA.gw==NULL ) {
8913 0 : memset(&wattrs,0,sizeof(wattrs));
8914 0 : wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict;
8915 0 : wattrs.event_masks = ~(1<<et_charup);
8916 0 : wattrs.restrict_input_to_me = 1;
8917 0 : wattrs.undercursor = 1;
8918 0 : wattrs.cursor = ct_pointer;
8919 0 : wattrs.utf8_window_title = windowTitle;
8920 0 : wattrs.is_dlg = true;
8921 0 : pos.x = pos.y = 0;
8922 0 : pos.width = GGadgetScale(GDrawPointsToPixels(NULL,170));
8923 0 : pos.height = GDrawPointsToPixels(NULL,90);
8924 0 : DATA.gw = gw = GDrawCreateTopWindow(NULL,&pos,getValueDialogData_e_h,&DATA,&wattrs);
8925 :
8926 0 : memset(&label,0,sizeof(label));
8927 0 : memset(&gcd, 0,sizeof(gcd));
8928 0 : memset(&boxes,0,sizeof(boxes));
8929 :
8930 0 : label[0].text = (unichar_t *) msg;
8931 0 : label[0].text_is_1byte = true;
8932 0 : label[0].text_in_resource = true;
8933 0 : gcd[0].gd.label = &label[0];
8934 0 : gcd[0].gd.pos.x = 5;
8935 0 : gcd[0].gd.pos.y = 5;
8936 0 : gcd[0].gd.flags = gg_enabled|gg_visible;
8937 0 : gcd[0].creator = GLabelCreate;
8938 0 : harray1[0] = GCD_Glue;
8939 0 : harray1[1] = &gcd[0];
8940 0 : harray1[2] = 0;
8941 :
8942 0 : label[1].text = (unichar_t *) defaultValue;
8943 0 : label[1].text_is_1byte = true;
8944 0 : DATA.label = label[1];
8945 0 : gcd[1].gd.label = &label[1];
8946 0 : gcd[1].gd.pos.x = 5;
8947 0 : gcd[1].gd.pos.y = 17+5;
8948 0 : gcd[1].gd.pos.width = 40;
8949 0 : gcd[1].gd.flags = gg_enabled|gg_visible;
8950 0 : gcd[1].gd.cid = CID_getValueFromUser;
8951 0 : gcd[1].creator = GTextFieldCreate;
8952 0 : harray2[0] = &gcd[1];
8953 0 : harray2[1] = 0;
8954 :
8955 0 : int idx = 2;
8956 0 : gcd[idx].gd.pos.x = 20-3;
8957 0 : gcd[idx].gd.pos.y = 17+37;
8958 0 : gcd[idx].gd.pos.width = -1;
8959 0 : gcd[idx].gd.pos.height = 0;
8960 0 : gcd[idx].gd.flags = gg_visible | gg_enabled | gg_but_default;
8961 0 : label[idx].text = (unichar_t *) _("_OK");
8962 0 : label[idx].text_is_1byte = true;
8963 0 : label[idx].text_in_resource = true;
8964 0 : gcd[idx].gd.mnemonic = 'O';
8965 0 : gcd[idx].gd.label = &label[idx];
8966 0 : gcd[idx].gd.handle_controlevent = getValueFromUser_OK;
8967 0 : gcd[idx].creator = GButtonCreate;
8968 0 : barray[0] = GCD_Glue;
8969 0 : barray[1] = &gcd[idx];
8970 0 : barray[2] = GCD_Glue;
8971 :
8972 0 : ++idx;
8973 0 : gcd[idx].gd.pos.x = -20;
8974 0 : gcd[idx].gd.pos.y = 17+37+3;
8975 0 : gcd[idx].gd.pos.width = -1;
8976 0 : gcd[idx].gd.pos.height = 0;
8977 0 : gcd[idx].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
8978 0 : label[idx].text = (unichar_t *) _("_Cancel");
8979 0 : label[idx].text_is_1byte = true;
8980 0 : label[idx].text_in_resource = true;
8981 0 : gcd[idx].gd.label = &label[idx];
8982 0 : gcd[idx].gd.mnemonic = 'C';
8983 0 : gcd[idx].gd.handle_controlevent = getValueFromUser_Cancel;
8984 0 : gcd[idx].creator = GButtonCreate;
8985 0 : barray[3] = GCD_Glue;
8986 0 : barray[4] = &gcd[idx];
8987 0 : barray[5] = GCD_Glue;
8988 0 : barray[6] = NULL;
8989 :
8990 0 : gcd[7].gd.pos.x = 5;
8991 0 : gcd[7].gd.pos.y = 17+31;
8992 0 : gcd[7].gd.pos.width = 170-10;
8993 0 : gcd[7].gd.flags = gg_enabled|gg_visible;
8994 0 : gcd[7].creator = GLineCreate;
8995 :
8996 0 : boxes[2].gd.flags = gg_enabled|gg_visible;
8997 0 : boxes[2].gd.u.boxelements = harray1;
8998 0 : boxes[2].creator = GHBoxCreate;
8999 :
9000 0 : boxes[3].gd.flags = gg_enabled|gg_visible;
9001 0 : boxes[3].gd.u.boxelements = harray2;
9002 0 : boxes[3].creator = GHBoxCreate;
9003 :
9004 0 : boxes[4].gd.flags = gg_enabled|gg_visible;
9005 0 : boxes[4].gd.u.boxelements = barray;
9006 0 : boxes[4].creator = GHBoxCreate;
9007 :
9008 0 : varray[0][0] = &boxes[2]; varray[0][1] = NULL;
9009 0 : varray[1][0] = &boxes[3]; varray[1][1] = NULL;
9010 0 : varray[2][0] = &gcd[7]; varray[2][1] = NULL;
9011 0 : varray[3][0] = &boxes[4]; varray[3][1] = NULL;
9012 0 : varray[4][0] = NULL;
9013 :
9014 0 : boxes[0].gd.pos.x = boxes[0].gd.pos.y = 2;
9015 0 : boxes[0].gd.flags = gg_enabled|gg_visible;
9016 0 : boxes[0].gd.u.boxelements = varray[0];
9017 0 : boxes[0].creator = GHVGroupCreate;
9018 :
9019 0 : GGadgetsCreate(gw,boxes);
9020 0 : GHVBoxSetExpandableCol(boxes[2].ret,gb_expandglue);
9021 0 : GHVBoxSetExpandableCol(boxes[3].ret,gb_expandglue);
9022 0 : GHVBoxSetExpandableCol(boxes[4].ret,gb_expandgluesame);
9023 0 : GHVBoxFitWindow(boxes[0].ret);
9024 : } else {
9025 0 : gw = DATA.gw;
9026 0 : snprintf( ret, retsz, "%s", defaultValue );
9027 0 : GGadgetSetTitle8(GWidgetGetControl(gw,CID_getValueFromUser),ret);
9028 0 : GDrawSetTransientFor(gw,(GWindow) -1);
9029 : }
9030 :
9031 0 : GWidgetIndicateFocusGadget(GWidgetGetControl(gw,CID_getValueFromUser));
9032 0 : GTextFieldSelect(GWidgetGetControl(gw,CID_getValueFromUser),0,-1);
9033 :
9034 0 : GWidgetHidePalettes();
9035 0 : GDrawSetVisible(gw,true);
9036 0 : while ( !DATA.done )
9037 0 : GDrawProcessOneEvent(NULL);
9038 0 : GDrawSetVisible(gw,false);
9039 :
9040 0 : if( DATA.cancelled )
9041 0 : return 0;
9042 0 : return ret;
9043 : }
9044 :
9045 :
9046 :
9047 0 : static void CVRemoveUndoes(GWindow gw,struct gmenuitem *mi,GEvent *e)
9048 : {
9049 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
9050 : static int lastValue = 10;
9051 0 : int v = toint(getValueFromUser( cv,
9052 0 : _("Trimming Undo Information"),
9053 0 : _("How many most-recent Undos should be kept?"),
9054 0 : tostr(lastValue)));
9055 0 : lastValue = v;
9056 0 : UndoesFreeButRetainFirstN(&cv->b.layerheads[cv->b.drawmode]->undoes,v);
9057 0 : UndoesFreeButRetainFirstN(&cv->b.layerheads[cv->b.drawmode]->redoes,v);
9058 0 : }
9059 :
9060 :
9061 : /* We can only paste if there's something in the copy buffer */
9062 : /* we can only copy if there's something selected to copy */
9063 : /* figure out what things are possible from the edit menu before the user */
9064 : /* pulls it down */
9065 0 : static void cv_edlistcheck(CharView *cv, struct gmenuitem *mi) {
9066 : int anypoints, anyrefs, anyimages, anyanchor;
9067 :
9068 0 : CVAnySel(cv,&anypoints,&anyrefs,&anyimages,&anyanchor);
9069 :
9070 0 : for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
9071 0 : switch ( mi->mid ) {
9072 : case MID_Join:
9073 0 : mi->ti.disabled = cv->b.layerheads[cv->b.drawmode]->splines==NULL;
9074 0 : break;
9075 : case MID_Merge:
9076 0 : mi->ti.disabled = !anypoints;
9077 0 : break;
9078 : case MID_MergeToLine:
9079 0 : mi->ti.disabled = !anypoints;
9080 0 : break;
9081 : case MID_Clear: case MID_Cut: /*case MID_Copy:*/
9082 : /* If nothing is selected, copy copies everything */
9083 : /* In spiro mode copy will copy all contours with at least (spiro) one point selected */
9084 0 : mi->ti.disabled = !anypoints && !anyrefs && !anyimages && !anyanchor;
9085 0 : break;
9086 : case MID_CopyLBearing: case MID_CopyRBearing:
9087 0 : mi->ti.disabled = cv->b.drawmode!=dm_fore ||
9088 0 : (cv->b.layerheads[cv->b.drawmode]->splines==NULL && cv->b.layerheads[cv->b.drawmode]->refs==NULL);
9089 0 : break;
9090 : case MID_CopyFgToBg:
9091 0 : mi->ti.disabled = cv->b.sc->layers[ly_fore].splines==NULL;
9092 0 : break;
9093 : case MID_CopyGridFit:
9094 0 : mi->ti.disabled = cv->b.gridfit==NULL;
9095 0 : break;
9096 : case MID_Paste:
9097 0 : mi->ti.disabled = !CopyContainsSomething() &&
9098 : #ifndef _NO_LIBPNG
9099 0 : !GDrawSelectionHasType(cv->gw,sn_clipboard,"image/png") &&
9100 : #endif
9101 0 : !GDrawSelectionHasType(cv->gw,sn_clipboard,"image/svg+xml") &&
9102 0 : !GDrawSelectionHasType(cv->gw,sn_clipboard,"image/svg-xml") &&
9103 0 : !GDrawSelectionHasType(cv->gw,sn_clipboard,"image/svg") &&
9104 0 : !GDrawSelectionHasType(cv->gw,sn_clipboard,"image/bmp") &&
9105 0 : !GDrawSelectionHasType(cv->gw,sn_clipboard,"image/eps") &&
9106 0 : !GDrawSelectionHasType(cv->gw,sn_clipboard,"image/ps");
9107 0 : break;
9108 : case MID_Undo:
9109 0 : mi->ti.disabled = cv->b.layerheads[cv->b.drawmode]->undoes==NULL;
9110 0 : break;
9111 : case MID_Redo:
9112 0 : mi->ti.disabled = cv->b.layerheads[cv->b.drawmode]->redoes==NULL;
9113 0 : break;
9114 : case MID_RemoveUndoes:
9115 0 : mi->ti.disabled = cv->b.layerheads[cv->b.drawmode]->undoes==NULL && cv->b.layerheads[cv->b.drawmode]->redoes==NULL;
9116 0 : break;
9117 : case MID_CopyRef:
9118 0 : mi->ti.disabled = cv->b.drawmode!=dm_fore || cv->b.container!=NULL;
9119 0 : break;
9120 : case MID_CopyLookupData:
9121 0 : mi->ti.disabled = (cv->b.sc->possub==NULL && cv->b.sc->kerns==NULL && cv->b.sc->vkerns==NULL) ||
9122 0 : cv->b.container!=NULL;
9123 0 : break;
9124 : case MID_UnlinkRef:
9125 0 : mi->ti.disabled = cv->b.layerheads[cv->b.drawmode]->refs==NULL;
9126 0 : break;
9127 : }
9128 : }
9129 0 : }
9130 :
9131 0 : static void edlistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
9132 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
9133 0 : cv_edlistcheck(cv, mi);
9134 0 : }
9135 :
9136 0 : static void CVMenuAcceptableExtrema(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
9137 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
9138 : SplineSet *ss;
9139 : Spline *s, *first;
9140 :
9141 0 : for ( ss = cv->b.layerheads[cv->b.drawmode]->splines; ss!=NULL ; ss = ss->next ) {
9142 0 : first = NULL;
9143 0 : for ( s=ss->first->next; s!=NULL && s!=first; s = s->to->next ) {
9144 0 : if ( first == NULL )
9145 0 : first = s;
9146 0 : if ( s->from->selected && s->to->selected )
9147 0 : s->acceptableextrema = !s->acceptableextrema;
9148 : }
9149 : }
9150 0 : }
9151 :
9152 0 : static void _CVMenuPointType(CharView *cv, struct gmenuitem *mi) {
9153 0 : int pointtype = mi->mid==MID_Corner?pt_corner:mi->mid==MID_Tangent?pt_tangent:
9154 0 : mi->mid==MID_Curve?pt_curve:pt_hvcurve;
9155 : SplinePointList *spl;
9156 : Spline *spline, *first;
9157 :
9158 0 : CVPreserveState(&cv->b); /* We should only get here if there's a selection */
9159 0 : for ( spl = cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL ; spl = spl->next ) {
9160 0 : first = NULL;
9161 0 : if ( spl->first->selected ) {
9162 0 : if ( spl->first->pointtype!=pointtype )
9163 0 : SPChangePointType(spl->first,pointtype);
9164 : }
9165 0 : for ( spline=spl->first->next; spline!=NULL && spline!=first ; spline = spline->to->next ) {
9166 0 : if ( spline->to->selected ) {
9167 0 : if ( spline->to->pointtype!=pointtype )
9168 0 : SPChangePointType(spline->to,pointtype);
9169 : }
9170 0 : if ( first == NULL ) first = spline;
9171 : }
9172 : }
9173 0 : CVCharChangedUpdate(&cv->b);
9174 0 : }
9175 :
9176 0 : static void _CVMenuSpiroPointType(CharView *cv, struct gmenuitem *mi) {
9177 0 : int pointtype = mi->mid==MID_SpiroCorner?SPIRO_CORNER:
9178 0 : mi->mid==MID_SpiroG4?SPIRO_G4:
9179 0 : mi->mid==MID_SpiroG2?SPIRO_G2:
9180 0 : mi->mid==MID_SpiroLeft?SPIRO_LEFT:SPIRO_RIGHT;
9181 : SplinePointList *spl;
9182 : int i, changes;
9183 :
9184 0 : CVPreserveState(&cv->b); /* We should only get here if there's a selection */
9185 0 : for ( spl = cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL ; spl = spl->next ) {
9186 0 : changes = false;
9187 0 : for ( i=0; i<spl->spiro_cnt-1; ++i ) {
9188 0 : if ( SPIRO_SELECTED(&spl->spiros[i]) ) {
9189 0 : if ( (spl->spiros[i].ty&0x7f)!=SPIRO_OPEN_CONTOUR ) {
9190 0 : spl->spiros[i].ty = pointtype|0x80;
9191 0 : changes = true;
9192 : }
9193 : }
9194 : }
9195 0 : if ( changes )
9196 0 : SSRegenerateFromSpiros(spl);
9197 : }
9198 0 : CVCharChangedUpdate(&cv->b);
9199 0 : }
9200 :
9201 :
9202 0 : void CVMenuPointType(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
9203 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
9204 0 : if ( cv->b.sc->inspiro && hasspiro())
9205 0 : _CVMenuSpiroPointType(cv, mi);
9206 : else
9207 0 : _CVMenuPointType(cv, mi);
9208 0 : }
9209 :
9210 0 : static void _CVMenuImplicit(CharView *cv, struct gmenuitem *mi) {
9211 : SplinePointList *spl;
9212 : Spline *spline, *first;
9213 0 : int dontinterpolate = mi->mid==MID_NoImplicitPt;
9214 :
9215 0 : if ( !cv->b.layerheads[cv->b.drawmode]->order2 )
9216 0 : return;
9217 0 : CVPreserveState(&cv->b); /* We should only get here if there's a selection */
9218 0 : for ( spl = cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL ; spl = spl->next ) {
9219 0 : first = NULL;
9220 0 : if ( spl->first->selected ) {
9221 0 : spl->first->dontinterpolate = dontinterpolate;
9222 : }
9223 0 : for ( spline=spl->first->next; spline!=NULL && spline!=first ; spline = spline->to->next ) {
9224 0 : if ( spline->to->selected ) {
9225 0 : spline->to->dontinterpolate = dontinterpolate;
9226 : }
9227 0 : if ( first == NULL ) first = spline;
9228 : }
9229 : }
9230 0 : SCNumberPoints(cv->b.sc,CVLayer((CharViewBase *) cv));
9231 0 : CVCharChangedUpdate(&cv->b);
9232 : }
9233 :
9234 0 : static void CVMenuImplicit(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
9235 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
9236 0 : _CVMenuImplicit(cv, mi);
9237 0 : }
9238 :
9239 : static GMenuItem2 spiroptlist[], ptlist[];
9240 0 : static void cv_ptlistcheck(CharView *cv, struct gmenuitem *mi) {
9241 0 : int type = -2, cnt=0, ccp_cnt=0, spline_selected=0;
9242 0 : int spirotype = -2, opencnt=0, spirocnt=0;
9243 0 : SplinePointList *spl, *sel=NULL, *onlysel=NULL;
9244 : Spline *spline, *first;
9245 0 : SplinePoint *selpt=NULL;
9246 0 : int notimplicit = -1;
9247 0 : int acceptable = -1;
9248 : uint16 junk;
9249 : int i;
9250 :
9251 0 : if ( cv->showing_spiro_pt_menu != (cv->b.sc->inspiro && hasspiro())) {
9252 0 : GMenuItemArrayFree(mi->sub);
9253 0 : mi->sub = GMenuItem2ArrayCopy(cv->b.sc->inspiro && hasspiro()?spiroptlist:ptlist,&junk);
9254 0 : cv->showing_spiro_pt_menu = cv->b.sc->inspiro && hasspiro();
9255 : }
9256 0 : for ( spl = cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL; spl = spl->next ) {
9257 0 : first = NULL;
9258 0 : if ( spl->first->selected ) {
9259 0 : sel = spl;
9260 0 : if ( onlysel==NULL || onlysel==spl ) onlysel = spl; else onlysel = (SplineSet *) (-1);
9261 0 : selpt = spl->first; ++cnt;
9262 0 : if ( type==-2 ) type = spl->first->pointtype;
9263 0 : else if ( type!=spl->first->pointtype ) type = -1;
9264 0 : if ( !spl->first->nonextcp && !spl->first->noprevcp && spl->first->prev!=NULL )
9265 0 : ++ccp_cnt;
9266 0 : if ( notimplicit==-1 ) notimplicit = spl->first->dontinterpolate;
9267 0 : else if ( notimplicit!=spl->first->dontinterpolate ) notimplicit = -2;
9268 : }
9269 0 : for ( spline=spl->first->next; spline!=NULL && spline!=first; spline = spline->to->next ) {
9270 0 : if ( spline->to->selected ) {
9271 0 : if ( type==-2 ) type = spline->to->pointtype;
9272 0 : else if ( type!=spline->to->pointtype ) type = -1;
9273 0 : selpt = spline->to;
9274 0 : if ( onlysel==NULL || onlysel==spl ) onlysel = spl; else onlysel = (SplineSet *) (-1);
9275 0 : sel = spl; ++cnt;
9276 0 : if ( !spline->to->nonextcp && !spline->to->noprevcp && spline->to->next!=NULL )
9277 0 : ++ccp_cnt;
9278 0 : if ( notimplicit==-1 ) notimplicit = spline->to->dontinterpolate;
9279 0 : else if ( notimplicit!=spline->to->dontinterpolate ) notimplicit = -2;
9280 0 : if ( spline->from->selected )
9281 0 : ++spline_selected;
9282 : }
9283 0 : if ( spline->to->selected && spline->from->selected ) {
9284 0 : if ( acceptable==-1 )
9285 0 : acceptable = spline->acceptableextrema;
9286 0 : else if ( acceptable!=spline->acceptableextrema )
9287 0 : acceptable = -2;
9288 : }
9289 0 : if ( first == NULL ) first = spline;
9290 : }
9291 0 : for ( i=0; i<spl->spiro_cnt-1; ++i ) {
9292 0 : if ( SPIRO_SELECTED(&spl->spiros[i])) {
9293 0 : int ty = spl->spiros[i].ty&0x7f;
9294 0 : ++spirocnt;
9295 0 : if ( ty==SPIRO_OPEN_CONTOUR )
9296 0 : ++opencnt;
9297 0 : else if ( spirotype==-2 )
9298 0 : spirotype = ty;
9299 0 : else if ( spirotype!=ty )
9300 0 : spirotype = -1;
9301 0 : if ( onlysel==NULL || onlysel==spl ) onlysel = spl; else onlysel = (SplineSet *) (-1);
9302 : }
9303 : }
9304 : }
9305 :
9306 0 : for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
9307 0 : switch ( mi->mid ) {
9308 : case MID_Corner:
9309 0 : mi->ti.disabled = type==-2;
9310 0 : mi->ti.checked = type==pt_corner;
9311 0 : break;
9312 : case MID_Tangent:
9313 0 : mi->ti.disabled = type==-2;
9314 0 : mi->ti.checked = type==pt_tangent;
9315 0 : break;
9316 : case MID_Curve:
9317 0 : mi->ti.disabled = type==-2;
9318 0 : mi->ti.checked = type==pt_curve;
9319 0 : break;
9320 : case MID_HVCurve:
9321 0 : mi->ti.disabled = type==-2;
9322 0 : mi->ti.checked = type==pt_hvcurve;
9323 0 : break;
9324 : case MID_SpiroG4:
9325 0 : mi->ti.disabled = spirotype==-2;
9326 0 : mi->ti.checked = spirotype==SPIRO_G4;
9327 0 : break;
9328 : case MID_SpiroG2:
9329 0 : mi->ti.disabled = spirotype==-2;
9330 0 : mi->ti.checked = spirotype==SPIRO_G2;
9331 0 : break;
9332 : case MID_SpiroCorner:
9333 0 : mi->ti.disabled = spirotype==-2;
9334 0 : mi->ti.checked = spirotype==SPIRO_CORNER;
9335 0 : break;
9336 : case MID_SpiroLeft:
9337 0 : mi->ti.disabled = spirotype==-2;
9338 0 : mi->ti.checked = spirotype==SPIRO_LEFT;
9339 0 : break;
9340 : case MID_SpiroRight:
9341 0 : mi->ti.disabled = spirotype==-2;
9342 0 : mi->ti.checked = spirotype==SPIRO_RIGHT;
9343 0 : break;
9344 : case MID_MakeFirst:
9345 0 : mi->ti.disabled = cnt!=1 || sel->first->prev==NULL || sel->first==selpt;
9346 0 : break;
9347 : case MID_SpiroMakeFirst:
9348 0 : mi->ti.disabled = opencnt!=0 || spirocnt!=1;
9349 0 : break;
9350 : case MID_MakeLine: case MID_MakeArc:
9351 0 : mi->ti.disabled = cnt<2;
9352 0 : break;
9353 : case MID_AcceptableExtrema:
9354 0 : mi->ti.disabled = acceptable<0;
9355 0 : mi->ti.checked = acceptable==1;
9356 0 : break;
9357 : case MID_NamePoint:
9358 0 : mi->ti.disabled = onlysel==NULL || onlysel == (SplineSet *) -1;
9359 0 : break;
9360 : case MID_NameContour:
9361 0 : mi->ti.disabled = onlysel==NULL || onlysel == (SplineSet *) -1;
9362 0 : break;
9363 : case MID_ClipPath:
9364 0 : mi->ti.disabled = !cv->b.sc->parent->multilayer;
9365 0 : break;
9366 : case MID_InsertPtOnSplineAt:
9367 0 : mi->ti.disabled = spline_selected!=1;
9368 0 : break;
9369 : case MID_CenterCP:
9370 0 : mi->ti.disabled = ccp_cnt==0;
9371 0 : break;
9372 : case MID_ImplicitPt:
9373 0 : mi->ti.disabled = !cv->b.layerheads[cv->b.drawmode]->order2;
9374 0 : mi->ti.checked = notimplicit==0;
9375 0 : break;
9376 : case MID_NoImplicitPt:
9377 0 : mi->ti.disabled = !cv->b.layerheads[cv->b.drawmode]->order2;
9378 0 : mi->ti.checked = notimplicit==1;
9379 0 : break;
9380 : case MID_AddAnchor:
9381 0 : mi->ti.disabled = cv->b.container!=NULL;
9382 0 : break;
9383 : }
9384 : }
9385 0 : }
9386 :
9387 0 : static void ptlistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
9388 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
9389 0 : cv_ptlistcheck(cv, mi);
9390 0 : }
9391 :
9392 0 : static void _CVMenuDir(CharView *cv, struct gmenuitem *mi) {
9393 : int splinepoints, dir;
9394 : SplinePointList *spl;
9395 : Spline *spline, *first;
9396 0 : int needsrefresh = false;
9397 :
9398 0 : for ( spl = cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL; spl = spl->next ) {
9399 0 : first = NULL;
9400 0 : splinepoints = 0;
9401 0 : if ( cv->b.sc->inspiro && hasspiro()) {
9402 : int i;
9403 0 : for ( i=0; i<spl->spiro_cnt-1; ++i )
9404 0 : if ( SPIRO_SELECTED(&spl->spiros[i])) {
9405 0 : splinepoints = true;
9406 0 : break;
9407 : }
9408 : } else {
9409 0 : if ( spl->first->selected ) splinepoints = true;
9410 0 : for ( spline=spl->first->next; spline!=NULL && spline!=first && !splinepoints; spline = spline->to->next ) {
9411 0 : if ( spline->to->selected ) splinepoints = true;
9412 0 : if ( first == NULL ) first = spline;
9413 : }
9414 : }
9415 0 : if ( splinepoints && spl->first->prev!=NULL ) {
9416 0 : dir = SplinePointListIsClockwise(spl);
9417 0 : if ( (mi->mid==MID_Clockwise && dir==0) || (mi->mid==MID_Counter && dir==1)) {
9418 0 : if ( !needsrefresh )
9419 0 : CVPreserveState(&cv->b);
9420 0 : SplineSetReverse(spl);
9421 0 : needsrefresh = true;
9422 : }
9423 : }
9424 : }
9425 0 : if ( needsrefresh )
9426 0 : CVCharChangedUpdate(&cv->b);
9427 0 : }
9428 :
9429 0 : static void CVMenuDir(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
9430 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
9431 0 : _CVMenuDir(cv, mi);
9432 0 : }
9433 :
9434 0 : static void CVMenuCheckSelf(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
9435 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
9436 0 : CVShows.checkselfintersects = cv->checkselfintersects = !cv->checkselfintersects;
9437 0 : }
9438 :
9439 0 : static void CVMenuGlyphSelfIntersects(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
9440 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
9441 0 : Spline *s=NULL, *s2=NULL;
9442 : SplineSet *ss;
9443 : DBounds b;
9444 : double off;
9445 :
9446 0 : ss = LayerAllSplines(cv->b.layerheads[cv->b.drawmode]);
9447 0 : SplineSetIntersect(ss,&s,&s2);
9448 0 : LayerUnAllSplines(cv->b.layerheads[cv->b.drawmode]);
9449 :
9450 0 : if ( s!=NULL || s2!=NULL ) {
9451 0 : memset(&b,0,sizeof(b));
9452 0 : CVClearSel(cv);
9453 0 : if ( s!=NULL ) {
9454 0 : b.minx = b.maxx = s->from->me.x;
9455 0 : b.miny = b.maxy = s->from->me.y;
9456 0 : } else if ( s2!=NULL ) {
9457 0 : b.minx = b.maxx = s2->from->me.x;
9458 0 : b.miny = b.maxy = s2->from->me.y;
9459 : }
9460 0 : if ( s!=NULL ) {
9461 0 : s->from->selected = s->to->selected = true;
9462 0 : if ( s->to->me.x>b.maxx ) b.maxx = s->to->me.x;
9463 0 : if ( s->to->me.x<b.minx ) b.minx = s->to->me.x;
9464 0 : if ( s->to->me.y>b.maxy ) b.maxy = s->to->me.y;
9465 0 : if ( s->to->me.y<b.miny ) b.miny = s->to->me.y;
9466 : }
9467 0 : if ( s2!=NULL ) {
9468 0 : s2->from->selected = s2->to->selected = true;
9469 0 : if ( s2->from->me.x>b.maxx ) b.maxx = s2->from->me.x;
9470 0 : if ( s2->from->me.x<b.minx ) b.minx = s2->from->me.x;
9471 0 : if ( s2->from->me.y>b.maxy ) b.maxy = s2->from->me.y;
9472 0 : if ( s2->from->me.y<b.miny ) b.miny = s2->from->me.y;
9473 0 : if ( s2->to->me.x>b.maxx ) b.maxx = s2->to->me.x;
9474 0 : if ( s2->to->me.x<b.minx ) b.minx = s2->to->me.x;
9475 0 : if ( s2->to->me.y>b.maxy ) b.maxy = s2->to->me.y;
9476 0 : if ( s2->to->me.y<b.miny ) b.miny = s2->to->me.y;
9477 : }
9478 0 : off = (b.maxx-b.minx)/10;
9479 0 : if ( off==0 ) off = 1;
9480 0 : b.minx -= off; b.maxx += off;
9481 0 : off = (b.maxy-b.miny)/10;
9482 0 : if ( off==0 ) off = 1;
9483 0 : b.miny -= off; b.maxy += off;
9484 0 : _CVFit(cv,&b,false);
9485 : } else
9486 0 : ff_post_notice(_("No Intersections"),_("No Intersections"));
9487 0 : }
9488 :
9489 0 : static int getorigin(void *d,BasePoint *base,int index) {
9490 0 : CharView *cv = (CharView *) d;
9491 :
9492 0 : base->x = base->y = 0;
9493 0 : switch ( index ) {
9494 : case 0: /* Character origin */
9495 : /* all done */
9496 0 : break;
9497 : case 1: /* Center of selection */
9498 0 : CVFindCenter(cv,base,!CVAnySel(cv,NULL,NULL,NULL,NULL));
9499 0 : break;
9500 : case 2: /* last press */
9501 0 : base->x = cv->p.cx;
9502 0 : base->y = cv->p.cy;
9503 : /* I don't have any way of telling if a press has happened. if one */
9504 : /* hasn't they'll just get a 0,0 origin. oh well */
9505 0 : break;
9506 : default:
9507 0 : return( false );
9508 : }
9509 0 : return( true );
9510 : }
9511 :
9512 0 : static void TransRef(RefChar *ref,real transform[6], enum fvtrans_flags flags) {
9513 : int j;
9514 : real t[6];
9515 :
9516 0 : for ( j=0; j<ref->layer_cnt; ++j )
9517 0 : SplinePointListTransform(ref->layers[j].splines,transform,tpt_AllPoints);
9518 0 : t[0] = ref->transform[0]*transform[0] +
9519 0 : ref->transform[1]*transform[2];
9520 0 : t[1] = ref->transform[0]*transform[1] +
9521 0 : ref->transform[1]*transform[3];
9522 0 : t[2] = ref->transform[2]*transform[0] +
9523 0 : ref->transform[3]*transform[2];
9524 0 : t[3] = ref->transform[2]*transform[1] +
9525 0 : ref->transform[3]*transform[3];
9526 0 : t[4] = ref->transform[4]*transform[0] +
9527 0 : ref->transform[5]*transform[2] +
9528 0 : transform[4];
9529 0 : t[5] = ref->transform[4]*transform[1] +
9530 0 : ref->transform[5]*transform[3] +
9531 0 : transform[5];
9532 0 : if ( flags&fvt_round_to_int ) {
9533 0 : t[4] = rint( t[4] );
9534 0 : t[5] = rint( t[5] );
9535 : }
9536 0 : memcpy(ref->transform,t,sizeof(t));
9537 0 : RefCharFindBounds(ref);
9538 0 : }
9539 :
9540 0 : void CVTransFuncLayer(CharView *cv,Layer *ly,real transform[6], enum fvtrans_flags flags)
9541 : {
9542 0 : int anysel = cv->p.transany;
9543 : RefChar *refs;
9544 : ImageList *img;
9545 : AnchorPoint *ap;
9546 : KernPair *kp;
9547 : PST *pst;
9548 : int l, cvlayer;
9549 0 : enum transformPointMask tpmask = 0;
9550 :
9551 0 : if ( cv->b.sc->inspiro && hasspiro() )
9552 0 : SplinePointListSpiroTransform(ly->splines,transform,!anysel);
9553 : else
9554 : {
9555 0 : if( cv->active_tool==cvt_scale )
9556 0 : tpmask |= tpmask_operateOnSelectedBCP;
9557 :
9558 0 : SplinePointListTransformExtended(
9559 : ly->splines, transform,
9560 0 : !anysel?tpt_AllPoints: interpCPsOnMotion?tpt_OnlySelectedInterpCPs:tpt_OnlySelected,
9561 : tpmask );
9562 : }
9563 :
9564 0 : if ( flags&fvt_round_to_int )
9565 0 : SplineSetsRound2Int(ly->splines,1.0,cv->b.sc->inspiro && hasspiro(),!anysel);
9566 0 : if ( ly->images!=NULL ) {
9567 0 : ImageListTransform(ly->images,transform,!anysel);
9568 0 : SCOutOfDateBackground(cv->b.sc);
9569 : }
9570 0 : for ( refs = ly->refs; refs!=NULL; refs=refs->next )
9571 0 : if ( refs->selected || !anysel )
9572 0 : TransRef(refs,transform,flags);
9573 0 : if ( cv->showanchor ) {
9574 0 : for ( ap=cv->b.sc->anchor; ap!=NULL; ap=ap->next ) if ( ap->selected || !anysel )
9575 0 : ApTransform(ap,transform);
9576 : }
9577 0 : if ( !anysel ) {
9578 0 : if ( flags & fvt_scalepstpos ) {
9579 0 : for ( kp=cv->b.sc->kerns; kp!=NULL; kp=kp->next )
9580 0 : kp->off = rint(kp->off*transform[0]);
9581 0 : for ( kp=cv->b.sc->vkerns; kp!=NULL; kp=kp->next )
9582 0 : kp->off = rint(kp->off*transform[3]);
9583 0 : for ( pst = cv->b.sc->possub; pst!=NULL; pst=pst->next ) {
9584 0 : if ( pst->type == pst_position )
9585 0 : VrTrans(&pst->u.pos,transform);
9586 0 : else if ( pst->type==pst_pair ) {
9587 0 : VrTrans(&pst->u.pair.vr[0],transform);
9588 0 : VrTrans(&pst->u.pair.vr[1],transform);
9589 : }
9590 : }
9591 : }
9592 0 : if ( transform[1]==0 && transform[2]==0 ) {
9593 0 : TransHints(cv->b.sc->hstem,transform[3],transform[5],transform[0],transform[4],flags&fvt_round_to_int);
9594 0 : TransHints(cv->b.sc->vstem,transform[0],transform[4],transform[3],transform[5],flags&fvt_round_to_int);
9595 0 : TransDStemHints(cv->b.sc->dstem,transform[0],transform[4],transform[3],transform[5],flags&fvt_round_to_int);
9596 : }
9597 0 : if ( transform[0]==1 && transform[3]==1 && transform[1]==0 &&
9598 0 : transform[2]==0 && transform[5]==0 &&
9599 0 : transform[4]!=0 && CVAllSelected(cv) &&
9600 0 : cv->b.sc->unicodeenc!=-1 && isalpha(cv->b.sc->unicodeenc)) {
9601 0 : SCUndoSetLBearingChange(cv->b.sc,(int) rint(transform[4]));
9602 0 : SCSynchronizeLBearing(cv->b.sc,transform[4],CVLayer((CharViewBase *) cv));
9603 : }
9604 : }
9605 0 : if ( !(flags&fvt_dontmovewidth) && (cv->widthsel || !anysel))
9606 0 : if ( transform[0]>0 && transform[3]>0 && transform[1]==0 &&
9607 0 : transform[2]==0 && transform[4]!=0 )
9608 0 : SCSynchronizeWidth(cv->b.sc,cv->b.sc->width*transform[0]+transform[4],cv->b.sc->width,NULL);
9609 0 : if ( !(flags&fvt_dontmovewidth) && (cv->vwidthsel || !anysel))
9610 0 : if ( transform[0]==1 && transform[3]==1 && transform[1]==0 &&
9611 0 : transform[2]==0 && transform[5]!=0 )
9612 0 : cv->b.sc->vwidth+=transform[5];
9613 0 : if ( (flags&fvt_alllayers) && !anysel ) {
9614 : /* SCPreserveBackground(cv->b.sc); */ /* done by caller */
9615 0 : cvlayer = CVLayer( (CharViewBase *) cv );
9616 0 : for ( l=0; l<cv->b.sc->layer_cnt; ++l ) if ( l!=cvlayer ) {
9617 0 : for ( img = cv->b.sc->layers[l].images; img!=NULL; img=img->next )
9618 0 : BackgroundImageTransform(cv->b.sc, img, transform);
9619 0 : SplinePointListTransform(cv->b.sc->layers[l].splines,
9620 : transform,tpt_AllPoints);
9621 0 : for ( refs=cv->b.sc->layers[l].refs; refs!=NULL; refs=refs->next )
9622 0 : TransRef(refs,transform,flags);
9623 : }
9624 : }
9625 0 : }
9626 :
9627 0 : void CVTransFunc(CharView *cv,real transform[6], enum fvtrans_flags flags)
9628 : {
9629 0 : Layer *ly = cv->b.layerheads[cv->b.drawmode];
9630 0 : CVTransFuncLayer( cv, ly, transform, flags );
9631 0 : }
9632 :
9633 0 : void CVTransFuncAllLayers(CharView *cv,real transform[6], enum fvtrans_flags flags)
9634 : {
9635 : int idx;
9636 0 : for( idx = 0; idx < cv->b.sc->layer_cnt; ++idx )
9637 : {
9638 0 : Layer *ly = &cv->b.sc->layers[ idx ];
9639 0 : CVTransFuncLayer( cv, ly, transform, flags );
9640 : }
9641 0 : }
9642 :
9643 0 : static void transfunc(void *d,real transform[6],int otype,BVTFunc *bvts,
9644 : enum fvtrans_flags flags) {
9645 0 : CharView *cv = (CharView *) d;
9646 0 : int anya, l, cvlayer = CVLayer((CharViewBase *) cv);
9647 :
9648 0 : if ( cv->b.layerheads[cv->b.drawmode]->undoes!=NULL &&
9649 0 : cv->b.layerheads[cv->b.drawmode]->undoes->undotype==ut_tstate )
9650 : {
9651 0 : CVDoUndo(&cv->b);
9652 : }
9653 :
9654 0 : if ( flags&fvt_revert )
9655 0 : return;
9656 :
9657 0 : cv->p.transany = CVAnySel(cv,NULL,NULL,NULL,&anya);
9658 0 : if ( flags&fvt_justapply )
9659 0 : CVPreserveTState(cv);
9660 : else {
9661 0 : CVPreserveStateHints(&cv->b);
9662 0 : if ( flags&fvt_alllayers )
9663 0 : for ( l=0; l<cv->b.sc->layer_cnt; ++l ) if ( l!=cvlayer )
9664 0 : SCPreserveLayer(cv->b.sc,l,false);
9665 : }
9666 :
9667 0 : CVPreserveMaybeState( cv, flags&fvt_justapply );
9668 0 : CVTransFunc(cv,transform,flags);
9669 0 : CVCharChangedUpdate(&cv->b);
9670 0 : collabclient_sendRedo( &cv->b );
9671 : }
9672 :
9673 0 : void CVDoTransform(CharView *cv, enum cvtools cvt ) {
9674 0 : int anysel = CVAnySel(cv,NULL,NULL,NULL,NULL);
9675 0 : TransformDlgCreate(cv,transfunc,getorigin,!anysel?(tdf_enableback|tdf_addapply):tdf_addapply,
9676 : cvt);
9677 0 : }
9678 :
9679 0 : static void CVMenuTransform(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
9680 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
9681 0 : CVDoTransform(cv,cvt_none);
9682 0 : }
9683 :
9684 0 : static void CVMenuPOV(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
9685 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
9686 : struct pov_data pov_data;
9687 0 : if ( PointOfViewDlg(&pov_data,cv->b.sc->parent,true)==-1 )
9688 0 : return;
9689 0 : CVPointOfView(cv,&pov_data);
9690 : }
9691 :
9692 0 : static void CVMenuNLTransform(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
9693 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
9694 0 : cv->lastselpt = NULL; cv->lastselcp = NULL;
9695 0 : NonLinearDlg(NULL,cv);
9696 0 : }
9697 :
9698 0 : void CVMenuConstrain(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
9699 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
9700 0 : CVConstrainSelection( cv,
9701 0 : mi->mid==MID_Average ? constrainSelection_AveragePoints :
9702 0 : mi->mid==MID_SpacePts ? constrainSelection_SpacePoints :
9703 : constrainSelection_SpaceSelectedRegions );
9704 0 : }
9705 :
9706 0 : static void CVMenuMakeParallel(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
9707 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
9708 0 : CVMakeParallel(cv);
9709 0 : }
9710 :
9711 0 : static void _CVMenuRound2Int(CharView *cv, double factor) {
9712 0 : int anysel = CVAnySel(cv,NULL,NULL,NULL,NULL);
9713 : RefChar *r;
9714 : AnchorPoint *ap;
9715 :
9716 0 : CVPreserveState(&cv->b);
9717 0 : SplineSetsRound2Int(cv->b.layerheads[cv->b.drawmode]->splines,factor,
9718 0 : cv->b.sc->inspiro && hasspiro(), anysel);
9719 0 : for ( r=cv->b.layerheads[cv->b.drawmode]->refs; r!=NULL; r=r->next ) {
9720 0 : if ( r->selected || !anysel ) {
9721 0 : r->transform[4] = rint(r->transform[4]*factor)/factor;
9722 0 : r->transform[5] = rint(r->transform[5]*factor)/factor;
9723 : }
9724 : }
9725 0 : if ( cv->b.drawmode==dm_fore ) {
9726 0 : for ( ap=cv->b.sc->anchor; ap!=NULL; ap=ap->next ) {
9727 0 : if ( ap->selected || !anysel ) {
9728 0 : ap->me.x = rint(ap->me.x*factor)/factor;
9729 0 : ap->me.y = rint(ap->me.y*factor)/factor;
9730 : }
9731 : }
9732 : }
9733 0 : CVCharChangedUpdate(&cv->b);
9734 0 : }
9735 :
9736 0 : static void CVMenuRound2Int(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
9737 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
9738 0 : _CVMenuRound2Int(cv,1.0);
9739 0 : }
9740 :
9741 0 : static void CVMenuRound2Hundredths(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
9742 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
9743 0 : _CVMenuRound2Int(cv,100.0);
9744 0 : }
9745 :
9746 0 : static void CVMenuCluster(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
9747 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
9748 0 : int layer = cv->b.drawmode == dm_grid ? ly_grid :
9749 0 : cv->b.drawmode == dm_back ? ly_back
9750 0 : : cv->b.layerheads[dm_fore] - cv->b.sc->layers;
9751 0 : SCRoundToCluster(cv->b.sc,layer,true,.1,.5);
9752 0 : }
9753 :
9754 0 : static void CVMenuStroke(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
9755 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
9756 0 : CVStroke(cv);
9757 0 : }
9758 :
9759 : #ifdef FONTFORGE_CONFIG_TILEPATH
9760 : static void CVMenuTilePath(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
9761 : CharView *cv = (CharView *) GDrawGetUserData(gw);
9762 : CVTile(cv);
9763 : }
9764 :
9765 : static void CVMenuPatternTile(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
9766 : CharView *cv = (CharView *) GDrawGetUserData(gw);
9767 : CVPatternTile(cv);
9768 : }
9769 : #endif
9770 :
9771 0 : static void _CVMenuOverlap(CharView *cv,enum overlap_type ot) {
9772 : /* We know it's more likely that we'll find a problem in the overlap code */
9773 : /* than anywhere else, so let's save the current state against a crash */
9774 0 : int layer = cv->b.drawmode == dm_grid ? ly_grid :
9775 0 : cv->b.drawmode == dm_back ? ly_back
9776 0 : : cv->b.layerheads[dm_fore] - cv->b.sc->layers;
9777 :
9778 0 : DoAutoSaves();
9779 : #if 0
9780 : // We await testing on the necessity of this operation.
9781 : if ( !SCRoundToCluster(cv->b.sc,layer,false,.03,.12))
9782 : CVPreserveState(&cv->b); /* SCRound2Cluster does this when it makes a change, not otherwise */
9783 : #else
9784 0 : CVPreserveState(&cv->b);
9785 : #endif // 0
9786 0 : if ( cv->b.drawmode==dm_fore ) {
9787 0 : MinimumDistancesFree(cv->b.sc->md);
9788 0 : cv->b.sc->md = NULL;
9789 : }
9790 0 : cv->b.layerheads[cv->b.drawmode]->splines = SplineSetRemoveOverlap(cv->b.sc,cv->b.layerheads[cv->b.drawmode]->splines,ot);
9791 0 : CVCharChangedUpdate(&cv->b);
9792 0 : }
9793 :
9794 0 : static void CVMenuOverlap(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
9795 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
9796 : int anysel;
9797 :
9798 0 : (void) CVAnySel(cv,&anysel,NULL,NULL,NULL);
9799 0 : _CVMenuOverlap(cv,mi->mid==MID_RmOverlap ? (anysel ? over_rmselected: over_remove) :
9800 0 : mi->mid==MID_Intersection ? (anysel ? over_intersel : over_intersect ) :
9801 0 : mi->mid==MID_Exclude ? over_exclude :
9802 0 : (anysel ? over_fisel : over_findinter));
9803 0 : }
9804 :
9805 0 : static void CVMenuOrder(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
9806 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
9807 : SplinePointList *spl;
9808 : RefChar *r;
9809 : ImageList *im;
9810 0 : int exactlyone = CVOneContourSel(cv,&spl,&r,&im);
9811 :
9812 0 : if ( !exactlyone )
9813 0 : return;
9814 :
9815 0 : CVPreserveState(&cv->b);
9816 0 : if ( spl!=NULL ) {
9817 : SplinePointList *p, *pp, *t;
9818 0 : p = pp = NULL;
9819 0 : for ( t=cv->b.layerheads[cv->b.drawmode]->splines; t!=NULL && t!=spl; t=t->next ) {
9820 0 : pp = p; p = t;
9821 : }
9822 0 : switch ( mi->mid ) {
9823 : case MID_First:
9824 0 : if ( p!=NULL ) {
9825 0 : p->next = spl->next;
9826 0 : spl->next = cv->b.layerheads[cv->b.drawmode]->splines;
9827 0 : cv->b.layerheads[cv->b.drawmode]->splines = spl;
9828 : }
9829 0 : break;
9830 : case MID_Earlier:
9831 0 : if ( p!=NULL ) {
9832 0 : p->next = spl->next;
9833 0 : spl->next = p;
9834 0 : if ( pp==NULL ) {
9835 0 : cv->b.layerheads[cv->b.drawmode]->splines = spl;
9836 : } else {
9837 0 : pp->next = spl;
9838 : }
9839 : }
9840 0 : break;
9841 : case MID_Last:
9842 0 : if ( spl->next!=NULL ) {
9843 0 : for ( t=cv->b.layerheads[cv->b.drawmode]->splines; t->next!=NULL; t=t->next );
9844 0 : t->next = spl;
9845 0 : if ( p==NULL )
9846 0 : cv->b.layerheads[cv->b.drawmode]->splines = spl->next;
9847 : else
9848 0 : p->next = spl->next;
9849 0 : spl->next = NULL;
9850 : }
9851 0 : break;
9852 : case MID_Later:
9853 0 : if ( spl->next!=NULL ) {
9854 0 : t = spl->next;
9855 0 : spl->next = t->next;
9856 0 : t->next = spl;
9857 0 : if ( p==NULL )
9858 0 : cv->b.layerheads[cv->b.drawmode]->splines = t;
9859 : else
9860 0 : p->next = t;
9861 : }
9862 0 : break;
9863 : }
9864 0 : } else if ( r!=NULL ) {
9865 : RefChar *p, *pp, *t;
9866 0 : p = pp = NULL;
9867 0 : for ( t=cv->b.layerheads[cv->b.drawmode]->refs; t!=NULL && t!=r; t=t->next ) {
9868 0 : pp = p; p = t;
9869 : }
9870 0 : switch ( mi->mid ) {
9871 : case MID_First:
9872 0 : if ( p!=NULL ) {
9873 0 : p->next = r->next;
9874 0 : r->next = cv->b.layerheads[cv->b.drawmode]->refs;
9875 0 : cv->b.layerheads[cv->b.drawmode]->refs = r;
9876 : }
9877 0 : break;
9878 : case MID_Earlier:
9879 0 : if ( p!=NULL ) {
9880 0 : p->next = r->next;
9881 0 : r->next = p;
9882 0 : if ( pp==NULL ) {
9883 0 : cv->b.layerheads[cv->b.drawmode]->refs = r;
9884 : } else {
9885 0 : pp->next = r;
9886 : }
9887 : }
9888 0 : break;
9889 : case MID_Last:
9890 0 : if ( r->next!=NULL ) {
9891 0 : for ( t=cv->b.layerheads[cv->b.drawmode]->refs; t->next!=NULL; t=t->next );
9892 0 : t->next = r;
9893 0 : if ( p==NULL )
9894 0 : cv->b.layerheads[cv->b.drawmode]->refs = r->next;
9895 : else
9896 0 : p->next = r->next;
9897 0 : r->next = NULL;
9898 : }
9899 0 : break;
9900 : case MID_Later:
9901 0 : if ( r->next!=NULL ) {
9902 0 : t = r->next;
9903 0 : r->next = t->next;
9904 0 : t->next = r;
9905 0 : if ( p==NULL )
9906 0 : cv->b.layerheads[cv->b.drawmode]->refs = t;
9907 : else
9908 0 : p->next = t;
9909 : }
9910 0 : break;
9911 : }
9912 0 : } else if ( im!=NULL ) {
9913 : ImageList *p, *pp, *t;
9914 0 : p = pp = NULL;
9915 0 : for ( t=cv->b.layerheads[cv->b.drawmode]->images; t!=NULL && t!=im; t=t->next ) {
9916 0 : pp = p; p = t;
9917 : }
9918 0 : switch ( mi->mid ) {
9919 : case MID_First:
9920 0 : if ( p!=NULL ) {
9921 0 : p->next = im->next;
9922 0 : im->next = cv->b.layerheads[cv->b.drawmode]->images;
9923 0 : cv->b.layerheads[cv->b.drawmode]->images = im;
9924 : }
9925 0 : break;
9926 : case MID_Earlier:
9927 0 : if ( p!=NULL ) {
9928 0 : p->next = im->next;
9929 0 : im->next = p;
9930 0 : if ( pp==NULL ) {
9931 0 : cv->b.layerheads[cv->b.drawmode]->images = im;
9932 : } else {
9933 0 : pp->next = im;
9934 : }
9935 : }
9936 0 : break;
9937 : case MID_Last:
9938 0 : if ( im->next!=NULL ) {
9939 0 : for ( t=cv->b.layerheads[cv->b.drawmode]->images; t->next!=NULL; t=t->next );
9940 0 : t->next = im;
9941 0 : if ( p==NULL )
9942 0 : cv->b.layerheads[cv->b.drawmode]->images = im->next;
9943 : else
9944 0 : p->next = im->next;
9945 0 : im->next = NULL;
9946 : }
9947 0 : break;
9948 : case MID_Later:
9949 0 : if ( im->next!=NULL ) {
9950 0 : t = im->next;
9951 0 : im->next = t->next;
9952 0 : t->next = im;
9953 0 : if ( p==NULL )
9954 0 : cv->b.layerheads[cv->b.drawmode]->images = t;
9955 : else
9956 0 : p->next = t;
9957 : }
9958 0 : break;
9959 : }
9960 : }
9961 0 : CVCharChangedUpdate(&cv->b);
9962 : }
9963 :
9964 0 : static void _CVMenuAddExtrema(CharView *cv) {
9965 : int anysel;
9966 0 : SplineFont *sf = cv->b.sc->parent;
9967 :
9968 0 : (void) CVAnySel(cv,&anysel,NULL,NULL,NULL);
9969 0 : CVPreserveState(&cv->b);
9970 0 : SplineCharAddExtrema(cv->b.sc,cv->b.layerheads[cv->b.drawmode]->splines,
9971 0 : anysel?ae_between_selected:ae_only_good,sf->ascent+sf->descent);
9972 0 : CVCharChangedUpdate(&cv->b);
9973 0 : }
9974 :
9975 0 : static void CVMenuAddExtrema(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
9976 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
9977 0 : _CVMenuAddExtrema(cv);
9978 0 : }
9979 :
9980 0 : static void CVSimplify(CharView *cv,int type) {
9981 : static struct simplifyinfo smpls[] = {
9982 : { sf_normal, 0, 0, 0, 0, 0, 0 },
9983 : { sf_normal,.75,.05,0,-1, 0, 0 },
9984 : { sf_normal,.75,.05,0,-1, 0, 0 }};
9985 0 : struct simplifyinfo *smpl = &smpls[type+1];
9986 :
9987 0 : if ( smpl->linelenmax==-1 || (type==0 && !smpl->set_as_default)) {
9988 0 : smpl->err = (cv->b.sc->parent->ascent+cv->b.sc->parent->descent)/1000.;
9989 0 : smpl->linelenmax = (cv->b.sc->parent->ascent+cv->b.sc->parent->descent)/100.;
9990 : }
9991 :
9992 0 : if ( type==1 ) {
9993 0 : if ( !SimplifyDlg(cv->b.sc->parent,smpl))
9994 0 : return;
9995 0 : if ( smpl->set_as_default )
9996 0 : smpls[1] = *smpl;
9997 : }
9998 :
9999 0 : CVPreserveState(&cv->b);
10000 0 : smpl->check_selected_contours = true;
10001 0 : cv->b.layerheads[cv->b.drawmode]->splines = SplineCharSimplify(cv->b.sc,cv->b.layerheads[cv->b.drawmode]->splines,
10002 : smpl);
10003 0 : CVCharChangedUpdate(&cv->b);
10004 : }
10005 :
10006 0 : static void CVMenuSimplify(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
10007 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
10008 0 : CVSimplify(cv,0);
10009 0 : }
10010 :
10011 0 : static void CVMenuSimplifyMore(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
10012 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
10013 0 : CVSimplify(cv,1);
10014 0 : }
10015 :
10016 0 : static void CVMenuCleanupGlyph(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
10017 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
10018 0 : CVSimplify(cv,-1);
10019 0 : }
10020 :
10021 0 : static int SPLSelected(SplineSet *ss) {
10022 : SplinePoint *sp;
10023 :
10024 0 : for ( sp=ss->first ;; ) {
10025 0 : if ( sp->selected )
10026 0 : return( true );
10027 0 : if ( sp->next==NULL )
10028 0 : return( false );
10029 0 : sp = sp->next->to;
10030 0 : if ( sp==ss->first )
10031 0 : return( false );
10032 0 : }
10033 : }
10034 :
10035 0 : static void CVCanonicalStart(CharView *cv) {
10036 : SplineSet *ss;
10037 0 : int changed = 0;
10038 :
10039 0 : for ( ss = cv->b.layerheads[cv->b.drawmode]->splines; ss!=NULL; ss=ss->next )
10040 0 : if ( ss->first==ss->last && SPLSelected(ss)) {
10041 0 : SPLStartToLeftmost(cv->b.sc,ss,&changed);
10042 : /* The above clears the spiros if needed */
10043 : }
10044 0 : }
10045 :
10046 0 : static void CVMenuCanonicalStart(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
10047 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
10048 0 : CVCanonicalStart(cv);
10049 0 : }
10050 :
10051 0 : static void CVCanonicalContour(CharView *cv) {
10052 0 : CanonicalContours(cv->b.sc,CVLayer((CharViewBase *) cv));
10053 0 : }
10054 :
10055 0 : static void CVMenuCanonicalContours(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
10056 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
10057 0 : CVCanonicalContour(cv);
10058 0 : }
10059 :
10060 0 : static void _CVMenuMakeFirst(CharView *cv) {
10061 0 : SplinePoint *selpt = NULL;
10062 0 : int anypoints = 0, splinepoints;
10063 : SplinePointList *spl, *sel;
10064 : Spline *spline, *first;
10065 :
10066 0 : sel = NULL;
10067 0 : for ( spl = cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL; spl = spl->next ) {
10068 0 : first = NULL;
10069 0 : splinepoints = 0;
10070 0 : if ( spl->first->selected ) { splinepoints = 1; sel = spl; selpt=spl->first; }
10071 0 : for ( spline=spl->first->next; spline!=NULL && spline!=first && !splinepoints; spline = spline->to->next ) {
10072 0 : if ( spline->to->selected ) { ++splinepoints; sel = spl; selpt=spline->to; }
10073 0 : if ( first == NULL ) first = spline;
10074 : }
10075 0 : anypoints += splinepoints;
10076 : }
10077 :
10078 0 : if ( anypoints!=1 || sel->first->prev==NULL || sel->first==selpt )
10079 0 : return;
10080 :
10081 0 : CVPreserveState(&cv->b);
10082 0 : sel->first = sel->last = selpt;
10083 0 : CVCharChangedUpdate(&cv->b);
10084 : }
10085 :
10086 0 : static void CVMenuMakeFirst(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
10087 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
10088 0 : _CVMenuMakeFirst(cv);
10089 0 : }
10090 :
10091 0 : static void _CVMenuSpiroMakeFirst(CharView *cv) {
10092 0 : int anypoints = 0, which;
10093 : SplinePointList *spl, *sel;
10094 : int i;
10095 : spiro_cp *newspiros;
10096 :
10097 0 : sel = NULL;
10098 0 : for ( spl = cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL; spl = spl->next ) {
10099 0 : for ( i=0; i<spl->spiro_cnt-1; ++i ) {
10100 0 : if ( SPIRO_SELECTED(&spl->spiros[i])) {
10101 0 : if ( SPIRO_SPL_OPEN(spl))
10102 0 : return;
10103 0 : ++anypoints;
10104 0 : sel = spl;
10105 0 : which = i;
10106 : }
10107 : }
10108 : }
10109 :
10110 0 : if ( anypoints!=1 || sel==NULL )
10111 0 : return;
10112 :
10113 0 : CVPreserveState(&cv->b);
10114 0 : newspiros = malloc((sel->spiro_max+1)*sizeof(spiro_cp));
10115 0 : memcpy(newspiros,sel->spiros+which,(sel->spiro_cnt-1-which)*sizeof(spiro_cp));
10116 0 : memcpy(newspiros+(sel->spiro_cnt-1-which),sel->spiros,which*sizeof(spiro_cp));
10117 0 : memcpy(newspiros+sel->spiro_cnt-1,sel->spiros+sel->spiro_cnt-1,sizeof(spiro_cp));
10118 0 : free(sel->spiros);
10119 0 : sel->spiros = newspiros;
10120 0 : SSRegenerateFromSpiros(sel);
10121 0 : CVCharChangedUpdate(&cv->b);
10122 : }
10123 :
10124 0 : static void CVMenuSpiroMakeFirst(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
10125 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
10126 0 : _CVMenuSpiroMakeFirst(cv);
10127 0 : }
10128 :
10129 0 : static void CVMenuMakeLine(GWindow gw, struct gmenuitem *mi, GEvent *e) {
10130 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
10131 0 : _CVMenuMakeLine((CharViewBase *) cv,mi->mid==MID_MakeArc, e!=NULL && (e->u.mouse.state&ksm_meta));
10132 0 : }
10133 :
10134 0 : void _CVMenuNamePoint(CharView *cv, SplinePoint *sp) {
10135 : char *ret, *name, *oldname;
10136 :
10137 0 : oldname = (sp->name && *sp->name) ? sp->name : NULL;
10138 0 : ret = gwwv_ask_string(_("Name this point"), oldname,
10139 0 : _("Please name this point"));
10140 0 : if ( ret!=NULL ) {
10141 0 : name = *ret ? ret : NULL;
10142 0 : if (name != oldname || (name && oldname && strcmp(name,oldname))) {
10143 0 : sp->name = name;
10144 0 : CVCharChangedUpdate(&cv->b);
10145 : }
10146 0 : if (name != ret) { free(ret); ret = NULL; }
10147 0 : if (name != oldname) { free(oldname); oldname = NULL; }
10148 : }
10149 0 : }
10150 :
10151 0 : static void CVMenuNamePoint(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
10152 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
10153 : SplinePointList *spl;
10154 : SplinePoint *sp;
10155 : RefChar *r;
10156 : ImageList *il;
10157 : spiro_cp *junk;
10158 :
10159 0 : if ( CVOneThingSel( cv, &sp, &spl, &r, &il, NULL, &junk ) && sp) {
10160 0 : _CVMenuNamePoint(cv, sp);
10161 : }
10162 0 : }
10163 :
10164 0 : void _CVMenuNameContour(CharView *cv) {
10165 0 : SplinePointList *spl, *onlysel = NULL;
10166 : SplinePoint *sp;
10167 : char *ret;
10168 : int i;
10169 :
10170 0 : for ( spl = cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL; spl = spl->next ) {
10171 0 : if ( !cv->b.sc->inspiro || !hasspiro()) {
10172 0 : for ( sp=spl->first; ; ) {
10173 0 : if ( sp->selected ) {
10174 0 : if ( onlysel==NULL )
10175 0 : onlysel = spl;
10176 0 : else if ( onlysel!=spl )
10177 0 : return;
10178 : }
10179 0 : if ( sp->next==NULL )
10180 0 : break;
10181 0 : sp = sp->next->to;
10182 0 : if ( sp==spl->first )
10183 0 : break;
10184 0 : }
10185 : } else {
10186 0 : for ( i=0; i<spl->spiro_cnt; ++i ) {
10187 0 : if ( SPIRO_SELECTED(&spl->spiros[i])) {
10188 0 : if ( onlysel==NULL )
10189 0 : onlysel = spl;
10190 0 : else if ( onlysel!=spl )
10191 0 : return;
10192 : }
10193 : }
10194 : }
10195 : }
10196 :
10197 0 : if ( onlysel!=NULL ) {
10198 0 : ret = gwwv_ask_string(_("Name this contour"),onlysel->contour_name,
10199 0 : _("Please name this contour"));
10200 0 : if ( ret!=NULL ) {
10201 0 : free(onlysel->contour_name);
10202 0 : if ( *ret!='\0' )
10203 0 : onlysel->contour_name = ret;
10204 : else {
10205 0 : onlysel->contour_name = NULL;
10206 0 : free(ret);
10207 : }
10208 0 : CVCharChangedUpdate(&cv->b);
10209 : }
10210 : }
10211 : }
10212 :
10213 0 : static void CVMenuNameContour(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
10214 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
10215 0 : _CVMenuNameContour(cv);
10216 0 : }
10217 :
10218 : struct insertonsplineat {
10219 : int done;
10220 : GWindow gw;
10221 : Spline *s;
10222 : CharView *cv;
10223 : };
10224 :
10225 : #define CID_X 1001
10226 : #define CID_Y 1002
10227 : #define CID_XR 1003
10228 : #define CID_YR 1004
10229 :
10230 0 : static int IOSA_OK(GGadget *g, GEvent *e) {
10231 :
10232 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
10233 0 : int err = false;
10234 0 : struct insertonsplineat *iosa = GDrawGetUserData(GGadgetGetWindow(g));
10235 : double val;
10236 : extended ts[3];
10237 : int which;
10238 : SplinePoint *sp;
10239 :
10240 0 : if ( GGadgetIsChecked(GWidgetGetControl(iosa->gw,CID_XR)) ) {
10241 0 : val = GetReal8(iosa->gw,CID_X,"X",&err);
10242 0 : which = 0;
10243 : } else {
10244 0 : val = GetReal8(iosa->gw,CID_Y,"Y",&err);
10245 0 : which = 1;
10246 : }
10247 0 : if ( err )
10248 0 : return(true);
10249 0 : if ( CubicSolve(&iosa->s->splines[which],val,ts)==0 ) {
10250 0 : ff_post_error(_("Out of Range"),_("The spline does not reach %g"), (double) val );
10251 0 : return( true );
10252 : }
10253 0 : iosa->done = true;
10254 0 : CVPreserveState(&iosa->cv->b);
10255 : for (;;) {
10256 0 : sp = SplineBisect(iosa->s,ts[0]);
10257 0 : SplinePointCategorize(sp);
10258 0 : if ( which==0 ) {
10259 0 : double off = val-sp->me.x;
10260 0 : sp->me.x = val; sp->nextcp.x += off; sp->prevcp.x += off;
10261 : } else {
10262 0 : double off = val-sp->me.y;
10263 0 : sp->me.y = val; sp->nextcp.y += off; sp->prevcp.y += off;
10264 : }
10265 0 : SplineRefigure(sp->prev); SplineRefigure(sp->next);
10266 0 : if ( ts[1]==-1 ) {
10267 0 : CVCharChangedUpdate(&iosa->cv->b);
10268 0 : return( true );
10269 : }
10270 0 : iosa->s = sp->next;
10271 0 : if ( CubicSolve(&iosa->s->splines[which],val,ts)==0 ) {
10272 : /* Odd. We found one earlier */
10273 0 : CVCharChangedUpdate(&iosa->cv->b);
10274 0 : return( true );
10275 : }
10276 0 : }
10277 : }
10278 0 : return( true );
10279 : }
10280 :
10281 0 : static int IOSA_Cancel(GGadget *g, GEvent *e) {
10282 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
10283 0 : struct insertonsplineat *iosa = GDrawGetUserData(GGadgetGetWindow(g));
10284 0 : iosa->done = true;
10285 : }
10286 0 : return( true );
10287 : }
10288 :
10289 0 : static int IOSA_FocusChange(GGadget *g, GEvent *e) {
10290 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_textfocuschanged ) {
10291 0 : struct insertonsplineat *iosa = GDrawGetUserData(GGadgetGetWindow(g));
10292 0 : int cid = (intpt) GGadgetGetUserData(g);
10293 0 : GGadgetSetChecked(GWidgetGetControl(iosa->gw,cid),true);
10294 : }
10295 0 : return( true );
10296 : }
10297 :
10298 0 : static int IOSA_RadioChange(GGadget *g, GEvent *e) {
10299 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_radiochanged ) {
10300 0 : struct insertonsplineat *iosa = GDrawGetUserData(GGadgetGetWindow(g));
10301 0 : int cid = (intpt) GGadgetGetUserData(g);
10302 0 : GWidgetIndicateFocusGadget(GWidgetGetControl(iosa->gw,cid));
10303 0 : GTextFieldSelect(GWidgetGetControl(iosa->gw,cid),0,-1);
10304 : }
10305 0 : return( true );
10306 : }
10307 :
10308 0 : static int iosa_e_h(GWindow gw, GEvent *event) {
10309 0 : if ( event->type==et_close ) {
10310 0 : struct insertonsplineat *iosa = GDrawGetUserData(gw);
10311 0 : iosa->done = true;
10312 0 : } else if ( event->type == et_char ) {
10313 0 : return( false );
10314 0 : } else if ( event->type == et_map ) {
10315 : /* Above palettes */
10316 0 : GDrawRaise(gw);
10317 : }
10318 0 : return( true );
10319 : }
10320 :
10321 0 : void _CVMenuInsertPt(CharView *cv) {
10322 : SplineSet *spl;
10323 0 : Spline *s, *found=NULL, *first;
10324 : struct insertonsplineat iosa;
10325 : GRect pos;
10326 : GWindowAttrs wattrs;
10327 : GGadgetCreateData gcd[11], boxes[2], topbox[2], *hvs[13], *varray[8], *buttons[6];
10328 : GTextInfo label[11];
10329 :
10330 0 : for ( spl = cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL; spl = spl->next ) {
10331 0 : first = NULL;
10332 0 : for ( s=spl->first->next; s!=NULL && s!=first ; s = s->to->next ) {
10333 0 : if ( first==NULL ) first=s;
10334 0 : if ( s->from->selected && s->to->selected ) {
10335 0 : if ( found!=NULL )
10336 0 : return; /* Can only work with one spline */
10337 0 : found = s;
10338 : }
10339 : }
10340 : }
10341 0 : if ( found==NULL )
10342 0 : return; /* Need a spline */
10343 :
10344 0 : memset(&iosa,0,sizeof(iosa));
10345 0 : iosa.s = found;
10346 0 : iosa.cv = cv;
10347 0 : memset(&wattrs,0,sizeof(wattrs));
10348 0 : wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict;
10349 0 : wattrs.event_masks = ~(1<<et_charup);
10350 0 : wattrs.restrict_input_to_me = 1;
10351 0 : wattrs.undercursor = 1;
10352 0 : wattrs.cursor = ct_pointer;
10353 0 : wattrs.utf8_window_title = _("Insert a point on the given spline at either...");
10354 0 : wattrs.is_dlg = true;
10355 0 : pos.x = pos.y = 0;
10356 0 : pos.width = GGadgetScale(GDrawPointsToPixels(NULL,210));
10357 0 : pos.height = GDrawPointsToPixels(NULL,120);
10358 0 : iosa.gw = GDrawCreateTopWindow(NULL,&pos,iosa_e_h,&iosa,&wattrs);
10359 :
10360 0 : memset(&label,0,sizeof(label));
10361 0 : memset(&gcd,0,sizeof(gcd));
10362 :
10363 0 : label[0].text = (unichar_t *) _("_X:");
10364 0 : label[0].text_is_1byte = true;
10365 0 : label[0].text_in_resource = true;
10366 0 : gcd[0].gd.label = &label[0];
10367 0 : gcd[0].gd.pos.x = 5; gcd[0].gd.pos.y = 5;
10368 0 : gcd[0].gd.flags = gg_enabled|gg_visible|gg_cb_on;
10369 0 : gcd[0].gd.cid = CID_XR;
10370 0 : gcd[0].gd.handle_controlevent = IOSA_RadioChange;
10371 0 : gcd[0].data = (void *) CID_X;
10372 0 : gcd[0].creator = GRadioCreate;
10373 :
10374 0 : label[1].text = (unichar_t *) _("_Y:");
10375 0 : label[1].text_is_1byte = true;
10376 0 : label[1].text_in_resource = true;
10377 0 : gcd[1].gd.label = &label[1];
10378 0 : gcd[1].gd.pos.x = 5; gcd[1].gd.pos.y = 32;
10379 0 : gcd[1].gd.flags = gg_enabled|gg_visible|gg_rad_continueold ;
10380 0 : gcd[1].gd.cid = CID_YR;
10381 0 : gcd[1].gd.handle_controlevent = IOSA_RadioChange;
10382 0 : gcd[1].data = (void *) CID_Y;
10383 0 : gcd[1].creator = GRadioCreate;
10384 :
10385 0 : gcd[2].gd.pos.x = 131; gcd[2].gd.pos.y = 5; gcd[2].gd.pos.width = 60;
10386 0 : gcd[2].gd.flags = gg_enabled|gg_visible;
10387 0 : gcd[2].gd.cid = CID_X;
10388 0 : gcd[2].gd.handle_controlevent = IOSA_FocusChange;
10389 0 : gcd[2].data = (void *) CID_XR;
10390 0 : gcd[2].creator = GTextFieldCreate;
10391 :
10392 0 : gcd[3].gd.pos.x = 131; gcd[3].gd.pos.y = 32; gcd[3].gd.pos.width = 60;
10393 0 : gcd[3].gd.flags = gg_enabled|gg_visible;
10394 0 : gcd[3].gd.cid = CID_Y;
10395 0 : gcd[3].gd.handle_controlevent = IOSA_FocusChange;
10396 0 : gcd[3].data = (void *) CID_YR;
10397 0 : gcd[3].creator = GTextFieldCreate;
10398 :
10399 0 : gcd[4].gd.pos.x = 20-3; gcd[4].gd.pos.y = 120-32-3;
10400 0 : gcd[4].gd.pos.width = -1; gcd[4].gd.pos.height = 0;
10401 0 : gcd[4].gd.flags = gg_visible | gg_enabled | gg_but_default;
10402 0 : label[4].text = (unichar_t *) _("_OK");
10403 0 : label[4].text_is_1byte = true;
10404 0 : label[4].text_in_resource = true;
10405 0 : gcd[4].gd.mnemonic = 'O';
10406 0 : gcd[4].gd.label = &label[4];
10407 0 : gcd[4].gd.handle_controlevent = IOSA_OK;
10408 0 : gcd[4].creator = GButtonCreate;
10409 :
10410 0 : gcd[5].gd.pos.x = -20; gcd[5].gd.pos.y = 120-32;
10411 0 : gcd[5].gd.pos.width = -1; gcd[5].gd.pos.height = 0;
10412 0 : gcd[5].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
10413 0 : label[5].text = (unichar_t *) _("_Cancel");
10414 0 : label[5].text_is_1byte = true;
10415 0 : label[5].text_in_resource = true;
10416 0 : gcd[5].gd.label = &label[5];
10417 0 : gcd[5].gd.mnemonic = 'C';
10418 0 : gcd[5].gd.handle_controlevent = IOSA_Cancel;
10419 0 : gcd[5].creator = GButtonCreate;
10420 :
10421 0 : hvs[0] = &gcd[0]; hvs[1] = &gcd[2]; hvs[2] = NULL;
10422 0 : hvs[3] = &gcd[1]; hvs[4] = &gcd[3]; hvs[5] = NULL;
10423 0 : hvs[6] = NULL;
10424 :
10425 0 : buttons[0] = buttons[2] = buttons[4] = GCD_Glue; buttons[5] = NULL;
10426 0 : buttons[1] = &gcd[4]; buttons[3] = &gcd[5];
10427 :
10428 0 : varray[0] = &boxes[1]; varray[1] = NULL;
10429 0 : varray[2] = GCD_Glue; varray[3] = NULL;
10430 0 : varray[4] = &boxes[0]; varray[5] = NULL;
10431 0 : varray[6] = NULL;
10432 :
10433 0 : memset(boxes,0,sizeof(boxes));
10434 0 : boxes[0].gd.flags = gg_enabled|gg_visible;
10435 0 : boxes[0].gd.u.boxelements = buttons;
10436 0 : boxes[0].creator = GHBoxCreate;
10437 :
10438 0 : boxes[1].gd.flags = gg_enabled|gg_visible;
10439 0 : boxes[1].gd.u.boxelements = hvs;
10440 0 : boxes[1].creator = GHVBoxCreate;
10441 :
10442 0 : memset(topbox,0,sizeof(topbox));
10443 0 : topbox[0].gd.pos.x = topbox[0].gd.pos.y = 2;
10444 0 : topbox[0].gd.pos.width = pos.width-4; topbox[0].gd.pos.height = pos.height-4;
10445 0 : topbox[0].gd.flags = gg_enabled|gg_visible;
10446 0 : topbox[0].gd.u.boxelements = varray;
10447 0 : topbox[0].creator = GHVGroupCreate;
10448 :
10449 :
10450 0 : GGadgetsCreate(iosa.gw,topbox);
10451 0 : GHVBoxSetExpandableRow(topbox[0].ret,1);
10452 0 : GHVBoxSetExpandableCol(boxes[0].ret,gb_expandgluesame);
10453 0 : GHVBoxSetExpandableCol(boxes[1].ret,1);
10454 0 : GWidgetIndicateFocusGadget(GWidgetGetControl(iosa.gw,CID_X));
10455 0 : GTextFieldSelect(GWidgetGetControl(iosa.gw,CID_X),0,-1);
10456 0 : GHVBoxFitWindow(topbox[0].ret);
10457 :
10458 0 : GDrawSetVisible(iosa.gw,true);
10459 0 : while ( !iosa.done )
10460 0 : GDrawProcessOneEvent(NULL);
10461 0 : GDrawDestroyWindow(iosa.gw);
10462 : }
10463 :
10464 0 : static void CVMenuInsertPt(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
10465 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
10466 0 : _CVMenuInsertPt(cv);
10467 0 : }
10468 :
10469 0 : static void _CVCenterCP(CharView *cv) {
10470 : SplinePointList *spl;
10471 : SplinePoint *sp;
10472 0 : int changed = false;
10473 0 : enum movething { mt_pt, mt_ncp, mt_pcp } movething = mt_pt;
10474 :
10475 0 : for ( spl = cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL; spl = spl->next ) {
10476 0 : for ( sp=spl->first; ; ) {
10477 0 : if ( sp->selected && sp->prev!=NULL && sp->next!=NULL &&
10478 0 : !sp->noprevcp && !sp->nonextcp ) {
10479 0 : if ( sp->me.x != (sp->nextcp.x+sp->prevcp.x)/2 ||
10480 0 : sp->me.y != (sp->nextcp.y+sp->prevcp.y)/2 ) {
10481 0 : if ( !changed ) {
10482 0 : CVPreserveState(&cv->b);
10483 0 : changed = true;
10484 : }
10485 0 : switch ( movething ) {
10486 : case mt_pt:
10487 0 : sp->me.x = (sp->nextcp.x+sp->prevcp.x)/2;
10488 0 : sp->me.y = (sp->nextcp.y+sp->prevcp.y)/2;
10489 0 : SplineRefigure(sp->prev);
10490 0 : SplineRefigure(sp->next);
10491 0 : break;
10492 : case mt_ncp:
10493 0 : sp->nextcp.x = sp->me.x - (sp->prevcp.x-sp->me.x);
10494 0 : sp->nextcp.y = sp->me.y - (sp->prevcp.y-sp->me.y);
10495 0 : if ( sp->next->order2 ) {
10496 0 : sp->next->to->prevcp = sp->nextcp;
10497 0 : sp->next->to->noprevcp = false;
10498 : }
10499 0 : SplineRefigure(sp->prev);
10500 0 : SplineRefigureFixup(sp->next);
10501 0 : break;
10502 : case mt_pcp:
10503 0 : sp->prevcp.x = sp->me.x - (sp->nextcp.x-sp->me.x);
10504 0 : sp->prevcp.y = sp->me.y - (sp->nextcp.y-sp->me.y);
10505 0 : if ( sp->prev->order2 ) {
10506 0 : sp->prev->from->nextcp = sp->prevcp;
10507 0 : sp->prev->from->nonextcp = false;
10508 : }
10509 0 : SplineRefigureFixup(sp->prev);
10510 0 : SplineRefigure(sp->next);
10511 0 : break;
10512 : }
10513 : }
10514 : }
10515 0 : if ( sp->next==NULL )
10516 0 : break;
10517 0 : sp = sp->next->to;
10518 0 : if ( sp==spl->first )
10519 0 : break;
10520 0 : }
10521 : }
10522 :
10523 0 : if ( changed )
10524 0 : CVCharChangedUpdate(&cv->b);
10525 0 : }
10526 :
10527 0 : static void CVMenuCenterCP(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
10528 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
10529 0 : _CVCenterCP(cv);
10530 0 : }
10531 :
10532 0 : void CVMakeClipPath(CharView *cv) {
10533 : SplineSet *ss;
10534 : SplinePoint *sp;
10535 : int sel;
10536 0 : int changed=false;
10537 :
10538 0 : for ( ss=cv->b.layerheads[cv->b.drawmode]->splines; ss!=NULL; ss=ss->next ) {
10539 0 : sel = false;
10540 0 : for ( sp=ss->first; ; ) {
10541 0 : if ( sp->selected ) {
10542 0 : sel = true;
10543 0 : break;
10544 : }
10545 0 : if ( sp->next==NULL )
10546 0 : break;
10547 0 : sp = sp->next->to;
10548 0 : if ( sp==ss->first )
10549 0 : break;
10550 0 : }
10551 0 : if ( sel!=ss->is_clip_path ) {
10552 0 : if ( !changed )
10553 0 : CVPreserveState((CharViewBase *) cv);
10554 0 : changed = true;
10555 0 : ss->is_clip_path = sel;
10556 : }
10557 : }
10558 0 : if ( changed )
10559 0 : CVCharChangedUpdate((CharViewBase *) cv);
10560 0 : }
10561 :
10562 0 : static void CVMenuClipPath(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
10563 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
10564 0 : CVMakeClipPath(cv);
10565 0 : }
10566 :
10567 0 : void CVAddAnchor(CharView *cv) {
10568 : int waslig;
10569 :
10570 0 : if ( AnchorClassUnused(cv->b.sc,&waslig)==NULL ) {
10571 0 : SplineFont *sf = cv->b.sc->parent;
10572 : AnchorClass *ac;
10573 : GTextInfo **ti;
10574 : int j;
10575 0 : char *name = gwwv_ask_string(_("Anchor Class Name"),"",_("Please enter the name of a Anchor point class to create"));
10576 0 : if ( name==NULL )
10577 0 : return;
10578 0 : ac = SFFindOrAddAnchorClass(sf,name,NULL);
10579 0 : free(name);
10580 0 : if ( AnchorClassUnused(cv->b.sc,&waslig)==NULL )
10581 0 : return;
10582 : }
10583 0 : ApGetInfo(cv,NULL);
10584 : }
10585 :
10586 0 : static void CVMenuAddAnchor(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
10587 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
10588 0 : CVAddAnchor(cv);
10589 0 : }
10590 :
10591 0 : static void CVMenuAutotrace(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *e) {
10592 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
10593 : GCursor ct;
10594 :
10595 0 : ct = GDrawGetCursor(cv->v);
10596 0 : GDrawSetCursor(cv->v,ct_watch);
10597 0 : ff_progress_allow_events();
10598 0 : SCAutoTrace(cv->b.sc,CVLayer((CharViewBase *) cv),e!=NULL && (e->u.mouse.state&ksm_shift));
10599 0 : GDrawSetCursor(cv->v,ct);
10600 0 : }
10601 :
10602 0 : static void CVMenuBuildAccent(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
10603 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
10604 : extern int onlycopydisplayed;
10605 0 : int layer = CVLayer((CharViewBase *) cv);
10606 :
10607 0 : if ( SFIsRotatable(cv->b.fv->sf,cv->b.sc))
10608 : /* It's ok */;
10609 0 : else if ( !SFIsSomethingBuildable(cv->b.fv->sf,cv->b.sc,layer,true) )
10610 0 : return;
10611 0 : SCBuildComposit(cv->b.fv->sf,cv->b.sc,layer,NULL,onlycopydisplayed);
10612 : }
10613 :
10614 0 : static void CVMenuBuildComposite(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
10615 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
10616 : extern int onlycopydisplayed;
10617 0 : int layer = CVLayer((CharViewBase *) cv);
10618 :
10619 0 : if ( SFIsRotatable(cv->b.fv->sf,cv->b.sc))
10620 : /* It's ok */;
10621 0 : else if ( !SFIsCompositBuildable(cv->b.fv->sf,cv->b.sc->unicodeenc,cv->b.sc,layer) )
10622 0 : return;
10623 0 : SCBuildComposit(cv->b.fv->sf,cv->b.sc,layer,NULL,onlycopydisplayed);
10624 : }
10625 :
10626 0 : static void CVMenuReverseDir(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
10627 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
10628 0 : int changed=false;
10629 : SplineSet *ss;
10630 :
10631 0 : for ( ss = cv->b.layerheads[cv->b.drawmode]->splines; ss!=NULL; ss=ss->next )
10632 0 : if ( PointListIsSelected(ss)) {
10633 0 : if ( !changed ) {
10634 0 : CVPreserveState(&cv->b);
10635 0 : changed = true;
10636 : }
10637 0 : SplineSetReverse(ss);
10638 : }
10639 :
10640 0 : if ( changed )
10641 0 : CVCharChangedUpdate(&cv->b);
10642 0 : }
10643 :
10644 0 : static void CVMenuCorrectDir(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
10645 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
10646 0 : int changed=false, refchanged=false;
10647 : RefChar *ref;
10648 0 : int asked=-1;
10649 0 : int layer = CVLayer( (CharViewBase *) cv);
10650 :
10651 0 : for ( ref=cv->b.sc->layers[layer].refs; ref!=NULL; ref=ref->next ) {
10652 0 : if ( ref->transform[0]*ref->transform[3]<0 ||
10653 0 : (ref->transform[0]==0 && ref->transform[1]*ref->transform[2]>0)) {
10654 0 : if ( asked==-1 ) {
10655 : char *buts[4];
10656 0 : buts[0] = _("_Unlink");
10657 0 : buts[1] = _("_No");
10658 0 : buts[2] = _("_Cancel");
10659 0 : buts[3] = NULL;
10660 0 : 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 );
10661 0 : if ( asked==2 )
10662 0 : return;
10663 0 : else if ( asked==1 )
10664 0 : break;
10665 : }
10666 0 : if ( asked==0 ) {
10667 0 : if ( !refchanged ) {
10668 0 : refchanged = true;
10669 0 : CVPreserveState(&cv->b);
10670 : }
10671 0 : SCRefToSplines(cv->b.sc,ref,layer);
10672 : }
10673 : }
10674 : }
10675 :
10676 0 : if ( !refchanged )
10677 0 : CVPreserveState(&cv->b);
10678 :
10679 0 : cv->b.layerheads[cv->b.drawmode]->splines = SplineSetsCorrect(cv->b.layerheads[cv->b.drawmode]->splines,&changed);
10680 0 : if ( changed || refchanged )
10681 0 : CVCharChangedUpdate(&cv->b);
10682 : }
10683 :
10684 0 : static void CVMenuInsertText(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
10685 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
10686 0 : InsertTextDlg(cv);
10687 0 : }
10688 :
10689 0 : static void CVMenuGetInfo(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
10690 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
10691 0 : CVGetInfo(cv);
10692 0 : }
10693 :
10694 0 : static void CVMenuCharInfo(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
10695 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
10696 0 : SCCharInfo(cv->b.sc,CVLayer((CharViewBase *) cv),cv->b.fv->map,CVCurEnc(cv));
10697 0 : }
10698 :
10699 0 : static void CVMenuShowDependentRefs(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
10700 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
10701 0 : SCRefBy(cv->b.sc);
10702 0 : }
10703 :
10704 0 : static void CVMenuShowDependentSubs(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
10705 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
10706 0 : SCSubBy(cv->b.sc);
10707 0 : }
10708 :
10709 0 : static void CVMenuBitmaps(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
10710 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
10711 0 : BitmapDlg((FontView *) (cv->b.fv),cv->b.sc,mi->mid==MID_RemoveBitmaps?-1: (mi->mid==MID_AvailBitmaps) );
10712 0 : }
10713 :
10714 0 : static void cv_allistcheck(CharView *cv, struct gmenuitem *mi) {
10715 0 : int selpoints = 0;
10716 : SplinePointList *spl;
10717 0 : SplinePoint *sp=NULL;
10718 :
10719 0 : for ( spl = cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL; spl = spl->next ) {
10720 0 : sp=spl->first;
10721 : while ( 1 ) {
10722 0 : if ( sp->selected )
10723 0 : ++selpoints;
10724 0 : if ( sp->next==NULL )
10725 0 : break;
10726 0 : sp = sp->next->to;
10727 0 : if ( sp==spl->first )
10728 0 : break;
10729 0 : }
10730 : }
10731 :
10732 0 : for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
10733 0 : switch ( mi->mid ) {
10734 : case MID_Average:
10735 0 : mi->ti.disabled = selpoints<2;
10736 0 : break;
10737 : case MID_SpacePts:
10738 0 : mi->ti.disabled = ((selpoints<3) && (selpoints!=1));
10739 0 : break;
10740 : case MID_SpaceRegion:
10741 0 : mi->ti.disabled = selpoints<3;
10742 0 : break;
10743 : case MID_MakeParallel:
10744 0 : mi->ti.disabled = selpoints!=4;
10745 0 : break;
10746 : }
10747 : }
10748 0 : }
10749 :
10750 0 : static void allistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
10751 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
10752 0 : cv_allistcheck(cv, mi);
10753 0 : }
10754 :
10755 0 : static void cv_balistcheck(CharView *cv, struct gmenuitem *mi) {
10756 0 : int layer = CVLayer((CharViewBase *) cv);
10757 :
10758 0 : for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
10759 0 : switch ( mi->mid ) {
10760 : case MID_BuildAccent:
10761 0 : mi->ti.disabled = !SFIsSomethingBuildable(cv->b.fv->sf,cv->b.sc,layer,true);
10762 0 : break;
10763 : case MID_BuildComposite:
10764 0 : mi->ti.disabled = !SFIsSomethingBuildable(cv->b.fv->sf,cv->b.sc,layer,false);
10765 0 : break;
10766 : }
10767 : }
10768 0 : }
10769 :
10770 0 : static void balistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
10771 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
10772 0 : cv_balistcheck(cv, mi);
10773 0 : }
10774 :
10775 0 : static void delistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
10776 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
10777 :
10778 0 : for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
10779 0 : switch ( mi->mid ) {
10780 : case MID_ShowDependentRefs:
10781 0 : mi->ti.disabled = cv->b.sc->dependents==NULL;
10782 0 : break;
10783 : case MID_ShowDependentSubs:
10784 0 : mi->ti.disabled = !SCUsedBySubs(cv->b.sc);
10785 0 : break;
10786 : }
10787 : }
10788 0 : }
10789 :
10790 0 : static void rndlistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
10791 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
10792 :
10793 0 : for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
10794 0 : switch ( mi->mid ) {
10795 : case MID_RoundToCluster:
10796 0 : mi->ti.disabled = cv->b.sc->inspiro && hasspiro();
10797 0 : break;
10798 : }
10799 : }
10800 0 : }
10801 :
10802 0 : static void cv_ellistcheck(CharView *cv, struct gmenuitem *mi) {
10803 0 : int anypoints = 0, splinepoints, dir = -2;
10804 0 : int self_intersects=-2;
10805 : SplinePointList *spl;
10806 : Spline *spline, *first;
10807 : AnchorPoint *ap;
10808 : spiro_cp *cp;
10809 : int i;
10810 :
10811 : #ifdef FONTFORGE_CONFIG_TILEPATH
10812 : int badsel = false;
10813 : RefChar *ref;
10814 : ImageList *il;
10815 :
10816 : for ( ref=cv->b.layerheads[cv->b.drawmode]->refs; ref!=NULL; ref=ref->next )
10817 : if ( ref->selected )
10818 : badsel = true;
10819 :
10820 : for ( il=cv->b.layerheads[cv->b.drawmode]->images; il!=NULL; il=il->next )
10821 : if ( il->selected )
10822 : badsel = true;
10823 : #endif
10824 :
10825 0 : if ( cv->checkselfintersects ) {
10826 : Spline *s, *s2;
10827 : SplineSet *ss;
10828 0 : ss = LayerAllSplines(cv->b.layerheads[cv->b.drawmode]);
10829 0 : self_intersects = SplineSetIntersect(ss,&s,&s2);
10830 0 : LayerUnAllSplines(cv->b.layerheads[cv->b.drawmode]);
10831 : }
10832 :
10833 0 : for ( spl = cv->b.layerheads[cv->b.drawmode]->splines; spl!=NULL; spl = spl->next ) {
10834 0 : first = NULL;
10835 0 : splinepoints = 0;
10836 0 : if ( cv->b.sc->inspiro && hasspiro()) {
10837 0 : for ( i=0; i<spl->spiro_cnt-1; ++i ) {
10838 0 : if ( SPIRO_SELECTED(&spl->spiros[i])) {
10839 0 : splinepoints = 1;
10840 0 : break;
10841 : }
10842 : }
10843 : } else {
10844 0 : if ( spl->first->selected ) { splinepoints = 1; }
10845 0 : for ( spline=spl->first->next; spline!=NULL && spline!=first && !splinepoints; spline = spline->to->next ) {
10846 0 : if ( spline->to->selected ) { ++splinepoints; }
10847 0 : if ( first == NULL ) first = spline;
10848 : }
10849 : }
10850 0 : if ( splinepoints ) {
10851 0 : anypoints += splinepoints;
10852 0 : if ( dir==-1 )
10853 : /* Do nothing */;
10854 0 : else if ( spl->first!=spl->last || spl->first->next==NULL ) {
10855 0 : if ( dir==-2 || dir==2 )
10856 0 : dir = 2; /* Not a closed path, no direction */
10857 : else
10858 0 : dir = -1;
10859 0 : } else if ( dir==-2 )
10860 0 : dir = SplinePointListIsClockwise(spl);
10861 0 : if ( dir==-1 )
10862 0 : self_intersects = 1; /* Sometimes the clockwise test finds intersections the main routine can't */
10863 : else {
10864 0 : int subdir = SplinePointListIsClockwise(spl);
10865 0 : if ( subdir==-1 )
10866 0 : self_intersects = 1;
10867 0 : if ( subdir!=dir )
10868 0 : dir = -1;
10869 : }
10870 : }
10871 : }
10872 :
10873 0 : for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
10874 0 : switch ( mi->mid ) {
10875 : case MID_FontInfo: case MID_CharInfo: case MID_ShowDependentRefs:
10876 : case MID_FindProblems:
10877 : case MID_AvailBitmaps:
10878 0 : mi->ti.disabled = cv->b.container!=NULL;
10879 0 : break;
10880 : case MID_GetInfo:
10881 : {
10882 : SplinePoint *sp; SplineSet *spl; RefChar *ref; ImageList *img;
10883 0 : mi->ti.disabled = !CVOneThingSel(cv,&sp,&spl,&ref,&img,&ap,&cp);
10884 : }
10885 0 : break;
10886 : case MID_CheckSelf:
10887 0 : mi->ti.checked = cv->checkselfintersects;
10888 0 : break;
10889 : case MID_GlyphSelfIntersects:
10890 0 : mi->ti.disabled = !cv->checkselfintersects;
10891 0 : mi->ti.checked = self_intersects==1;
10892 0 : break;
10893 : case MID_Clockwise:
10894 0 : mi->ti.disabled = !anypoints || dir==2 || dir<0;
10895 0 : mi->ti.checked = dir==1;
10896 0 : break;
10897 : case MID_Counter:
10898 0 : mi->ti.disabled = !anypoints || dir==2 || dir<0;
10899 0 : mi->ti.checked = dir==0;
10900 0 : break;
10901 : case MID_Correct:
10902 0 : mi->ti.disabled = (cv->b.layerheads[cv->b.drawmode]->splines==NULL && cv->b.layerheads[cv->b.drawmode]->refs==NULL) ||
10903 0 : dir==2 || self_intersects==1;
10904 0 : break;
10905 : case MID_ReverseDir:
10906 0 : mi->ti.disabled = !anypoints;
10907 0 : break;
10908 : case MID_Stroke:
10909 : case MID_RmOverlap:
10910 : case MID_Styles:
10911 0 : mi->ti.disabled = cv->b.layerheads[cv->b.drawmode]->splines==NULL ||
10912 0 : cv->b.container!=NULL;
10913 0 : break;
10914 : #ifdef FONTFORGE_CONFIG_TILEPATH
10915 : case MID_TilePath:
10916 : mi->ti.disabled = badsel;
10917 : break;
10918 : #endif
10919 : case MID_RegenBitmaps: case MID_RemoveBitmaps:
10920 0 : mi->ti.disabled = cv->b.fv->sf->bitmaps==NULL;
10921 0 : break;
10922 : case MID_AddExtrema:
10923 0 : mi->ti.disabled = cv->b.layerheads[cv->b.drawmode]->splines==NULL || (cv->b.sc->inspiro && hasspiro());
10924 : /* Like Simplify, always available, but may not do anything if */
10925 : /* all extrema have points. I'm not going to check for that, too hard */
10926 0 : break;
10927 : case MID_Simplify:
10928 0 : mi->ti.disabled = cv->b.layerheads[cv->b.drawmode]->splines==NULL || (cv->b.sc->inspiro && hasspiro());
10929 : /* Simplify is always available (it may not do anything though) */
10930 : /* well, ok. Disable it if there is absolutely nothing to work on */
10931 0 : break;
10932 : case MID_BuildAccent:
10933 0 : mi->ti.disabled = !SFIsSomethingBuildable(cv->b.fv->sf,cv->b.sc,
10934 : CVLayer((CharViewBase *) cv),false);
10935 0 : break;
10936 : case MID_Autotrace:
10937 0 : mi->ti.disabled = FindAutoTraceName()==NULL || cv->b.sc->layers[ly_back].images==NULL;
10938 0 : break;
10939 : case MID_Align:
10940 0 : mi->ti.disabled = cv->b.sc->inspiro && hasspiro();
10941 0 : break;
10942 : }
10943 : }
10944 0 : }
10945 :
10946 0 : static void ellistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
10947 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
10948 0 : cv_ellistcheck(cv, mi);
10949 0 : }
10950 :
10951 0 : static void CVMenuAutoHint(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
10952 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
10953 : /*int removeOverlap = e==NULL || !(e->u.mouse.state&ksm_shift);*/
10954 0 : int was = cv->b.sc->changedsincelasthinted;
10955 :
10956 : /* Hint undoes are done in _SplineCharAutoHint */
10957 0 : cv->b.sc->manualhints = false;
10958 0 : SplineCharAutoHint(cv->b.sc,CVLayer((CharViewBase *) cv),NULL);
10959 0 : SCUpdateAll(cv->b.sc);
10960 0 : if ( was ) {
10961 : FontView *fvs;
10962 0 : for ( fvs=(FontView *) (cv->b.fv); fvs!=NULL; fvs=(FontView *) (fvs->b.nextsame) )
10963 0 : GDrawRequestExpose(fvs->v,NULL,false); /* Clear any changedsincelasthinted marks */
10964 : }
10965 0 : }
10966 :
10967 0 : static void CVMenuAutoHintSubs(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
10968 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
10969 0 : SCFigureHintMasks(cv->b.sc,CVLayer((CharViewBase *) cv));
10970 0 : SCUpdateAll(cv->b.sc);
10971 0 : }
10972 :
10973 0 : static void CVMenuAutoCounter(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
10974 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
10975 0 : SCFigureCounterMasks(cv->b.sc);
10976 0 : }
10977 :
10978 0 : static void CVMenuDontAutoHint(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
10979 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
10980 0 : cv->b.sc->manualhints = !cv->b.sc->manualhints;
10981 0 : }
10982 :
10983 0 : static void CVMenuNowakAutoInstr(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
10984 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
10985 0 : SplineChar *sc = cv->b.sc;
10986 : GlobalInstrCt gic;
10987 :
10988 0 : if ( cv->b.layerheads[cv->b.drawmode]->splines!=NULL && sc->hstem==NULL && sc->vstem==NULL
10989 0 : && sc->dstem==NULL && !no_windowing_ui )
10990 0 : ff_post_notice(_("Things could be better..."), _("Glyph, %s, has no hints. FontForge will not produce many instructions."),
10991 : sc->name );
10992 :
10993 0 : InitGlobalInstrCt(&gic, sc->parent, CVLayer((CharViewBase *) cv), NULL);
10994 0 : NowakowskiSCAutoInstr(&gic, sc);
10995 0 : FreeGlobalInstrCt(&gic);
10996 0 : SCUpdateAll(sc);
10997 0 : }
10998 :
10999 0 : static void CVMenuClearHints(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
11000 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
11001 :
11002 0 : SCPreserveHints(cv->b.sc,CVLayer((CharViewBase *) cv));
11003 0 : SCHintsChanged(cv->b.sc);
11004 0 : if ( mi->mid==MID_ClearHStem ) {
11005 0 : StemInfosFree(cv->b.sc->hstem);
11006 0 : cv->b.sc->hstem = NULL;
11007 0 : cv->b.sc->hconflicts = false;
11008 0 : } else if ( mi->mid==MID_ClearVStem ) {
11009 0 : StemInfosFree(cv->b.sc->vstem);
11010 0 : cv->b.sc->vstem = NULL;
11011 0 : cv->b.sc->vconflicts = false;
11012 0 : } else if ( mi->mid==MID_ClearDStem ) {
11013 0 : DStemInfosFree(cv->b.sc->dstem);
11014 0 : cv->b.sc->dstem = NULL;
11015 : }
11016 0 : cv->b.sc->manualhints = true;
11017 :
11018 0 : if ( mi->mid != MID_ClearDStem ) {
11019 0 : SCClearHintMasks(cv->b.sc,CVLayer((CharViewBase *) cv),true);
11020 : }
11021 0 : SCOutOfDateBackground(cv->b.sc);
11022 0 : SCUpdateAll(cv->b.sc);
11023 0 : }
11024 :
11025 : /* This is an improved version of the older CVTwoForePointsSelected function. */
11026 : /* Unlike the former, it doesn't just check if there are exactly two points */
11027 : /* selected, but rather returns the number of selected points (whatever this */
11028 : /* number can be) and puts references to those points into an array. It is up */
11029 : /* to the calling code to see if the returned result is satisfiable (there */
11030 : /* should be exactly two points selected for specifying a vertical or */
11031 : /* horizontal stem and four points for a diagonal stem). */
11032 0 : static int CVNumForePointsSelected(CharView *cv, BasePoint **bp) {
11033 : SplineSet *spl;
11034 : SplinePoint *test, *first;
11035 : BasePoint *bps[5];
11036 : int i, cnt;
11037 :
11038 0 : if ( cv->b.drawmode!=dm_fore )
11039 0 : return( 0 ) ;
11040 0 : cnt = 0;
11041 0 : for ( spl = cv->b.sc->layers[ly_fore].splines; spl!=NULL; spl = spl->next ) {
11042 0 : first = NULL;
11043 0 : for ( test = spl->first; test!=first; test = test->next->to ) {
11044 0 : if ( test->selected ) {
11045 0 : bps[cnt++] = &(test->me);
11046 0 : if ( cnt>4 )
11047 0 : return( 0 );
11048 : }
11049 0 : if ( first == NULL ) first = test;
11050 0 : if ( test->next==NULL )
11051 0 : break;
11052 : }
11053 : }
11054 0 : for (i=0; i<cnt; i++) {
11055 0 : bp[i] = bps[i];
11056 : }
11057 0 : return( cnt );
11058 : }
11059 :
11060 0 : static void CVMenuAddHint(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
11061 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
11062 : BasePoint *bp[4], unit;
11063 0 : StemInfo *h=NULL;
11064 : DStemInfo *d;
11065 : int num;
11066 0 : int layer = CVLayer((CharViewBase *) cv);
11067 :
11068 0 : num = CVNumForePointsSelected( cv,bp );
11069 :
11070 : /* We need exactly 2 points to specify a horizontal or vertical stem */
11071 : /* and exactly 4 points to specify a diagonal stem */
11072 0 : if ( !(num == 2 && mi->mid != MID_AddDHint) &&
11073 0 : !(num == 4 && mi->mid == MID_AddDHint))
11074 0 : return;
11075 :
11076 0 : SCPreserveHints(cv->b.sc,CVLayer((CharViewBase *) cv));
11077 0 : SCHintsChanged(cv->b.sc);
11078 0 : if ( mi->mid==MID_AddHHint ) {
11079 0 : if ( bp[0]->y==bp[1]->y )
11080 0 : return;
11081 0 : h = chunkalloc(sizeof(StemInfo));
11082 0 : if ( bp[1]->y>bp[0]->y ) {
11083 0 : h->start = bp[0]->y;
11084 0 : h->width = bp[1]->y-bp[0]->y;
11085 : } else {
11086 0 : h->start = bp[1]->y;
11087 0 : h->width = bp[0]->y-bp[1]->y;
11088 : }
11089 0 : SCGuessHHintInstancesAndAdd(cv->b.sc,layer,h,bp[0]->x,bp[1]->x);
11090 0 : cv->b.sc->hconflicts = StemListAnyConflicts(cv->b.sc->hstem);
11091 0 : } else if ( mi->mid==MID_AddVHint ) {
11092 0 : if ( bp[0]->x==bp[1]->x )
11093 0 : return;
11094 0 : h = chunkalloc(sizeof(StemInfo));
11095 0 : if ( bp[1]->x>bp[0]->x ) {
11096 0 : h->start = bp[0]->x;
11097 0 : h->width = bp[1]->x-bp[0]->x;
11098 : } else {
11099 0 : h->start = bp[1]->x;
11100 0 : h->width = bp[0]->x-bp[1]->x;
11101 : }
11102 0 : SCGuessVHintInstancesAndAdd(cv->b.sc,layer,h,bp[0]->y,bp[1]->y);
11103 0 : cv->b.sc->vconflicts = StemListAnyConflicts(cv->b.sc->vstem);
11104 : } else {
11105 0 : if ( !PointsDiagonalable( cv->b.sc->parent,bp,&unit ))
11106 0 : return;
11107 : /* No additional tests, as the points should have already been */
11108 : /* reordered by PointsDiagonalable */
11109 0 : d = chunkalloc(sizeof(DStemInfo));
11110 0 : d->where = NULL;
11111 0 : d->left = *bp[0];
11112 0 : d->right = *bp[1];
11113 0 : d->unit = unit;
11114 0 : SCGuessDHintInstances( cv->b.sc,layer,d );
11115 0 : if ( d->where == NULL )
11116 0 : DStemInfoFree( d );
11117 : else
11118 0 : MergeDStemInfo( cv->b.sc->parent,&cv->b.sc->dstem,d );
11119 : }
11120 0 : cv->b.sc->manualhints = true;
11121 :
11122 : /* Hint Masks are not relevant for diagonal stems, so modifying */
11123 : /* diagonal stems should not affect them */
11124 0 : if ( (mi->mid==MID_AddVHint) || (mi->mid==MID_AddHHint) ) {
11125 0 : if ( h!=NULL && cv->b.sc->parent->mm==NULL )
11126 0 : SCModifyHintMasksAdd(cv->b.sc,layer,h);
11127 : else
11128 0 : SCClearHintMasks(cv->b.sc,layer,true);
11129 : }
11130 0 : SCOutOfDateBackground(cv->b.sc);
11131 0 : SCUpdateAll(cv->b.sc);
11132 : }
11133 :
11134 0 : static void CVMenuCreateHint(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
11135 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
11136 0 : CVCreateHint(cv,mi->mid==MID_CreateHHint,true);
11137 0 : }
11138 :
11139 0 : static void CVMenuReviewHints(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
11140 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
11141 :
11142 0 : if ( cv->b.sc->hstem==NULL && cv->b.sc->vstem==NULL )
11143 0 : return;
11144 0 : CVReviewHints(cv);
11145 : }
11146 :
11147 0 : static void htlistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
11148 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
11149 0 : int cvlayer = CVLayer((CharViewBase *) cv);
11150 : BasePoint *bp[4], unit;
11151 0 : int multilayer = cv->b.sc->parent->multilayer;
11152 0 : int i=0, num = 0;
11153 :
11154 0 : for (i=0; i<4; i++) {bp[i]=NULL;}
11155 :
11156 0 : num = CVNumForePointsSelected(cv,bp);
11157 :
11158 0 : for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
11159 0 : switch ( mi->mid ) {
11160 : case MID_AutoHint:
11161 0 : mi->ti.disabled = cvlayer == ly_grid || multilayer;
11162 0 : break;
11163 : case MID_HintSubsPt:
11164 0 : mi->ti.disabled = multilayer ||
11165 0 : cv->b.layerheads[cv->b.drawmode]->order2 ||
11166 : cvlayer == ly_grid;
11167 0 : break;
11168 : case MID_AutoCounter:
11169 0 : mi->ti.disabled = multilayer;
11170 0 : break;
11171 : case MID_DontAutoHint:
11172 0 : mi->ti.disabled = cv->b.layerheads[cv->b.drawmode]->order2 || multilayer;
11173 0 : mi->ti.checked = cv->b.sc->manualhints;
11174 0 : break;
11175 : case MID_AutoInstr:
11176 : case MID_EditInstructions:
11177 0 : mi->ti.disabled = multilayer ||
11178 0 : !cv->b.layerheads[cv->b.drawmode]->order2 ||
11179 : cvlayer == ly_grid;
11180 0 : break;
11181 : case MID_Debug:
11182 0 : mi->ti.disabled = multilayer ||
11183 0 : !cv->b.layerheads[cv->b.drawmode]->order2 ||
11184 0 : !hasFreeTypeDebugger();
11185 0 : break;
11186 : case MID_Deltas:
11187 0 : mi->ti.disabled = multilayer ||
11188 0 : !cv->b.layerheads[cv->b.drawmode]->order2 ||
11189 0 : !hasFreeTypeDebugger();
11190 0 : break;
11191 : case MID_ClearHStem:
11192 : case MID_ClearVStem:
11193 : case MID_ClearDStem:
11194 0 : mi->ti.disabled = cvlayer == ly_grid;
11195 0 : break;
11196 : case MID_ClearInstr:
11197 0 : mi->ti.disabled = cv->b.sc->ttf_instrs_len==0;
11198 0 : break;
11199 : case MID_AddHHint:
11200 0 : mi->ti.disabled = num != 2 || bp[1]->y==bp[0]->y || multilayer;
11201 0 : break;
11202 : case MID_AddVHint:
11203 0 : mi->ti.disabled = num != 2 || bp[1]->x==bp[0]->x || multilayer;
11204 0 : break;
11205 : case MID_AddDHint:
11206 0 : mi->ti.disabled = num != 4 || !PointsDiagonalable( cv->b.sc->parent,bp,&unit ) || multilayer;
11207 0 : break;
11208 : case MID_CreateHHint:
11209 : case MID_CreateVHint:
11210 0 : mi->ti.disabled = cvlayer == ly_grid;
11211 0 : break;
11212 : case MID_ReviewHints:
11213 0 : mi->ti.disabled = (cv->b.sc->hstem==NULL && cv->b.sc->vstem==NULL ) || multilayer;
11214 0 : break;
11215 : }
11216 : }
11217 0 : }
11218 :
11219 0 : static void mtlistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
11220 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
11221 0 : RefChar *r = HasUseMyMetrics(cv->b.sc,CVLayer((CharViewBase *) cv));
11222 :
11223 0 : for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
11224 0 : switch ( mi->mid ) {
11225 : case MID_RemoveKerns:
11226 0 : mi->ti.disabled = cv->b.sc->kerns==NULL;
11227 0 : break;
11228 : case MID_RemoveVKerns:
11229 0 : mi->ti.disabled = cv->b.sc->vkerns==NULL;
11230 0 : break;
11231 : case MID_SetVWidth:
11232 0 : mi->ti.disabled = !cv->b.sc->parent->hasvmetrics || r!=NULL;
11233 0 : break;
11234 : case MID_AnchorsAway:
11235 0 : mi->ti.disabled = cv->b.sc->anchor==NULL;
11236 0 : break;
11237 : case MID_SetWidth: case MID_SetLBearing: case MID_SetRBearing: case MID_SetBearings:
11238 0 : mi->ti.disabled = r!=NULL;
11239 0 : break;
11240 : }
11241 : }
11242 0 : }
11243 :
11244 0 : static void cv_sllistcheck(CharView *cv, struct gmenuitem *mi) {
11245 : SplinePoint *sp; SplineSet *spl; RefChar *r; ImageList *im;
11246 : spiro_cp *scp;
11247 : SplineSet *test;
11248 0 : int exactlyone = CVOneThingSel(cv,&sp,&spl,&r,&im,NULL,&scp);
11249 :
11250 0 : for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
11251 0 : switch ( mi->mid ) {
11252 : case MID_NextCP: case MID_PrevCP:
11253 0 : mi->ti.disabled = !exactlyone || sp==NULL || (cv->b.sc->inspiro && hasspiro());
11254 0 : break;
11255 : case MID_NextPt: case MID_PrevPt:
11256 : case MID_FirstPtNextCont:
11257 0 : mi->ti.disabled = !exactlyone || (sp==NULL && scp==NULL);
11258 0 : break;
11259 : case MID_FirstPt: case MID_SelPointAt:
11260 0 : mi->ti.disabled = cv->b.layerheads[cv->b.drawmode]->splines==NULL;
11261 0 : break;
11262 : case MID_Contours:
11263 0 : mi->ti.disabled = !CVAnySelPoints(cv);
11264 0 : break;
11265 : case MID_SelectOpenContours:
11266 0 : mi->ti.disabled = true;
11267 0 : for ( test=cv->b.layerheads[cv->b.drawmode]->splines; test!=NULL; test=test->next ) {
11268 0 : if ( test->first->prev==NULL ) {
11269 0 : mi->ti.disabled = false;
11270 0 : break;
11271 : }
11272 : }
11273 0 : break;
11274 : case MID_SelectWidth:
11275 0 : mi->ti.disabled = !cv->showhmetrics;
11276 0 : if ( HasUseMyMetrics(cv->b.sc,CVLayer((CharViewBase *) cv))!=NULL )
11277 0 : mi->ti.disabled = true;
11278 0 : if ( !mi->ti.disabled ) {
11279 0 : free(mi->ti.text);
11280 0 : mi->ti.text = utf82u_copy(cv->widthsel?_("Deselect Width"):_("Width"));
11281 : }
11282 0 : break;
11283 : case MID_SelectVWidth:
11284 0 : mi->ti.disabled = !cv->showvmetrics || !cv->b.sc->parent->hasvmetrics;
11285 0 : if ( HasUseMyMetrics(cv->b.sc,CVLayer((CharViewBase *) cv))!=NULL )
11286 0 : mi->ti.disabled = true;
11287 0 : if ( !mi->ti.disabled ) {
11288 0 : free(mi->ti.text);
11289 0 : mi->ti.text = utf82u_copy(cv->vwidthsel?_("Deselect VWidth"):_("VWidth"));
11290 : }
11291 0 : break;
11292 : case MID_SelectHM:
11293 0 : mi->ti.disabled = !exactlyone || sp==NULL || sp->hintmask==NULL;
11294 0 : break;
11295 : }
11296 : }
11297 0 : }
11298 :
11299 0 : static void sllistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
11300 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
11301 0 : cv_sllistcheck(cv, mi);
11302 0 : }
11303 :
11304 0 : static void cv_cblistcheck(CharView *cv, struct gmenuitem *mi) {
11305 : int i;
11306 : KernPair *kp;
11307 0 : SplineChar *sc = cv->b.sc;
11308 0 : SplineFont *sf = sc->parent;
11309 : PST *pst;
11310 : char *name;
11311 :
11312 0 : for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
11313 0 : switch ( mi->mid ) {
11314 : case MID_AnchorPairs:
11315 0 : mi->ti.disabled = sc->anchor==NULL;
11316 0 : break;
11317 : case MID_AnchorControl:
11318 0 : mi->ti.disabled = sc->anchor==NULL;
11319 0 : break;
11320 : case MID_AnchorGlyph:
11321 0 : if ( cv->apmine!=NULL )
11322 0 : mi->ti.disabled = false;
11323 : else
11324 0 : mi->ti.disabled = sc->anchor==NULL;
11325 0 : break;
11326 : case MID_KernPairs:
11327 0 : mi->ti.disabled = sc->kerns==NULL;
11328 0 : if ( sc->kerns==NULL ) {
11329 0 : for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
11330 0 : for ( kp = sf->glyphs[i]->kerns; kp!=NULL; kp=kp->next ) {
11331 0 : if ( kp->sc == sc ) {
11332 0 : mi->ti.disabled = false;
11333 0 : goto out;
11334 : }
11335 : }
11336 : }
11337 : out:;
11338 : }
11339 0 : break;
11340 : case MID_Ligatures:
11341 0 : name = sc->name;
11342 0 : for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
11343 0 : for ( pst=sf->glyphs[i]->possub; pst!=NULL; pst=pst->next ) {
11344 0 : if ( pst->type==pst_ligature &&
11345 0 : PSTContains(pst->u.lig.components,name)) {
11346 0 : mi->ti.disabled = false;
11347 0 : goto break_out_2;
11348 : }
11349 : }
11350 : }
11351 0 : mi->ti.disabled = true;
11352 : break_out_2:;
11353 0 : break;
11354 : }
11355 : }
11356 0 : }
11357 :
11358 0 : static void cv_nplistcheck(CharView *cv, struct gmenuitem *mi) {
11359 0 : SplineChar *sc = cv->b.sc;
11360 0 : int order2 = cv->b.layerheads[cv->b.drawmode]->order2;
11361 0 : int is_grid_layer = cv->b.drawmode == dm_grid;
11362 :
11363 0 : for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
11364 0 : switch ( mi->mid ) {
11365 : case MID_PtsNone:
11366 0 : mi->ti.disabled = !order2 || is_grid_layer;
11367 0 : mi->ti.checked = (cv->showpointnumbers == 0);
11368 0 : break;
11369 : case MID_PtsTrue:
11370 0 : mi->ti.disabled = !order2 || is_grid_layer;
11371 0 : mi->ti.checked = cv->showpointnumbers && order2;
11372 0 : break;
11373 : case MID_PtsPost:
11374 0 : mi->ti.disabled = order2 || is_grid_layer;
11375 0 : mi->ti.checked = cv->showpointnumbers && !order2 && sc->numberpointsbackards;
11376 0 : break;
11377 : case MID_PtsSVG:
11378 0 : mi->ti.disabled = order2 || is_grid_layer;
11379 0 : mi->ti.checked = cv->showpointnumbers && !order2 && !sc->numberpointsbackards;
11380 0 : break;
11381 : case MID_PtsPos:
11382 0 : mi->ti.disabled = is_grid_layer;
11383 0 : mi->ti.checked = (cv->showpointnumbers == 2);
11384 : }
11385 : }
11386 0 : }
11387 :
11388 0 : static void gflistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
11389 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
11390 :
11391 0 : for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
11392 0 : switch ( mi->mid ) {
11393 : case MID_ShowGridFit:
11394 0 : mi->ti.disabled = !hasFreeType() || cv->dv!=NULL;
11395 0 : mi->ti.checked = cv->show_ft_results;
11396 0 : break;
11397 : case MID_ShowGridFitLiveUpdate:
11398 0 : mi->ti.disabled = !hasFreeType() || cv->dv!=NULL;
11399 0 : mi->ti.checked = cv->show_ft_results_live_update;
11400 0 : break;
11401 : case MID_Bigger:
11402 0 : mi->ti.disabled = !cv->show_ft_results;
11403 0 : break;
11404 : case MID_Smaller:
11405 0 : mi->ti.disabled = !cv->show_ft_results || cv->ft_pointsizex<2 || cv->ft_pointsizey<2;
11406 0 : break;
11407 : case MID_GridFitAA:
11408 0 : mi->ti.disabled = !cv->show_ft_results;
11409 0 : mi->ti.checked = cv->ft_depth==8;
11410 0 : break;
11411 : case MID_GridFitOff:
11412 0 : mi->ti.disabled = !cv->show_ft_results;
11413 0 : break;
11414 : }
11415 : }
11416 0 : }
11417 :
11418 0 : static void swlistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
11419 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
11420 0 : SplineFont *sf = cv->b.sc->parent;
11421 :
11422 0 : for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
11423 0 : switch ( mi->mid ) {
11424 : case MID_MarkExtrema:
11425 0 : mi->ti.checked = cv->markextrema;
11426 0 : mi->ti.disabled = cv->b.sc->inspiro && hasspiro();
11427 0 : break;
11428 : case MID_MarkPointsOfInflection:
11429 0 : mi->ti.checked = cv->markpoi;
11430 0 : mi->ti.disabled = cv->b.sc->inspiro && hasspiro();
11431 0 : break;
11432 : case MID_ShowAlmostHV:
11433 0 : mi->ti.checked = cv->showalmosthvlines;
11434 0 : break;
11435 : case MID_ShowAlmostHVCurves:
11436 0 : mi->ti.checked = cv->showalmosthvcurves;
11437 0 : break;
11438 : case MID_DefineAlmost:
11439 0 : mi->ti.disabled = !cv->showalmosthvlines && !cv->showalmosthvcurves;
11440 0 : break;
11441 : case MID_ShowCPInfo:
11442 0 : mi->ti.checked = cv->showcpinfo;
11443 0 : break;
11444 : case MID_DraggingComparisonOutline:
11445 0 : mi->ti.checked = prefs_create_dragging_comparison_outline;
11446 0 : break;
11447 : case MID_ShowSideBearings:
11448 0 : mi->ti.checked = cv->showsidebearings;
11449 0 : break;
11450 : case MID_ShowRefNames:
11451 0 : mi->ti.checked = cv->showrefnames;
11452 0 : break;
11453 : case MID_ShowTabs:
11454 0 : mi->ti.checked = cv->showtabs;
11455 0 : mi->ti.disabled = cv->former_cnt<=1;
11456 0 : break;
11457 : case MID_HidePoints:
11458 0 : mi->ti.checked = cv->showpoints;
11459 0 : break;
11460 : case MID_HideControlPoints:
11461 0 : mi->ti.checked = cv->alwaysshowcontrolpoints;
11462 0 : break;
11463 : case MID_HideRulers:
11464 0 : mi->ti.checked = cv->showrulers;
11465 0 : break;
11466 : case MID_Fill:
11467 0 : mi->ti.checked = cv->showfilled;
11468 0 : break;
11469 : case MID_ShowHHints:
11470 0 : mi->ti.checked = cv->showhhints;
11471 0 : mi->ti.disabled = sf->multilayer;
11472 0 : break;
11473 : case MID_ShowVHints:
11474 0 : mi->ti.checked = cv->showvhints;
11475 0 : mi->ti.disabled = sf->multilayer;
11476 0 : break;
11477 : case MID_ShowDHints:
11478 0 : mi->ti.checked = cv->showdhints;
11479 0 : mi->ti.disabled = sf->multilayer;
11480 0 : break;
11481 : case MID_ShowBlueValues:
11482 0 : mi->ti.checked = cv->showblues;
11483 0 : mi->ti.disabled = sf->multilayer;
11484 0 : break;
11485 : case MID_ShowFamilyBlues:
11486 0 : mi->ti.checked = cv->showfamilyblues;
11487 0 : mi->ti.disabled = sf->multilayer;
11488 0 : break;
11489 : case MID_ShowAnchors:
11490 0 : mi->ti.checked = cv->showanchor;
11491 0 : mi->ti.disabled = sf->multilayer;
11492 0 : break;
11493 : case MID_ShowHMetrics:
11494 0 : mi->ti.checked = cv->showhmetrics;
11495 0 : break;
11496 : case MID_ShowVMetrics:
11497 0 : mi->ti.checked = cv->showvmetrics;
11498 0 : mi->ti.disabled = !sf->hasvmetrics;
11499 0 : break;
11500 : case MID_ShowDebugChanges:
11501 0 : mi->ti.checked = cv->showdebugchanges;
11502 0 : break;
11503 : case MID_SnapOutlines:
11504 : #ifndef _NO_LIBCAIRO
11505 0 : if ( GDrawHasCairo(cv->v)&gc_alpha ) {
11506 0 : mi->ti.checked = cv->snapoutlines;
11507 0 : mi->ti.disabled = false;
11508 : } else
11509 : #endif
11510 : {
11511 0 : mi->ti.checked = true;
11512 0 : mi->ti.disabled = true;
11513 : }
11514 0 : break;
11515 : }
11516 : }
11517 0 : }
11518 :
11519 0 : static void cv_vwlistcheck(CharView *cv, struct gmenuitem *mi) {
11520 : int pos, gid;
11521 0 : SplineFont *sf = cv->b.sc->parent;
11522 0 : EncMap *map = cv->b.fv->map;
11523 :
11524 0 : for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
11525 0 : switch ( mi->mid ) {
11526 : case MID_NextDef:
11527 0 : if ( cv->b.container==NULL ) {
11528 0 : for ( pos = CVCurEnc(cv)+1; pos<map->enccount && ((gid=map->map[pos])==-1 || !SCWorthOutputting(sf->glyphs[gid])); ++pos );
11529 0 : mi->ti.disabled = pos==map->enccount;
11530 : } else
11531 0 : mi->ti.disabled = !(cv->b.container->funcs->canNavigate)(cv->b.container,nt_nextdef);
11532 0 : break;
11533 : case MID_PrevDef:
11534 0 : if ( cv->b.container==NULL ) {
11535 0 : for ( pos = CVCurEnc(cv)-1; pos>=0 && ((gid=map->map[pos])==-1 || !SCWorthOutputting(sf->glyphs[gid])); --pos );
11536 0 : mi->ti.disabled = pos<0 || cv->b.container!=NULL;
11537 : } else
11538 0 : mi->ti.disabled = !(cv->b.container->funcs->canNavigate)(cv->b.container,nt_nextdef);
11539 0 : break;
11540 : case MID_Next:
11541 0 : mi->ti.disabled = cv->b.container==NULL ? CVCurEnc(cv)==map->enccount-1 : !(cv->b.container->funcs->canNavigate)(cv->b.container,nt_nextdef);
11542 0 : break;
11543 : case MID_Prev:
11544 0 : mi->ti.disabled = cv->b.container==NULL ? CVCurEnc(cv)==0 : !(cv->b.container->funcs->canNavigate)(cv->b.container,nt_nextdef);
11545 0 : break;
11546 : case MID_Former:
11547 0 : if ( cv->former_cnt<=1 )
11548 0 : pos = -1;
11549 0 : else for ( pos = sf->glyphcnt-1; pos>=0 ; --pos )
11550 0 : if ( sf->glyphs[pos]!=NULL && strcmp(sf->glyphs[pos]->name,cv->former_names[1])==0 )
11551 0 : break;
11552 0 : mi->ti.disabled = pos==-1 || cv->b.container!=NULL;
11553 0 : break;
11554 : case MID_Goto:
11555 0 : mi->ti.disabled = cv->b.container!=NULL && !(cv->b.container->funcs->canNavigate)(cv->b.container,nt_goto);
11556 0 : break;
11557 : case MID_FindInFontView:
11558 0 : mi->ti.disabled = cv->b.container!=NULL;
11559 0 : break;
11560 : #if HANYANG
11561 : case MID_DisplayCompositions:
11562 : mi->ti.disabled = !cv->b.sc->compositionunit || cv->b.sc->parent->rules==NULL;
11563 : break;
11564 : #endif
11565 : }
11566 : }
11567 0 : }
11568 :
11569 0 : static void cblistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
11570 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
11571 0 : cv_cblistcheck(cv, mi);
11572 0 : }
11573 :
11574 0 : static void nplistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
11575 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
11576 0 : cv_nplistcheck(cv, mi);
11577 0 : }
11578 :
11579 0 : static void vwlistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
11580 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
11581 0 : cv_vwlistcheck(cv, mi);
11582 0 : }
11583 :
11584 0 : static void CVMenuCenter(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
11585 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
11586 : DBounds bb;
11587 : real transform[6];
11588 0 : int drawmode = cv->b.drawmode;
11589 :
11590 0 : cv->b.drawmode = dm_fore;
11591 :
11592 0 : memset(transform,0,sizeof(transform));
11593 0 : transform[0] = transform[3] = 1.0;
11594 0 : transform[1] = transform[2] = transform[5] = 0.0;
11595 0 : if ( cv->b.sc->parent->italicangle==0 )
11596 0 : SplineCharFindBounds(cv->b.sc,&bb);
11597 : else {
11598 : SplineSet *base, *temp;
11599 0 : base = LayerAllSplines(cv->b.layerheads[cv->b.drawmode]);
11600 0 : transform[2] = tan( cv->b.sc->parent->italicangle * 3.1415926535897932/180.0 );
11601 0 : temp = SplinePointListTransform(SplinePointListCopy(base),transform,tpt_AllPoints);
11602 0 : transform[2] = 0;
11603 0 : LayerUnAllSplines(cv->b.layerheads[cv->b.drawmode]);
11604 0 : SplineSetFindBounds(temp,&bb);
11605 0 : SplinePointListsFree(temp);
11606 : }
11607 :
11608 0 : if ( mi->mid==MID_Center )
11609 0 : transform[4] = (cv->b.sc->width-(bb.maxx-bb.minx))/2 - bb.minx;
11610 : else
11611 0 : transform[4] = (cv->b.sc->width-(bb.maxx-bb.minx))/3 - bb.minx;
11612 0 : if ( transform[4]!=0 ) {
11613 0 : cv->p.transany = false;
11614 0 : CVPreserveState(&cv->b);
11615 0 : CVTransFuncAllLayers(cv, transform, fvt_dontmovewidth );
11616 0 : CVCharChangedUpdate(&cv->b);
11617 : }
11618 0 : cv->b.drawmode = drawmode;
11619 0 : }
11620 :
11621 0 : static void CVMenuSetWidth(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
11622 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
11623 :
11624 0 : if ( mi->mid == MID_SetVWidth && !cv->b.sc->parent->hasvmetrics )
11625 0 : return;
11626 0 : CVSetWidth(cv,mi->mid==MID_SetWidth?wt_width:
11627 0 : mi->mid==MID_SetLBearing?wt_lbearing:
11628 0 : mi->mid==MID_SetRBearing?wt_rbearing:
11629 0 : mi->mid==MID_SetBearings?wt_bearings:
11630 : wt_vwidth);
11631 : }
11632 :
11633 0 : static void CVMenuRemoveKern(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
11634 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
11635 0 : SCRemoveKern(cv->b.sc);
11636 0 : }
11637 :
11638 0 : static void CVMenuRemoveVKern(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
11639 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
11640 0 : SCRemoveVKern(cv->b.sc);
11641 0 : }
11642 :
11643 0 : static void CVMenuKPCloseup(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
11644 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
11645 0 : KernPairD(cv->b.sc->parent,cv->b.sc,NULL,CVLayer((CharViewBase *) cv),false);
11646 0 : }
11647 :
11648 0 : static void CVMenuAnchorsAway(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
11649 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
11650 : AnchorPoint *ap;
11651 :
11652 0 : ap = mi->ti.userdata;
11653 0 : if ( ap==NULL )
11654 0 : for ( ap = cv->b.sc->anchor; ap!=NULL && !ap->selected; ap = ap->next );
11655 0 : if ( ap==NULL ) ap= cv->b.sc->anchor;
11656 0 : if ( ap==NULL )
11657 0 : return;
11658 :
11659 0 : GDrawSetCursor(cv->v,ct_watch);
11660 0 : GDrawSync(NULL);
11661 0 : GDrawProcessPendingEvents(NULL);
11662 0 : AnchorControl(cv->b.sc,ap,CVLayer((CharViewBase *) cv));
11663 0 : GDrawSetCursor(cv->v,ct_pointer);
11664 : }
11665 :
11666 : static GMenuItem2 wnmenu[] = {
11667 : { { (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 },
11668 : { { (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 },
11669 : { { (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 },
11670 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11671 : { { (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 },
11672 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11673 : GMENUITEM2_EMPTY
11674 : };
11675 :
11676 0 : static void CVWindowMenuBuild(GWindow gw, struct gmenuitem *mi, GEvent *e) {
11677 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
11678 : struct gmenuitem *wmi;
11679 :
11680 0 : WindowMenuBuild(gw,mi,e);
11681 0 : for ( wmi = mi->sub; wmi->ti.text!=NULL || wmi->ti.line ; ++wmi ) {
11682 0 : switch ( wmi->mid ) {
11683 : case MID_OpenBitmap:
11684 0 : wmi->ti.disabled = cv->b.sc->parent->bitmaps==NULL;
11685 0 : break;
11686 : case MID_Warnings:
11687 0 : wmi->ti.disabled = ErrorWindowExists();
11688 0 : break;
11689 : }
11690 : }
11691 0 : if ( cv->b.container!=NULL ) {
11692 0 : int canopen = (cv->b.container->funcs->canOpen)(cv->b.container);
11693 0 : if ( !canopen ) {
11694 0 : for ( wmi = mi->sub; wmi->ti.text!=NULL || wmi->ti.line ; ++wmi ) {
11695 0 : wmi->ti.disabled = true;
11696 : }
11697 : }
11698 : }
11699 0 : }
11700 :
11701 : static GMenuItem2 dummyitem[] = {
11702 : { { (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 },
11703 : GMENUITEM2_EMPTY
11704 : };
11705 : static GMenuItem2 fllist[] = {
11706 : { { (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 },
11707 : { { (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 },
11708 : { { (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 },
11709 : { { (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 },
11710 : { { (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 },
11711 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11712 : { { (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 },
11713 : { { (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 },
11714 : { { (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 },
11715 : { { (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 },
11716 : { { (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 },
11717 : { { (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 },
11718 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11719 : { { (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 },
11720 : { { (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 },
11721 : { { (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 },
11722 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11723 : { { (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 },
11724 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11725 : { { (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 },
11726 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11727 : #if !defined(_NO_PYTHON)
11728 : { { (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 },
11729 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11730 : #endif
11731 : { { (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 },
11732 : { { (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 },
11733 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11734 : { { (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 },
11735 : GMENUITEM2_EMPTY
11736 : };
11737 :
11738 : static GMenuItem2 sllist[] = {
11739 : { { (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 },
11740 : { { (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 },
11741 : { { (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 },
11742 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11743 : { { (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 },
11744 : { { (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 },
11745 : { { (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 },
11746 : { { (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 },
11747 : { { (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 },
11748 : { { (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 },
11749 : { { (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 },
11750 : { { (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 },
11751 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11752 : { { (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 },
11753 : { { (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 },
11754 : { { (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 },
11755 : { { (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 },
11756 : { { (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 },
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_("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 },
11759 : GMENUITEM2_EMPTY
11760 : };
11761 :
11762 : static GMenuItem2 edlist[] = {
11763 : { { (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 },
11764 : { { (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 },
11765 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11766 : { { (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 },
11767 : { { (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 },
11768 : { { (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 },
11769 : { { (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 },
11770 : { { (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 },
11771 : { { (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 },
11772 : { { (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 },
11773 : { { (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 },
11774 : { { (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 },
11775 : { { (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 },
11776 : { { (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 },
11777 : { { (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 },
11778 : /*{ { (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 },*/
11779 : { { (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 },
11780 : { { (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 },
11781 : { { (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 },
11782 : { { (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 },
11783 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11784 : { { (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 },
11785 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11786 : { { (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 },
11787 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11788 : { { (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 },
11789 : GMENUITEM2_EMPTY
11790 : };
11791 :
11792 : static GMenuItem2 ptlist[] = {
11793 : { { (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 },
11794 : { { (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 },
11795 : { { (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 },
11796 : { { (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 },
11797 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11798 : /* GT: Make this (selected) point the first point in the glyph */
11799 : { { (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 },
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_("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 },
11802 : { { (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 },
11803 : { { (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 },
11804 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11805 : { { (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 },
11806 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11807 : { { (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 },
11808 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11809 : { { (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 },
11810 : { { (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 },
11811 : { { (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 },
11812 : { { (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 },
11813 : { { (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 },
11814 : { { (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 },
11815 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11816 : { { (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 },
11817 : GMENUITEM2_EMPTY
11818 : };
11819 :
11820 : static GMenuItem2 spiroptlist[] = {
11821 : { { (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 },
11822 : { { (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 },
11823 : { { (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 },
11824 : { { (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_("Prev Constraint|No Shortcut"), NULL, NULL, CVMenuPointType, MID_SpiroLeft },
11825 : { { (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_("Next Constraint|No Shortcut"), NULL, NULL, CVMenuPointType, MID_SpiroRight },
11826 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11827 : /* GT: Make this (selected) point the first point in the glyph */
11828 : { { (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 },
11829 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11830 : { { (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 },
11831 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11832 : { { (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 },
11833 : { { (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 },
11834 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11835 : { { (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 },
11836 : GMENUITEM2_EMPTY
11837 : };
11838 :
11839 : static GMenuItem2 allist[] = {
11840 : /* GT: Align these points to their average position */
11841 : { { (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 },
11842 : { { (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 },
11843 : { { (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 },
11844 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11845 : { { (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 },
11846 : GMENUITEM2_EMPTY
11847 : };
11848 :
11849 : static GMenuItem2 smlist[] = {
11850 : { { (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 },
11851 : { { (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 },
11852 : { { (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 },
11853 : { { (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 },
11854 : { { (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 },
11855 : GMENUITEM2_EMPTY
11856 : };
11857 :
11858 0 : static void smlistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
11859 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
11860 :
11861 0 : for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
11862 0 : switch ( mi->mid ) {
11863 : case MID_Simplify:
11864 : case MID_CleanupGlyph:
11865 : case MID_SimplifyMore:
11866 0 : mi->ti.disabled = cv->b.layerheads[cv->b.drawmode]->splines==NULL;
11867 0 : break;
11868 : case MID_CanonicalStart:
11869 0 : mi->ti.disabled = cv->b.layerheads[cv->b.drawmode]->splines==NULL ||
11870 0 : (cv->b.sc->inspiro && hasspiro());
11871 0 : break;
11872 : case MID_CanonicalContours:
11873 0 : mi->ti.disabled = cv->b.layerheads[cv->b.drawmode]->splines==NULL ||
11874 0 : cv->b.layerheads[cv->b.drawmode]->splines->next==NULL ||
11875 0 : cv->b.drawmode!=dm_fore;
11876 0 : break;
11877 : }
11878 : }
11879 0 : }
11880 :
11881 : static GMenuItem2 orlist[] = {
11882 : { { (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 },
11883 : { { (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 },
11884 : { { (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 },
11885 : { { (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 },
11886 : GMENUITEM2_EMPTY
11887 : };
11888 :
11889 0 : static void orlistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
11890 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
11891 : SplinePointList *spl;
11892 : RefChar *r;
11893 : ImageList *im;
11894 0 : int exactlyone = CVOneContourSel(cv,&spl,&r,&im);
11895 : int isfirst, islast;
11896 :
11897 0 : isfirst = islast = false;
11898 0 : if ( spl!=NULL ) {
11899 0 : isfirst = cv->b.layerheads[cv->b.drawmode]->splines==spl;
11900 0 : islast = spl->next==NULL;
11901 0 : } else if ( r!=NULL ) {
11902 0 : isfirst = cv->b.layerheads[cv->b.drawmode]->refs==r;
11903 0 : islast = r->next==NULL;
11904 0 : } else if ( im!=NULL ) {
11905 0 : isfirst = cv->b.layerheads[cv->b.drawmode]->images==im;
11906 0 : islast = im->next==NULL;
11907 : }
11908 :
11909 0 : for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
11910 0 : switch ( mi->mid ) {
11911 : case MID_First:
11912 : case MID_Earlier:
11913 0 : mi->ti.disabled = !exactlyone || isfirst;
11914 0 : break;
11915 : case MID_Last:
11916 : case MID_Later:
11917 0 : mi->ti.disabled = !exactlyone || islast;
11918 0 : break;
11919 : }
11920 : }
11921 0 : }
11922 :
11923 : static GMenuItem2 rmlist[] = {
11924 : { { (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 },
11925 : { { (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 },
11926 : { { (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 },
11927 : { { (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 },
11928 : GMENUITEM2_EMPTY
11929 : };
11930 :
11931 : static GMenuItem2 eflist[] = {
11932 : { { (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 },
11933 : { { (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 },
11934 : { { (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 },
11935 : { { (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...|No Shortcut"), NULL, NULL, CVMenuCondense, MID_Condense },
11936 : { { (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 XHeight...|No Shortcut"), NULL, NULL, CVMenuChangeXHeight, MID_ChangeXHeight },
11937 : { { (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 },
11938 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11939 : { { (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 },
11940 : { { (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 },
11941 : { { (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 },
11942 : { { (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 },
11943 : GMENUITEM2_EMPTY
11944 : };
11945 :
11946 : static GMenuItem2 balist[] = {
11947 : { { (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 },
11948 : { { (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 },
11949 : GMENUITEM2_EMPTY
11950 : };
11951 :
11952 : static GMenuItem2 delist[] = {
11953 : { { (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 },
11954 : { { (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 },
11955 : GMENUITEM2_EMPTY
11956 : };
11957 :
11958 : static GMenuItem2 trlist[] = {
11959 : { { (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 },
11960 : { { (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 },
11961 : { { (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 },
11962 : GMENUITEM2_EMPTY
11963 : };
11964 :
11965 : static GMenuItem2 rndlist[] = {
11966 : { { (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 },
11967 : { { (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 },
11968 : { { (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 },
11969 : GMENUITEM2_EMPTY
11970 : };
11971 :
11972 : static GMenuItem2 ellist[] = {
11973 : { { (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 },
11974 : { { (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 },
11975 : { { (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 },
11976 : { { (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 },
11977 : { { (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 },
11978 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11979 : { { (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 },
11980 : { { (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 },
11981 : { { (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 },
11982 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11983 : { { (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 },
11984 : { { (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 },
11985 : { { (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 },
11986 : #ifdef FONTFORGE_CONFIG_TILEPATH
11987 : { { (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 },
11988 : { { (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 },
11989 : #endif
11990 : { { (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 },
11991 : { { (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 },
11992 : { { (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 },
11993 : { { (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 },
11994 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11995 : { { (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 },
11996 : { { (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 },
11997 : { { (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 },
11998 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
11999 : { { (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_("Clockwise|No Shortcut"), NULL, NULL, CVMenuCheckSelf, MID_CheckSelf },
12000 : { { (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_("Clockwise|No Shortcut"), NULL, NULL, CVMenuGlyphSelfIntersects, MID_GlyphSelfIntersects },
12001 : { { (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 },
12002 : { { (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 },
12003 : { { (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 },
12004 : { { (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 },
12005 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
12006 : { { (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 },
12007 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
12008 : { { (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 },
12009 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
12010 : { { (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 },
12011 : GMENUITEM2_EMPTY
12012 : };
12013 :
12014 : static GMenuItem2 htlist[] = {
12015 : { { (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 },
12016 : { { (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 },
12017 : { { (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 },
12018 : { { (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 },
12019 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
12020 : { { (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 },
12021 : { { (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 },
12022 : { { (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 },
12023 : { { (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 },
12024 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
12025 : { { (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 },
12026 : { { (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 },
12027 : { { (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 },
12028 : { { (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 },
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_("_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 },
12031 : { { (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 },
12032 : { { (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 },
12033 : { { (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 },
12034 : { { (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 },
12035 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
12036 : { { (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 },
12037 : GMENUITEM2_EMPTY
12038 : };
12039 :
12040 : static GMenuItem2 ap2list[] = {
12041 : GMENUITEM2_EMPTY
12042 : };
12043 :
12044 0 : static void ap2listbuild(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
12045 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
12046 : char buf[300];
12047 : GMenuItem *sub;
12048 : int k, cnt;
12049 : AnchorPoint *ap;
12050 :
12051 0 : if ( mi->sub!=NULL ) {
12052 0 : GMenuItemArrayFree(mi->sub);
12053 0 : mi->sub = NULL;
12054 : }
12055 :
12056 0 : for ( k=0; k<2; ++k ) {
12057 0 : cnt = 0;
12058 0 : for ( ap=cv->b.sc->anchor; ap!=NULL; ap=ap->next ) {
12059 0 : if ( k ) {
12060 0 : if ( ap->type==at_baselig )
12061 : /* GT: In the next few lines the "%s" is the name of an anchor class, and the */
12062 : /* GT: rest of the string identifies the type of the anchor */
12063 0 : snprintf(buf,sizeof(buf), _("%s at ligature pos %d"), ap->anchor->name, ap->lig_index );
12064 : else
12065 0 : snprintf(buf,sizeof(buf),
12066 0 : ap->type==at_cexit ? _("%s exit"):
12067 0 : ap->type==at_centry ? _("%s entry"):
12068 0 : ap->type==at_mark ? _("%s mark"):
12069 0 : _("%s base"),ap->anchor->name );
12070 0 : sub[cnt].ti.text = utf82u_copy(buf);
12071 0 : sub[cnt].ti.userdata = ap;
12072 0 : sub[cnt].ti.bg = sub[cnt].ti.fg = COLOR_DEFAULT;
12073 0 : sub[cnt].invoke = CVMenuAnchorsAway;
12074 : }
12075 0 : ++cnt;
12076 : }
12077 0 : if ( !k )
12078 0 : sub = calloc(cnt+1,sizeof(GMenuItem));
12079 : }
12080 0 : mi->sub = sub;
12081 0 : }
12082 :
12083 0 : static void CVMenuKernByClasses(GWindow gw,struct gmenuitem *mi,GEvent *e) {
12084 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
12085 0 : MetricsView *mv = 0;
12086 0 : SplineFont *sf = cv->b.sc->parent;
12087 0 : int cvlayer = CVLayer((CharViewBase *) cv);
12088 0 : ShowKernClasses(sf, mv, cvlayer, false);
12089 0 : }
12090 :
12091 0 : static void CVMenuVKernByClasses(GWindow gw,struct gmenuitem *mi,GEvent *e) {
12092 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
12093 0 : MetricsView *mv = 0;
12094 0 : SplineFont *sf = cv->b.sc->parent;
12095 0 : int cvlayer = CVLayer((CharViewBase *) cv);
12096 0 : ShowKernClasses(sf, mv, cvlayer, true);
12097 0 : }
12098 :
12099 0 : static void CVMenuVKernFromHKern(GWindow gw,struct gmenuitem *mi,GEvent *e) {
12100 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
12101 0 : FVVKernFromHKern((FontViewBase *) cv->b.fv);
12102 0 : }
12103 :
12104 : static GMenuItem2 mtlist[] = {
12105 : { { (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 },
12106 : GMENUITEM2_LINE,
12107 : { { (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 },
12108 : { { (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 },
12109 : { { (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 },
12110 : { { (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 },
12111 : { { (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 },
12112 : { { (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 },
12113 : GMENUITEM2_LINE,
12114 : { { (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 },
12115 : GMENUITEM2_LINE,
12116 : { { (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 },
12117 : { { (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 },
12118 : { { (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 },
12119 : { { (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 },
12120 : { { (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 },
12121 : { { (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 },
12122 : GMENUITEM2_EMPTY
12123 : };
12124 :
12125 : static GMenuItem2 pllist[] = {
12126 : { { (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 },
12127 : { { (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 },
12128 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
12129 : { { (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 },
12130 : GMENUITEM2_EMPTY
12131 : };
12132 :
12133 : static GMenuItem2 aplist[] = {
12134 : { { (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 },
12135 : GMENUITEM2_EMPTY
12136 : };
12137 :
12138 0 : static void aplistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
12139 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
12140 0 : SplineChar *sc = cv->b.sc, **glyphs;
12141 0 : SplineFont *sf = sc->parent;
12142 : AnchorPoint *ap, *found;
12143 : GMenuItem2 *mit;
12144 : int cnt;
12145 :
12146 0 : found = NULL;
12147 0 : for ( ap=sc->anchor; ap!=NULL; ap=ap->next ) {
12148 0 : if ( ap->selected ) {
12149 0 : if ( found==NULL )
12150 0 : found = ap;
12151 : else {
12152 : /* Can't deal with two selected anchors */
12153 0 : found = NULL;
12154 0 : break;
12155 : }
12156 : }
12157 : }
12158 :
12159 0 : GMenuItemArrayFree(mi->sub);
12160 0 : if ( found==NULL )
12161 0 : glyphs = NULL;
12162 : else
12163 0 : glyphs = GlyphsMatchingAP(sf,found);
12164 0 : if ( glyphs==NULL ) {
12165 0 : mi->sub = GMenuItem2ArrayCopy(aplist,NULL);
12166 0 : mi->sub->ti.disabled = (cv->apmine==NULL);
12167 0 : return;
12168 : }
12169 :
12170 0 : for ( cnt = 0; glyphs[cnt]!=NULL; ++cnt );
12171 0 : mit = calloc(cnt+2,sizeof(GMenuItem2));
12172 0 : mit[0] = aplist[0];
12173 0 : mit[0].ti.text = (unichar_t *) copy( (char *) mit[0].ti.text );
12174 0 : mit[0].ti.disabled = (cv->apmine==NULL);
12175 0 : for ( cnt = 0; glyphs[cnt]!=NULL; ++cnt ) {
12176 0 : mit[cnt+1].ti.text = (unichar_t *) copy(glyphs[cnt]->name);
12177 0 : mit[cnt+1].ti.text_is_1byte = true;
12178 0 : mit[cnt+1].ti.fg = mit[cnt+1].ti.bg = COLOR_DEFAULT;
12179 0 : mit[cnt+1].ti.userdata = glyphs[cnt];
12180 0 : mit[cnt+1].invoke = CVMenuAPAttachSC;
12181 0 : if ( glyphs[cnt]==cv->apsc )
12182 0 : mit[cnt+1].ti.checked = mit[cnt+1].ti.checkable = true;
12183 : }
12184 0 : free(glyphs);
12185 0 : mi->sub = GMenuItem2ArrayCopy(mit,NULL);
12186 0 : GMenuItem2ArrayFree(mit);
12187 : }
12188 :
12189 0 : static void CVMoveInWordListByOffset( CharView* cv, int offset )
12190 : {
12191 0 : Wordlist_MoveByOffset( cv->charselector, &cv->charselectoridx, offset );
12192 0 : }
12193 :
12194 0 : static void CVMenuNextLineInWordList(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
12195 0 : CharView* cv = (CharView*) GDrawGetUserData(gw);
12196 0 : CVMoveInWordListByOffset( cv, 1 );
12197 0 : }
12198 0 : static void CVMenuPrevLineInWordList(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
12199 0 : CharView* cv = (CharView*) GDrawGetUserData(gw);
12200 0 : CVMoveInWordListByOffset( cv, -1 );
12201 0 : }
12202 :
12203 : static GMenuItem2 cblist[] = {
12204 : { { (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 },
12205 : { { (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 },
12206 : { { (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 },
12207 : { { (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 },
12208 : { { (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 },
12209 : GMENUITEM2_EMPTY
12210 : };
12211 :
12212 : static GMenuItem2 nplist[] = {
12213 : { { (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 },
12214 : { { (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 },
12215 : { { (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 },
12216 : { { (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 },
12217 : { { (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 },
12218 : GMENUITEM2_EMPTY
12219 : };
12220 :
12221 : static GMenuItem2 gflist[] = {
12222 : { { (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 },
12223 : { { (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 },
12224 : { { (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 },
12225 : { { (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 },
12226 : { { (unichar_t *) N_("_Anti Alias"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'L' }, H_("Grid Fit Anti Alias|No Shortcut"), NULL, NULL, CVMenuChangePointSize, MID_GridFitAA },
12227 : { { (unichar_t *) N_("_Off"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'S' }, H_("Grid Fit Off|No Shortcut"), NULL, NULL, CVMenuChangePointSize, MID_GridFitOff },
12228 : GMENUITEM2_EMPTY
12229 : };
12230 :
12231 : static GMenuItem2 swlist[] = {
12232 : { { (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 },
12233 : { { (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 },
12234 : { { (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 },
12235 : { { (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 },
12236 : { { (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 },
12237 : { { (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 },
12238 : { { (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 },
12239 : { { (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 },
12240 : { { (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 },
12241 : { { (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 },
12242 : { { (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 },
12243 : { { (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 },
12244 : { { (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 },
12245 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
12246 : { { (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 },
12247 : { { (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 },
12248 : { { (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 },
12249 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
12250 : { { (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 },
12251 : { { (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 },
12252 : { { (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 },
12253 : /* GT: You might not want to translate this, it's a keyword in PostScript font files */
12254 : { { (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 },
12255 : /* GT: You might not want to translate this, it's a keyword in PostScript font files */
12256 : { { (unichar_t *) N_("FamilyBl_ues"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'R' }, H_("Family Blues|No Shortcut"), NULL, NULL, CVMenuShowHints, MID_ShowFamilyBlues },
12257 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
12258 : { { (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 },
12259 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
12260 : { { (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 },
12261 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
12262 : { { (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_("Hori_zontal Metric Lines|No Shortcut"), NULL, NULL, CVMenuShowHints, MID_ShowHMetrics },
12263 : { { (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 },
12264 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
12265 : { { (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 },
12266 : GMENUITEM2_EMPTY
12267 : };
12268 :
12269 : static GMenuItem2 vwlist[] = {
12270 : { { (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 },
12271 : { { (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 },
12272 : { { (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 },
12273 : #if HANYANG
12274 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
12275 : { { (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 },
12276 : #endif
12277 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
12278 : { { (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 },
12279 : { { (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 },
12280 : { { (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 },
12281 : { { (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 },
12282 : { { (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 },
12283 : { { (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 },
12284 : { { (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 },
12285 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
12286 : { { (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 },
12287 : { { (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 },
12288 : { { (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 },
12289 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
12290 : { { (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 },
12291 : GMENUITEM2_LINE,
12292 : { { (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 },
12293 : { { (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 },
12294 : GMENUITEM2_EMPTY
12295 : };
12296 :
12297 0 : static void CVMenuShowMMMask(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
12298 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
12299 0 : uint32 changemask = (uint32) (intpt) mi->ti.userdata;
12300 : /* Change which mms get displayed in the "background" */
12301 :
12302 0 : if ( mi->mid==MID_MMAll ) {
12303 0 : if ( (cv->mmvisible&changemask)==changemask ) cv->mmvisible = 0;
12304 0 : else cv->mmvisible = changemask;
12305 0 : } else if ( mi->mid == MID_MMNone ) {
12306 0 : if ( cv->mmvisible==0 ) cv->mmvisible = (1<<(cv->b.sc->parent->mm->instance_count+1))-1;
12307 0 : else cv->mmvisible = 0;
12308 : } else
12309 0 : cv->mmvisible ^= changemask;
12310 0 : GDrawRequestExpose(cv->v,NULL,false);
12311 0 : }
12312 :
12313 : static GMenuItem2 mvlist[] = {
12314 : { { (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 },
12315 : { { (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 },
12316 : GMENUITEM2_EMPTY
12317 : };
12318 :
12319 0 : static void mvlistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
12320 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
12321 : int i, base, j;
12322 0 : MMSet *mm = cv->b.sc->parent->mm;
12323 : uint32 submask;
12324 : SplineFont *sub;
12325 : GMenuItem2 *mml;
12326 :
12327 0 : base = 3;
12328 0 : if ( mm==NULL )
12329 0 : mml = mvlist;
12330 : else {
12331 0 : mml = calloc(base+mm->instance_count+2,sizeof(GMenuItem2));
12332 0 : memcpy(mml,mvlist,sizeof(mvlist));
12333 0 : mml[base-1].ti.fg = mml[base-1].ti.bg = COLOR_DEFAULT;
12334 0 : mml[base-1].ti.line = true;
12335 0 : submask = 0;
12336 0 : for ( j = 0, i=base; j<mm->instance_count+1; ++i, ++j ) {
12337 0 : if ( j==0 )
12338 0 : sub = mm->normal;
12339 : else
12340 0 : sub = mm->instances[j-1];
12341 0 : mml[i].ti.text = uc_copy(sub->fontname);
12342 0 : mml[i].ti.checkable = true;
12343 0 : mml[i].ti.checked = (cv->mmvisible & (1<<j))?1:0;
12344 0 : mml[i].ti.userdata = (void *) (intpt) (1<<j);
12345 0 : mml[i].invoke = CVMenuShowMMMask;
12346 0 : mml[i].ti.fg = mml[i].ti.bg = COLOR_DEFAULT;
12347 0 : if ( sub==cv->b.sc->parent )
12348 0 : submask = (1<<j);
12349 : }
12350 : /* All */
12351 0 : mml[0].ti.userdata = (void *) (intpt) ((1<<j)-1);
12352 0 : mml[0].ti.checked = (cv->mmvisible == (uint32) (intpt) mml[0].ti.userdata);
12353 : /* None */
12354 0 : mml[1].ti.checked = (cv->mmvisible == 0 || cv->mmvisible == submask);
12355 : }
12356 0 : GMenuItemArrayFree(mi->sub);
12357 0 : mi->sub = GMenuItem2ArrayCopy(mml,NULL);
12358 0 : if ( mml!=mvlist ) {
12359 0 : for ( i=base; mml[i].ti.text!=NULL; ++i )
12360 0 : free( mml[i].ti.text);
12361 0 : free(mml);
12362 : }
12363 0 : }
12364 :
12365 0 : static void CVMenuReblend(GWindow gw, struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
12366 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
12367 : char *err;
12368 0 : MMSet *mm = cv->b.sc->parent->mm;
12369 :
12370 0 : if ( mm==NULL || mm->apple || cv->b.sc->parent!=mm->normal )
12371 0 : return;
12372 0 : err = MMBlendChar(mm,cv->b.sc->orig_pos);
12373 0 : if ( mm->normal->glyphs[cv->b.sc->orig_pos]!=NULL )
12374 0 : _SCCharChangedUpdate(mm->normal->glyphs[cv->b.sc->orig_pos],CVLayer((CharViewBase *)cv->b.sc),-1);
12375 0 : if ( err!=0 )
12376 0 : ff_post_error(_("Bad Multiple Master Font"),err);
12377 : }
12378 :
12379 : static GMenuItem2 mmlist[] = {
12380 : /* GT: Here (and following) MM means "MultiMaster" */
12381 : { { (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 },
12382 : { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
12383 : { { (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 },
12384 : GMENUITEM2_EMPTY
12385 : };
12386 :
12387 0 : static void CVMenuShowSubChar(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
12388 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
12389 0 : SplineFont *new = mi->ti.userdata;
12390 : /* Change to the same char in a different instance font of the mm */
12391 :
12392 0 : CVChangeSC(cv,SFMakeChar(new,cv->b.fv->map,CVCurEnc(cv)));
12393 0 : cv->b.layerheads[dm_grid] = &new->grid;
12394 0 : }
12395 :
12396 0 : static void mmlistcheck(GWindow gw, struct gmenuitem *mi, GEvent *UNUSED(e)) {
12397 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
12398 : int i, base, j;
12399 0 : MMSet *mm = cv->b.sc->parent->mm;
12400 : SplineFont *sub;
12401 : GMenuItem2 *mml;
12402 :
12403 0 : base = sizeof(mmlist)/sizeof(mmlist[0]);
12404 0 : if ( mm==NULL )
12405 0 : mml = mmlist;
12406 : else {
12407 0 : mml = calloc(base+mm->instance_count+2,sizeof(GMenuItem2));
12408 0 : memcpy(mml,mmlist,sizeof(mmlist));
12409 0 : mml[base-1].ti.fg = mml[base-1].ti.bg = COLOR_DEFAULT;
12410 0 : mml[base-1].ti.line = true;
12411 0 : for ( j = 0, i=base; j<mm->instance_count+1; ++i, ++j ) {
12412 0 : if ( j==0 )
12413 0 : sub = mm->normal;
12414 : else
12415 0 : sub = mm->instances[j-1];
12416 0 : mml[i].ti.text = uc_copy(sub->fontname);
12417 0 : mml[i].ti.checkable = true;
12418 0 : mml[i].ti.checked = sub==cv->b.sc->parent;
12419 0 : mml[i].ti.userdata = sub;
12420 0 : mml[i].invoke = CVMenuShowSubChar;
12421 0 : mml[i].ti.fg = mml[i].ti.bg = COLOR_DEFAULT;
12422 : }
12423 : }
12424 0 : mml[0].ti.disabled = (mm==NULL || cv->b.sc->parent!=mm->normal || mm->apple);
12425 0 : GMenuItemArrayFree(mi->sub);
12426 0 : mi->sub = GMenuItem2ArrayCopy(mml,NULL);
12427 0 : if ( mml!=mmlist ) {
12428 0 : for ( i=base; mml[i].ti.text!=NULL; ++i )
12429 0 : free( mml[i].ti.text);
12430 0 : free(mml);
12431 : }
12432 0 : }
12433 :
12434 0 : static void CVMenuContextualHelp(GWindow UNUSED(gw), struct gmenuitem *UNUSED(mi), GEvent *UNUSED(e)) {
12435 0 : help("charview.html");
12436 0 : }
12437 :
12438 : static GMenuItem2 mblist[] = {
12439 : { { (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 },
12440 : { { (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 },
12441 : { { (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 },
12442 : { { (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 },
12443 : #ifndef _NO_PYTHON
12444 : { { (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 },
12445 : #endif
12446 : #ifdef NATIVE_CALLBACKS
12447 : { { (unichar_t *) N_("Tools_2"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 'l' }, H_("Tools 2|No Shortcut"), NULL, cv_tl2listcheck, NULL, 0},
12448 : #endif
12449 : { { (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 },
12450 : { { (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 },
12451 : { { (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 },
12452 : /* GT: Here (and following) MM means "MultiMaster" */
12453 : { { (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 },
12454 : { { (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 },
12455 : { { (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 },
12456 : GMENUITEM2_EMPTY
12457 : };
12458 :
12459 : static GMenuItem2 mblist_nomm[] = {
12460 : { { (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 },
12461 : { { (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 },
12462 : { { (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 },
12463 : { { (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 },
12464 : #ifndef _NO_PYTHON
12465 : { { (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 },
12466 : #endif
12467 : #ifdef NATIVE_CALLBACKS
12468 : { { (unichar_t *) N_("Tools_2"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 1, 0, 0, 0, 0, 0, 1, 1, 0, 'l' }, H_("Tools 2|No Shortcut"), NULL, cv_tl2listcheck, NULL, 0},
12469 : #endif
12470 : { { (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 },
12471 : { { (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 },
12472 : { { (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 },
12473 : { { (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 },
12474 : { { (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 },
12475 : GMENUITEM2_EMPTY
12476 : };
12477 :
12478 0 : static void _CharViewCreate(CharView *cv, SplineChar *sc, FontView *fv,int enc,int show) {
12479 : GRect pos;
12480 : GWindowAttrs wattrs;
12481 : GGadgetData gd;
12482 : int sbsize;
12483 : FontRequest rq;
12484 : int as, ds, ld;
12485 : extern int updateflex;
12486 : static char *infofamily=NULL;
12487 : GTextBounds textbounds;
12488 : /* extern int cv_auto_goto; */
12489 : extern enum cvtools cv_b1_tool, cv_cb1_tool, cv_b2_tool, cv_cb2_tool;
12490 :
12491 0 : if ( !cvcolsinited )
12492 0 : CVColInit();
12493 :
12494 : static int firstCharView = 1;
12495 0 : if( firstCharView )
12496 : {
12497 0 : firstCharView = 0;
12498 0 : CVShows.alwaysshowcontrolpoints = prefs_cv_show_control_points_always_initially;
12499 : }
12500 :
12501 0 : cv->b.sc = sc;
12502 0 : cv->scale = .5;
12503 0 : cv->xoff = cv->yoff = 20;
12504 0 : cv->b.next = sc->views;
12505 0 : sc->views = &cv->b;
12506 0 : cv->b.fv = &fv->b;
12507 0 : cv->map_of_enc = fv->b.map;
12508 0 : cv->enc = enc;
12509 0 : cv->p.pretransform_spl = 0;
12510 0 : cv->b.drawmode = dm_fore;
12511 :
12512 0 : memset(cv->showback,-1,sizeof(cv->showback));
12513 0 : if ( !CVShows.showback )
12514 0 : cv->showback[0] &= ~1;
12515 0 : cv->showfore = CVShows.showfore;
12516 0 : cv->showgrids = CVShows.showgrids;
12517 0 : cv->showhhints = CVShows.showhhints;
12518 0 : cv->showvhints = CVShows.showvhints;
12519 0 : cv->showdhints = CVShows.showdhints;
12520 0 : cv->showpoints = CVShows.showpoints;
12521 0 : cv->alwaysshowcontrolpoints = CVShows.alwaysshowcontrolpoints;
12522 0 : cv->showrulers = CVShows.showrulers;
12523 0 : cv->showfilled = CVShows.showfilled;
12524 0 : cv->showrounds = CVShows.showrounds;
12525 0 : cv->showmdx = CVShows.showmdx;
12526 0 : cv->showmdy = CVShows.showmdy;
12527 0 : cv->showhmetrics = CVShows.showhmetrics;
12528 0 : cv->showvmetrics = CVShows.showvmetrics;
12529 0 : cv->markextrema = CVShows.markextrema;
12530 0 : cv->showsidebearings = CVShows.showsidebearings;
12531 0 : cv->showrefnames = CVShows.showrefnames;
12532 0 : cv->snapoutlines = CVShows.snapoutlines;
12533 0 : cv->markpoi = CVShows.markpoi;
12534 0 : cv->showalmosthvlines = CVShows.showalmosthvlines;
12535 0 : cv->showalmosthvcurves = CVShows.showalmosthvcurves;
12536 0 : cv->hvoffset = CVShows.hvoffset;
12537 0 : cv->showblues = CVShows.showblues;
12538 0 : cv->showfamilyblues = CVShows.showfamilyblues;
12539 0 : cv->showanchor = CVShows.showanchor;
12540 0 : cv->showcpinfo = CVShows.showcpinfo;
12541 0 : cv->showtabs = CVShows.showtabs;
12542 0 : cv->inPreviewMode = 0;
12543 0 : cv->checkselfintersects = CVShows.checkselfintersects;
12544 :
12545 0 : cv->showdebugchanges = CVShows.showdebugchanges;
12546 :
12547 0 : cv->infoh = 13;
12548 : #if defined(__MINGW32__)||defined(__CYGWIN__)
12549 : cv->infoh = 26;
12550 : #endif
12551 0 : cv->rulerh = 16;
12552 :
12553 0 : GDrawGetSize(cv->gw,&pos);
12554 0 : memset(&gd,0,sizeof(gd));
12555 0 : gd.pos.y = cv->mbh+cv->charselectorh+cv->infoh;
12556 0 : gd.pos.width = sbsize = GDrawPointsToPixels(cv->gw,_GScrollBar_Width);
12557 0 : gd.pos.height = pos.height-cv->mbh-cv->charselectorh-cv->infoh - sbsize;
12558 0 : gd.pos.x = pos.width-sbsize;
12559 0 : gd.flags = gg_visible|gg_enabled|gg_pos_in_pixels|gg_sb_vert;
12560 0 : cv->vsb = GScrollBarCreate(cv->gw,&gd,cv);
12561 :
12562 0 : gd.pos.y = pos.height-sbsize; gd.pos.height = sbsize;
12563 0 : gd.pos.width = pos.width - sbsize;
12564 0 : gd.pos.x = 0;
12565 0 : gd.flags = gg_visible|gg_enabled|gg_pos_in_pixels|gg_text_xim;
12566 0 : cv->hsb = GScrollBarCreate(cv->gw,&gd,cv);
12567 :
12568 0 : GDrawGetSize(cv->gw,&pos);
12569 0 : pos.y = cv->mbh+cv->charselectorh+cv->infoh; pos.height -= cv->mbh + cv->charselectorh + sbsize + cv->infoh;
12570 0 : pos.x = 0; pos.width -= sbsize;
12571 0 : if ( cv->showrulers ) {
12572 0 : pos.y += cv->rulerh; pos.height -= cv->rulerh;
12573 0 : pos.x += cv->rulerh; pos.width -= cv->rulerh;
12574 : }
12575 0 : memset(&wattrs,0,sizeof(wattrs));
12576 0 : wattrs.mask = wam_events|wam_cursor|wam_backcol;
12577 0 : wattrs.background_color = view_bgcol;
12578 0 : wattrs.event_masks = -1;
12579 0 : wattrs.cursor = ct_mypointer;
12580 0 : cv->v = GWidgetCreateSubWindow(cv->gw,&pos,v_e_h,cv,&wattrs);
12581 0 : GDrawSetWindowTypeName(cv->v, "CharView");
12582 :
12583 0 : if ( GDrawRequestDeviceEvents(cv->v,input_em_cnt,input_em)>0 ) {
12584 : /* Success! They've got a wacom tablet */
12585 : }
12586 :
12587 0 : if ( infofamily==NULL ) {
12588 0 : infofamily = copy(GResourceFindString("CharView.InfoFamily"));
12589 : /* FontConfig doesn't have access to all the X11 bitmap fonts */
12590 : /* so the font I used to use isn't found, and a huge monster is */
12591 : /* inserted instead */
12592 0 : if ( infofamily==NULL )
12593 0 : infofamily = SANS_UI_FAMILIES;
12594 : }
12595 :
12596 0 : memset(&rq,0,sizeof(rq));
12597 0 : rq.utf8_family_name = infofamily;
12598 0 : rq.point_size = GResourceFindInt("CharView.Rulers.FontSize", -10);
12599 0 : rq.weight = 400;
12600 0 : cv->small = GDrawInstanciateFont(cv->gw,&rq);
12601 0 : GDrawWindowFontMetrics(cv->gw,cv->small,&as,&ds,&ld);
12602 0 : cv->sfh = as+ds; cv->sas = as;
12603 0 : GDrawSetFont(cv->gw,cv->small);
12604 0 : GDrawGetText8Bounds(cv->gw,"0123456789",10,&textbounds);
12605 0 : cv->sdh = textbounds.as+textbounds.ds+1;
12606 0 : rq.point_size = 10;
12607 0 : cv->normal = GDrawInstanciateFont(cv->gw,&rq);
12608 0 : GDrawWindowFontMetrics(cv->gw,cv->normal,&as,&ds,&ld);
12609 0 : cv->nfh = as+ds; cv->nas = as;
12610 :
12611 0 : cv->height = pos.height; cv->width = pos.width;
12612 0 : cv->gi.u.image = calloc(1,sizeof(struct _GImage));
12613 0 : cv->gi.u.image->image_type = it_mono;
12614 0 : cv->gi.u.image->clut = calloc(1,sizeof(GClut));
12615 0 : cv->gi.u.image->clut->trans_index = cv->gi.u.image->trans = 0;
12616 0 : cv->gi.u.image->clut->clut_len = 2;
12617 0 : cv->gi.u.image->clut->clut[0] = view_bgcol;
12618 0 : cv->gi.u.image->clut->clut[1] = fillcol;
12619 0 : cv->b1_tool = cv_b1_tool; cv->cb1_tool = cv_cb1_tool;
12620 0 : cv->b1_tool_old = cv->b1_tool;
12621 0 : cv->b2_tool = cv_b2_tool; cv->cb2_tool = cv_cb2_tool;
12622 0 : cv->s1_tool = cvt_freehand; cv->s2_tool = cvt_pen;
12623 0 : cv->er_tool = cvt_knife;
12624 0 : cv->showing_tool = cvt_pointer;
12625 0 : cv->pressed_tool = cv->pressed_display = cv->active_tool = cvt_none;
12626 0 : cv->spacebar_hold = 0;
12627 0 : cv->b.layerheads[dm_fore] = &sc->layers[ly_fore];
12628 0 : cv->b.layerheads[dm_back] = &sc->layers[ly_back];
12629 0 : cv->b.layerheads[dm_grid] = &fv->b.sf->grid;
12630 0 : if ( !sc->parent->multilayer && fv->b.active_layer!=ly_fore ) {
12631 0 : cv->b.layerheads[dm_back] = &sc->layers[fv->b.active_layer];
12632 0 : cv->b.drawmode = dm_back;
12633 : }
12634 :
12635 : #if HANYANG
12636 : if ( sc->parent->rules!=NULL && sc->compositionunit )
12637 : Disp_DefaultTemplate(cv);
12638 : #endif
12639 :
12640 0 : cv->olde.x = -1;
12641 :
12642 0 : cv->ft_dpi = 72; cv->ft_pointsizex = cv->ft_pointsizey = 12.0;
12643 0 : cv->ft_ppemx = cv->ft_ppemy = 12;
12644 :
12645 : /*GWidgetHidePalettes();*/
12646 : /*cv->tools = CVMakeTools(cv);*/
12647 : /*cv->layers = CVMakeLayers(cv);*/
12648 :
12649 0 : CVFit(cv);
12650 0 : GDrawSetVisible(cv->v,true);
12651 0 : GWindowClearFocusGadgetOfWindow(cv->v);
12652 :
12653 : /*if ( cv_auto_goto )*/ /* Chinese input method steals hot key key-strokes */
12654 : /* But if we don't do this, then people can't type menu short-cuts */
12655 0 : cv->gic = GDrawCreateInputContext(cv->v,gic_root|gic_orlesser);
12656 0 : GDrawSetGIC(cv->v,cv->gic,0,20);
12657 0 : cv->gwgic = GDrawCreateInputContext(cv->gw,gic_root|gic_orlesser);
12658 0 : GDrawSetGIC(cv->gw,cv->gwgic,0,20);
12659 0 : if( show )
12660 : {
12661 0 : GDrawSetVisible(cv->gw,true);
12662 : }
12663 :
12664 0 : if ( (CharView *) (sc->views)==NULL && updateflex )
12665 0 : SplineCharIsFlexible(sc,CVLayer((CharViewBase *) cv));
12666 0 : if ( sc->inspiro && !hasspiro() && !sc->parent->complained_about_spiros ) {
12667 0 : sc->parent->complained_about_spiros = true;
12668 : #ifdef _NO_LIBSPIRO
12669 : 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."));
12670 : #else
12671 0 : 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."));
12672 : #endif
12673 : }
12674 :
12675 0 : }
12676 :
12677 0 : void DefaultY(GRect *pos) {
12678 : static int nexty=0;
12679 : GRect size;
12680 :
12681 0 : GDrawGetSize(GDrawGetRoot(NULL),&size);
12682 0 : if ( nexty!=0 ) {
12683 : FontView *fv;
12684 0 : int any=0, i;
12685 : BDFFont *bdf;
12686 : /* are there any open cv/bv windows? */
12687 0 : for ( fv = fv_list; fv!=NULL && !any; fv = (FontView *) (fv->b.next) ) {
12688 0 : for ( i=0; i<fv->b.sf->glyphcnt; ++i ) if ( fv->b.sf->glyphs[i]!=NULL ) {
12689 0 : if ( fv->b.sf->glyphs[i]->views!=NULL ) {
12690 0 : any = true;
12691 0 : break;
12692 : }
12693 : }
12694 0 : for ( bdf = fv->b.sf->bitmaps; bdf!=NULL && !any; bdf=bdf->next ) {
12695 0 : for ( i=0; i<bdf->glyphcnt; ++i ) if ( bdf->glyphs[i]!=NULL ) {
12696 0 : if ( bdf->glyphs[i]->views!=NULL ) {
12697 0 : any = true;
12698 0 : break;
12699 : }
12700 : }
12701 : }
12702 : }
12703 0 : if ( !any ) nexty = 0;
12704 : }
12705 0 : pos->y = nexty;
12706 0 : nexty += 200;
12707 0 : if ( nexty+pos->height > size.height )
12708 0 : nexty = 0;
12709 0 : }
12710 :
12711 : static void CharViewInit(void);
12712 :
12713 0 : static int CV_OnCharSelectorTextChanged( GGadget *g, GEvent *e )
12714 : {
12715 0 : CharView* cv = GGadgetGetUserData(g);
12716 0 : SplineChar *sc = cv->b.sc;
12717 0 : SplineFont* sf = sc->parent;
12718 :
12719 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_textchanged )
12720 : {
12721 0 : int pos = e->u.control.u.tf_changed.from_pulldown;
12722 :
12723 0 : if ( pos!=-1 )
12724 : {
12725 : int32 len;
12726 0 : GTextInfo **ti = GGadgetGetList(g,&len);
12727 0 : GTextInfo *cur = ti[pos];
12728 0 : int type = (intpt) cur->userdata;
12729 0 : if ( type < 0 )
12730 : {
12731 : TRACE("load wordlist...! pos:%d\n",pos);
12732 :
12733 0 : WordlistLoadToGTextInfo( cv->charselector, &cv->charselectoridx );
12734 0 : return 0;
12735 : }
12736 : }
12737 :
12738 :
12739 0 : cv->charselectoridx = pos;
12740 0 : char* txt = GGadgetGetTitle8( cv->charselector );
12741 : TRACE("char selector changed to:%s\n", txt );
12742 : {
12743 0 : int tabnum = GTabSetGetSel(cv->tabs);
12744 : TRACE("tab num:%d\n", tabnum );
12745 :
12746 0 : CharViewTab* t = &cv->cvtabs[tabnum];
12747 0 : strncpy( t->tablabeltxt, txt, charviewtab_charselectedsz );
12748 0 : GTabSetChangeTabName(cv->tabs,t->tablabeltxt,tabnum);
12749 0 : GTabSetRemetric(cv->tabs);
12750 0 : GTabSetSetSel(cv->tabs,tabnum); /* This does a redraw */
12751 : }
12752 :
12753 0 : memset( cv->additionalCharsToShow, 0, sizeof(SplineChar*) * additionalCharsToShowLimit );
12754 0 : cv->additionalCharsToShowActiveIndex = 0;
12755 0 : cv->additionalCharsToShow[0] = cv->b.sc;
12756 :
12757 0 : int hadSelection = 0;
12758 0 : if( txt[0] == '\0' )
12759 : {
12760 0 : CVSetCharSelectorValueFromSC( cv, cv->b.sc );
12761 : }
12762 0 : else if( strlen(txt) > 1 )
12763 : {
12764 0 : int i=0;
12765 0 : unichar_t *ret = GGadgetGetTitle( cv->charselector );
12766 0 : WordListLine wll = WordlistEscapedInputStringToParsedData( sf, ret );
12767 0 : WordListLine pt = wll;
12768 0 : WordListLine ept = WordListLine_end(wll);
12769 0 : WordListLine tpt = 0;
12770 0 : for ( tpt=pt; tpt<ept; ++tpt )
12771 : {
12772 0 : if( tpt == pt )
12773 : {
12774 : // your own char at the leading of the text
12775 0 : cv->additionalCharsToShow[i] = tpt->sc;
12776 0 : i++;
12777 0 : continue;
12778 : }
12779 :
12780 0 : cv->additionalCharsToShow[i] = tpt->sc;
12781 :
12782 0 : i++;
12783 0 : if( i >= additionalCharsToShowLimit )
12784 0 : break;
12785 : }
12786 0 : free(ret);
12787 :
12788 0 : if( wll->sc )
12789 : {
12790 0 : if( wll->isSelected )
12791 : {
12792 : // first char selected, nothing to do!
12793 : }
12794 : else
12795 : {
12796 0 : while( wll->sc && !(wll->isSelected))
12797 0 : wll++;
12798 0 : if( wll->sc && wll->isSelected )
12799 : {
12800 0 : SplineChar* xc = wll->sc;
12801 0 : if( xc )
12802 : {
12803 : TRACE("selected v:%d xc:%s\n", wll->currentGlyphIndex, xc->name );
12804 0 : int xoff = cv->xoff;
12805 0 : CVSwitchActiveSC( cv, xc, wll->currentGlyphIndex );
12806 0 : CVHScrollSetPos( cv, xoff );
12807 0 : hadSelection = 1;
12808 : }
12809 :
12810 : }
12811 : }
12812 : }
12813 : }
12814 0 : free(txt);
12815 :
12816 0 : int i=0;
12817 0 : for( i=0; cv->additionalCharsToShow[i]; i++ )
12818 : {
12819 : TRACE("i:%d %p .. ", i, cv->additionalCharsToShow[i] );
12820 : TRACE(" %s\n", cv->additionalCharsToShow[i]->name );
12821 : }
12822 :
12823 0 : if( !hadSelection )
12824 0 : CVSwitchActiveSC( cv, 0, 0 );
12825 0 : GDrawRequestExpose(cv->v,NULL,false);
12826 : }
12827 0 : return( true );
12828 : }
12829 :
12830 : GTextInfo cv_charselector_init[] = {
12831 : { (unichar_t *) "", NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 1, 0, 1, 0, 0, '\0'},
12832 : { NULL, NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 1, 0, 0, 0, '\0'},
12833 : { (unichar_t *) N_("Load Word List..."), NULL, 0, 0, (void *) -1, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
12834 : // { (unichar_t *) N_("Load Glyph Name List..."), NULL, 0, 0, (void *) -2, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0'},
12835 : GTEXTINFO_EMPTY
12836 : };
12837 :
12838 :
12839 0 : CharView *CharViewCreateExtended(SplineChar *sc, FontView *fv,int enc, int show )
12840 : {
12841 0 : CharView *cv = calloc(1,sizeof(CharView));
12842 : GWindowAttrs wattrs;
12843 : GRect pos, zoom;
12844 : GWindow gw;
12845 : GGadgetData gd;
12846 : GTabInfo aspects[2];
12847 : GRect gsize;
12848 : char buf[300];
12849 : GTextInfo label[9];
12850 :
12851 0 : CharViewInit();
12852 :
12853 0 : cv->b.sc = sc;
12854 0 : cv->b.fv = &fv->b;
12855 0 : cv->enc = enc;
12856 0 : 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 */
12857 :
12858 0 : cv->infoh = 13;
12859 : #if defined(__MINGW32__)||defined(__CYGWIN__)
12860 : cv->infoh = 26;
12861 : #endif
12862 0 : cv->rulerh = 16;
12863 :
12864 :
12865 0 : SCLigCaretCheck(sc,false);
12866 :
12867 0 : memset(&wattrs,0,sizeof(wattrs));
12868 0 : wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_utf8_ititle;
12869 0 : wattrs.event_masks = -1;
12870 0 : wattrs.cursor = ct_mypointer;
12871 0 : wattrs.utf8_icon_title = (const char*)CVMakeTitles(cv,buf,sizeof(buf));
12872 0 : wattrs.utf8_window_title = buf;
12873 0 : wattrs.icon = CharIcon(cv, fv);
12874 0 : if ( wattrs.icon )
12875 0 : wattrs.mask |= wam_icon;
12876 0 : pos.x = GGadgetScale(104)+6;
12877 0 : pos.width = (cv_width > 0) ? cv_width : default_cv_width;
12878 0 : pos.height = (cv_height > 0) ? cv_height : default_cv_height;
12879 0 : DefaultY(&pos);
12880 :
12881 0 : cv->gw = gw = GDrawCreateTopWindow(NULL,&pos,cv_e_h,cv,&wattrs);
12882 0 : free( (unichar_t *) wattrs.icon_title );
12883 0 : free((char*)wattrs.utf8_icon_title);
12884 0 : GDrawSetWindowTypeName(cv->gw, "CharView");
12885 :
12886 : // FIXME: cant do this until gw is shown?
12887 : GTextBounds textbounds;
12888 0 : GDrawGetText8Bounds(cv->gw,"0123456789hl",10,&textbounds);
12889 : TRACE("XXXXXX as:%d ds:%d\n", textbounds.as, textbounds.ds );
12890 0 : cv->charselectorh = textbounds.as+textbounds.ds+1;
12891 : TRACE("XXXXXX h:%d\n", GDrawGetText8Height( cv->gw, "0123456AZgplh", 10));
12892 0 : cv->charselectorh = 35;
12893 :
12894 :
12895 0 : GDrawGetSize(GDrawGetRoot(screen_display),&zoom);
12896 0 : zoom.x = CVPalettesWidth(); zoom.width -= zoom.x-10;
12897 0 : zoom.height -= 30; /* Room for title bar & such */
12898 0 : GDrawSetZoom(gw,&zoom,-1);
12899 :
12900 0 : memset(&gd,0,sizeof(gd));
12901 0 : gd.flags = gg_visible | gg_enabled;
12902 0 : helplist[0].invoke = CVMenuContextualHelp;
12903 : #ifndef _NO_PYTHON
12904 0 : if ( cvpy_menu!=NULL )
12905 0 : mblist[4].ti.disabled = mblist_nomm[4].ti.disabled = false;
12906 0 : mblist[4].sub = mblist_nomm[4].sub = cvpy_menu;
12907 : #define CALLBACKS_INDEX 5 /* FIXME: There has to be a better way than this. */
12908 : #else
12909 : #define CALLBACKS_INDEX 4 /* FIXME: There has to be a better way than this. */
12910 : #endif /* _NO_PYTHON */
12911 : #ifdef NATIVE_CALLBACKS
12912 : if ( cv_menu!=NULL )
12913 : mblist[CALLBACKS_INDEX].ti.disabled = mblist_nomm[CALLBACKS_INDEX].ti.disabled = false;
12914 : mblist[CALLBACKS_INDEX].sub = mblist_nomm[CALLBACKS_INDEX].sub = cv_menu;
12915 : #endif /* NATIVE_CALLBACKS */
12916 0 : gd.u.menu2 = sc->parent->mm==NULL ? mblist_nomm : mblist;
12917 0 : cv->mb = GMenu2BarCreate( gw, &gd, NULL);
12918 0 : GGadgetGetSize(cv->mb,&gsize);
12919 0 : cv->mbh = gsize.height;
12920 :
12921 : // TRACE("pos.x:%d pos.y:%d pos.w:%d pos.h:%d\n", pos.x, pos.y, pos.width, pos.height );
12922 0 : GDrawGetSize(cv->gw,&pos);
12923 0 : memset(&gd,0,sizeof(gd));
12924 : // gd.pos.x = pos.x;
12925 0 : gd.pos.x = 3;
12926 0 : gd.pos.y = cv->mbh+2;
12927 0 : gd.pos.height = cv->charselectorh-4;
12928 0 : gd.pos.width = cv_width / 2;
12929 0 : gd.flags = gg_visible|gg_enabled|gg_pos_in_pixels|gg_text_xim;
12930 0 : gd.handle_controlevent = CV_OnCharSelectorTextChanged;
12931 0 : gd.u.list = cv_charselector_init;
12932 0 : cv->charselector = GListFieldCreate(cv->gw,&gd,cv);
12933 0 : CVSetCharSelectorValueFromSC( cv, sc );
12934 0 : GGadgetSetSkipUnQualifiedHotkeyProcessing( cv->charselector, 1 );
12935 :
12936 : // Up and Down buttons for moving through the word list.
12937 : {
12938 0 : GGadgetData xgd = gd;
12939 0 : gd.pos.width += 2 * xgd.pos.height + 4;
12940 0 : memset(label, '\0', sizeof(GTextInfo));
12941 0 : xgd.pos.x += xgd.pos.width + 2;
12942 0 : xgd.pos.width = xgd.pos.height;
12943 0 : xgd.flags = gg_visible|gg_enabled|gg_pos_in_pixels;
12944 0 : xgd.handle_controlevent = CVMoveToPrevInWordList;
12945 0 : xgd.label = &label[0];
12946 0 : label[0].text = (unichar_t *) "⇞";
12947 0 : label[0].text_is_1byte = true;
12948 0 : cv->charselectorPrev = GButtonCreate(cv->gw,&xgd,cv);
12949 0 : memset(label, '\0', sizeof(GTextInfo));
12950 0 : xgd.pos.x += xgd.pos.width + 2;
12951 0 : xgd.pos.width = xgd.pos.height;
12952 0 : xgd.flags = gg_visible|gg_enabled|gg_pos_in_pixels;
12953 0 : xgd.handle_controlevent = CVMoveToNextInWordList;
12954 0 : xgd.label = &label[0];
12955 0 : label[0].text = (unichar_t *) "⇟";
12956 0 : label[0].text_is_1byte = true;
12957 0 : cv->charselectorNext = GButtonCreate(cv->gw,&xgd,cv);
12958 : }
12959 :
12960 :
12961 0 : memset(aspects,0,sizeof(aspects));
12962 0 : aspects[0].text = (unichar_t *) sc->name;
12963 0 : aspects[0].text_is_1byte = true;
12964 : /* NOT visible until we add a second glyph to the stack */
12965 0 : gd.flags = gg_enabled|gg_tabset_nowindow|gg_tabset_scroll|gg_pos_in_pixels;
12966 0 : gd.u.menu = NULL;
12967 0 : gd.u.tabs = aspects;
12968 0 : gd.pos.x = 0;
12969 0 : gd.pos.y = cv->mbh;
12970 0 : gd.handle_controlevent = CVChangeToFormer;
12971 0 : cv->tabs = GTabSetCreate( gw, &gd, NULL );
12972 0 : cv->former_cnt = 1;
12973 0 : cv->former_names[0] = copy(sc->name);
12974 0 : GGadgetTakesKeyboard(cv->tabs,false);
12975 :
12976 0 : _CharViewCreate( cv, sc, fv, enc, show );
12977 : // Frank wants to avoid needing to implement scaling twice.
12978 0 : CVResize(cv);
12979 :
12980 0 : return( cv );
12981 : }
12982 :
12983 0 : CharView *CharViewCreate(SplineChar *sc, FontView *fv,int enc)
12984 : {
12985 0 : return CharViewCreateExtended( sc, fv, enc, 1 );
12986 : }
12987 :
12988 0 : void CharViewFree(CharView *cv) {
12989 : int i;
12990 :
12991 0 : if ( cv->qg != NULL )
12992 0 : QGRmCharView(cv->qg,cv);
12993 0 : BDFCharFree(cv->filled);
12994 0 : if ( cv->ruler_w ) {
12995 0 : GDrawDestroyWindow(cv->ruler_w);
12996 0 : cv->ruler_w = NULL;
12997 : }
12998 0 : if ( cv->ruler_linger_w ) {
12999 0 : GDrawDestroyWindow(cv->ruler_linger_w);
13000 0 : cv->ruler_linger_w = NULL;
13001 : }
13002 0 : free(cv->gi.u.image->clut);
13003 0 : free(cv->gi.u.image);
13004 : #if HANYANG
13005 : if ( cv->jamodisplay!=NULL )
13006 : Disp_DoFinish(cv->jamodisplay,true);
13007 : #endif
13008 :
13009 0 : CVDebugFree(cv->dv);
13010 :
13011 0 : SplinePointListsFree(cv->b.gridfit);
13012 0 : FreeType_FreeRaster(cv->oldraster);
13013 0 : FreeType_FreeRaster(cv->raster);
13014 :
13015 0 : CVDebugFree(cv->dv);
13016 :
13017 0 : for ( i=0; i<cv->former_cnt; ++i )
13018 0 : free(cv->former_names[i]);
13019 :
13020 0 : free(cv->ruler_intersections);
13021 0 : free(cv);
13022 0 : }
13023 :
13024 0 : int CVValid(SplineFont *sf, SplineChar *sc, CharView *cv) {
13025 : /* A charview may have been closed. A splinechar may have been removed */
13026 : /* from a font */
13027 : CharView *test;
13028 :
13029 0 : if ( cv->b.sc!=sc || sc->parent!=sf )
13030 0 : return( false );
13031 0 : if ( sc->orig_pos<0 || sc->orig_pos>sf->glyphcnt )
13032 0 : return( false );
13033 0 : if ( sf->glyphs[sc->orig_pos]!=sc )
13034 0 : return( false );
13035 0 : for ( test=(CharView *) (sc->views); test!=NULL; test=(CharView *) (test->b.next) )
13036 0 : if ( test==cv )
13037 0 : return( true );
13038 :
13039 0 : return( false );
13040 : }
13041 :
13042 : static int charview_ready = false;
13043 :
13044 0 : static void CharViewFinish() {
13045 : // The memory leak is limited and reachable.
13046 0 : if ( !charview_ready ) return;
13047 0 : charview_ready = false;
13048 0 : mb2FreeGetText(mblist);
13049 0 : mb2FreeGetText(spiroptlist);
13050 : int i;
13051 0 : for ( i=0; mblist_nomm[i].ti.text!=NULL; ++i ) {
13052 0 : free(mblist_nomm[i].ti.text_untranslated); mblist_nomm[i].ti.text_untranslated = NULL;
13053 : }
13054 : }
13055 :
13056 0 : void CharViewFinishNonStatic() {
13057 0 : CharViewFinish();
13058 0 : }
13059 :
13060 0 : static void CharViewInit(void) {
13061 : int i;
13062 : // static int done = false; // superseded by charview_ready.
13063 :
13064 0 : if ( charview_ready )
13065 0 : return;
13066 0 : charview_ready = true;
13067 : // TRACE("CharViewInit(top) mblist[0].text before translation: %s\n", mblist[0].ti.text );
13068 :
13069 0 : mb2DoGetText(mblist);
13070 :
13071 : // TRACE("CharViewInit(2) mblist[0].text after translation: %s\n", u_to_c(mblist[0].ti.text) );
13072 : // TRACE("CharViewInit(2) mblist[0].text_untranslated notrans: %s\n", mblist[0].ti.text_untranslated );
13073 :
13074 0 : mb2DoGetText(spiroptlist);
13075 0 : for ( i=0; mblist_nomm[i].ti.text!=NULL; ++i )
13076 : {
13077 : // Note that because we are doing this ourself we have to set
13078 : // the text_untranslated ourself too.
13079 0 : if( mblist_nomm[i].shortcut )
13080 0 : mblist_nomm[i].ti.text_untranslated = copy(mblist_nomm[i].shortcut);
13081 : else
13082 0 : mblist_nomm[i].ti.text_untranslated = copy((char*)mblist_nomm[i].ti.text);
13083 :
13084 0 : mblist_nomm[i].ti.text = (unichar_t *) _((char *) mblist_nomm[i].ti.text);
13085 : }
13086 0 : atexit(&CharViewFinishNonStatic);
13087 : }
13088 :
13089 0 : static int nested_cv_e_h(GWindow gw, GEvent *event) {
13090 0 : CharView *cv = (CharView *) GDrawGetUserData(gw);
13091 :
13092 0 : switch ( event->type ) {
13093 : case et_expose:
13094 0 : InfoExpose(cv,gw,event);
13095 0 : CVLogoExpose(cv,gw,event);
13096 0 : break;
13097 : case et_char:
13098 0 : (cv->b.container->funcs->charEvent)(cv->b.container,event);
13099 0 : break;
13100 : case et_charup:
13101 0 : CVCharUp(cv,event);
13102 0 : break;
13103 : case et_controlevent:
13104 0 : switch ( event->u.control.subtype ) {
13105 : case et_scrollbarchange:
13106 0 : if ( event->u.control.g == cv->hsb )
13107 0 : CVHScroll(cv,&event->u.control.u.sb);
13108 : else
13109 0 : CVVScroll(cv,&event->u.control.u.sb);
13110 0 : break;
13111 : }
13112 0 : break;
13113 : case et_map:
13114 0 : if ( event->u.map.is_visible )
13115 0 : CVPaletteActivate(cv);
13116 : else
13117 0 : CVPalettesHideIfMine(cv);
13118 0 : break;
13119 : case et_resize:
13120 0 : if ( event->u.resize.sized )
13121 0 : CVResize(cv);
13122 0 : break;
13123 : case et_destroy:
13124 0 : if ( cv->backimgs!=NULL ) {
13125 0 : GDrawDestroyWindow(cv->backimgs);
13126 0 : cv->backimgs = NULL;
13127 : }
13128 0 : break;
13129 : case et_mouseup: case et_mousedown:
13130 0 : GGadgetEndPopup();
13131 0 : CVPaletteActivate(cv);
13132 0 : break;
13133 : }
13134 0 : return( true );
13135 : }
13136 :
13137 0 : void SVCharViewInits(SearchView *sv) {
13138 : GGadgetData gd;
13139 : GWindowAttrs wattrs;
13140 : GRect pos, gsize;
13141 :
13142 0 : CharViewInit();
13143 :
13144 0 : memset(&gd,0,sizeof(gd));
13145 0 : gd.flags = gg_visible | gg_enabled;
13146 0 : helplist[0].invoke = CVMenuContextualHelp;
13147 0 : gd.u.menu2 = mblist_nomm;
13148 0 : sv->mb = GMenu2BarCreate( sv->gw, &gd, NULL);
13149 0 : GGadgetGetSize(sv->mb,&gsize);
13150 0 : sv->mbh = gsize.height;
13151 :
13152 0 : pos.y = sv->mbh+sv->fh+10; pos.height = 220;
13153 0 : pos.width = pos.height; pos.x = 10+pos.width+20; /* Do replace first so palettes appear propperly */
13154 0 : sv->rpl_x = pos.x; sv->cv_y = pos.y;
13155 0 : sv->cv_height = pos.height; sv->cv_width = pos.width;
13156 0 : memset(&wattrs,0,sizeof(wattrs));
13157 0 : wattrs.mask = wam_events|wam_cursor;
13158 0 : wattrs.event_masks = -1;
13159 0 : wattrs.cursor = ct_mypointer;
13160 0 : sv->cv_rpl.gw = GWidgetCreateSubWindow(sv->gw,&pos,nested_cv_e_h,&sv->cv_rpl,&wattrs);
13161 0 : _CharViewCreate(&sv->cv_rpl, &sv->sd.sc_rpl, &sv->dummy_fv, 1, 1);
13162 :
13163 0 : pos.x = 10;
13164 0 : sv->cv_srch.gw = GWidgetCreateSubWindow(sv->gw,&pos,nested_cv_e_h,&sv->cv_srch,&wattrs);
13165 0 : _CharViewCreate(&sv->cv_srch, &sv->sd.sc_srch, &sv->dummy_fv, 0, 1);
13166 0 : }
13167 :
13168 : /* Same for the MATH Kern dlg */
13169 :
13170 0 : void MKDCharViewInits(MathKernDlg *mkd) {
13171 : GGadgetData gd;
13172 : GWindowAttrs wattrs;
13173 : GRect pos, gsize;
13174 : int i;
13175 :
13176 0 : CharViewInit();
13177 :
13178 0 : memset(&gd,0,sizeof(gd));
13179 0 : gd.flags = gg_visible | gg_enabled;
13180 0 : helplist[0].invoke = CVMenuContextualHelp;
13181 0 : gd.u.menu2 = mblist_nomm;
13182 0 : mkd->mb = GMenu2BarCreate( mkd->gw, &gd, NULL);
13183 0 : GGadgetGetSize(mkd->mb,&gsize);
13184 0 : mkd->mbh = gsize.height;
13185 :
13186 0 : mkd->mid_space = 20;
13187 0 : for ( i=3; i>=0; --i ) { /* Create backwards so palettes get set in topright (last created) */
13188 0 : pos.y = mkd->fh+10; pos.height = 220; /* Size doesn't matter, adjusted later */
13189 0 : pos.width = pos.height; pos.x = 10+i*(pos.width+20);
13190 0 : mkd->cv_y = pos.y;
13191 0 : mkd->cv_height = pos.height; mkd->cv_width = pos.width;
13192 0 : memset(&wattrs,0,sizeof(wattrs));
13193 0 : wattrs.mask = wam_events|wam_cursor;
13194 0 : wattrs.event_masks = -1;
13195 0 : wattrs.cursor = ct_mypointer;
13196 0 : (&mkd->cv_topright)[i].gw = GWidgetCreateSubWindow(mkd->cvparent_w,&pos,nested_cv_e_h,(&mkd->cv_topright)+i,&wattrs);
13197 0 : _CharViewCreate((&mkd->cv_topright)+i, (&mkd->sc_topright)+i, &mkd->dummy_fv, i, 1);
13198 : }
13199 0 : }
13200 :
13201 : /* Same for the Tile Path dlg */
13202 :
13203 : #ifdef FONTFORGE_CONFIG_TILEPATH
13204 :
13205 : void TPDCharViewInits(TilePathDlg *tpd, int cid) {
13206 : GGadgetData gd;
13207 : GWindowAttrs wattrs;
13208 : GRect pos, gsize;
13209 : int i;
13210 :
13211 : CharViewInit();
13212 :
13213 : memset(&gd,0,sizeof(gd));
13214 : gd.flags = gg_visible | gg_enabled;
13215 : helplist[0].invoke = CVMenuContextualHelp;
13216 : gd.u.menu2 = mblist_nomm;
13217 : tpd->mb = GMenu2BarCreate( tpd->gw, &gd, NULL);
13218 : GGadgetGetSize(tpd->mb,&gsize);
13219 : tpd->mbh = gsize.height;
13220 :
13221 : tpd->mid_space = 20;
13222 : for ( i=3; i>=0; --i ) { /* Create backwards so palettes get set in topright (last created) */
13223 : pos.y = 0; pos.height = 220; /* Size doesn't matter, adjusted later */
13224 : pos.width = pos.height; pos.x = 0;
13225 : tpd->cv_y = pos.y;
13226 : tpd->cv_height = pos.height; tpd->cv_width = pos.width;
13227 : memset(&wattrs,0,sizeof(wattrs));
13228 : wattrs.mask = wam_events|wam_cursor;
13229 : wattrs.event_masks = -1;
13230 : wattrs.cursor = ct_mypointer;
13231 : (&tpd->cv_first)[i].gw = GWidgetCreateSubWindow(GDrawableGetWindow(GWidgetGetControl(tpd->gw,cid+i)),
13232 : &pos,nested_cv_e_h,(&tpd->cv_first)+i,&wattrs);
13233 : _CharViewCreate((&tpd->cv_first)+i, (&tpd->sc_first)+i, &tpd->dummy_fv, i, 1 );
13234 : }
13235 : }
13236 :
13237 : void PTDCharViewInits(TilePathDlg *tpd, int cid) {
13238 : GGadgetData gd;
13239 : GWindowAttrs wattrs;
13240 : GRect pos, gsize;
13241 :
13242 : CharViewInit();
13243 :
13244 : memset(&gd,0,sizeof(gd));
13245 : gd.flags = gg_visible | gg_enabled;
13246 : helplist[0].invoke = CVMenuContextualHelp;
13247 : gd.u.menu2 = mblist_nomm;
13248 : tpd->mb = GMenu2BarCreate( tpd->gw, &gd, NULL);
13249 : GGadgetGetSize(tpd->mb,&gsize);
13250 : tpd->mbh = gsize.height;
13251 :
13252 : tpd->mid_space = 20;
13253 : {
13254 : pos.y = 0; pos.height = 220; /* Size doesn't matter, adjusted later */
13255 : pos.width = pos.height; pos.x = 0;
13256 : tpd->cv_y = pos.y;
13257 : tpd->cv_height = pos.height; tpd->cv_width = pos.width;
13258 : memset(&wattrs,0,sizeof(wattrs));
13259 : wattrs.mask = wam_events|wam_cursor;
13260 : wattrs.event_masks = -1;
13261 : wattrs.cursor = ct_mypointer;
13262 : tpd->cv_first.gw = GWidgetCreateSubWindow(GDrawableGetWindow(GWidgetGetControl(tpd->gw,cid)),
13263 : &pos,nested_cv_e_h,&tpd->cv_first,&wattrs);
13264 : _CharViewCreate(&tpd->cv_first, &tpd->sc_first, &tpd->dummy_fv, 0, 1 );
13265 : }
13266 : }
13267 : #endif /* TilePath */
13268 :
13269 0 : void GDDCharViewInits(GradientDlg *gdd, int cid) {
13270 : GGadgetData gd;
13271 : GWindowAttrs wattrs;
13272 : GRect pos, gsize;
13273 :
13274 0 : CharViewInit();
13275 :
13276 0 : memset(&gd,0,sizeof(gd));
13277 0 : gd.flags = gg_visible | gg_enabled;
13278 0 : helplist[0].invoke = CVMenuContextualHelp;
13279 0 : gd.u.menu2 = mblist_nomm;
13280 0 : gdd->mb = GMenu2BarCreate( gdd->gw, &gd, NULL);
13281 0 : GGadgetGetSize(gdd->mb,&gsize);
13282 0 : gdd->mbh = gsize.height;
13283 :
13284 0 : memset(&wattrs,0,sizeof(wattrs));
13285 0 : wattrs.mask = wam_events|wam_cursor;
13286 0 : wattrs.event_masks = -1;
13287 0 : wattrs.cursor = ct_mypointer;
13288 :
13289 0 : pos.y = 1; pos.height = 220;
13290 0 : pos.width = pos.height; pos.x = 0;
13291 0 : gdd->cv_grad.gw = GWidgetCreateSubWindow(
13292 0 : GDrawableGetWindow(GWidgetGetControl(gdd->gw,cid)),
13293 0 : &pos,nested_cv_e_h,&gdd->cv_grad,&wattrs);
13294 0 : _CharViewCreate(&gdd->cv_grad, &gdd->sc_grad, &gdd->dummy_fv, 0, 1 );
13295 0 : }
13296 :
13297 0 : void StrokeCharViewInits(StrokeDlg *sd, int cid) {
13298 : GGadgetData gd;
13299 : GWindowAttrs wattrs;
13300 : GRect pos, gsize;
13301 :
13302 0 : CharViewInit();
13303 :
13304 0 : memset(&gd,0,sizeof(gd));
13305 0 : gd.flags = gg_visible | gg_enabled;
13306 0 : helplist[0].invoke = CVMenuContextualHelp;
13307 0 : gd.u.menu2 = mblist_nomm;
13308 0 : sd->mb = GMenu2BarCreate( sd->gw, &gd, NULL);
13309 0 : GGadgetGetSize(sd->mb,&gsize);
13310 0 : sd->mbh = gsize.height;
13311 :
13312 0 : memset(&wattrs,0,sizeof(wattrs));
13313 0 : wattrs.mask = wam_events|wam_cursor;
13314 0 : wattrs.event_masks = -1;
13315 0 : wattrs.cursor = ct_mypointer;
13316 :
13317 0 : pos.y = 1; pos.height = 220;
13318 0 : pos.width = pos.height; pos.x = 0;
13319 0 : sd->cv_stroke.gw = GWidgetCreateSubWindow(
13320 0 : GDrawableGetWindow(GWidgetGetControl(sd->gw,cid)),
13321 0 : &pos,nested_cv_e_h,&sd->cv_stroke,&wattrs);
13322 0 : _CharViewCreate(&sd->cv_stroke, &sd->sc_stroke, &sd->dummy_fv, 0, 1 );
13323 0 : }
13324 :
13325 0 : static void SC_CloseAllWindows(SplineChar *sc) {
13326 : CharViewBase *cv, *next;
13327 : BitmapView *bv, *bvnext;
13328 : BDFFont *bdf;
13329 : BDFChar *bfc;
13330 : FontView *fvs;
13331 :
13332 0 : if ( sc->views ) {
13333 0 : for ( cv = sc->views; cv!=NULL; cv=next ) {
13334 0 : next = cv->next;
13335 0 : GDrawDestroyWindow(((CharView *) cv)->gw);
13336 : }
13337 0 : GDrawSync(NULL);
13338 0 : GDrawProcessPendingEvents(NULL);
13339 0 : GDrawSync(NULL);
13340 0 : GDrawProcessPendingEvents(NULL);
13341 : }
13342 :
13343 0 : for ( bdf=sc->parent->bitmaps; bdf!=NULL; bdf = bdf->next ) {
13344 0 : if ( sc->orig_pos<bdf->glyphcnt && (bfc = bdf->glyphs[sc->orig_pos])!= NULL ) {
13345 0 : if ( bfc->views!=NULL ) {
13346 0 : for ( bv= bfc->views; bv!=NULL; bv=bvnext ) {
13347 0 : bvnext = bv->next;
13348 0 : GDrawDestroyWindow(bv->gw);
13349 : }
13350 0 : GDrawSync(NULL);
13351 0 : GDrawProcessPendingEvents(NULL);
13352 0 : GDrawSync(NULL);
13353 0 : GDrawProcessPendingEvents(NULL);
13354 : }
13355 : }
13356 : }
13357 :
13358 : /* Turn any searcher references to this glyph into inline copies of it */
13359 0 : for ( fvs=(FontView *) sc->parent->fv; fvs!=NULL; fvs=(FontView *) fvs->b.nextsame ) {
13360 0 : if ( fvs->sv!=NULL ) {
13361 : RefChar *rf, *rnext;
13362 0 : for ( rf = fvs->sv->sd.sc_srch.layers[ly_fore].refs; rf!=NULL; rf=rnext ) {
13363 0 : rnext = rf->next;
13364 0 : if ( rf->sc==sc )
13365 0 : SCRefToSplines(&fvs->sv->sd.sc_srch,rf,ly_fore);
13366 : }
13367 0 : for ( rf = fvs->sv->sd.sc_rpl.layers[ly_fore].refs; rf!=NULL; rf=rnext ) {
13368 0 : rnext = rf->next;
13369 0 : if ( rf->sc==sc )
13370 0 : SCRefToSplines(&fvs->sv->sd.sc_rpl,rf,ly_fore);
13371 : }
13372 : }
13373 : }
13374 0 : }
13375 :
13376 : struct sc_interface gdraw_sc_interface = {
13377 : SC_UpdateAll,
13378 : SC_OutOfDateBackground,
13379 : SC_RefreshTitles,
13380 : SC_HintsChanged,
13381 : SC_CharChangedUpdate,
13382 : _SC_CharChangedUpdate,
13383 : SC_MarkInstrDlgAsChanged,
13384 : SC_CloseAllWindows,
13385 : SC_MoreLayers
13386 : };
13387 :
13388 0 : static void UI_CVGlyphRenameFixup(SplineFont *sf, const char *oldname, const char *newname) {
13389 : int gid, i;
13390 : SplineChar *sc;
13391 : CharView *cv;
13392 :
13393 0 : if ( no_windowing_ui )
13394 0 : return;
13395 :
13396 0 : for ( gid=0; gid<sf->glyphcnt; ++gid ) if ( (sc=sf->glyphs[gid])!=NULL) {
13397 0 : for ( cv=(CharView *) (sc->views); cv!=NULL; cv = (CharView *) (cv->b.next)) {
13398 0 : for ( i=0; i<cv->former_cnt; ++i ) if ( strcmp(oldname,cv->former_names[i])==0 ) {
13399 0 : free( cv->former_names[i] );
13400 0 : cv->former_names[i] = copy( newname );
13401 0 : if ( cv->tabs!=NULL ) {
13402 0 : GTabSetChangeTabName(cv->tabs,newname,i);
13403 0 : GTabSetRemetric(cv->tabs);
13404 0 : GGadgetRedraw(cv->tabs);
13405 : }
13406 : }
13407 : }
13408 : }
13409 : }
13410 :
13411 : struct cv_interface gdraw_cv_interface = {
13412 : (void (*)(CharViewBase *)) CV_CharChangedUpdate,
13413 : (void (*)(CharViewBase *,int)) _CV_CharChangedUpdate,
13414 : UI_CVGlyphRenameFixup,
13415 : CV_LayerPaletteCheck
13416 : };
13417 :
13418 : extern GResInfo metricsview_ri;
13419 : GResInfo charview2_ri = {
13420 : &metricsview_ri, NULL,NULL, NULL,
13421 : NULL,
13422 : NULL,
13423 : NULL,
13424 : charview2_re,
13425 : N_("Outline View 2"),
13426 : N_("This window displays a single outline glyph (more data)"),
13427 : "CharView",
13428 : "fontforge",
13429 : false,
13430 : 0,
13431 : NULL,
13432 : GBOX_EMPTY,
13433 : NULL,
13434 : NULL,
13435 : NULL
13436 : };
13437 : GResInfo charview_ri = {
13438 : &charview2_ri, NULL,NULL, NULL,
13439 : NULL,
13440 : NULL,
13441 : NULL,
13442 : charview_re,
13443 : N_("Outline View"),
13444 : N_("This window displays a single outline glyph"),
13445 : "CharView",
13446 : "fontforge",
13447 : false,
13448 : 0,
13449 : NULL,
13450 : GBOX_EMPTY,
13451 : NULL,
13452 : NULL,
13453 : NULL
13454 : };
13455 :
13456 :
13457 0 : void SPSelectNextPoint( SplinePoint *sp, int state )
13458 : {
13459 0 : if( !sp )
13460 0 : return;
13461 0 : if( !sp->next )
13462 0 : return;
13463 0 : if( !sp->next->to )
13464 0 : return;
13465 0 : sp->next->to->selected = state;
13466 : }
13467 :
13468 0 : void SPSelectPrevPoint( SplinePoint *sp, int state )
13469 : {
13470 0 : if( !sp )
13471 0 : return;
13472 0 : if( !sp->prev )
13473 0 : return;
13474 0 : if( !sp->prev->from )
13475 0 : return;
13476 0 : sp->prev->from->selected = state;
13477 : }
13478 :
13479 :
13480 :
13481 0 : bool SPIsNextCPSelectedSingle( SplinePoint *sp, CharView *cv )
13482 : {
13483 0 : if( cv )
13484 : {
13485 0 : int iscurrent = sp == (cv->p.sp!=NULL?cv->p.sp:cv->lastselpt);
13486 0 : if( iscurrent && cv->p.nextcp )
13487 0 : return true;
13488 : }
13489 0 : return false;
13490 : }
13491 :
13492 :
13493 0 : bool SPIsNextCPSelected( SplinePoint *sp, CharView *cv )
13494 : {
13495 0 : if( SPIsNextCPSelectedSingle( sp, cv ))
13496 0 : return true;
13497 0 : return sp->nextcpselected;
13498 : }
13499 :
13500 0 : bool SPIsPrevCPSelectedSingle( SplinePoint *sp, CharView *cv )
13501 : {
13502 0 : if( cv )
13503 : {
13504 0 : int iscurrent = sp == (cv->p.sp!=NULL?cv->p.sp:cv->lastselpt);
13505 0 : if( iscurrent && cv->p.prevcp )
13506 0 : return true;
13507 : }
13508 0 : return false;
13509 : }
13510 :
13511 0 : bool SPIsPrevCPSelected( SplinePoint *sp, CharView *cv )
13512 : {
13513 0 : if( SPIsPrevCPSelectedSingle( sp, cv ))
13514 : {
13515 0 : return true;
13516 : }
13517 0 : return sp->prevcpselected;
13518 : }
13519 :
13520 0 : bool CVShouldInterpolateCPsOnMotion( CharView* cv )
13521 : {
13522 0 : bool ret = interpCPsOnMotion;
13523 :
13524 0 : if( cv->activeModifierControl && cv->activeModifierAlt )
13525 0 : ret = !ret;
13526 :
13527 0 : return ret;
13528 : }
13529 :
|