LCOV - code coverage report
Current view: top level - fontforgeexe - charview.c (source / functions) Hit Total Coverage
Test: FontForge coverage report 2017-08-04 01:21:11+02:00 (commit d35f7e4107a9e1db65cce47c468fcc914cecb8fd) Lines: 92 8080 1.1 %
Date: 2017-08-04 Functions: 9 433 2.1 %

          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             : 

Generated by: LCOV version 1.10