1 /* Copyright (C) 2000-2012 by George Williams */
2 /*
3  * Redistribution and use in source and binary forms, with or without
4  * modification, are permitted provided that the following conditions are met:
5 
6  * Redistributions of source code must retain the above copyright notice, this
7  * list of conditions and the following disclaimer.
8 
9  * Redistributions in binary form must reproduce the above copyright notice,
10  * this list of conditions and the following disclaimer in the documentation
11  * and/or other materials provided with the distribution.
12 
13  * The name of the author may not be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15 
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <fontforge-config.h>
29 
30 #include "cvundoes.h"
31 #include "fontforgeui.h"
32 #include "spiro.h"
33 #include "splinefill.h"
34 #include "splineorder2.h"
35 #include "splineutil.h"
36 #include "splineutil2.h"
37 #include "ustring.h"
38 
39 #include "charview_private.h"
40 #include "gkeysym.h"
41 #include "gresource.h"
42 #include "hotkeys.h"
43 #include "splinefont.h"
44 #include "ustring.h"
45 #include "utype.h"
46 
47 #include <math.h>
48 
49 int palettes_docked=1;
50 int rectelipse=0, polystar=0, regular_star=1;
51 int center_out[2] = { false, true };
52 float rr_radius=0;
53 int ps_pointcnt=6;
54 float star_percent=1.7320508;	/* Regular 6 pointed star */
55 extern int interpCPsOnMotion;
56 
57 static void CVLCheckLayerCount(CharView *cv, int resize);
58 
59 extern void CVDebugFree(DebugView *dv);
60 
61 extern GBox _ggadget_Default_Box;
62 #define ACTIVE_BORDER   (_ggadget_Default_Box.active_border)
63 #define MAIN_FOREGROUND (_ggadget_Default_Box.main_foreground)
64 
65 extern GDevEventMask input_em[];
66 extern const int input_em_cnt;
67 
68 int cvvisible[2] = { 1, 1}, bvvisible[3]= { 1,1,1 };
69 static GWindow cvlayers, cvtools, bvlayers, bvtools, bvshades;
70 static GWindow cvlayers2=NULL;
71 
72 #define LSHOW_CUBIC   1
73 #define LSHOW_FG      2
74 #define LSHOW_PREVIEW 4
75 static int layerscols = LSHOW_CUBIC|LSHOW_FG|LSHOW_PREVIEW; /* which columns to show in layers1 palette */
76 static int layer_height = 0;        /* height of each layer row in layers1 palette */
77 static int layer_header_height = 0; /* height of initial stuff in layers1 palette  */
78 static int layer_footer_height = 0; /* height of +/- buttons at bottom of layers1 palette */
79 static int layers_max = 2; /* Maximum number of layers for which widgets have been allocated in layers1 palette */
80 struct l2 {
81     int active;           /* index of the active layer */
82     int offtop;           /* first layer to show at the top line in layers palette */
83     int visible_layers;   /* number of layers apart from the guides layer to show before using a scrollbar      */
84     int current_layers;   /* number of layers for the current character, and the number used in l2.layers       */
85     int max_layers;       /* maximum number of layers for which layer controls and previews have been allocated */
86     BDFChar **layers;     /* layer thumbnail previews              */
87     int sb_start;         /* x pixel position of the scrollbar     */
88     int column_width;     /* width of various indicator columns    */
89     int header_height;    /* height of the header in pixels before the first layer */
90     int mo_col, mo_layer; /* mouse over column and layer           */
91     int rename_active;    /* If >=2, layer number for which the edit box for layer names is active */
92     GClut *clut;
93     GFont *font;          /* font to draw text in the palette with */
94 } layerinfo = {           /* info about the current layers in the layers palette */
95     2, 0, 0, 0, 0, NULL, 0, 0, 0, 0, 0, 0, NULL, NULL
96 };
97 
98 struct l2 layer2 = { 2, 0, 0, 0, 0, NULL, 0, 0, 0, 0, 0, 0, NULL, NULL };
99 static int layers2_active = -1;
100 static GPoint cvtoolsoff = { -9999, -9999 }, cvlayersoff = { -9999, -9999 }, bvlayersoff = { -9999, -9999 }, bvtoolsoff = { -9999, -9999 }, bvshadesoff = { -9999, -9999 };
101 int palettes_fixed=1;
102 static GCursor tools[cvt_max+1] = { ct_pointer }, spirotools[cvt_max+1];
103 
104 enum cvtools cv_b1_tool = cvt_pointer, cv_cb1_tool = cvt_pointer,
105 	     cv_b2_tool = cvt_magnify, cv_cb2_tool = cvt_ruler;
106 
107 static GFont *toolsfont=NULL, *layersfont=NULL;
108 
109 #define CV_LAYERS_WIDTH		104
110 #define CV_LAYERS_HEIGHT	100
111 #define CV_LAYERS_INITIALCNT	6
112 #define CV_LAYERS_LINE_HEIGHT	25
113 #define CV_LAYERS2_WIDTH	185
114 #define CV_LAYERS2_HEIGHT	126
115 #define CV_LAYERS2_LINE_HEIGHT	25
116 #define CV_LAYERS2_HEADER_HEIGHT	20
117 #define BV_TOOLS_WIDTH		53
118 #define BV_TOOLS_HEIGHT		80
119 #define BV_LAYERS_HEIGHT	73
120 #define BV_LAYERS_WIDTH		73
121 #define BV_SHADES_HEIGHT	(8+9*16)
122 
123 /* These are control ids for the layers palette controls */
124 #define CID_VBase	1000
125 #define CID_VGrid	(CID_VBase+ly_grid)
126 #define CID_VBack	(CID_VBase+ly_back)
127 #define CID_VFore	(CID_VBase+ly_fore)
128 
129 #define CID_EBase	3000
130 #define CID_EGrid	(CID_EBase+ly_grid)
131 #define CID_EBack	(CID_EBase+ly_back)
132 #define CID_EFore	(CID_EBase+ly_fore)
133 
134 #define CID_QBase	5000
135 #define CID_QGrid	(CID_QBase+ly_grid)
136 #define CID_QBack	(CID_QBase+ly_back)
137 #define CID_QFore	(CID_QBase+ly_fore)
138 
139 #define CID_FBase	7000
140 
141 #define CID_SB		8000
142 #define CID_Edit	8001
143 
144 #define CID_AddLayer    9000
145 #define CID_RemoveLayer 9001
146 #define CID_RenameLayer 9002
147 #define CID_LayersMenu  9003
148 #define CID_LayerLabel  9004
149 
150 /* Initialize a window that is to be used for a palette. Specific widgets and other functionality are added elsewhere. */
CreatePalette(GWindow w,GRect * pos,int (* eh)(GWindow,GEvent *),void * user_data,GWindowAttrs * wattrs,GWindow v)151 static GWindow CreatePalette(GWindow w, GRect *pos, int (*eh)(GWindow,GEvent *), void *user_data, GWindowAttrs *wattrs, GWindow v) {
152     GWindow gw;
153     GPoint pt, base;
154     GRect newpos;
155     GWindow root;
156     GRect ownerpos, screensize;
157 
158     pt.x = pos->x; pt.y = pos->y;
159     if ( !palettes_fixed ) {
160 	root = GDrawGetRoot(NULL);
161 	GDrawGetSize(w,&ownerpos);
162 	GDrawGetSize(root,&screensize);
163 	GDrawTranslateCoordinates(w,root,&pt);
164 	base.x = base.y = 0;
165 	GDrawTranslateCoordinates(w,root,&base);
166 	if ( pt.x<0 ) {
167 	    if ( base.x+ownerpos.width+20+pos->width+20 > screensize.width )
168 		pt.x=0;
169 	    else
170 		pt.x = base.x+ownerpos.width+20;
171 	}
172 	if ( pt.y<0 ) pt.y=0;
173 	if ( pt.x+pos->width>screensize.width )
174 	    pt.x = screensize.width-pos->width;
175 	if ( pt.y+pos->height>screensize.height )
176 	    pt.y = screensize.height-pos->height;
177     }
178     wattrs->mask |= wam_bordcol|wam_bordwidth;
179     wattrs->border_width = 1;
180     wattrs->border_color = GDrawGetDefaultForeground(NULL);
181 
182     newpos.x = pt.x; newpos.y = pt.y; newpos.width = pos->width; newpos.height = pos->height;
183     wattrs->mask|= wam_positioned;
184     wattrs->positioned = true;
185     if (palettes_docked) {
186         pos->x = 0;
187         gw = GDrawCreateSubWindow(v, pos, eh, user_data, wattrs);
188     } else {
189         wattrs->mask |= wam_palette;
190         gw = GDrawCreateTopWindow(NULL,&newpos,eh,user_data,wattrs);
191     }
192 
193 return( gw );
194 }
195 
196 
197 
198 /* Return screen coordinates of the palette in off, relative to the root window origin. */
SaveOffsets(GWindow main,GWindow palette,GPoint * off)199 static void SaveOffsets(GWindow main, GWindow palette, GPoint *off) {
200     if ( !palettes_docked && !palettes_fixed && GDrawIsVisible(palette)) {
201 	GRect mr, pr;
202 	GWindow root, temp;
203 	root = GDrawGetRoot(NULL);
204 	while ( (temp=GDrawGetParentWindow(main))!=root )
205 	    main = temp;
206 	GDrawGetSize(main,&mr);
207 	GDrawGetSize(palette,&pr);
208 	off->x = pr.x-mr.x;
209 	off->y = pr.y-mr.y;
210 	if ( off->x<0 ) off->x = 0;
211 	if ( off->y<0 ) off->y = 0;
212     }
213 }
214 
215 /* Set the palette window position to off, a point in the root window space. */
RestoreOffsets(GWindow main,GWindow palette,GPoint * off)216 static void RestoreOffsets(GWindow main, GWindow palette, GPoint *off) {
217     GPoint pt;
218     GWindow root,temp;
219     GRect screensize, pos;
220 
221     if ( palettes_fixed )
222 return;
223     pt = *off;
224     root = GDrawGetRoot(NULL);
225     GDrawGetSize(root,&screensize);
226     GDrawGetSize(palette,&pos);
227     while ( (temp=GDrawGetParentWindow(main))!=root )
228 	main = temp;
229     GDrawTranslateCoordinates(main,root,&pt);
230     if ( pt.x<0 ) pt.x=0;
231     if ( pt.y<0 ) pt.y=0;
232     if ( pt.x+pos.width>screensize.width )
233 	pt.x = screensize.width-pos.width;
234     if ( pt.y+pos.height>screensize.height )
235 	pt.y = screensize.height-pos.height;
236     GDrawTrueMove(palette,pt.x,pt.y);
237     GDrawRaise(palette);
238 }
239 
CVMenuTool(GWindow gw,struct gmenuitem * mi,GEvent * e)240 static void CVMenuTool(GWindow gw,struct gmenuitem *mi,GEvent *e) {
241     CharView *cv = (CharView *) GDrawGetUserData(gw);
242     cv->b1_tool = mi->mid;
243     if ( cvtools!=NULL )
244 	GDrawRequestExpose(cvtools,NULL,false);
245     CVToolsSetCursor(cv,0,NULL);
246 }
247 
248 static void CVChangeSpiroMode(CharView *cv);
CVMenuSpiroSet(GWindow gw,struct gmenuitem * mi,GEvent * e)249 static void CVMenuSpiroSet(GWindow gw,struct gmenuitem *mi,GEvent *e) {
250     CharView *cv = (CharView *) GDrawGetUserData(gw);
251     CVChangeSpiroMode(cv);
252 }
253 
cvtoollist_check(GWindow gw,struct gmenuitem * mi,GEvent * e)254 void cvtoollist_check(GWindow gw,struct gmenuitem *mi,GEvent *e) {
255     CharView *cv = (CharView *) GDrawGetUserData(gw);
256     int order2 = cv->b.layerheads[cv->b.drawmode]->order2;
257 
258     for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
259 	mi->ti.checked = mi->mid==cv->b1_tool;
260 	switch ( mi->mid ) {
261 	  case cvt_freehand:
262 	    mi->ti.disabled = order2;
263 	  break;
264 	  case cvt_spiro:
265 	    mi->ti.disabled = !hasspiro();
266 	  break;
267         }
268     }
269 }
270 
271 /* Note: If you change this ordering, change enum cvtools */
272 static char *popupsres[] = {
273     N_("Pointer"),               N_("Magnify (Minify with alt)"),
274     N_("Draw a freehand curve"), N_("Scroll by hand"),
275     N_("Cut splines in two"),    N_("Measure distance, angle between points"),
276     N_("Add a point, then drag out its control points"), N_("Change whether spiro is active or not"),
277     N_("Add a curve point"),     N_("Add a curve point always either horizontal or vertical"),
278     N_("Add a corner point"),    N_("Add a tangent point"),
279     N_("Scale the selection"),   N_("Rotate the selection"),
280     N_("Flip the selection"),  N_("Skew the selection"),
281     N_("Rotate the selection in 3D and project back to plane"), N_("Perform a perspective transformation on the selection"),
282     N_("Rectangle or Ellipse"),  N_("Polygon or Star"),
283     N_("Rectangle or Ellipse"),  N_("Polygon or Star")};
284 GMenuItem2 cvtoollist[] = {
285     { { (unichar_t *) N_("_Pointer"), (GImage *) "toolspointer.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'C' }, H_("Pointer|No Shortcut"), NULL, NULL, CVMenuTool, cvt_pointer },
286     { { (unichar_t *) N_("_Magnify"), (GImage *) "toolsmagnify.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'C' }, H_("Magnify|No Shortcut"), NULL, NULL, CVMenuTool, cvt_magnify },
287     { { (unichar_t *) N_("_Freehand"), (GImage *) "toolsfreehand.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'C' }, H_("Freehand|No Shortcut"), NULL, NULL, CVMenuTool, cvt_freehand },
288     { { (unichar_t *) N_("_Scroll"), (GImage *) "toolsscroll.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'C' }, H_("Scroll|No Shortcut"), NULL, NULL, CVMenuTool, cvt_hand },
289     { { (unichar_t *) N_("_Knife"), (GImage *) "toolsknife.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Knife|No Shortcut"), NULL, NULL, CVMenuTool, cvt_knife },
290     { { (unichar_t *) N_("_Ruler"), (GImage *) "toolsruler.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Ruler|No Shortcut"), NULL, NULL, CVMenuTool, cvt_ruler },
291     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
292     { { (unichar_t *) N_("P_en"), (GImage *) "toolspen.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Pen|No Shortcut"), NULL, NULL, CVMenuTool, cvt_pen },
293     { { (unichar_t *) N_("_Activate Spiro"), (GImage *) "toolsspiro.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Activate Spiro|No Shortcut"), NULL, NULL, CVMenuSpiroSet, cvt_spiro },
294     { { (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, CVMenuTool, cvt_curve },
295     { { (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, CVMenuTool, cvt_hvcurve },
296     { { (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, CVMenuTool, cvt_corner },
297     { { (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, CVMenuTool, cvt_tangent },
298     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
299     { { (unichar_t *) N_("Sca_le"), (GImage *) "toolsscale.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Scale|No Shortcut"), NULL, NULL, CVMenuTool, cvt_scale },
300     { { (unichar_t *) N_("Rotate"), (GImage *) "toolsrotate.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Rotate|No Shortcut"), NULL, NULL, CVMenuTool, cvt_rotate },
301     { { (unichar_t *) N_("Flip"), (GImage *) "toolsflip.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Flip|No Shortcut"), NULL, NULL, CVMenuTool, cvt_flip },
302     { { (unichar_t *) N_("Ske_w"), (GImage *) "toolsskew.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Skew|No Shortcut"), NULL, NULL, CVMenuTool, cvt_skew },
303     { { (unichar_t *) N_("_3D Rotate"), (GImage *) "tools3drotate.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("3D Rotate|No Shortcut"), NULL, NULL, CVMenuTool, cvt_3d_rotate },
304     { { (unichar_t *) N_("Perspecti_ve"), (GImage *) "toolsperspective.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Perspective|No Shortcut"), NULL, NULL, CVMenuTool, cvt_perspective },
305     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
306     { { (unichar_t *) N_("Rectan_gle"), (GImage *) "toolsrect.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Rectangle|No Shortcut"), NULL, NULL, CVMenuTool, cvt_rect },
307     { { (unichar_t *) N_("Pol_ygon"), (GImage *) "toolspolygon.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Polygon|No Shortcut"), NULL, NULL, CVMenuTool, cvt_poly },
308     { { (unichar_t *) N_("Ellipse"), (GImage *) "toolselipse.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Ellipse|No Shortcut"), NULL, NULL, CVMenuTool, cvt_elipse },
309     { { (unichar_t *) N_("Star"), (GImage *) "toolsstar.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Star|No Shortcut"), NULL, NULL, CVMenuTool, cvt_star },
310     GMENUITEM2_EMPTY
311 };
312 GMenuItem2 cvspirotoollist[] = {
313     { { (unichar_t *) N_("_Pointer"), (GImage *) "toolspointer.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'C' }, H_("Pointer|No Shortcut"), NULL, NULL, CVMenuTool, cvt_pointer },
314     { { (unichar_t *) N_("_Magnify"), (GImage *) "toolsmagnify.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'C' }, H_("Magnify|No Shortcut"), NULL, NULL, CVMenuTool, cvt_magnify },
315     { { (unichar_t *) N_("_Freehand"), (GImage *) "toolsfreehand.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'C' }, H_("Freehand|No Shortcut"), NULL, NULL, CVMenuTool, cvt_freehand },
316     { { (unichar_t *) N_("_Scroll"), (GImage *) "toolsscroll.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'C' }, H_("Scroll|No Shortcut"), NULL, NULL, CVMenuTool, cvt_hand },
317     { { (unichar_t *) N_("_Knife"), (GImage *) "toolsknife.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Knife|No Shortcut"), NULL, NULL, CVMenuTool, cvt_knife },
318     { { (unichar_t *) N_("_Ruler"), (GImage *) "toolsruler.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Ruler|No Shortcut"), NULL, NULL, CVMenuTool, cvt_ruler },
319     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
320     { { (unichar_t *) N_("_Knife"), (GImage *) "toolsknife.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Knife|No Shortcut"), NULL, NULL, CVMenuTool, cvt_knife },
321     { { (unichar_t *) N_("_Ruler"), (GImage *) "toolsruler.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Ruler|No Shortcut"), NULL, NULL, CVMenuTool, cvt_ruler },
322     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
323     { { (unichar_t *) N_("De_activate Spiro"), (GImage *) "toolsspiro.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Activate Spiro|No Shortcut"), NULL, NULL, CVMenuSpiroSet, cvt_spiro },
324     { { (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, CVMenuTool, cvt_spirocorner },
325     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
326     { { (unichar_t *) N_("G_4"), (GImage *) "pointscurve.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'C' }, H_("G4|No Shortcut"), NULL, NULL, CVMenuTool, cvt_spirog4 },
327     { { (unichar_t *) N_("G_2"), (GImage *) "pointsG2curve.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'o' }, H_("G2|No Shortcut"), NULL, NULL, CVMenuTool, cvt_spirog2 },
328     { { (unichar_t *) N_("Lef_t"), (GImage *) "pointsspiroprev.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Left|No Shortcut"), NULL, NULL, CVMenuTool, cvt_spiroleft },
329     { { (unichar_t *) N_("Rig_ht"), (GImage *) "pointsspironext.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Right|No Shortcut"), NULL, NULL, CVMenuTool, cvt_spiroright },
330     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
331     { { (unichar_t *) N_("Sca_le"), (GImage *) "toolsscale.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Scale|No Shortcut"), NULL, NULL, CVMenuTool, cvt_scale },
332     { { (unichar_t *) N_("Rotate"), (GImage *) "toolsrotate.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Rotate|No Shortcut"), NULL, NULL, CVMenuTool, cvt_rotate },
333     { { (unichar_t *) N_("Flip"), (GImage *) "toolsflip.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Flip|No Shortcut"), NULL, NULL, CVMenuTool, cvt_flip },
334     { { (unichar_t *) N_("Ske_w"), (GImage *) "toolsskew.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Skew|No Shortcut"), NULL, NULL, CVMenuTool, cvt_skew },
335     { { (unichar_t *) N_("_3D Rotate"), (GImage *) "tools3drotate.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("3D Rotate|No Shortcut"), NULL, NULL, CVMenuTool, cvt_3d_rotate },
336     { { (unichar_t *) N_("Perspecti_ve"), (GImage *) "toolsperspective.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Perspective|No Shortcut"), NULL, NULL, CVMenuTool, cvt_perspective },
337     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
338     { { (unichar_t *) N_("Rectan_gle"), (GImage *) "toolsrect.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Rectangle|No Shortcut"), NULL, NULL, CVMenuTool, cvt_rect },
339     { { (unichar_t *) N_("Pol_ygon"), (GImage *) "toolspolygon.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Polygon|No Shortcut"), NULL, NULL, CVMenuTool, cvt_poly },
340     { { (unichar_t *) N_("Ellipse"), (GImage *) "toolselipse.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Ellipse|No Shortcut"), NULL, NULL, CVMenuTool, cvt_elipse },
341     { { (unichar_t *) N_("Star"), (GImage *) "toolsstar.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Star|No Shortcut"), NULL, NULL, CVMenuTool, cvt_star },
342     GMENUITEM2_EMPTY
343 };
344 
345 static char *editablelayers[] = {
346 /* GT: Foreground, make it short */
347     N_("F_ore"),
348 /* GT: Background, make it short */
349     N_("_Back"),
350 /* GT: Guide layer, make it short */
351     N_("_Guide")
352 };
353 static real raddiam_x = 20, raddiam_y = 20, rotate_by=0;
354 
CVRoundRectRadius(void)355 real CVRoundRectRadius(void) {
356 return( rr_radius );
357 }
358 
CVRectElipseCenter(void)359 int CVRectElipseCenter(void) {
360 return( center_out[rectelipse] );
361 }
362 
CVPolyStarPoints(void)363 int CVPolyStarPoints(void) {
364 return( ps_pointcnt );
365 }
366 
CVStarRatio(void)367 real CVStarRatio(void) {
368     if ( regular_star )
369 return( sin(FF_PI/ps_pointcnt)*tan(2*FF_PI/ps_pointcnt)+cos(FF_PI/ps_pointcnt) );
370 
371 return( star_percent );
372 }
373 
374 struct ask_info {
375     GWindow gw;
376     int done;
377     int ret;
378     float *val;
379     int *co;
380     GGadget *rb1;
381     GGadget *reg;
382     GGadget *pts;
383     int ispolystar;
384     int haspos;
385     char *lab;
386     CharView *cv;
387 };
388 #define CID_ValText		1001
389 #define CID_PointPercent	1002
390 #define CID_CentCornLab		1003
391 #define CID_CentCornX		1004
392 #define CID_CentCornY		1005
393 #define CID_RadDiamLab		1006
394 #define CID_RadDiamX		1007
395 #define CID_RadDiamY		1008
396 #define CID_Angle		1009
397 
FakeShapeEvents(CharView * cv)398 static void FakeShapeEvents(CharView *cv) {
399     GEvent event;
400     real trans[6];
401 
402     cv->active_tool = rectelipse ? cvt_elipse : cvt_rect;
403     if ( cv->b.sc->inspiro && hasspiro() ) {
404 	GDrawSetCursor(cv->v,spirotools[cv->active_tool]);
405 	GDrawSetCursor(cvtools,spirotools[cv->active_tool]);
406     } else {
407 	GDrawSetCursor(cv->v,tools[cv->active_tool]);
408 	GDrawSetCursor(cvtools,tools[cv->active_tool]);
409     }
410     cv->showing_tool = cv->active_tool;
411 
412     memset(&event,0,sizeof(event));
413     event.type = et_mousedown;
414     CVMouseDownShape(cv,&event);
415     cv->info.x += raddiam_x;
416     cv->info.y += raddiam_y;
417     CVMouseMoveShape(cv);
418     CVMouseUpShape(cv);
419     if ( raddiam_x!=0 && raddiam_y!=0 && rotate_by!=0 ) {
420 	trans[0] = trans[3] = cos ( rotate_by*FF_PI/180. );
421 	trans[1] = sin( rotate_by*FF_PI/180. );
422 	trans[2] = -trans[1];
423 	trans[4] = -cv->p.x*trans[0] - cv->p.y*trans[2] + cv->p.x;
424 	trans[5] = -cv->p.x*trans[1] - cv->p.y*trans[3] + cv->p.y;
425 	SplinePointListTransform(cv->b.layerheads[cv->b.drawmode]->splines,trans,
426 		interpCPsOnMotion?tpt_OnlySelectedInterpCPs:tpt_OnlySelected);
427 	SCUpdateAll(cv->b.sc);
428     }
429     cv->active_tool = cvt_none;
430 }
431 
TA_OK(GGadget * g,GEvent * e)432 static int TA_OK(GGadget *g, GEvent *e) {
433     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
434 	struct ask_info *d = GDrawGetUserData(GGadgetGetWindow(g));
435 	real val, val2=0;
436 	int err=0;
437 	int re = !GGadgetIsChecked(d->rb1);
438 	if ( d->ispolystar ) {
439 	    val = GetInt8(d->gw,CID_ValText,d->lab,&err);
440 	    if ( !(regular_star = GGadgetIsChecked(d->reg)))
441 		val2 = GetReal8(d->gw,CID_PointPercent,_("Size of Points"),&err);
442 	} else {
443 	    val = GetReal8(d->gw,CID_ValText,d->lab,&err);
444 	    d->co[re] = !GGadgetIsChecked(d->reg);
445 	}
446 	if ( err )
447 return( true );
448 	if ( d->haspos ) {
449 	    real x,y, radx,rady, ang;
450 	    x = GetInt8(d->gw,CID_CentCornX,_("_X"),&err);
451 	    y = GetInt8(d->gw,CID_CentCornY,_("_Y"),&err);
452 	    radx = GetInt8(d->gw,CID_RadDiamX,_("Radius:   "),&err);
453 	    rady = GetInt8(d->gw,CID_RadDiamY,_("Radius:   "),&err);
454 	    ang = GetInt8(d->gw,CID_Angle,_("Angle:"),&err);
455 	    if ( err )
456 return( true );
457 	    d->cv->p.x = d->cv->info.x = x;
458 	    d->cv->p.y = d->cv->info.y = y;
459 	    raddiam_x = radx; raddiam_y = rady;
460 	    rotate_by = ang;
461 	    rectelipse = re;
462 	    *d->val = val;
463 	    FakeShapeEvents(d->cv);
464 	}
465 	*d->val = val;
466 	d->ret = re;
467 	d->done = true;
468 	if ( !regular_star && d->ispolystar )
469 	    star_percent = val2/100;
470 	SavePrefs(true);
471     }
472 return( true );
473 }
474 
TA_Cancel(GGadget * g,GEvent * e)475 static int TA_Cancel(GGadget *g, GEvent *e) {
476     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
477 	struct ask_info *d = GDrawGetUserData(GGadgetGetWindow(g));
478 	d->done = true;
479     }
480 return( true );
481 }
482 
TA_CenRadChange(GGadget * g,GEvent * e)483 static int TA_CenRadChange(GGadget *g, GEvent *e) {
484     if ( e->type==et_controlevent && e->u.control.subtype == et_radiochanged ) {
485 	struct ask_info *d = GDrawGetUserData(GGadgetGetWindow(g));
486 	int is_bb = GGadgetIsChecked(d->reg);
487 	GGadgetSetTitle8(GWidgetGetControl(d->gw,CID_CentCornLab),
488 		is_bb ? _("Corner") : _("C_enter"));
489 	GGadgetSetTitle8(GWidgetGetControl(d->gw,CID_RadDiamLab),
490 		is_bb ? _("Diameter:") : _("Radius:   "));
491     }
492 return( true );
493 }
494 
TA_RadChange(GGadget * g,GEvent * e)495 static int TA_RadChange(GGadget *g, GEvent *e) {
496     if ( e->type==et_controlevent && e->u.control.subtype == et_radiochanged ) {
497 	struct ask_info *d = GDrawGetUserData(GGadgetGetWindow(g));
498 	int is_ellipse = !GGadgetIsChecked(d->rb1);
499 	GGadgetSetEnabled(GWidgetGetControl(d->gw,CID_ValText), !is_ellipse );
500 	GGadgetSetChecked(d->reg,!center_out[is_ellipse]);
501 	GGadgetSetChecked(d->pts,center_out[is_ellipse]);
502 	if ( d->haspos )
503 	    TA_CenRadChange(g,e);
504     }
505 return( true );
506 }
507 
toolask_e_h(GWindow gw,GEvent * event)508 static int toolask_e_h(GWindow gw, GEvent *event) {
509     if ( event->type==et_close ) {
510 	struct ask_info *d = GDrawGetUserData(gw);
511 	d->done = true;
512     } else if ( event->type == et_map ) {
513 	/* Above palettes */
514 	GDrawRaise(gw);
515     }
516 return( event->type!=et_char );
517 }
518 
Ask(char * rb1,char * rb2,int rb,char * lab,float * val,int * co,int ispolystar,CharView * cv)519 static int Ask(char *rb1, char *rb2, int rb, char *lab, float *val, int *co,
520 	int ispolystar, CharView *cv ) {
521     struct ask_info d;
522     char buffer[20], buf[20];
523     char cenx[20], ceny[20], radx[20], rady[20], angle[20];
524     GRect pos;
525     GWindowAttrs wattrs;
526     GGadgetCreateData gcd[19];
527     GTextInfo label[19];
528     int off = ((ispolystar&1)?15:0) + ((ispolystar&2)?84:0);
529     int haspos = (ispolystar&2)?1:0;
530 
531     ispolystar &= 1;
532 
533     d.done = false;
534     d.ret = rb;
535     d.val = val;
536     d.co = co;
537     d.ispolystar = ispolystar;
538     d.haspos = haspos;
539     d.lab = lab;
540     d.cv = cv;
541 
542 	memset(&wattrs,0,sizeof(wattrs));
543 	wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict;
544 	wattrs.event_masks = ~(1<<et_charup);
545 	wattrs.restrict_input_to_me = 1;
546 	wattrs.undercursor = 1;
547 	wattrs.cursor = ct_pointer;
548 	wattrs.utf8_window_title = _("Shape Type");
549 	wattrs.is_dlg = true;
550 	pos.x = pos.y = 0;
551 	pos.width = GGadgetScale(GDrawPointsToPixels(NULL,190));
552 	pos.height = GDrawPointsToPixels(NULL,120+off);
553 	d.gw = GDrawCreateTopWindow(NULL,&pos,toolask_e_h,&d,&wattrs);
554 
555 	memset(&label,0,sizeof(label));
556 	memset(&gcd,0,sizeof(gcd));
557 
558 	label[0].text = (unichar_t *) rb1;
559 	label[0].text_is_1byte = true;
560 	gcd[0].gd.label = &label[0];
561 	gcd[0].gd.pos.x = 5; gcd[0].gd.pos.y = 5;
562 	gcd[0].gd.flags = gg_enabled|gg_visible | (rb==0?gg_cb_on:0);
563 	gcd[0].creator = GRadioCreate;
564 
565 	label[1].text = (unichar_t *) rb2;
566 	label[1].text_is_1byte = true;
567 	gcd[1].gd.label = &label[1];
568 	gcd[1].gd.pos.x = ispolystar?65:75; gcd[1].gd.pos.y = 5;
569 	gcd[1].gd.flags = gg_enabled|gg_visible | (rb==1?gg_cb_on:0);
570 	gcd[1].creator = GRadioCreate;
571 
572 	label[2].text = (unichar_t *) lab;
573 	label[2].text_is_1byte = true;
574 	gcd[2].gd.label = &label[2];
575 	gcd[2].gd.pos.x = 5; gcd[2].gd.pos.y = 25;
576 	gcd[2].gd.flags = gg_enabled|gg_visible ;
577 	gcd[2].creator = GLabelCreate;
578 
579 	sprintf( buffer, "%g", *val );
580 	label[3].text = (unichar_t *) buffer;
581 	label[3].text_is_1byte = true;
582 	gcd[3].gd.label = &label[3];
583 	gcd[3].gd.pos.x = 5; gcd[3].gd.pos.y = 40;
584 	gcd[3].gd.flags = gg_enabled|gg_visible ;
585 	gcd[3].gd.cid = CID_ValText;
586 	gcd[3].creator = GTextFieldCreate;
587 
588 	gcd[4].gd.pos.x = 20-3; gcd[4].gd.pos.y = 85+off;
589 	gcd[4].gd.pos.width = -1; gcd[4].gd.pos.height = 0;
590 	gcd[4].gd.flags = gg_visible | gg_enabled | gg_but_default;
591 	label[4].text = (unichar_t *) _("_OK");
592 	label[4].text_is_1byte = true;
593 	label[4].text_in_resource = true;
594 	gcd[4].gd.mnemonic = 'O';
595 	gcd[4].gd.label = &label[4];
596 	gcd[4].gd.handle_controlevent = TA_OK;
597 	gcd[4].creator = GButtonCreate;
598 
599 	gcd[5].gd.pos.x = -20; gcd[5].gd.pos.y = 85+3+off;
600 	gcd[5].gd.pos.width = -1; gcd[5].gd.pos.height = 0;
601 	gcd[5].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
602 	label[5].text = (unichar_t *) _("_Cancel");
603 	label[5].text_is_1byte = true;
604 	label[5].text_in_resource = true;
605 	gcd[5].gd.label = &label[5];
606 	gcd[5].gd.mnemonic = 'C';
607 	gcd[5].gd.handle_controlevent = TA_Cancel;
608 	gcd[5].creator = GButtonCreate;
609 
610 	if ( ispolystar ) {
611 	    label[6].text = (unichar_t *) _("Regular");
612 	    label[6].text_is_1byte = true;
613 	    gcd[6].gd.label = &label[6];
614 	    gcd[6].gd.pos.x = 5; gcd[6].gd.pos.y = 70;
615 	    gcd[6].gd.flags = gg_enabled|gg_visible | (rb==0?gg_cb_on:0);
616 	    gcd[6].creator = GRadioCreate;
617 
618 	    label[7].text = (unichar_t *) _("Points:");
619 	    label[7].text_is_1byte = true;
620 	    gcd[7].gd.label = &label[7];
621 	    gcd[7].gd.pos.x = 65; gcd[7].gd.pos.y = 70;
622 	    gcd[7].gd.flags = gg_enabled|gg_visible | (rb==1?gg_cb_on:0);
623 	    gcd[7].creator = GRadioCreate;
624 
625 	    sprintf( buf, "%4g", star_percent*100 );
626 	    label[8].text = (unichar_t *) buf;
627 	    label[8].text_is_1byte = true;
628 	    gcd[8].gd.label = &label[8];
629 	    gcd[8].gd.pos.x = 125; gcd[8].gd.pos.y = 70;  gcd[8].gd.pos.width=50;
630 	    gcd[8].gd.flags = gg_enabled|gg_visible ;
631 	    gcd[8].gd.cid = CID_PointPercent;
632 	    gcd[8].creator = GTextFieldCreate;
633 
634 	    label[9].text = (unichar_t *) "%";
635 	    label[9].text_is_1byte = true;
636 	    gcd[9].gd.label = &label[9];
637 	    gcd[9].gd.pos.x = 180; gcd[9].gd.pos.y = 70;
638 	    gcd[9].gd.flags = gg_enabled|gg_visible ;
639 	    gcd[9].creator = GLabelCreate;
640 	} else {
641 	    label[6].text = (unichar_t *) _("Bounding Box");
642 	    label[6].text_is_1byte = true;
643 	    gcd[6].gd.label = &label[6];
644 	    gcd[6].gd.pos.x = 5; gcd[6].gd.pos.y = 65;
645 	    gcd[6].gd.flags = gg_enabled|gg_visible | (co[rb]==0?gg_cb_on:0);
646 	    gcd[6].creator = GRadioCreate;
647 
648 	    label[7].text = (unichar_t *) _("Center Out");
649 	    label[7].text_is_1byte = true;
650 	    gcd[7].gd.label = &label[7];
651 	    gcd[7].gd.pos.x = 90; gcd[7].gd.pos.y = 65;
652 	    gcd[7].gd.flags = gg_enabled|gg_visible | (co[rb]==1?gg_cb_on:0);
653 	    gcd[7].creator = GRadioCreate;
654 
655 	    if ( rb )
656 		gcd[3].gd.flags = gg_visible;
657 	    gcd[0].gd.handle_controlevent = TA_RadChange;
658 	    gcd[1].gd.handle_controlevent = TA_RadChange;
659 
660 	    if ( haspos ) {
661 		gcd[6].gd.handle_controlevent = TA_CenRadChange;
662 		gcd[7].gd.handle_controlevent = TA_CenRadChange;
663 
664 		label[8].text = (unichar_t *) _("_X");
665 		label[8].text_is_1byte = true;
666 		label[8].text_in_resource = true;
667 		gcd[8].gd.label = &label[8];
668 		gcd[8].gd.pos.x = 70; gcd[8].gd.pos.y = gcd[7].gd.pos.y+15;
669 		gcd[8].gd.flags = gg_enabled|gg_visible;
670 		gcd[8].creator = GLabelCreate;
671 
672 		label[9].text = (unichar_t *) _("_Y");
673 		label[9].text_is_1byte = true;
674 		label[9].text_in_resource = true;
675 		gcd[9].gd.label = &label[9];
676 		gcd[9].gd.pos.x = 120; gcd[9].gd.pos.y = gcd[8].gd.pos.y;
677 		gcd[9].gd.flags = gg_enabled|gg_visible;
678 		gcd[9].creator = GLabelCreate;
679 
680 		label[10].text = (unichar_t *) (co[rb] ? _("C_enter") : _("C_orner") );
681 		label[10].text_is_1byte = true;
682 		label[10].text_in_resource = true;
683 		gcd[10].gd.label = &label[10];
684 		gcd[10].gd.pos.x = 5; gcd[10].gd.pos.y = gcd[8].gd.pos.y+17;
685 		gcd[10].gd.flags = gg_enabled|gg_visible;
686 		gcd[10].gd.cid = CID_CentCornLab;
687 		gcd[10].creator = GLabelCreate;
688 
689 		sprintf( cenx, "%g", (double) cv->info.x );
690 		label[11].text = (unichar_t *) cenx;
691 		label[11].text_is_1byte = true;
692 		gcd[11].gd.label = &label[11];
693 		gcd[11].gd.pos.x = 60; gcd[11].gd.pos.y = gcd[10].gd.pos.y-4;
694 		gcd[11].gd.pos.width = 40;
695 		gcd[11].gd.flags = gg_enabled|gg_visible;
696 		gcd[11].gd.cid = CID_CentCornX;
697 		gcd[11].creator = GTextFieldCreate;
698 
699 		sprintf( ceny, "%g", (double) cv->info.y );
700 		label[12].text = (unichar_t *) ceny;
701 		label[12].text_is_1byte = true;
702 		gcd[12].gd.label = &label[12];
703 		gcd[12].gd.pos.x = 110; gcd[12].gd.pos.y = gcd[11].gd.pos.y;
704 		gcd[12].gd.pos.width = gcd[11].gd.pos.width;
705 		gcd[12].gd.flags = gg_enabled|gg_visible;
706 		gcd[12].gd.cid = CID_CentCornY;
707 		gcd[12].creator = GTextFieldCreate;
708 
709 		label[13].text = (unichar_t *) (co[rb] ? _("Radius:   ") : _("Diameter:") );
710 		label[13].text_is_1byte = true;
711 		gcd[13].gd.label = &label[13];
712 		gcd[13].gd.pos.x = 5; gcd[13].gd.pos.y = gcd[10].gd.pos.y+24;
713 		gcd[13].gd.flags = gg_enabled|gg_visible;
714 		gcd[13].gd.cid = CID_RadDiamLab;
715 		gcd[13].creator = GLabelCreate;
716 
717 		sprintf( radx, "%g", (double) raddiam_x );
718 		label[14].text = (unichar_t *) radx;
719 		label[14].text_is_1byte = true;
720 		gcd[14].gd.label = &label[14];
721 		gcd[14].gd.pos.x = gcd[11].gd.pos.x; gcd[14].gd.pos.y = gcd[13].gd.pos.y-4;
722 		gcd[14].gd.pos.width = gcd[11].gd.pos.width;
723 		gcd[14].gd.flags = gg_enabled|gg_visible;
724 		gcd[14].gd.cid = CID_RadDiamX;
725 		gcd[14].creator = GTextFieldCreate;
726 
727 		sprintf( rady, "%g", (double) raddiam_y );
728 		label[15].text = (unichar_t *) rady;
729 		label[15].text_is_1byte = true;
730 		gcd[15].gd.label = &label[15];
731 		gcd[15].gd.pos.x = gcd[12].gd.pos.x; gcd[15].gd.pos.y = gcd[14].gd.pos.y;
732 		gcd[15].gd.pos.width = gcd[11].gd.pos.width;
733 		gcd[15].gd.flags = gg_enabled|gg_visible;
734 		gcd[15].gd.cid = CID_RadDiamY;
735 		gcd[15].creator = GTextFieldCreate;
736 
737 		label[16].text = (unichar_t *) _("Angle:");
738 		label[16].text_is_1byte = true;
739 		gcd[16].gd.label = &label[16];
740 		gcd[16].gd.pos.x = 5; gcd[16].gd.pos.y = gcd[13].gd.pos.y+24;
741 		gcd[16].gd.flags = gg_enabled|gg_visible;
742 		gcd[16].creator = GLabelCreate;
743 
744 		sprintf( angle, "%g", (double) rotate_by );
745 		label[17].text = (unichar_t *) angle;
746 		label[17].text_is_1byte = true;
747 		gcd[17].gd.label = &label[17];
748 		gcd[17].gd.pos.x = 60; gcd[17].gd.pos.y = gcd[16].gd.pos.y-4;
749 		gcd[17].gd.pos.width = gcd[11].gd.pos.width;
750 		gcd[17].gd.flags = gg_enabled|gg_visible;
751 		gcd[17].gd.cid = CID_Angle;
752 		gcd[17].creator = GTextFieldCreate;
753 	    }
754 	}
755 	GGadgetsCreate(d.gw,gcd);
756     d.rb1 = gcd[0].ret;
757     d.reg = gcd[6].ret;
758     d.pts = gcd[7].ret;
759 
760     GWidgetHidePalettes();
761     GDrawSetVisible(d.gw,true);
762     while ( !d.done )
763 	GDrawProcessOneEvent(NULL);
764     GDrawDestroyWindow(d.gw);
765 return( d.ret );
766 }
767 
CVRectElipse(CharView * cv)768 static void CVRectElipse(CharView *cv) {
769     rectelipse = Ask(_("Rectangle"),_("Ellipse"),rectelipse,
770 	    _("Round Rectangle Radius"),&rr_radius,center_out,false, cv);
771     GDrawRequestExpose(cvtools,NULL,false);
772 }
773 
CVRectEllipsePosDlg(CharView * cv)774 void CVRectEllipsePosDlg(CharView *cv) {
775     rectelipse = Ask(_("Rectangle"),_("Ellipse"),rectelipse,
776 	    _("Round Rectangle Radius"),&rr_radius,center_out,2, cv);
777     GDrawRequestExpose(cvtools,NULL,false);
778 }
779 
CVPolyStar(CharView * cv)780 static void CVPolyStar(CharView *cv) {
781     float temp = ps_pointcnt;
782     int foo[2];
783     polystar = Ask(_("Polygon"),_("Star"),polystar,
784 	    _("Number of star points/Polygon vertices"),&temp,foo,true, cv);
785     ps_pointcnt = temp;
786 }
787 
788 /* Note: If you change this ordering, change enum cvtools */
789 // index0 is non selected / selected image
790 // index1 is the row    in the toolbar
791 // index2 is the column in the toolbar
792 //
793 // This is two null terminated collections. The second collection
794 // contains the alternate icons for circle and star at the bottom of
795 // the toolbar.
796 static GImage *normbuttons[2][14][2] = {
797     {
798 	{ &GIcon_pointer,  &GIcon_magnify },
799 	{ &GIcon_freehand, &GIcon_hand },
800 	{ &GIcon_knife,    &GIcon_ruler },
801 	{ &GIcon_pen,      &GIcon_spirodisabled },
802 	{ &GIcon_curve,    &GIcon_hvcurve },
803 	{ &GIcon_corner,   &GIcon_tangent},
804 	{ &GIcon_scale,    &GIcon_rotate },
805 	{ &GIcon_flip,     &GIcon_skew },
806 	{ &GIcon_3drotate, &GIcon_perspective },
807 	{ &GIcon_rect,     &GIcon_poly},
808 	{ 0, 0 },
809 	{ &GIcon_elipse,   &GIcon_star},
810 	{ 0, 0 },
811 	{ 0, 0 }
812     }
813     , {
814 	{ &GIcon_pointer_selected,  &GIcon_magnify_selected },
815 	{ &GIcon_freehand_selected, &GIcon_hand_selected },
816 	{ &GIcon_knife_selected,    &GIcon_ruler_selected },
817 	{ &GIcon_pen_selected,      &GIcon_spiroup_selected },
818 	{ &GIcon_curve_selected,    &GIcon_hvcurve_selected },
819 	{ &GIcon_corner_selected,   &GIcon_tangent_selected},
820 	{ &GIcon_scale_selected,    &GIcon_rotate_selected },
821 	{ &GIcon_flip_selected,     &GIcon_skew_selected },
822 	{ &GIcon_3drotate_selected, &GIcon_perspective_selected },
823 	{ &GIcon_rect_selected,     &GIcon_poly_selected},
824 	{ 0, 0 },
825 	{ &GIcon_elipse_selected,   &GIcon_star_selected},
826 	{ 0, 0 },
827 	{ 0, 0 }
828     }};
829 static GImage *spirobuttons[2][14][2] = {
830     {
831 	{ &GIcon_pointer,      &GIcon_magnify },
832 	{ &GIcon_freehand,     &GIcon_hand },
833 	{ &GIcon_knife,        &GIcon_ruler },
834 	{ &GIcon_spiroright,   &GIcon_spirodown },
835 	{ &GIcon_spirocurve,   &GIcon_spirog2curve },
836 	{ &GIcon_spirocorner,  &GIcon_spiroleft },
837 	{ &GIcon_scale,        &GIcon_rotate },
838 	{ &GIcon_flip,         &GIcon_skew },
839 	{ &GIcon_3drotate,     &GIcon_perspective },
840 	{ &GIcon_rect,         &GIcon_poly},
841 	{ 0, 0 },
842 	{ &GIcon_elipse,       &GIcon_star},
843 	{ 0, 0 },
844 	{ 0, 0 }
845     }
846     , {
847 	{ &GIcon_pointer_selected,     &GIcon_magnify_selected },
848 	{ &GIcon_freehand_selected,    &GIcon_hand_selected },
849 	{ &GIcon_knife_selected,       &GIcon_ruler_selected },
850 	{ &GIcon_spiroright_selected,  &GIcon_spirodown_selected },
851 	{ &GIcon_spirocurve_selected,  &GIcon_spirog2curve_selected },
852 	{ &GIcon_spirocorner_selected, &GIcon_spiroleft_selected },
853 	{ &GIcon_scale_selected,       &GIcon_rotate_selected },
854 	{ &GIcon_flip_selected,        &GIcon_skew_selected },
855 	{ &GIcon_3drotate_selected,    &GIcon_perspective_selected },
856 	{ &GIcon_rect_selected,        &GIcon_poly_selected},
857 	{ 0, 0 },
858 	{ &GIcon_elipse_selected,      &GIcon_star_selected},
859 	{ 0, 0 },
860 	{ 0, 0 }
861     }};
862 static GImage *normsmalls[] = { &GIcon_smallpointer,  &GIcon_smallmag,
863 				&GIcon_smallpencil,   &GIcon_smallhand,
864 				&GIcon_smallknife,    &GIcon_smallruler,
865 				&GIcon_smallpen,      NULL,
866 				&GIcon_smallcurve,    &GIcon_smallhvcurve,
867 				&GIcon_smallcorner,   &GIcon_smalltangent,
868 				&GIcon_smallscale,    &GIcon_smallrotate,
869 				&GIcon_smallflip,     &GIcon_smallskew,
870 				&GIcon_small3drotate, &GIcon_smallperspective,
871 				&GIcon_smallrect,     &GIcon_smallpoly,
872 				&GIcon_smallelipse,   &GIcon_smallstar };
873 static GImage *spirosmalls[] = { &GIcon_smallpointer, &GIcon_smallmag,
874 				 &GIcon_smallpencil,  &GIcon_smallhand,
875 				 &GIcon_smallknife,   &GIcon_smallruler,
876 				 &GIcon_smallspiroright,  NULL,
877 				 &GIcon_smallspirocurve,  &GIcon_smallspirog2curve,
878 				 &GIcon_smallspirocorner, &GIcon_smallspiroleft,
879 				 &GIcon_smallscale,       &GIcon_smallrotate,
880 				 &GIcon_smallflip,        &GIcon_smallskew,
881 				 &GIcon_small3drotate,    &GIcon_smallperspective,
882 				 &GIcon_smallrect,        &GIcon_smallpoly,
883 				 &GIcon_smallelipse,      &GIcon_smallstar };
884 
getSmallIconsHeight()885 static int getSmallIconsHeight()
886 {
887     return GIcon_smallpointer.u.image->height;
888 }
889 
getToolbarWidth(CharView * cv)890 static int getToolbarWidth( CharView *cv )
891 {
892     int cache = 0;
893     if( !cache ) {
894 	GImage* (*buttons)[14][2] = (CVInSpiro(cv) ? spirobuttons : normbuttons);
895 	int i = 0;
896 
897 	for ( i=0; buttons[0][i][0]; ++i ) {
898 	    cache = MAX( cache, buttons[0][i][0]->u.image->width + buttons[0][i][1]->u.image->width );
899 	}
900     }
901     return cache;
902 }
903 
getToolbarHeight(CharView * cv)904 static int getToolbarHeight( CharView *cv )
905 {
906     int cache = 0;
907     if( !cache ) {
908 	GImage* (*buttons)[14][2] = (CVInSpiro(cv) ? spirobuttons : normbuttons);
909 	int i = 0;
910 
911 	for ( i=0; buttons[0][i][0]; ++i ) {
912 	    cache += MAX( buttons[0][i][0]->u.image->height, buttons[0][i][1]->u.image->height );
913 	}
914     }
915     cache += getSmallIconsHeight() * 4;
916     cache += 6;
917     return cache;
918 }
919 
920 
921 typedef struct _IJ
922 {
923     int i;
924     int j;
925 } IJ;
926 
927 typedef void (*visitButtonsVisitor) ( CharView *cv,             // CharView passed to visitButtons()
928 				      GImage* gimage, int mi,   // button we are visiting and adjusted 'i'
929 				      int i, int j,             // i and j position of button (j is across 0,1) (i is down 0...11)
930 				      int iconx, int icony,     // pixel where this button starts
931 				      int selected,             // is this button the active tool
932 				      void* udata );            // user data
933 
934 
935 /**
936  * Visit every button in the toolbar calling the function 'v' with a
937  * collection of interesting state data.
938  */
visitButtons(CharView * cv,visitButtonsVisitor v,void * udata)939 static void visitButtons( CharView* cv, visitButtonsVisitor v, void* udata )
940 {
941     GImage* (*buttons)[14][2] = (CVInSpiro(cv) ? spirobuttons : normbuttons);
942     int i,j,sel,norm, mi;
943     int tool = cv->cntrldown?cv->cb1_tool:cv->b1_tool;
944     int icony = 1;
945     for ( i=0; buttons[0][i][0]; ++i ) {
946 	int iconx = 1;
947 	for ( j=0; j<2 && buttons[0][i][j]; ++j ) {
948 
949 	    mi = i;
950 	    sel = (tool == mi*2+j );
951 	    if( buttons[0][mi][j] == &GIcon_rect && rectelipse
952 		|| buttons[0][mi][j] == &GIcon_poly && polystar )
953 	    {
954 		sel = (tool == (mi+1)*2+j );
955 		mi+=2;
956 	    }
957 
958 	    v( cv, buttons[sel][mi][j], mi, i, j, iconx, icony, sel, udata );
959 	    iconx += buttons[sel][mi][j]->u.image->width;
960 	}
961 	icony += MAX( buttons[0][i][0]->u.image->width, buttons[0][i][1]->u.image->width );
962     }
963 }
964 
965 typedef struct _getIJFromMouseVisitorData
966 {
967     int mx, my;
968     IJ ret;
969 } getIJFromMouseVisitorData;
970 
getIJFromMouseVisitor(CharView * cv,GImage * gimage,int mi,int i,int j,int iconx,int icony,int selected,void * udata)971 static void getIJFromMouseVisitor( CharView *cv, GImage* gimage,
972 				   int mi, int i, int j,
973 				   int iconx, int icony, int selected, void* udata )
974 {
975     getIJFromMouseVisitorData* d = (getIJFromMouseVisitorData*)udata;
976     if( IS_IN_ORDER3( iconx, d->mx, iconx + gimage->u.image->width )
977 	&& IS_IN_ORDER3( icony, d->my, icony + gimage->u.image->height ))
978 	{
979 	    d->ret.i = i;
980 	    d->ret.j = j;
981 	}
982 }
983 
984 /**
985  * Get the i,j coordinates of the toolbar button that is under the
986  * mouse at mx,my or return -1,-1 if nothing is under the mouse.
987  */
getIJFromMouse(CharView * cv,int mx,int my)988 static IJ getIJFromMouse( CharView* cv, int mx, int my )
989 {
990     getIJFromMouseVisitorData d;
991     d.mx = mx;
992     d.my = my;
993     d.ret.i = -1;
994     d.ret.j = -1;
995     visitButtons( cv, getIJFromMouseVisitor, &d );
996     return d.ret;
997 }
998 
999 /*
1000  * This draws the three-dimensional relief on a button. It gets the dimensions from the button image.
1001  */
1002 
cvp_draw_relief(GWindow pixmap,GImage * iconimg,int iconx,int icony,int selected)1003 void cvp_draw_relief(GWindow pixmap, GImage *iconimg, int iconx, int icony, int selected) {
1004 	extern Color cvbutton3dedgelightcol; // Default 0xe0e0e0.
1005 	extern Color cvbutton3dedgedarkcol; // Default 0x707070.
1006 	int iconw = iconimg->u.image->width;
1007 	int iconh = iconimg->u.image->height;
1008 	int norm = !selected;
1009 	// Note: The original code placed the right and bottom fake relief
1010 	// outside of the button image area (offset by 25 instead of 24),
1011 	// but we are staying just inside the image area now.
1012 	GDrawDrawLine(pixmap,iconx,icony,iconx+iconw,icony,norm?cvbutton3dedgelightcol:cvbutton3dedgedarkcol);
1013 	GDrawDrawLine(pixmap,iconx,icony,iconx,icony+iconh,norm?cvbutton3dedgelightcol:cvbutton3dedgedarkcol);
1014 	GDrawDrawLine(pixmap,iconx,icony+iconh,iconx+iconw,icony+iconh,norm?cvbutton3dedgedarkcol:cvbutton3dedgelightcol);
1015 	GDrawDrawLine(pixmap,iconx+iconw,icony,iconx+iconw,icony+iconh,norm?cvbutton3dedgedarkcol:cvbutton3dedgelightcol);
1016 }
1017 
1018 
1019 /**
1020  * This visitor draws the actual image for each toolbar button
1021  * The drawing is done to d->pixmap.
1022  * icony is the max
1023  */
1024 typedef struct _ToolsExposeVisitorData
1025 {
1026     GWindow pixmap;
1027     int     maxicony;       //< largest icony that the visitor saw
1028     int     lastIconHeight; //< height of the last icon visited
1029 } ToolsExposeVisitorData;
ToolsExposeVisitor(CharView * cv,GImage * gimage,int mi,int i,int j,int iconx,int icony,int selected,void * udata)1030 static void ToolsExposeVisitor( CharView *cv, GImage* gimage,
1031 				int mi, int i, int j,
1032 				int iconx, int icony, int selected, void* udata )
1033 {
1034 		extern int cvbutton3d; // This comes from elsewhere.
1035     ToolsExposeVisitorData* d = (ToolsExposeVisitorData*)udata;
1036     GImage* (*buttons)[14][2] = (CVInSpiro(cv) ? spirobuttons : normbuttons);
1037 
1038 		// We draw the button image onto the toolbar image.
1039 		GDrawDrawImage(d->pixmap,buttons[selected][mi][j],NULL,iconx,icony);
1040 
1041 		// We may need to draw relief, too.
1042 		if (cvbutton3d > 0) cvp_draw_relief(d->pixmap, buttons[0][mi][j], iconx, icony, selected);
1043 
1044     d->maxicony = MAX( d->maxicony, icony );
1045     d->lastIconHeight = buttons[selected][mi][j]->u.image->height;
1046 }
1047 
1048 
ToolsExpose(GWindow pixmap,CharView * cv,GRect * r)1049 static void ToolsExpose(GWindow pixmap, CharView *cv, GRect *r) {
1050     GRect old;
1051     static const unichar_t _Mouse[][9] = {
1052 	    { 'M', 's', 'e', '1',  '\0' },
1053 	    { '^', 'M', 's', 'e', '1',  '\0' },
1054 	    { 'M', 's', 'e', '2',  '\0' },
1055 	    { '^', 'M', 's', 'e', '2',  '\0' }};
1056     int i,j,sel,norm, mi;
1057     int tool = cv->cntrldown?cv->cb1_tool:cv->b1_tool;
1058     int dither = GDrawSetDither(NULL,false);
1059     GRect temp;
1060     int canspiro = hasspiro(), inspiro = canspiro && cv->b.sc->inspiro;
1061     GImage* (*buttons)[14][2] = (inspiro ? spirobuttons : normbuttons);
1062     GImage **smalls = inspiro ? spirosmalls : normsmalls;
1063 
1064     normbuttons[0][3][1] = canspiro ? &GIcon_spiroup : &GIcon_spirodisabled;
1065 
1066     GDrawPushClip(pixmap,r,&old);
1067     GDrawFillRect(pixmap,r,GDrawGetDefaultBackground(NULL));
1068     GDrawSetLineWidth(pixmap,0);
1069 
1070     ToolsExposeVisitorData d;
1071     d.pixmap = pixmap;
1072     d.maxicony = 0;
1073     visitButtons( cv, ToolsExposeVisitor, &d );
1074     int bottomOfMainIconsY = d.maxicony + d.lastIconHeight;
1075 
1076 
1077     GDrawSetFont(pixmap,toolsfont);
1078     temp.x = 52-16;
1079     temp.y = bottomOfMainIconsY;
1080     temp.width = 16;
1081     temp.height = 4*12;
1082     GDrawFillRect(pixmap,&temp,GDrawGetDefaultBackground(NULL));
1083     for ( j=0; j<4; ++j ) {
1084 	GDrawDrawText(pixmap,2,bottomOfMainIconsY+j*getSmallIconsHeight()+10,
1085 		      (unichar_t *) _Mouse[j],-1,GDrawGetDefaultForeground(NULL));
1086 	if ( (&cv->b1_tool)[j]!=cvt_none && smalls[(&cv->b1_tool)[j]])
1087 	    GDrawDrawImage(pixmap,smalls[(&cv->b1_tool)[j]],NULL,52-16,bottomOfMainIconsY+j*getSmallIconsHeight());
1088     }
1089     GDrawPopClip(pixmap,&old);
1090     GDrawSetDither(NULL,dither);
1091 }
1092 
TrueCharState(GEvent * event)1093 int TrueCharState(GEvent *event) {
1094     int bit = 0;
1095     /* X doesn't set the state until after the event. I want the state to */
1096     /*  reflect whatever key just got depressed/released */
1097     int keysym = event->u.chr.keysym;
1098 
1099     if ( keysym == GK_Caps_Lock || keysym == GK_Shift_Lock ) {
1100 	static int set_on_last_down = false;
1101 	/* caps lock is sticky and doesn't work like the other modifiers */
1102 	/* but it is even worse. the bit seems to be set on key down, but */
1103 	/* unset on key up. In other words on key up, the bit will always */
1104 	/* set and we have no idea which way it will go. So we guess, and */
1105 	/* if they haven't messed with the key outside ff we should be right */
1106 	if ( event->type == et_char ) {
1107 	    set_on_last_down = (event->u.chr.state ^ ksm_capslock)& ksm_capslock;
1108 return( event->u.chr.state ^ ksm_capslock );
1109 	} else if ( !(event->u.chr.state & ksm_capslock) || set_on_last_down )
1110 return( event->u.chr.state );
1111 	else
1112 return( event->u.chr.state & ~ksm_capslock );
1113     }
1114 
1115     if ( keysym == GK_Meta_L || keysym == GK_Meta_R ||
1116 	    keysym == GK_Alt_L || keysym == GK_Alt_R )
1117 	bit = ksm_meta;
1118     else if ( keysym == GK_Shift_L || keysym == GK_Shift_R )
1119 	bit = ksm_shift;
1120     else if ( keysym == GK_Control_L || keysym == GK_Control_R )
1121 	bit = ksm_control;
1122     else if ( keysym == GK_Super_L || keysym == GK_Super_R )
1123 	bit = ksm_super;
1124     else if ( keysym == GK_Hyper_L || keysym == GK_Hyper_R )
1125 	bit = ksm_hyper;
1126     else
1127 return( event->u.chr.state );
1128 
1129     if ( event->type == et_char )
1130 return( event->u.chr.state | bit );
1131     else
1132 return( event->u.chr.state & ~bit );
1133 }
1134 
CVToolsSetCursor(CharView * cv,int state,char * device)1135 void CVToolsSetCursor(CharView *cv, int state, char *device) {
1136     int shouldshow;
1137     int cntrl;
1138 
1139     if ( tools[0] == ct_pointer ) {
1140 	tools[cvt_pointer] = ct_mypointer;
1141 	tools[cvt_magnify] = ct_magplus;
1142 	tools[cvt_freehand] = ct_pencil;
1143 	tools[cvt_hand] = ct_myhand;
1144 	tools[cvt_curve] = ct_circle;
1145 	tools[cvt_hvcurve] = ct_hvcircle;
1146 	tools[cvt_corner] = ct_square;
1147 	tools[cvt_tangent] = ct_triangle;
1148 	tools[cvt_pen] = ct_pen;
1149 	tools[cvt_knife] = ct_knife;
1150 	tools[cvt_ruler] = ct_ruler;
1151 	tools[cvt_scale] = ct_scale;
1152 	tools[cvt_flip] = ct_flip;
1153 	tools[cvt_rotate] = ct_rotate;
1154 	tools[cvt_skew] = ct_skew;
1155 	tools[cvt_3d_rotate] = ct_3drotate;
1156 	tools[cvt_perspective] = ct_perspective;
1157 	tools[cvt_rect] = ct_rect;
1158 	tools[cvt_poly] = ct_poly;
1159 	tools[cvt_elipse] = ct_elipse;
1160 	tools[cvt_star] = ct_star;
1161 	tools[cvt_minify] = ct_magminus;
1162 	memcpy(spirotools,tools,sizeof(tools));
1163 	spirotools[cvt_spirog2] = ct_g2circle;
1164 	spirotools[cvt_spiroleft] = ct_spiroleft;
1165 	spirotools[cvt_spiroright] = ct_spiroright;
1166     }
1167 
1168     shouldshow = cvt_none;
1169     if ( cv->active_tool!=cvt_none )
1170 	shouldshow = cv->active_tool;
1171     else if ( cv->pressed_display!=cvt_none )
1172 	shouldshow = cv->pressed_display;
1173     else if ( device==NULL || strcmp(device,"Mouse1")==0 ) {
1174 	if ( (state&(ksm_shift|ksm_control)) && (state&ksm_button4))
1175 	    shouldshow = cvt_magnify;
1176 	else if ( (state&(ksm_shift|ksm_control)) && (state&ksm_button5))
1177 	    shouldshow = cvt_minify;
1178 	else if ( (state&ksm_control) && (state&(ksm_button2|ksm_super)) )
1179 	    shouldshow = cv->cb2_tool;
1180 	else if ( (state&(ksm_button2|ksm_super)) )
1181 	    shouldshow = cv->b2_tool;
1182 	else if ( (state&ksm_control) )
1183 	    shouldshow = cv->cb1_tool;
1184 	else
1185 	    shouldshow = cv->b1_tool;
1186     } else if ( strcmp(device,"eraser")==0 )
1187 	shouldshow = cv->er_tool;
1188     else if ( strcmp(device,"stylus")==0 ) {
1189 	if ( (state&(ksm_button2|ksm_control|ksm_super)) )
1190 	    shouldshow = cv->s2_tool;
1191 	else
1192 	    shouldshow = cv->s1_tool;
1193     }
1194     if ( shouldshow==cvt_magnify && (state&ksm_meta))
1195 	shouldshow = cvt_minify;
1196     if ( shouldshow!=cv->showing_tool ) {
1197 	CPEndInfo(cv);
1198 	if ( cv->b.sc->inspiro && hasspiro()) {
1199 	    GDrawSetCursor(cv->v,spirotools[shouldshow]);
1200 	    if ( cvtools!=NULL )	/* Might happen if window owning docked palette destroyed */
1201 		GDrawSetCursor(cvtools,spirotools[shouldshow]);
1202 	} else {
1203 	    GDrawSetCursor(cv->v,tools[shouldshow]);
1204 	    if ( cvtools!=NULL )	/* Might happen if window owning docked palette destroyed */
1205 		GDrawSetCursor(cvtools,tools[shouldshow]);
1206 	}
1207 	cv->showing_tool = shouldshow;
1208     }
1209 
1210     if ( device==NULL || strcmp(device,"stylus")==0 ) {
1211 	cntrl = (state&ksm_control)?1:0;
1212 	if ( device!=NULL && (state&ksm_button2))
1213 	    cntrl = true;
1214 	if ( cntrl != cv->cntrldown ) {
1215 	    cv->cntrldown = cntrl;
1216 	    GDrawRequestExpose(cvtools,NULL,false);
1217 	}
1218     }
1219 }
1220 
CVCurrentTool(CharView * cv,GEvent * event)1221 static int CVCurrentTool(CharView *cv, GEvent *event) {
1222     if ( event->u.mouse.device!=NULL && strcmp(event->u.mouse.device,"eraser")==0 )
1223 return( cv->er_tool );
1224     else if ( event->u.mouse.device!=NULL && strcmp(event->u.mouse.device,"stylus")==0 ) {
1225 	if ( event->u.mouse.button==2 )
1226 	    /* Only thing that matters is touch which maps to button 1 */;
1227 	else if ( cv->had_control )
1228 return( cv->s2_tool );
1229 	else
1230 return( cv->s1_tool );
1231     }
1232     if ( cv->had_control && event->u.mouse.button==2 )
1233 return( cv->cb2_tool );
1234     else if ( event->u.mouse.button==2 )
1235 return( cv->b2_tool );
1236     else if ( cv->had_control ) {
1237 return( cv->cb1_tool );
1238     } else {
1239 return( cv->b1_tool );
1240     }
1241 }
1242 
SCCheckForSSToOptimize(SplineChar * sc,SplineSet * ss,int order2)1243 static void SCCheckForSSToOptimize(SplineChar *sc, SplineSet *ss,int order2) {
1244 
1245     for ( ; ss!=NULL ; ss = ss->next ) {
1246 	if ( ss->beziers_need_optimizer ) {
1247 	    SplineSetAddExtrema(sc,ss,ae_only_good,sc->parent->ascent+sc->parent->descent);
1248 	    ss->beziers_need_optimizer = false;
1249 	}
1250 	if ( order2 && ss->first->next!=NULL && !ss->first->next->order2 ) {
1251 	    SplineSet *temp = SSttfApprox(ss), foo;
1252 	    foo = *ss;
1253 	    ss->first = temp->first; ss->last = temp->last;
1254 	    temp->first = foo.first; temp->last = foo.last;
1255 	    SplinePointListFree(temp);
1256 	}
1257     }
1258 }
1259 
CVChangeSpiroMode(CharView * cv)1260 static void CVChangeSpiroMode(CharView *cv) {
1261     if ( hasspiro() ) {
1262 	cv->b.sc->inspiro = !cv->b.sc->inspiro;
1263 	cv->showing_tool = cvt_none;
1264 	CVClearSel(cv);
1265 	if ( !cv->b.sc->inspiro )
1266 	    SCCheckForSSToOptimize(cv->b.sc,cv->b.layerheads[cv->b.drawmode]->splines,
1267 		    cv->b.layerheads[cv->b.drawmode]->order2);
1268 	GDrawRequestExpose(cvtools,NULL,false);
1269 	SCUpdateAll(cv->b.sc);
1270     } else
1271 #ifdef _NO_LIBSPIRO
1272 	ff_post_error(_("You may not use spiros"),_("This version of fontforge was not linked with the spiro library, so you may not use them."));
1273 #else
1274 	ff_post_error(_("You may not use spiros"),_("FontForge was unable to load libspiro, spiros are not available for use."));
1275 #endif
1276 }
1277 
1278 char* HKTextInfoToUntranslatedTextFromTextInfo( GTextInfo* ti ); // From ../gdraw/gmenu.c.
1279 
1280 
ToolsMouse(CharView * cv,GEvent * event)1281 static void ToolsMouse(CharView *cv, GEvent *event) {
1282     IJ ij = getIJFromMouse( cv, event->u.mouse.x, event->u.mouse.y );
1283     int i = ij.i;
1284     int j = ij.j;
1285     int mi = i;
1286     int pos;
1287     int isstylus = event->u.mouse.device!=NULL && strcmp(event->u.mouse.device,"stylus")==0;
1288     int styluscntl = isstylus && (event->u.mouse.state&0x200);
1289     static int settings[2];
1290 
1291     if( j==-1 || i==-1 )
1292 	return;
1293 
1294     if(j >= 2)
1295 	return;			/* If the wm gave me a window the wrong size */
1296 
1297 
1298     if ( i==(cvt_rect)/2 ) {
1299 	int current = CVCurrentTool(cv,event);
1300 	int changed = false;
1301 	if ( event->type == et_mousedown && event->u.mouse.clicks>=2 ) {
1302 	    rectelipse = settings[0];
1303 	    polystar = settings[1];
1304 	} else if ( event->type == et_mousedown ) {
1305 	    settings[0] = rectelipse; settings[1] = polystar;
1306 	    /* A double click will change the type twice, which leaves it where it was, which is desired */
1307 	    if ( j==0 && ((!rectelipse && current==cvt_rect) || (rectelipse && current==cvt_elipse)) ) {
1308 		rectelipse = !rectelipse;
1309 		changed = true;
1310 	    } else if (j==1 && ((!polystar && current==cvt_poly) || (polystar && current==cvt_star)) ) {
1311 		polystar = !polystar;
1312 		changed = true;
1313 	    }
1314 	    if ( changed ) {
1315 		SavePrefs(true);
1316 		GDrawRequestExpose(cvtools,NULL,false);
1317 	    }
1318 	}
1319 	if ( (j==0 && rectelipse) || (j==1 && polystar) )
1320 	    ++mi;
1321     }
1322     pos = mi*2 + j;
1323     GGadgetEndPopup();
1324     /* we have two fewer buttons than commands as two bottons each control two commands */
1325     if ( pos<0 || pos>=cvt_max )
1326 	pos = cvt_none;
1327     if ( event->type == et_mousedown ) {
1328 	if ( isstylus && event->u.mouse.button==2 )
1329 	    /* Not a real button press, only touch counts. This is a modifier */;
1330 	else if ( pos==cvt_spiro ) {
1331 	    CVChangeSpiroMode(cv);
1332 	    /* This is just a button that indicates a state */
1333 	} else {
1334 	    cv->pressed_tool = cv->pressed_display = pos;
1335 	    cv->had_control = ((event->u.mouse.state&ksm_control) || styluscntl)?1:0;
1336 	    event->u.mouse.state |= (1<<(7+event->u.mouse.button));
1337 	}
1338 	if ( event->u.mouse.clicks>=2 &&
1339 		(pos/2 == cvt_scale/2 || pos/2 == cvt_rotate/2 || pos == cvt_3d_rotate ))
1340 	    CVDoTransform(cv,pos);
1341     } else if ( event->type == et_mousemove ) {
1342 	if ( cv->pressed_tool==cvt_none && pos!=cvt_none ) {
1343 	    /* Not pressed */
1344 	    char *msg = _(popupsres[pos]);
1345 	    if ( cv->b.sc->inspiro && hasspiro()) {
1346 		if ( pos==cvt_spirog2 )
1347 		    msg = _("Add a g2 curve point");
1348 		else if ( pos==cvt_spiroleft )
1349 		    msg = _("Add a prev constraint point (sometimes like a tangent)");
1350 		else if ( pos==cvt_spiroright )
1351 		    msg = _("Add a next constraint point (sometimes like a tangent)");
1352 	    }
1353 	    // We want to display the hotkey for the key in question if possible.
1354 	    char * mininame = HKTextInfoToUntranslatedTextFromTextInfo(&cvtoollist[pos].ti);
1355 	    char * menuname = NULL;
1356 	    Hotkey* toolhotkey = NULL;
1357             if (mininame != NULL) {
1358               if ( (menuname = smprintf("%s%s", "Point.Tools.", mininame)) != NULL) {
1359 	        toolhotkey = hotkeyFindByMenuPath(cv->gw, menuname);
1360 	        free(menuname); menuname = NULL;
1361               }
1362               free(mininame); mininame = NULL;
1363             }
1364 	    char * finalmsg = NULL;
1365 	    if (toolhotkey != NULL && (finalmsg = smprintf("%s (%s)", msg, toolhotkey->text)) != NULL) {
1366 	      GGadgetPreparePopup8(cvtools, finalmsg);
1367 	      free(finalmsg); finalmsg = NULL;
1368 	    } else GGadgetPreparePopup8(cvtools, msg); // That's what we were doing before. Much simpler.
1369 	} else if ( pos!=cv->pressed_tool || cv->had_control != (((event->u.mouse.state&ksm_control) || styluscntl)?1:0) )
1370 	    cv->pressed_display = cvt_none;
1371 	else
1372 	    cv->pressed_display = cv->pressed_tool;
1373     } else if ( event->type == et_mouseup ) {
1374 	if ( pos==cvt_freehand && event->u.mouse.clicks==2 ) {
1375 	    FreeHandStrokeDlg(CVFreeHandInfo());
1376 	} else if ( pos==cvt_pointer && event->u.mouse.clicks==2 ) {
1377 	    PointerDlg(cv);
1378 	} else if ( pos==cvt_ruler && event->u.mouse.clicks==2 ) {
1379 	    RulerDlg(cv);
1380 	} else if ( i==cvt_rect/2 && event->u.mouse.clicks==2 ) {
1381 	    ((j==0)?CVRectElipse:CVPolyStar)(cv);
1382 	    mi = i;
1383 	    if ( (j==0 && rectelipse) || (j==1 && polystar) )
1384 		++mi;
1385 	    pos = mi*2 + j;
1386 	    cv->pressed_tool = cv->pressed_display = pos;
1387 	}
1388 	if ( pos!=cv->pressed_tool || cv->had_control != (((event->u.mouse.state&ksm_control)||styluscntl)?1:0) )
1389 	    cv->pressed_tool = cv->pressed_display = cvt_none;
1390 	else {
1391 	    if ( event->u.mouse.device!=NULL && strcmp(event->u.mouse.device,"eraser")==0 )
1392 		cv->er_tool = pos;
1393 	    else if ( isstylus ) {
1394 	        if ( event->u.mouse.button==2 )
1395 		    /* Only thing that matters is touch which maps to button 1 */;
1396 		else if ( cv->had_control )
1397 		    cv->s2_tool = pos;
1398 		else
1399 		    cv->s1_tool = pos;
1400 	    } else if ( cv->had_control && event->u.mouse.button==2 )
1401 		cv->cb2_tool = cv_cb2_tool = pos;
1402 	    else if ( event->u.mouse.button==2 )
1403 		cv->b2_tool = cv_b2_tool = pos;
1404 	    else if ( cv->had_control ) {
1405 		cv->cb1_tool = cv_cb1_tool = pos;
1406 	    } else {
1407 		cv->b1_tool = cv_b1_tool = pos;
1408 	    }
1409 	    SavePrefs(true);
1410 	    cv->pressed_tool = cv->pressed_display = cvt_none;
1411 	}
1412 	GDrawRequestExpose(cvtools,NULL,false);
1413 	event->u.chr.state &= ~(1<<(7+event->u.mouse.button));
1414     }
1415     CVToolsSetCursor(cv,event->u.mouse.state,event->u.mouse.device);
1416 }
1417 
PostCharToWindow(GWindow to,GEvent * e)1418 static void PostCharToWindow(GWindow to, GEvent *e) {
1419     GPoint p;
1420 
1421     p.x = e->u.chr.x; p.y = e->u.chr.y;
1422     GDrawTranslateCoordinates(e->w,to,&p);
1423     e->u.chr.x = p.x; e->u.chr.y = p.y;
1424     e->w = to;
1425     GDrawPostEvent(e);
1426 }
1427 
cvtools_e_h(GWindow gw,GEvent * event)1428 static int cvtools_e_h(GWindow gw, GEvent *event) {
1429     CharView *cv = (CharView *) GDrawGetUserData(gw);
1430 
1431     if ( event->type==et_destroy && cvtools == gw ) {
1432 	cvtools = NULL;
1433 return( true );
1434     }
1435 
1436     if ( cv==NULL )
1437 return( true );
1438 
1439     GGadgetPopupExternalEvent(event);
1440     switch ( event->type ) {
1441       case et_expose:
1442 	ToolsExpose(gw,cv,&event->u.expose.rect);
1443       break;
1444       case et_mousedown:
1445 	ToolsMouse(cv,event);
1446       break;
1447       case et_mousemove:
1448 	ToolsMouse(cv,event);
1449       break;
1450       case et_mouseup:
1451 	ToolsMouse(cv,event);
1452       break;
1453       case et_crossing:
1454 	cv->pressed_display = cvt_none;
1455 	CVToolsSetCursor(cv,event->u.mouse.state,NULL);
1456       break;
1457       case et_char: case et_charup:
1458 	if ( cv->had_control != ((event->u.chr.state&ksm_control)?1:0) )
1459 	    cv->pressed_display = cvt_none;
1460 	PostCharToWindow(cv->gw,event);
1461       break;
1462       case et_close:
1463 	GDrawSetVisible(gw,false);
1464       break;
1465     }
1466 return( true );
1467 }
1468 
CVMakeTools(CharView * cv)1469 GWindow CVMakeTools(CharView *cv) {
1470     GRect r;
1471     GWindowAttrs wattrs;
1472     FontRequest rq;
1473 
1474     if ( cvtools!=NULL )
1475 return( cvtools );
1476 
1477     memset(&wattrs,0,sizeof(wattrs));
1478     wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_positioned|wam_isdlg;
1479     wattrs.event_masks = -1;
1480     wattrs.cursor = ct_mypointer;
1481     wattrs.positioned = true;
1482     wattrs.is_dlg = true;
1483     wattrs.utf8_window_title = _("Tools");
1484 
1485     r.width = getToolbarWidth(cv); r.height = getToolbarHeight(cv);
1486     if ( cvtoolsoff.x==-9999 ) {
1487 	cvtoolsoff.x = -r.width-6; cvtoolsoff.y = cv->mbh+20;
1488     }
1489     r.x = cvtoolsoff.x; r.y = cvtoolsoff.y;
1490     if ( palettes_docked )
1491 	r.x = r.y = 0;
1492     cvtools = CreatePalette( cv->gw, &r, cvtools_e_h, NULL, &wattrs, cv->v );
1493 
1494     if ( GDrawRequestDeviceEvents(cvtools,input_em_cnt,input_em)>0 ) {
1495 	/* Success! They've got a wacom tablet */
1496     }
1497 
1498     if ( toolsfont==NULL ) {
1499 	memset(&rq,0,sizeof(rq));
1500 	rq.utf8_family_name = SANS_UI_FAMILIES;
1501 	rq.point_size = -10;
1502 	rq.weight = 400;
1503 	toolsfont = GDrawInstanciateFont(NULL,&rq);
1504 	toolsfont = GResourceFindFont("ToolsPalette.Font",toolsfont);
1505     }
1506 
1507     if ( cvvisible[1])
1508 	GDrawSetVisible(cvtools,true);
1509 return( cvtools );
1510 }
1511 
1512 
1513     /* ********************************************************* */
1514     /* ******************  Layers Palette  ********************* */
1515     /* ********************************************************* */
1516 
1517 
1518 
1519 /* Create a layer thumbnail */
BDFCharFromLayer(SplineChar * sc,int layer)1520 static BDFChar *BDFCharFromLayer(SplineChar *sc,int layer) {
1521     SplineChar dummy;
1522     memset(&dummy,0,sizeof(dummy));
1523     dummy.layer_cnt = 2;
1524     dummy.layers = sc->layers+layer-1;
1525     dummy.parent = sc->parent;
1526 return( SplineCharAntiAlias(&dummy,ly_fore,24,4));
1527 }
1528 
1529 /**
1530  *  \brief Recalculate the number of visible layers,
1531  *         reposition the visibility checkboxes, and
1532  *         if requested, reposition/resize the scrollbar.
1533  *
1534  *  \param [in] cv The charview
1535  */
CVLayers2Reflow(CharView * cv,bool resize)1536 static void CVLayers2Reflow(CharView *cv, bool resize) {
1537     extern int _GScrollBar_Width;
1538     GGadget *scrollbar;
1539     GRect cvl2size;
1540 
1541     GDrawGetSize(cvlayers2, &cvl2size);
1542     // Minus 2 because we always have the 'Guide' and 'Back' entries
1543     layer2.visible_layers = (cvl2size.height - layer2.header_height - 2 * CV_LAYERS2_LINE_HEIGHT) / CV_LAYERS2_LINE_HEIGHT;
1544     if (layer2.visible_layers < 0) {
1545         layer2.visible_layers = 0;
1546     }
1547 
1548     // Reposition the visibility checkboxes
1549     int num_potentially_visible = 2 + layer2.visible_layers + 1;
1550     if (num_potentially_visible > layer2.current_layers){
1551         num_potentially_visible = layer2.current_layers;
1552     }
1553     for (int i = 2, first_visible = 2 + layer2.offtop; i < layer2.current_layers; i++) {
1554         GGadget *vis = GWidgetGetControl(cvlayers2, CID_VBase + i - 1);
1555         if (vis == NULL) {
1556             break;
1557         }
1558         if (i >= first_visible && (i - layer2.offtop) < num_potentially_visible) {
1559             GGadgetMove(vis, 5, layer2.header_height + (i - layer2.offtop) * CV_LAYERS2_LINE_HEIGHT);
1560             GGadgetSetVisible(vis, true);
1561         } else {
1562             GGadgetSetVisible(vis, false);
1563         }
1564     }
1565 
1566     if (!resize) {
1567         return;
1568     }
1569 
1570     scrollbar = GWidgetGetControl(cvlayers2, CID_SB);
1571     // Check if we need the scrollbar or not.
1572     if (layer2.current_layers - 2 <= layer2.visible_layers || layer2.visible_layers <= 0) {
1573         GGadgetSetVisible(scrollbar, false);
1574         layer2.sb_start = cvl2size.width;
1575         layer2.offtop = 0;
1576     } else {
1577         layer2.sb_start = cvl2size.width - GDrawPointsToPixels(cv->gw, _GScrollBar_Width);
1578         GGadgetMove(scrollbar, layer2.sb_start, 0);
1579         GGadgetResize(scrollbar, GDrawPointsToPixels(cv->gw, _GScrollBar_Width), cvl2size.height);
1580         GGadgetSetVisible(scrollbar, true);
1581 
1582         GScrollBarSetBounds(scrollbar, 0, layer2.current_layers - 2, layer2.visible_layers);
1583         GScrollBarSetPos(scrollbar, layer2.offtop);
1584     }
1585 
1586     GDrawRequestExpose(cvlayers2, NULL, false);
1587 }
1588 
1589 /* Update the type3 layers palette to the given character view */
CVLayers2Set(CharView * cv)1590 static void CVLayers2Set(CharView *cv) {
1591     int i, top;
1592 
1593     GGadgetSetChecked(GWidgetGetControl(cvlayers2,CID_VFore),cv->showfore);
1594     GGadgetSetChecked(GWidgetGetControl(cvlayers2,CID_VBack),cv->showback[0]&1);
1595     GGadgetSetChecked(GWidgetGetControl(cvlayers2,CID_VGrid),cv->showgrids);
1596 
1597     int ly = 0;
1598     // We want to look at the unhandled layers.
1599     if (ly <= ly_back) ly = ly_back + 1;
1600     if (ly <= ly_fore) ly = ly_fore + 1;
1601     if (ly <= ly_grid) ly = ly_grid + 1;
1602     while (ly < cv->b.sc->parent->layer_cnt) {
1603       GGadget *tmpgadget = GWidgetGetControl(cvlayers2, CID_VBase + ly);
1604       if (tmpgadget != NULL) {
1605         // We set a low cap on the number of layers provisioned with check boxes for safety.
1606         // So it is important to check that this exists.
1607         GGadgetSetChecked(tmpgadget, cv->showback[ly>>5]&(1<<(ly&31)));
1608       }
1609       ly ++;
1610     }
1611 
1612 	 /* set old to NULL */
1613     layer2.offtop = 0;
1614     for ( i=2; i<layer2.current_layers; ++i ) {
1615 	BDFCharFree(layer2.layers[i]);
1616 	layer2.layers[i]=NULL;
1617     }
1618 
1619 	 /* reallocate enough space if necessary */
1620     if ( cv->b.sc->layer_cnt+1>=layer2.max_layers ) {
1621 	top = cv->b.sc->layer_cnt+10;
1622 	if ( layer2.layers==NULL )
1623 	    layer2.layers = calloc(top,sizeof(BDFChar *));
1624 	else {
1625 	    layer2.layers = realloc(layer2.layers,top*sizeof(BDFChar *));
1626 	    for ( i=layer2.current_layers; i<top; ++i )
1627 		layer2.layers[i] = NULL;
1628 	}
1629 	layer2.max_layers = top;
1630     }
1631     layer2.current_layers = cv->b.sc->layer_cnt+1;
1632     for ( i=ly_fore; i<cv->b.sc->layer_cnt; ++i )
1633 	layer2.layers[i+1] = BDFCharFromLayer(cv->b.sc,i);
1634     layer2.active = CVLayer(&cv->b)+1;
1635 
1636     CVLayers2Reflow(cv, true);
1637 }
1638 
Layers2Expose(CharView * cv,GWindow pixmap,GEvent * event)1639 static void Layers2Expose(CharView *cv,GWindow pixmap,GEvent *event) {
1640     int i, ll;
1641     const char *str;
1642     GRect r, oldclip;
1643     struct _GImage base;
1644     GImage gi;
1645     int as = (24*cv->b.sc->parent->ascent)/(cv->b.sc->parent->ascent+cv->b.sc->parent->descent);
1646     int leftOffset, layerCount;
1647 
1648     if ( event->u.expose.rect.y+event->u.expose.rect.height<layer2.header_height )
1649 return;
1650 
1651     // Calculate the left offset (from the checkboxes)
1652     GGadgetGetSize(GWidgetGetControl(cvlayers2, CID_VGrid), &r);
1653     leftOffset = r.x + r.width;
1654     // Compute the drawable area and clip to it.
1655     GDrawGetSize(cvlayers2, &r);
1656     r.x = leftOffset;
1657     r.width = layer2.sb_start - r.x;
1658     r.y = layer2.header_height;
1659     r.height = r.height - layer2.header_height;
1660     GDrawPushClip(pixmap, &r, &oldclip);
1661     GDrawFillRect(pixmap,&r,GDrawGetDefaultBackground(NULL));
1662 
1663     GDrawSetDither(NULL, false);	/* on 8 bit displays we don't want any dithering */
1664 
1665     memset(&gi,0,sizeof(gi));
1666     memset(&base,0,sizeof(base));
1667     gi.u.image = &base;
1668     base.image_type = it_index;
1669     base.clut = layer2.clut;
1670     base.trans = -1;
1671     GDrawSetFont(pixmap,layer2.font);
1672 
1673     // +2 for the defaults, +1 to show one extra (could be partially visible)
1674     layerCount = layer2.visible_layers + 2 + 1;
1675     if (layerCount > layer2.current_layers) {
1676         layerCount = layer2.current_layers;
1677     }
1678     for (i = 0; i < layerCount; ++i) {
1679 	ll = i<2 ? i : i+layer2.offtop;
1680 	if ( ll==layer2.active ) {
1681             r.x = leftOffset;
1682             r.width = layer2.sb_start - r.x;
1683             r.y = layer2.header_height + i * CV_LAYERS2_LINE_HEIGHT;
1684 	    r.height = CV_LAYERS2_LINE_HEIGHT;
1685 	    GDrawFillRect(pixmap,&r,GDrawGetDefaultForeground(NULL));
1686 	}
1687         GDrawDrawLine(pixmap, r.x, layer2.header_height + i * CV_LAYERS2_LINE_HEIGHT,
1688                       r.x + r.width, layer2.header_height + i * CV_LAYERS2_LINE_HEIGHT,
1689 		0x808080);
1690 	if ( i==0 || i==1 ) {
1691 	    str = i==0?_("Guide") : _("Back");
1692             GDrawDrawText8(pixmap, r.x + 2, layer2.header_height + i * CV_LAYERS2_LINE_HEIGHT + (CV_LAYERS2_LINE_HEIGHT - 12) / 2 + 12,
1693 		    (char *) str,-1,ll==layer2.active?0xffffff:GDrawGetDefaultForeground(NULL));
1694 	} else if ( layer2.offtop+i>=layer2.current_layers ) {
1695     break;
1696 	} else if ( layer2.layers[layer2.offtop+i]!=NULL ) {
1697 #if 0
1698 	    // This is currently broken, and we do not have time to fix it.
1699 	    BDFChar *bdfc = layer2.layers[layer2.offtop+i];
1700 	    base.data = bdfc->bitmap;
1701 	    base.bytes_per_line = bdfc->bytes_per_line;
1702 	    base.width = bdfc->xmax-bdfc->xmin+1;
1703 	    base.height = bdfc->ymax-bdfc->ymin+1;
1704 	    GDrawDrawImage(pixmap,&gi,NULL,
1705 		    r.x+2+bdfc->xmin,
1706                            layer2.header_height + i * CV_LAYERS2_LINE_HEIGHT + as - bdfc->ymax);
1707 #else
1708 	    // This logic comes from CVInfoDrawText.
1709 	    const int layernamesz = 100;
1710 	    char layername[layernamesz+1];
1711 	    strncpy(layername,_("Guide"),layernamesz);
1712 	    int idx = layer2.offtop+i-1;
1713 	    if(idx >= 0 && idx < cv->b.sc->parent->layer_cnt) {
1714 	      strncpy(layername,cv->b.sc->parent->layers[idx].name,layernamesz);
1715 	    } else {
1716 	      fprintf(stderr, "Invalid layer!\n");
1717 	    }
1718 	    // And this comes from above.
1719             GDrawDrawText8(pixmap, r.x + 2, layer2.header_height + i * CV_LAYERS2_LINE_HEIGHT + (CV_LAYERS2_LINE_HEIGHT - 12) / 2 + 12,
1720 		    (char *) layername,-1,ll==layer2.active?0xffffff:GDrawGetDefaultForeground(NULL));
1721 #endif // 0
1722 	}
1723     }
1724     GDrawPopClip(pixmap, &oldclip);
1725 }
1726 
1727 // Frank changed the prefix from MID to MIDL in order to avert conflicts with values set in charview_private.h.
1728 #define MIDL_LayerInfo	1
1729 #define MIDL_NewLayer	2
1730 #define MIDL_DelLayer	3
1731 #define MIDL_First	4
1732 #define MIDL_Earlier	5
1733 #define MIDL_Later	6
1734 #define MIDL_Last	7
1735 #define MIDL_MakeLine 100
1736 #define MIDL_MakeArc  200
1737 #define MIDL_InsertPtOnSplineAt  2309
1738 #define MIDL_NamePoint  2318
1739 #define MIDL_NameContour  2319
1740 
CVLayer2Invoked(GWindow v,GMenuItem * mi,GEvent * e)1741 static void CVLayer2Invoked(GWindow v, GMenuItem *mi, GEvent *e) {
1742     CharView *cv = (CharView *) GDrawGetUserData(v);
1743     Layer temp;
1744     int layer = CVLayer(&cv->b);
1745     SplineChar *sc = cv->b.sc;
1746     int i;
1747     char *buts[3];
1748     buts[0] = _("_Yes"); buts[1]=_("_No"); buts[2] = NULL;
1749 
1750     switch ( mi->mid ) {
1751       case MIDL_LayerInfo:
1752 	if ( !LayerDialog(cv->b.layerheads[cv->b.drawmode],cv->b.sc->parent))
1753 return;
1754       break;
1755       case MIDL_NewLayer:
1756 	LayerDefault(&temp);
1757 	if ( !LayerDialog(&temp,cv->b.sc->parent))
1758 return;
1759 	sc->layers = realloc(sc->layers,(sc->layer_cnt+1)*sizeof(Layer));
1760 	sc->layers[sc->layer_cnt] = temp;
1761 	cv->b.layerheads[dm_fore] = &sc->layers[sc->layer_cnt];
1762 	cv->b.layerheads[dm_back] = &sc->layers[ly_back];
1763 	++sc->layer_cnt;
1764       break;
1765       case MIDL_DelLayer:
1766 	if ( sc->layer_cnt==2 )		/* May not delete the last foreground layer */
1767 return;
1768 	if ( gwwv_ask(_("Cannot Be Undone"),(const char **) buts,0,1,_("This operation cannot be undone, do it anyway?"))==1 )
1769 return;
1770 	SplinePointListsFree(sc->layers[layer].splines);
1771 	RefCharsFree(sc->layers[layer].refs);
1772 	ImageListsFree(sc->layers[layer].images);
1773 	UndoesFree(sc->layers[layer].undoes);
1774 	UndoesFree(sc->layers[layer].redoes);
1775 	for ( i=layer+1; i<sc->layer_cnt; ++i )
1776 	    sc->layers[i-1] = sc->layers[i];
1777 	--sc->layer_cnt;
1778 	if ( layer==sc->layer_cnt )
1779 	    cv->b.layerheads[dm_fore] = &sc->layers[layer-1];
1780       break;
1781       case MIDL_First:
1782 	if ( layer==ly_fore )
1783 return;
1784 	temp = sc->layers[layer];
1785 	for ( i=layer-1; i>=ly_fore; --i )
1786 	    sc->layers[i+1] = sc->layers[i];
1787 	sc->layers[i+1] = temp;
1788 	cv->b.layerheads[dm_fore] = &sc->layers[ly_fore];
1789       break;
1790       case MIDL_Earlier:
1791 	if ( layer==ly_fore )
1792 return;
1793 	temp = sc->layers[layer];
1794 	sc->layers[layer] = sc->layers[layer-1];
1795 	sc->layers[layer-1] = temp;
1796 	cv->b.layerheads[dm_fore] = &sc->layers[layer-1];
1797       break;
1798       case MIDL_Later:
1799 	if ( layer==sc->layer_cnt-1 )
1800 return;
1801 	temp = sc->layers[layer];
1802 	sc->layers[layer] = sc->layers[layer+1];
1803 	sc->layers[layer+1] = temp;
1804 	cv->b.layerheads[dm_fore] = &sc->layers[layer+1];
1805       break;
1806       case MIDL_Last:
1807 	if ( layer==sc->layer_cnt-1 )
1808 return;
1809 	temp = sc->layers[layer];
1810 	for ( i=layer+1; i<sc->layer_cnt; ++i )
1811 	    sc->layers[i-1] = sc->layers[i];
1812 	sc->layers[i-1] = temp;
1813 	cv->b.layerheads[dm_fore] = &sc->layers[i-1];
1814       break;
1815     }
1816     CVLayers2Set(cv);
1817     CVCharChangedUpdate(&cv->b);
1818 }
1819 
Layer2Menu(CharView * cv,GEvent * event,int nolayer)1820 static void Layer2Menu(CharView *cv,GEvent *event, int nolayer) {
1821     GMenuItem mi[20];
1822     int i;
1823     static char *names[] = { N_("Layer Info..."), N_("New Layer..."), N_("Del Layer"), (char *) -1,
1824 	    N_("_First"), N_("_Earlier"), N_("L_ater"), N_("_Last"), NULL };
1825     static int mids[] = { MIDL_LayerInfo, MIDL_NewLayer, MIDL_DelLayer, -1,
1826 	    MIDL_First, MIDL_Earlier, MIDL_Later, MIDL_Last, 0 };
1827     int layer = CVLayer(&cv->b);
1828 
1829     memset(mi,'\0',sizeof(mi));
1830     for ( i=0; names[i]!=0; ++i ) {
1831 	if ( names[i]!=(char *) -1 ) {
1832 	    mi[i].ti.text = (unichar_t *) _(names[i]);
1833 	    mi[i].ti.text_is_1byte = true;
1834 	} else
1835 	    mi[i].ti.line = true;
1836 	mi[i].ti.fg = COLOR_DEFAULT;
1837 	mi[i].ti.bg = COLOR_DEFAULT;
1838 	mi[i].mid = mids[i];
1839 	mi[i].invoke = CVLayer2Invoked;
1840 	if ( mids[i]!=MIDL_NewLayer && nolayer )
1841 	    mi[i].ti.disabled = true;
1842 	if (( mids[i]==MIDL_First || mids[i]==MIDL_Earlier ) && layer==ly_fore )
1843 	    mi[i].ti.disabled = true;
1844 	if (( mids[i]==MIDL_Last || mids[i]==MIDL_Later ) && layer==cv->b.sc->layer_cnt-1 )
1845 	    mi[i].ti.disabled = true;
1846 	if ( mids[i]==MIDL_DelLayer && cv->b.sc->layer_cnt==2 )
1847 	    mi[i].ti.disabled = true;
1848     }
1849     GMenuCreatePopupMenu(cvlayers2,event, mi);
1850 }
1851 
Layer2Scroll(CharView * cv,GEvent * event)1852 static void Layer2Scroll(CharView *cv, GEvent *event) {
1853     int off = 0;
1854     enum sb sbt = event->u.control.u.sb.type;
1855 
1856     if ( sbt==et_sb_top )
1857 	off = 0;
1858     else if ( sbt==et_sb_bottom )
1859 	off = cv->b.sc->layer_cnt-1-layer2.visible_layers;
1860     else if ( sbt==et_sb_up ) {
1861 	off = layer2.offtop-1;
1862     } else if ( sbt==et_sb_down ) {
1863 	off = layer2.offtop+1;
1864     } else if ( sbt==et_sb_uppage ) {
1865 	off = layer2.offtop-layer2.visible_layers+1;
1866     } else if ( sbt==et_sb_downpage ) {
1867 	off = layer2.offtop+layer2.visible_layers-1;
1868     } else /* if ( sbt==et_sb_thumb || sbt==et_sb_thumbrelease ) */ {
1869 	off = event->u.control.u.sb.pos;
1870     }
1871     if ( off>cv->b.sc->layer_cnt-1-layer2.visible_layers )
1872 	off = cv->b.sc->layer_cnt-1-layer2.visible_layers;
1873     if ( off<0 ) off=0;
1874     if ( off==layer2.offtop )
1875 return;
1876     layer2.offtop = off;
1877     GScrollBarSetPos(GWidgetGetControl(cvlayers2,CID_SB),off);
1878     CVLayers2Reflow(cv, false);
1879     GDrawRequestExpose(cvlayers2,NULL,false);
1880 }
1881 
cvlayers2_e_h(GWindow gw,GEvent * event)1882 static int cvlayers2_e_h(GWindow gw, GEvent *event) {
1883     CharView *cv = (CharView *) GDrawGetUserData(gw);
1884 
1885     if ( event->type==et_destroy && cvlayers2 == gw ) {
1886 	cvlayers2 = NULL;
1887 return( true );
1888     }
1889 
1890     if ( cv==NULL )
1891 return( true );
1892 
1893     switch ( event->type ) {
1894       case et_close:
1895 	GDrawSetVisible(gw,false);
1896       break;
1897       case et_char: case et_charup:
1898 	PostCharToWindow(cv->gw,event);
1899       break;
1900       case et_resize:
1901         CVLayers2Reflow(cv, true);
1902       break;
1903       case et_expose:
1904 	Layers2Expose(cv,gw,event);
1905       break;
1906       case et_mousedown: {
1907 	if ( event->u.mouse.y>CV_LAYERS2_HEADER_HEIGHT ) {
1908         if (event->u.mouse.button >= 4) {
1909             // Scroll the list
1910             event->u.control.u.sb.type = (event->u.mouse.button == 4 || event->u.mouse.button == 6) ? et_sb_up : et_sb_down;
1911             Layer2Scroll(cv, event);
1912             return true;
1913         }
1914 	int layer = (event->u.mouse.y-CV_LAYERS2_HEADER_HEIGHT)/CV_LAYERS2_LINE_HEIGHT;
1915 	    if ( layer<2 ) {
1916 		cv->b.drawmode = layer==0 ? dm_grid : dm_back;
1917 		layer2.active = layer;
1918 	    } else if ( layer-1+layer2.offtop >= cv->b.sc->layer_cnt ) {
1919 		if ( event->u.mouse.button==3 )
1920 		    Layer2Menu(cv,event,true);
1921 		else
1922 		    GDrawBeep(NULL);
1923 return(true);
1924 	    } else {
1925 		layer2.active = layer+layer2.offtop;
1926 		cv->b.drawmode = dm_fore;
1927 		cv->b.layerheads[dm_fore] = &cv->b.sc->layers[layer-1+layer2.offtop];
1928 	    }
1929 	    GDrawRequestExpose(cvlayers2,NULL,false);
1930 	    GDrawRequestExpose(cv->v,NULL,false);
1931 	    GDrawRequestExpose(cv->gw,NULL,false);	/* the logo (where the scrollbars join) shows what layer we are in */
1932 	    if ( event->u.mouse.button==3 )
1933 		Layer2Menu(cv,event,cv->b.drawmode!=dm_fore);
1934 	    else if ( event->u.mouse.clicks==2 && cv->b.drawmode==dm_fore ) {
1935 		if ( LayerDialog(cv->b.layerheads[cv->b.drawmode],cv->b.sc->parent))
1936 		    CVCharChangedUpdate(&cv->b);
1937 	    }
1938 	}
1939       } break;
1940       case et_controlevent:
1941 	if ( event->u.control.subtype == et_radiochanged ) {
1942 	    enum drawmode dm = cv->b.drawmode;
1943 	    int tmpcid = -1;
1944 	    int tmplayer = -1;
1945 	    switch(GGadgetGetCid(event->u.control.g)) {
1946 	      case CID_VFore:
1947 		CVShows.showfore = cv->showfore = GGadgetIsChecked(event->u.control.g);
1948 		if ( CVShows.showback )
1949 		    cv->showback[0] |= 2;
1950 		else
1951 		    cv->showback[0] &= ~2;
1952 	      break;
1953 	      case CID_VBack:
1954 		CVShows.showback = GGadgetIsChecked(event->u.control.g);
1955 		if ( CVShows.showback )
1956 		    cv->showback[0] |= 1;
1957 		else
1958 		    cv->showback[0] &= ~1;
1959 		cv->back_img_out_of_date = true;
1960 	      break;
1961 	      case CID_VGrid:
1962 		CVShows.showgrids = cv->showgrids = GGadgetIsChecked(event->u.control.g);
1963 	      break;
1964 	      default:
1965 		tmpcid = GGadgetGetCid(event->u.control.g);
1966 		tmplayer = tmpcid - CID_VBase;
1967 		if (tmpcid < 0 || tmplayer < 0) break;
1968 		// We check that the layer is valid (since the code does not presently, as far as Frank knows, handle layer deletion).
1969 		// We also check that the CID is within the allocated range (although this may not be necessary since the checkbox would not exist otherwise).
1970 		if (tmplayer > 0 && tmplayer < 999 && tmplayer < cv->b.sc->parent->layer_cnt) {
1971 		  if (GGadgetIsChecked(event->u.control.g)) {
1972 		    cv->showback[tmplayer>>5]|=(1<<(tmplayer&31));
1973 		  } else {
1974 		    cv->showback[tmplayer>>5]&=~(1<<(tmplayer&31));
1975 		  }
1976 		}
1977 		break;
1978 	    }
1979 	    GDrawRequestExpose(cv->v,NULL,false);
1980 	    if ( dm!=cv->b.drawmode )
1981 		GDrawRequestExpose(cv->gw,NULL,false);	/* the logo (where the scrollbars join) shows what layer we are in */
1982 	} else
1983 	    Layer2Scroll(cv,event);
1984       break;
1985     }
1986 return( true );
1987 }
1988 
1989 /* This is used for Type 3 fonts. CVMakeLayers is used for other fonts. */
CVMakeLayers2(CharView * cv)1990 static void CVMakeLayers2(CharView *cv) {
1991     GRect r;
1992     GWindowAttrs wattrs;
1993     GGadgetCreateData gcd[25];
1994     GTextInfo label[25];
1995     static GBox radio_box = { bt_none, bs_rect, 0, 0, 0, 0, 0, 0, 0, 0, COLOR_DEFAULT, COLOR_DEFAULT, 0, 0, 0, 0, 0, 0, 0 };
1996     FontRequest rq;
1997     int i;
1998     extern int _GScrollBar_Width;
1999 
2000     if ( layer2.clut==NULL )
2001 	layer2.clut = _BDFClut(4);
2002     if ( cvlayers2!=NULL )
2003 return;
2004     memset(&wattrs,0,sizeof(wattrs));
2005     wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_positioned|wam_isdlg;
2006     wattrs.event_masks = -1;
2007     wattrs.cursor = ct_mypointer;
2008     wattrs.positioned = true;
2009     wattrs.is_dlg = true;
2010     wattrs.utf8_window_title = _("Layers");
2011 
2012     r.width = GGadgetScale(CV_LAYERS2_WIDTH); r.height = CV_LAYERS2_HEIGHT;
2013     if ( cvlayersoff.x==-9999 ) {
2014 	cvlayersoff.x = -r.width-6;
2015 	cvlayersoff.y = cv->mbh+getToolbarHeight(cv)+45/*25*/;	/* 45 is right if there's decor, 25 when none. twm gives none, kde gives decor */
2016     }
2017     r.x = cvlayersoff.x; r.y = cvlayersoff.y;
2018     if ( palettes_docked ) { r.x = 0; r.y=getToolbarHeight(cv)+2; }
2019     cvlayers2 = CreatePalette( cv->gw, &r, cvlayers2_e_h, NULL, &wattrs, cv->v );
2020 
2021     memset(&label,0,sizeof(label));
2022     memset(&gcd,0,sizeof(gcd));
2023 
2024     if ( layersfont==NULL ) {
2025 	memset(&rq,'\0',sizeof(rq));
2026 	rq.utf8_family_name = SANS_UI_FAMILIES;
2027 	rq.point_size = -12;
2028 	rq.weight = 400;
2029 	layersfont = GDrawInstanciateFont(cvlayers2,&rq);
2030 	layersfont = GResourceFindFont("LayersPalette.Font",layersfont);
2031     }
2032 
2033     for ( i=0; i<sizeof(label)/sizeof(label[0]); ++i )
2034 	label[i].font = layersfont;
2035     layer2.font = layersfont;
2036 
2037     gcd[0].gd.pos.width = GDrawPointsToPixels(cv->gw,_GScrollBar_Width);
2038     gcd[0].gd.pos.x = CV_LAYERS2_WIDTH-gcd[0].gd.pos.width;
2039     gcd[0].gd.pos.y = CV_LAYERS2_HEADER_HEIGHT+2*CV_LAYERS2_LINE_HEIGHT;
2040     gcd[0].gd.pos.height = CV_LAYERS2_HEIGHT-gcd[0].gd.pos.y;
2041     gcd[0].gd.flags = gg_enabled|gg_visible|gg_pos_in_pixels|gg_sb_vert;
2042     gcd[0].gd.cid = CID_SB;
2043     gcd[0].creator = GScrollBarCreate;
2044     layer2.sb_start = gcd[0].gd.pos.x;
2045 
2046 /* GT: Abbreviation for "Visible" */
2047     label[1].text = (unichar_t *) _("V");
2048     label[1].text_is_1byte = true;
2049     gcd[1].gd.label = &label[1];
2050     gcd[1].gd.pos.x = 7; gcd[1].gd.pos.y = 5;
2051     gcd[1].gd.flags = gg_enabled|gg_visible|gg_pos_in_pixels;
2052     gcd[1].gd.popup_msg = _("Is Layer Visible?");
2053     gcd[1].creator = GLabelCreate;
2054 
2055     label[2].text = (unichar_t *) _("Layer");
2056     label[2].text_is_1byte = true;
2057     gcd[2].gd.label = &label[2];
2058     gcd[2].gd.pos.x = 30; gcd[2].gd.pos.y = 5;
2059     gcd[2].gd.flags = gg_enabled|gg_visible|gg_pos_in_pixels;
2060     gcd[2].gd.cid = CID_LayerLabel;
2061     gcd[2].gd.popup_msg = _("Is Layer Editable?");
2062     gcd[2].creator = GLabelCreate;
2063 
2064     gcd[3].gd.pos.x = 5; gcd[3].gd.pos.y = CV_LAYERS2_HEADER_HEIGHT+(CV_LAYERS2_LINE_HEIGHT-12)/2;
2065     gcd[3].gd.flags = gg_enabled|gg_visible|gg_dontcopybox|gg_pos_in_pixels;
2066     gcd[3].gd.cid = CID_VGrid;
2067     gcd[3].gd.popup_msg = _("Is Layer Visible?");
2068     gcd[3].gd.box = &radio_box;
2069     gcd[3].creator = GCheckBoxCreate;
2070 
2071     gcd[4].gd.pos.x = 5; gcd[4].gd.pos.y = gcd[3].gd.pos.y+CV_LAYERS2_LINE_HEIGHT;
2072     gcd[4].gd.flags = gg_enabled|gg_visible|gg_dontcopybox|gg_pos_in_pixels;
2073     gcd[4].gd.cid = CID_VBack;
2074     gcd[4].gd.popup_msg = _("Is Layer Visible?");
2075     gcd[4].gd.box = &radio_box;
2076     gcd[4].creator = GCheckBoxCreate;
2077 
2078     gcd[5].gd.pos.x = 5; gcd[5].gd.pos.y = gcd[4].gd.pos.y+CV_LAYERS2_LINE_HEIGHT;
2079     gcd[5].gd.flags = gg_enabled|gg_visible|gg_dontcopybox|gg_pos_in_pixels;
2080     gcd[5].gd.cid = CID_VFore;
2081     gcd[5].gd.popup_msg = _("Is Layer Visible?");
2082     gcd[5].gd.box = &radio_box;
2083     gcd[5].creator = GCheckBoxCreate;
2084 
2085     int wi = 6; // Widget index.
2086     int ly = 0;
2087     // We want to look at the unhandled layers.
2088     if (ly <= ly_back) ly = ly_back + 1;
2089     if (ly <= ly_fore) ly = ly_fore + 1;
2090     if (ly <= ly_grid) ly = ly_grid + 1;
2091     while (ly < cv->b.sc->parent->layer_cnt && wi < 24) {
2092       gcd[wi].gd.pos.x = 5; gcd[wi].gd.pos.y = gcd[wi-1].gd.pos.y+CV_LAYERS2_LINE_HEIGHT;
2093       gcd[wi].gd.flags = gg_enabled|gg_visible|gg_dontcopybox|gg_pos_in_pixels;
2094       gcd[wi].gd.cid = CID_VBase + ly; // There are plenty of CID values available for these above CID_VBase.
2095       gcd[wi].gd.popup_msg = _("Is Layer Visible?");
2096       gcd[wi].gd.box = &radio_box;
2097       gcd[wi].creator = GCheckBoxCreate;
2098       ly++;
2099       wi++;
2100     }
2101 
2102     if ( cv->showgrids ) gcd[3].gd.flags |= gg_cb_on;
2103     if ( cv->showback[0]&1 ) gcd[4].gd.flags |= gg_cb_on;
2104     if ( cv->showfore ) gcd[5].gd.flags |= gg_cb_on;
2105 
2106     GGadgetsCreate(cvlayers2, gcd);
2107     // Calculate the header height. The '-1' is magic! Needed to obtain symmetry
2108     layer2.header_height = GGadgetGetY(GWidgetGetControl(cvlayers2, CID_VGrid)) - 1;
2109     // Move the "Layer" label into the correct position based on the width of the checkbox
2110     GGadgetGetSize(GWidgetGetControl(cvlayers2, CID_VGrid), &r);
2111     GGadgetMove(GWidgetGetControl(cvlayers2, CID_LayerLabel), r.x + r.width, 5);
2112     if ( cvvisible[0] )
2113 	GDrawSetVisible(cvlayers2,true);
2114 }
2115 
LayersSwitch(CharView * cv)2116 static void LayersSwitch(CharView *cv) {
2117 }
2118 
SC_MoreLayers(SplineChar * sc,Layer * old)2119 void SC_MoreLayers(SplineChar *sc, Layer *old) { /* We've added more layers */
2120     CharView *curcv, *cv;
2121     if ( sc->parent==NULL || !sc->parent->multilayer )
2122 return;
2123     for ( cv=(CharView *) (sc->views); cv!=NULL ; cv=(CharView *) (cv->b.next) ) {
2124 	cv->b.layerheads[dm_fore] = &cv->b.sc->layers[cv->b.layerheads[dm_fore]-old];
2125 	cv->b.layerheads[dm_back] = &cv->b.sc->layers[ly_back];
2126     }
2127     if ( cvtools==NULL )
2128 return;
2129     curcv = GDrawGetUserData(cvtools);
2130     if ( curcv==NULL || curcv->b.sc!=sc )
2131 return;
2132     CVLayers2Set(curcv);
2133 }
2134 
SCLayersChange(SplineChar * sc)2135 void SCLayersChange(SplineChar *sc) { /* many of the foreground layers need to be redrawn */
2136     CharView *curcv;
2137     if ( cvtools==NULL || !sc->parent->multilayer )
2138 return;
2139     curcv = GDrawGetUserData(cvtools);
2140     if ( curcv==NULL || curcv->b.sc!=sc )
2141 return;
2142     CVLayers2Set(curcv);
2143 }
2144 
CVLayerChange(CharView * cv)2145 void CVLayerChange(CharView *cv) { /* Current layer needs to be redrawn */
2146     CharView *curcv;
2147     int layer;
2148 
2149     if ( cvtools==NULL  || !cv->b.sc->parent->multilayer )
2150 return;
2151     curcv = GDrawGetUserData(cvtools);
2152     if ( curcv!=cv )
2153 return;
2154     if ( cv->b.drawmode==dm_grid || cv->b.drawmode==dm_back )
2155 return;
2156     layer = CVLayer(&cv->b);
2157     BDFCharFree(layer2.layers[layer+1]);
2158     layer2.layers[layer+1] = BDFCharFromLayer(cv->b.sc,layer);
2159     GDrawRequestExpose(cvlayers2,NULL,false);
2160 }
2161 
2162 /* Update the state of the controls of the non-type3 layers palette to the given character view */
2163 /* New widgets are not allocated here. For that, see CVLCheckLayerCount(). */
CVLayers1Set(CharView * cv)2164 static void CVLayers1Set(CharView *cv) {
2165     int i, top;
2166 
2167     GGadgetSetChecked(GWidgetGetControl(cvlayers,CID_VFore),cv->showfore);
2168     GGadgetSetChecked(GWidgetGetControl(cvlayers,CID_VBack),cv->showback[0]&1);
2169     GGadgetSetChecked(GWidgetGetControl(cvlayers,CID_VGrid),cv->showgrids);
2170 
2171      /* clear old layer previews */
2172     layerinfo.offtop = 0;
2173     for ( i=2; i<layerinfo.current_layers; ++i ) {
2174 	BDFCharFree(layerinfo.layers[i]);
2175 	layerinfo.layers[i]=NULL;
2176     }
2177 
2178      /* reallocate enough space if necessary */
2179     if ( cv->b.sc->layer_cnt+1>=layerinfo.max_layers ) {
2180 	top = cv->b.sc->layer_cnt+10;
2181 	if ( layerinfo.layers==NULL )
2182 	    layerinfo.layers = calloc(top,sizeof(BDFChar *));
2183 	else {
2184 	    layerinfo.layers = realloc(layerinfo.layers,top*sizeof(BDFChar *));
2185 	    for ( i=layerinfo.current_layers; i<top; ++i )
2186 		layerinfo.layers[i] = NULL;
2187 	}
2188 	layerinfo.max_layers = top;
2189     }
2190     layerinfo.current_layers = cv->b.sc->layer_cnt+1;
2191     for ( i=ly_fore; i<cv->b.sc->layer_cnt; ++i )
2192 	layerinfo.layers[i+1] = BDFCharFromLayer(cv->b.sc,i);
2193     layerinfo.active = CVLayer(&cv->b)+1;
2194 
2195     if ( layerinfo.visible_layers==0 ) {
2196         GRect size;
2197         GDrawGetSize(cvlayers,&size);
2198         layerinfo.visible_layers=(size.height-layer_header_height)/layer_height;
2199     }
2200     GScrollBarSetBounds(GWidgetGetControl(cvlayers,CID_SB),0,cv->b.sc->layer_cnt+1-2, layerinfo.visible_layers);
2201     if ( layerinfo.offtop>cv->b.sc->layer_cnt-1-layerinfo.visible_layers )
2202         layerinfo.offtop = cv->b.sc->layer_cnt-1-layerinfo.visible_layers;
2203     if ( layerinfo.offtop<0 ) layerinfo.offtop = 0;
2204     GScrollBarSetPos(GWidgetGetControl(cvlayers,CID_SB),layerinfo.offtop);
2205 
2206     for ( i=0; i<cv->b.sc->layer_cnt; i++ ) {
2207         GGadgetSetChecked(GWidgetGetControl(cvlayers,CID_VBase+i),cv->showback[i>>5]&(1<<(i&31)));
2208     }
2209 
2210     layerinfo.active = CVLayer(&cv->b); /* the index of the active layer */
2211     GDrawRequestExpose(cvlayers,NULL,false);
2212 }
2213 
2214 /* Update the layers palette to reflect the given character view. No new gadgets
2215  * are created or hid here, only the state of existing gadgets is changed.
2216  * New layer gadgets are created in CVLCheckLayerCount(). */
CVLayersSet(CharView * cv)2217 void CVLayersSet(CharView *cv) {
2218     if ( cv->b.sc->parent->multilayer ) {
2219 	CVLayers2Set(cv);
2220 return;
2221     }
2222      /* This is for the non-type3 layers palette: */
2223     CVLayers1Set(cv);
2224 }
2225 
2226 /**
2227  * Get the offset at the right hand size of the eyeball to show/hide
2228  * a layer. This is the x offset where the Q/C indicators might be drawn.
2229  */
Layers_getOffsetAtRightOfViewLayer(CharView * cv)2230 static int32 Layers_getOffsetAtRightOfViewLayer(CharView *cv)
2231 {
2232     int32 ret = 64;
2233     GGadget *v = GWidgetGetControl(cvlayers,CID_VBack);
2234     if( v )
2235     {
2236 	GRect size;
2237 	GGadgetGetSize(v,&size);
2238 	ret = 7 + size.width;
2239     }
2240     return ret;
2241 }
2242 
2243 
2244  /* Draw the fg/bg, cubic/quadratic columns, plus layer preview and label name */
LayersExpose(CharView * cv,GWindow pixmap,GEvent * event)2245 static void LayersExpose(CharView *cv,GWindow pixmap,GEvent *event) {
2246     int i, ll, y;
2247     const char *str;
2248     GRect r;
2249     struct _GImage base;
2250     GImage gi;
2251     Color mocolor = ACTIVE_BORDER; /* mouse over color */
2252     int ww;
2253 
2254     int yt = .7*layer_height; /* vertical spacer to add when drawing text in the row */
2255     int column_width;
2256     int quadcol, fgcol, editcol;
2257 
2258     if ( event->u.expose.rect.y+event->u.expose.rect.height<layer_header_height )
2259 return;
2260 
2261     int offsetAtRightOfViewLayer = Layers_getOffsetAtRightOfViewLayer(cv);
2262     column_width = layerinfo.column_width;
2263 
2264     GDrawSetDither(NULL, false);	/* on 8 bit displays we don't want any dithering */
2265     ww=layerinfo.sb_start;
2266 
2267     memset(&gi,0,sizeof(gi));
2268     memset(&base,0,sizeof(base));
2269     gi.u.image = &base;
2270     base.image_type = it_index;
2271     base.clut = layer2.clut;
2272     base.trans = -1;
2273     GDrawSetFont(pixmap,layerinfo.font);
2274 
2275     quadcol=fgcol=offsetAtRightOfViewLayer;
2276     if ( layerscols & LSHOW_CUBIC )
2277     {
2278 	/* show quad col */
2279 	quadcol = offsetAtRightOfViewLayer;
2280 	fgcol   = offsetAtRightOfViewLayer+column_width;
2281     }
2282     if ( layerscols & LSHOW_FG )
2283     {
2284 	/* show fg col */
2285 	fgcol = quadcol+column_width;
2286     }
2287     // editcol is the X offset where the layer name label should be drawn
2288     editcol = fgcol+column_width;
2289     int bottomOfLast = 0;
2290 
2291      /* loop once per layer, where 0==guides, 1=back, 2=fore, etc */
2292     for ( i=(event->u.expose.rect.y-layer_header_height)/layer_height;
2293 	    i<(event->u.expose.rect.y+event->u.expose.rect.height+layer_height-layer_header_height)/layer_height;
2294 	    ++i ) {
2295 	ll = i-1+layerinfo.offtop;
2296         if ( ll>=cv->b.sc->layer_cnt || ll<-1 ) continue;
2297 
2298         y = layer_header_height + i*layer_height;
2299 	bottomOfLast = y + layer_height;
2300         if ( y<layer_header_height ) continue;
2301 
2302          /* draw quadratic/cubic toggle */
2303         if ( layerscols & LSHOW_CUBIC ) {
2304             if ( layerinfo.mo_layer==ll && layerinfo.mo_col==CID_QBase ) {
2305                 r.x = quadcol; r.width = column_width;
2306                 r.y = y;
2307                 r.height = layer_height;
2308                 GDrawFillRect(pixmap,&r,mocolor);
2309             }
2310             str = ( ll>=0 && ll<cv->b.sc->layer_cnt ? (cv->b.sc->layers[ll].order2? "Q" : "C") : " ");
2311 	    GDrawDrawText8(pixmap, quadcol, y + yt,
2312 		    (char *) str,-1,GDrawGetDefaultForeground(NULL));
2313         }
2314 
2315          /* draw fg/bg toggle */
2316         if ( layerscols & LSHOW_FG ) {
2317             if ( layerinfo.mo_layer==ll && layerinfo.mo_col==CID_FBase ) {
2318                 r.x = fgcol; r.width = column_width;
2319                 r.y = y;
2320                 r.height = layer_height;
2321                 GDrawFillRect(pixmap,&r,mocolor);
2322             }
2323             str = ( ll>=0 && ll<cv->b.sc->layer_cnt ? (cv->b.sc->layers[ll].background? "B" : "F") : "#");
2324 	    GDrawDrawText8(pixmap, fgcol, y + yt,
2325 		    (char *) str,-1,GDrawGetDefaultForeground(NULL));
2326         }
2327 
2328          /* draw layer thumbnail and label */
2329 	if ( ll==layerinfo.active ) {
2330             r.x = editcol; r.width = ww-r.x;
2331 	    r.y = y;
2332 	    r.height = layer_height;
2333 	    GDrawFillRect(pixmap,&r,GDrawGetDefaultForeground(NULL));
2334 	} else if ( layerinfo.mo_layer==ll && layerinfo.mo_col==CID_EBase ) {
2335             r.x = editcol; r.width = ww-r.x;
2336             r.y = y;
2337             r.height = layer_height;
2338             GDrawFillRect(pixmap,&r,mocolor);
2339         }
2340         r.x=editcol;
2341 	if ( ll==-1 || ll==0 || ll==1) {
2342 	    str = ll==-1 ? _("Guide") : (ll==0 ?_("Back") : _("Fore")) ;
2343 	    GDrawDrawText8(pixmap,r.x+2,y + yt,
2344 		    (char *) str,-1,ll==layerinfo.active?0xffffff:GDrawGetDefaultForeground(NULL));
2345 	} else if ( ll>=layerinfo.current_layers ) {
2346              break; /* no more layers to draw! */
2347 	} else if ( ll>=0 && layerinfo.layers[ll]!=NULL ) {
2348 	    BDFChar *bdfc = layerinfo.layers[ll];
2349 	    base.data = bdfc->bitmap;
2350 	    base.bytes_per_line = bdfc->bytes_per_line;
2351 	    base.width = bdfc->xmax-bdfc->xmin+1;
2352 	    base.height = bdfc->ymax-bdfc->ymin+1;
2353 //	    GDrawDrawImage(pixmap,&gi,NULL,
2354 //		    r.x+2+bdfc->xmin,
2355 //		    y+as-bdfc->ymax);
2356             str = cv->b.sc->parent->layers[ll].name;
2357             if ( !str || !*str ) str="-";
2358 	    GDrawDrawText8(pixmap, r.x+2, y + yt,
2359 		        (char *) str,-1,ll==layerinfo.active?0xffffff:GDrawGetDefaultForeground(NULL));
2360 	}
2361     }
2362 
2363     if( bottomOfLast )
2364     {
2365 	GGadgetSetY(GWidgetGetControl(cvlayers,CID_AddLayer),    bottomOfLast + 2 );
2366 	GGadgetSetY(GWidgetGetControl(cvlayers,CID_RemoveLayer), bottomOfLast + 2 );
2367 	GGadgetSetY(GWidgetGetControl(cvlayers,CID_LayersMenu),  bottomOfLast + 2 );
2368     }
2369 
2370 }
2371 
2372 /* Remove the layer rename edit box. If save!=0, then record the text as the new layer name. */
CVLRemoveEdit(CharView * cv,int save)2373 static void CVLRemoveEdit(CharView *cv, int save) {
2374     if ( layerinfo.rename_active ) {
2375 	GGadget *g = GWidgetGetControl(cvlayers,CID_Edit);
2376 	const unichar_t *str = GGadgetGetTitle(g);
2377 	int l = layerinfo.active;
2378 
2379 	if ( save
2380 		&& layerinfo.active>=0 && str!=NULL && str[0]!='\0'
2381 		&& uc_strcmp( str,cv->b.sc->parent->layers[l].name) ) {
2382 	    free( cv->b.sc->parent->layers[l].name );
2383 	    cv->b.sc->parent->layers[l].name = cu_copy( str );
2384 
2385 	    CVLCheckLayerCount(cv,true);
2386 	    CVLayersSet(cv);
2387 	}
2388 	GGadgetSetVisible(g,false);
2389 	GDrawRequestExpose(cvlayers,NULL,false);
2390 
2391 	layerinfo.rename_active = 0;
2392 	CVInfoDrawText(cv,cv->gw);
2393     }
2394 }
2395 
2396  /* Make sure we've got the right number of gadgets in the layers palette, and that
2397   * they are positioned properly. Their state are updated in CVLayers1Set().
2398   * If resize, then make the palette fit the layers up to a max number of layers. */
CVLCheckLayerCount(CharView * cv,int resize)2399 static void CVLCheckLayerCount(CharView *cv, int resize) {
2400 
2401     SplineChar *sc = cv->b.sc;
2402     int i;
2403     GGadgetCreateData gcd[4];
2404     GTextInfo label[3];
2405     GRect size;
2406     int width;
2407     int maxwidth=0;
2408     int togsize=0;
2409     int x, y;
2410     int column_width = layerinfo.column_width;
2411     char namebuf[40];
2412     int viscol=0, quadcol, fgcol, editcol;
2413     extern int _GScrollBar_Width;
2414     int offsetAtRightOfViewLayer = Layers_getOffsetAtRightOfViewLayer(cv);
2415 
2416     if (layerinfo.rename_active) CVLRemoveEdit(cv,true);
2417 
2418     quadcol=fgcol=offsetAtRightOfViewLayer;
2419     if ( layerscols & LSHOW_CUBIC )
2420     {
2421 	quadcol = offsetAtRightOfViewLayer;
2422 	fgcol   = offsetAtRightOfViewLayer+column_width;
2423     }
2424     if ( layerscols & LSHOW_FG )
2425     {
2426 	fgcol = quadcol+column_width;
2427     }
2428     // editcol is the X offset where the layer name label should be drawn
2429     editcol = fgcol+column_width;
2430 
2431     /* First figure out if we need to create any new widgets. If we have more */
2432     /* widgets than we need, we just set them to be invisible.                */
2433     if ( sc->layer_cnt > layers_max ) {
2434 	memset(&label,0,sizeof(label));
2435 	memset(&gcd,0,sizeof(gcd));
2436 	for ( i=layers_max; i<sc->layer_cnt; ++i ) {
2437 	     /* for each new layer, create new widgets */
2438 
2439 	     /* Visibility toggle */
2440 	    gcd[0].gd.flags = gg_enabled;
2441 	    gcd[0].gd.cid = CID_VBase+i;
2442 	    gcd[0].gd.popup_msg = _("Is Layer Visible?");
2443 	    gcd[0].creator = GVisibilityBoxCreate;
2444 
2445 	    GGadgetsCreate(cvlayers,gcd);
2446 	    GVisibilityBoxSetToMinWH(GWidgetGetControl(cvlayers,CID_VBase+i));
2447 	}
2448 	layers_max = sc->layer_cnt;
2449     }
2450 
2451     /* Then position everything, and name it properly */
2452 
2453     GDrawSetFont(cvlayers,layerinfo.font); /* for width finding code, need this */
2454 
2455      /* First need to position the add, remove, and layers gadgets */
2456     GGadgetGetSize(GWidgetGetControl(cvlayers,CID_RemoveLayer),&size);
2457     x = 7+size.width;
2458     y = layer_header_height;
2459     GGadgetMove(GWidgetGetControl(cvlayers,CID_AddLayer), x, 5);
2460     GGadgetSetSize(GWidgetGetControl(cvlayers,CID_AddLayer),&size);
2461     GGadgetGetSize(GWidgetGetControl(cvlayers,CID_AddLayer),&size);
2462     x += size.width;
2463     GGadgetGetSize(GWidgetGetControl(cvlayers,CID_LayersMenu),&size);
2464     GGadgetMove(GWidgetGetControl(cvlayers,CID_LayersMenu), x+5, 5+(y-8-size.height)/2);
2465     maxwidth=x+5+size.width;
2466 
2467     if ( !resize )
2468     {
2469          /* adjust the number of layers that can be visible in the palette */
2470         GDrawGetSize(cvlayers,&size);
2471         layerinfo.visible_layers=(size.height-layer_header_height)/layer_height;
2472         if ( layerinfo.offtop+layerinfo.visible_layers>=sc->layer_cnt )
2473             layerinfo.offtop = sc->layer_cnt-layerinfo.visible_layers;
2474         if ( layerinfo.offtop<0 ) layerinfo.offtop=0;
2475     }
2476     if ( layerinfo.visible_layers<2 ) layerinfo.visible_layers=2;
2477 
2478      /* Now position each layer row */
2479     for ( i=-1; i<layers_max; ++i ) {
2480 	GGadget *v = GWidgetGetControl(cvlayers,CID_VBase+i);
2481 
2482         width=0;
2483 	togsize = editcol;
2484 
2485 	if ( i>=0 && i<sc->layer_cnt ) {
2486 	    char *hasmn = strchr(sc->parent->layers[i].name,'_');
2487 	    if ( hasmn==NULL && i>=2 && i<9 && strlen(sc->parent->layers[i].name)<30 ) {
2488 		 /* For the first 10 or so layers, add a mnemonic like "(_3)" to the name label */
2489 		 /* if it does not already have a mnemonic.                                     */
2490 		/* sprintf(namebuf, "%s (_%d)", sc->parent->layers[i].name, i+1); */
2491 		sprintf(namebuf, "%s", sc->parent->layers[i].name);
2492 	    } else if ( hasmn==NULL ) {
2493                 sprintf(namebuf,"%s", i==-1 ? _("Guide") : (i==0 ?_("Back") : _("Fore")) );
2494             }
2495             width = GDrawGetText8Width(cvlayers, namebuf, -1);
2496 	    width += 10; // padding takes up some space.
2497 	    if ( width+togsize>maxwidth ) maxwidth = width + togsize;
2498 	} else if ( i==-1 ) {
2499 	    if ( width+togsize>maxwidth ) maxwidth = width + togsize;
2500         }
2501 
2502 	if ( i+1<layerinfo.offtop || i>=layerinfo.offtop+layerinfo.visible_layers ||
2503 		(sc->layer_cnt<=layerinfo.visible_layers && i>=sc->layer_cnt)) {
2504              /* layer is currently scrolled out of palette */
2505 	    GGadgetSetVisible(v,false);
2506 	} else {
2507 	    GGadgetMove(v,viscol ,y);
2508 	    GGadgetSetVisible(v,true);
2509 	    y += layer_height;
2510 	}
2511     }
2512 
2513      /* Update the scroll bar */
2514     if ( sc->layer_cnt+1<=layerinfo.visible_layers ) {
2515          /* don't need the scroll bar, so turn it off */
2516 	GGadgetSetVisible(GWidgetGetControl(cvlayers,CID_SB),false);
2517     } else {
2518 	if( !resize )
2519 	{
2520 	    GGadget *sb = GWidgetGetControl(cvlayers,CID_SB);
2521 	    maxwidth += 2 + GDrawPointsToPixels(cv->gw,_GScrollBar_Width);
2522 	    GScrollBarSetBounds(sb,0,sc->layer_cnt,layerinfo.visible_layers);
2523 	    GScrollBarSetPos(sb,cv->layers_off_top);
2524 	    GGadgetSetVisible(sb,true);
2525 	}
2526     }
2527 
2528      /* Resize the palette to fit */
2529     if ( resize )
2530     {
2531         y += GDrawPointsToPixels(NULL,3);
2532         GDrawGetSize(cvlayers,&size);
2533 	GDrawResize(cvlayers,maxwidth,y+layer_footer_height);
2534     }
2535 
2536     GDrawGetSize(cvlayers,&size);
2537     layerinfo.sb_start = size.width
2538                 - (sc->layer_cnt+1<=layerinfo.visible_layers ? 0 : GDrawPointsToPixels(cv->gw,_GScrollBar_Width));
2539     GGadget *sb = GWidgetGetControl(cvlayers,CID_SB);
2540     GGadgetResize(sb, GDrawPointsToPixels(cv->gw,_GScrollBar_Width), size.height-layer_header_height);
2541     GGadgetMove(sb,layerinfo.sb_start,layer_header_height);
2542 
2543     GDrawRequestExpose(cvlayers,NULL,false);
2544 }
2545 
2546 /* Respond to scroll events from cvlayers scrollbar. */
LayerScroll(CharView * cv,GEvent * event)2547 static void LayerScroll(CharView *cv, GEvent *event) {
2548     int off = 0;
2549     enum sb sbt = event->u.control.u.sb.type;
2550 
2551     if ( sbt==et_sb_top )
2552 	off = 0;
2553     else if ( sbt==et_sb_bottom )
2554 	off = cv->b.sc->layer_cnt-layerinfo.visible_layers;
2555     else if ( sbt==et_sb_up ) {
2556 	off = cv->layers_off_top-1;
2557     } else if ( sbt==et_sb_down ) {
2558 	off = cv->layers_off_top+1;
2559     } else if ( sbt==et_sb_uppage ) {
2560 	off = cv->layers_off_top-layerinfo.visible_layers+1;
2561     } else if ( sbt==et_sb_downpage ) {
2562 	off = cv->layers_off_top+layerinfo.visible_layers-1;
2563     } else /* if ( sbt==et_sb_thumb || sbt==et_sb_thumbrelease ) */ {
2564 	off = event->u.control.u.sb.pos;
2565     }
2566     if ( off>cv->b.sc->layer_cnt-layerinfo.visible_layers )
2567 	off = cv->b.sc->layer_cnt-layerinfo.visible_layers;
2568     if ( off<0 ) off=0;
2569     if ( off==cv->layers_off_top )
2570 return;
2571     cv->layers_off_top = off;
2572     layerinfo.offtop = off;
2573     CVLCheckLayerCount(cv, false);
2574     GScrollBarSetPos(GWidgetGetControl(cvlayers,CID_SB),off);
2575     GDrawRequestExpose(cvlayers,NULL,false);
2576 }
2577 
2578 /* Layers palette menu ids */
2579 #define LMID_LayerInfo	1
2580 #define LMID_NewLayer	2
2581 #define LMID_DelLayer	3
2582 #define LMID_Fill       4
2583 #define LMID_First	5
2584 #define LMID_Up     	6
2585 #define LMID_Down	7
2586 #define LMID_Last	8
2587 #define LMID_Foreground 9
2588 #define LMID_Background 10
2589 #define LMID_Cubic      11
2590 #define LMID_Quadratic  12
2591 #define LMID_ShowCubic  13
2592 #define LMID_ShowFore   14
2593 
2594 /* Return a unique layer name based on base.
2595  * This just appends a number to base until the name is not found. */
UniqueLayerName(SplineChar * sc,const char * base)2596 static char *UniqueLayerName(SplineChar *sc, const char *base)
2597 {
2598     static char buffer[100];
2599     const char *basestr=base;
2600     int i=1, c;
2601 
2602     if ( basestr==NULL || basestr[0]=='\0' ) basestr=_("Layer");
2603 
2604     while (1) {
2605         if (i==1) sprintf( buffer,"%s",basestr );
2606         else sprintf( buffer,"%s %d",basestr, i );
2607 
2608         for (c=0; c<sc->layer_cnt; c++) {
2609             if (!strcmp(sc->parent->layers[c].name,buffer)) break;
2610         }
2611 
2612         if ( c==sc->layer_cnt ) break;
2613         i++;
2614     }
2615 
2616     return buffer;
2617 }
2618 
2619 /* Layers palette menu selection */
CVLayerInvoked(GWindow v,GMenuItem * mi,GEvent * e)2620 static void CVLayerInvoked(GWindow v, GMenuItem *mi, GEvent *e) {
2621     CharView *cv = (CharView *) GDrawGetUserData(v);
2622     int layer = CVLayer(&cv->b);
2623     SplineChar *sc = cv->b.sc;
2624     Layer temp;
2625     int i;
2626     char *buts[3];
2627     buts[0] = _("_Yes"); buts[1]=_("_No"); buts[2] = NULL;
2628 
2629     switch ( mi->mid ) {
2630       case LMID_Fill:
2631         cv->showfilled = !cv->showfilled;
2632         CVRegenFill(cv);
2633         GDrawRequestExpose(cv->v,NULL,false);
2634       break;
2635 
2636       case LMID_ShowCubic:
2637         layerscols=(layerscols&~LSHOW_CUBIC)|((layerscols&LSHOW_CUBIC)?0:1);
2638         CVLCheckLayerCount(cv, true);
2639       break;
2640 
2641       case LMID_ShowFore:
2642         layerscols=(layerscols&~LSHOW_FG)|((layerscols&LSHOW_FG)?0:2);
2643         CVLCheckLayerCount(cv, true);
2644       break;
2645 
2646       case LMID_Foreground:
2647         if ( layer>ly_fore && cv->b.sc->parent->layers[layer].background==1) {
2648             SFLayerSetBackground(cv->b.sc->parent,layer,0);
2649 	    GDrawRequestExpose(cvlayers,NULL,false);
2650         }
2651       break;
2652 
2653       case LMID_Background:
2654         if ( layer>=ly_fore && cv->b.sc->parent->layers[layer].background==0) {
2655             SFLayerSetBackground(cv->b.sc->parent,layer,1);
2656 	    GDrawRequestExpose(cvlayers,NULL,false);
2657         }
2658       break;
2659 
2660       case LMID_Cubic:
2661         if ( layer!=ly_grid && cv->b.sc->layers[layer].order2 ) {
2662             SFConvertLayerToOrder3(cv->b.sc->parent, layer);
2663 	    GDrawRequestExpose(cvlayers,NULL,false);
2664             cv->back_img_out_of_date = true;
2665         }
2666       break;
2667 
2668       case LMID_Quadratic:
2669         if ( layer!=ly_grid && !cv->b.sc->layers[layer].order2 ) {
2670             SFConvertLayerToOrder2(cv->b.sc->parent, layer);
2671 	    GDrawRequestExpose(cvlayers,NULL,false);
2672             cv->back_img_out_of_date = true;
2673         }
2674       break;
2675 
2676       case LMID_NewLayer:
2677         SFAddLayer(cv->b.sc->parent, /* font of the glyph in the charview */
2678                         UniqueLayerName(sc,_("Back")),     /* Name */
2679                         0,         /* 0=cubic, 1=quad */
2680                         1);       /* 1=back,  0=fore */
2681 
2682         layer=cv->b.sc->parent->layer_cnt-1;
2683 
2684         cv->showback[layer>>5] |=  (1<<(layer&31)); /* make it visible */
2685         CVLCheckLayerCount(cv, true); /* update widget existence */
2686         CVLayersSet(cv);       /* update widget state     */
2687       break;
2688       case LMID_DelLayer:
2689         layer = CVLayer((CharViewBase *) cv); /* the index of the active layer */
2690         if (layer==ly_fore || layer==ly_back || layer==ly_grid)
2691 return;
2692         if ( gwwv_ask(_("Cannot Be Undone"),(const char **) buts,0,1,_("This operation cannot be undone, do it anyway?"))==1 )
2693 return;
2694         SFRemoveLayer(cv->b.sc->parent, layer);
2695         CVLCheckLayerCount(cv, true); /* update widget existence */
2696         CVLayersSet(cv);       /* update widget state     */
2697       break;
2698 
2699       case LMID_First: /* move layer contents to top */
2700 	if ( layer==ly_fore )
2701 return;
2702 	temp = sc->layers[layer];
2703 	for ( i=layer-1; i>=ly_fore; --i )
2704 	    sc->layers[i+1] = sc->layers[i];
2705 	sc->layers[i+1] = temp;
2706 	cv->b.layerheads[dm_fore] = &sc->layers[ly_fore];
2707       break;
2708       case LMID_Up: /* move layer contents one up */
2709 	if ( layer==ly_fore )
2710 return;
2711 	temp = sc->layers[layer];
2712 	sc->layers[layer] = sc->layers[layer-1];
2713 	sc->layers[layer-1] = temp;
2714 	cv->b.layerheads[dm_fore] = &sc->layers[layer-1];
2715       break;
2716       case LMID_Down: /* move layer contents one down */
2717 	if ( layer==sc->layer_cnt-1 )
2718 return;
2719 	temp = sc->layers[layer];
2720 	sc->layers[layer] = sc->layers[layer+1];
2721 	sc->layers[layer+1] = temp;
2722 	cv->b.layerheads[dm_fore] = &sc->layers[layer+1];
2723       break;
2724       case LMID_Last:
2725 	if ( layer==sc->layer_cnt-1 )
2726 return;
2727 	temp = sc->layers[layer]; /* move layer contents to bottom */
2728 	for ( i=layer+1; i<sc->layer_cnt; ++i )
2729 	    sc->layers[i-1] = sc->layers[i];
2730 	sc->layers[i-1] = temp;
2731 	cv->b.layerheads[dm_fore] = &sc->layers[i-1];
2732       break;
2733     }
2734     CVLayersSet(cv);
2735     CVCharChangedUpdate(&cv->b);
2736 }
2737 
2738 /* Pop up the layers palette context menu */
LayerMenu(CharView * cv,GEvent * event,int nolayer)2739 static void LayerMenu(CharView *cv,GEvent *event, int nolayer) {
2740     GMenuItem mi[20];
2741     int i;
2742     static char *names[] = {
2743                      /*N_("Rename Layer..."),*/
2744                      N_("New Layer"),
2745                      N_("Del Layer"),
2746                      (char *) -1,
2747                      N_("Shift Contents To _First"),
2748                      N_("Shift Contents _Up"),
2749                      N_("Shift Contents _Down"),
2750                      N_("Shift Contents To _Last"),
2751                      (char *) -1,
2752                      N_("Make Foreground"),/* or N_("Make Background"), */
2753                      N_("Make Cubic"),     /* or N_("Make Quadratic"),  */
2754                      (char *) -1,
2755                      N_("Fill"),
2756                      (char *) -1,
2757                      N_("Show Cubic Column"),
2758                      N_("Show Fore/Back Column"),
2759                      NULL,
2760                     };
2761     static int mids[] = {
2762                      /*LMID_RenameLayer,*/
2763                      LMID_NewLayer,
2764                      LMID_DelLayer,
2765                      -1,
2766                      LMID_First,
2767                      LMID_Up,
2768                      LMID_Down,
2769                      LMID_Last,
2770                      -1,
2771                      LMID_Foreground, /* or LMID_Background, */
2772                      LMID_Cubic,      /* or LMID_Quadratic,  */
2773                      -1,
2774                      LMID_Fill,
2775                      -1,
2776                      LMID_ShowCubic,
2777                      LMID_ShowFore,
2778                      0
2779                     };
2780     int layer = CVLayer(&cv->b);
2781 
2782     memset(mi,'\0',sizeof(mi));
2783     for ( i=0; names[i]!=0; ++i ) {
2784 	if ( names[i]!=(char *) -1 ) {
2785 	    mi[i].ti.text = (unichar_t *) _(names[i]);
2786 	    mi[i].ti.text_is_1byte = true;
2787 	    mi[i].ti.text_in_resource = true;
2788 	} else
2789 	    mi[i].ti.line = true;
2790 
2791 	mi[i].ti.fg = COLOR_DEFAULT;
2792 	mi[i].ti.bg = COLOR_DEFAULT;
2793 	mi[i].mid = mids[i];
2794 	mi[i].invoke = CVLayerInvoked;
2795 
2796 	/*if ( mids[i]!=LMID_NewLayer && nolayer )
2797 	    mi[i].ti.disabled = true;*/
2798 
2799 	if ( ( mids[i]==LMID_First || mids[i]==LMID_Up ) && ( layer==-1 || layer==0) )
2800 	    mi[i].ti.disabled = true;
2801 
2802         else if ( ( mids[i]==LMID_Last || mids[i]==LMID_Down ) && (layer==ly_grid || layer==cv->b.sc->layer_cnt-1) )
2803 	    mi[i].ti.disabled = true;
2804 
2805         else if ( mids[i]==LMID_DelLayer && ( layer<2 || cv->b.sc->layer_cnt==2) )
2806 	    mi[i].ti.disabled = true;
2807 
2808         else if ( mids[i]==LMID_Fill ) {
2809             mi[i].ti.checkable = 1;
2810             mi[i].ti.checked = cv->showfilled;
2811 
2812         } else if ( mids[i]==LMID_Foreground ) {
2813             if ( layer>=0 ) {
2814                 if ( ! cv->b.sc->layers[layer].background ) {
2815                     mi[i].mid = LMID_Background;
2816                     mi[i].ti.text = (unichar_t *) _("Make Background");
2817                 }
2818             } else {
2819 	        mi[i].ti.disabled = true;
2820             }
2821         } else if ( mids[i]==LMID_Cubic ) {
2822             if ( ! cv->b.sc->layers[layer].order2 ) {
2823                 mi[i].mid = LMID_Quadratic;
2824                 mi[i].ti.text = (unichar_t *) _("Make Quadratic");
2825             }
2826 
2827         } else if ( mids[i]==LMID_ShowCubic ) {
2828             mi[i].ti.checkable = 1;
2829             mi[i].ti.checked = (layerscols & LSHOW_CUBIC)?1:0;
2830 
2831         } else if ( mids[i]==LMID_ShowFore ) {
2832             mi[i].ti.checkable = 1;
2833             mi[i].ti.checked = (layerscols & LSHOW_FG)?1:0;
2834         }
2835     }
2836     GMenuCreatePopupMenu(cvlayers, event, mi);
2837 }
2838 
2839 /* Scan for which layer and column one clicks on in the layers 1 palette                */
2840 /* -1 is the guides layer, 0 is default back, 1 default fore, etc.                      */
2841 /* col will be set to either -1 for none, CID_VBase, CID_QBase, CID_FBase, or CID_EBase */
CVLScanForItem(int x,int y,int * col)2842 static int CVLScanForItem(int x, int y, int *col) {
2843     int l=(y-layer_header_height)/layer_height + layerinfo.offtop - 1;
2844     int viscol=0, quadcol, fgcol, editcol;
2845     int cw=layerinfo.column_width;
2846 
2847     quadcol=fgcol=viscol;
2848     if ( layerscols & LSHOW_CUBIC ) { quadcol = viscol+cw; fgcol=viscol+cw; }
2849     if ( layerscols & LSHOW_FG    ) { fgcol = quadcol+cw; }
2850     editcol=fgcol+cw;
2851 
2852     *col=-1;
2853     if ( x>0 && x<viscol+cw ) *col=CID_VBase;
2854     /**
2855      * The two below options, CID_QBase and CID_FBase allow the curve
2856      * type and foreground/background to be changed simply by clicking
2857      * on them. The cubic/quadratic and background/foreground
2858      * attributes should NOT be buttons that can change these
2859      * attributes, they should only SHOW the attribute. Changing the
2860      * attributes can be done in Font Info, Layers, and is done
2861      * infrequently and has a lot of implications so shouldn't be
2862      * easily done by mistake.
2863      */
2864 //    else if ( (layerscols & LSHOW_CUBIC) && x>=quadcol && x<quadcol+cw ) *col=CID_QBase;
2865 //    else if ( (layerscols & LSHOW_FG) && x>=fgcol && x<fgcol+cw ) *col=CID_FBase;
2866     else if ( x>=editcol ) *col=CID_EBase;
2867 
2868     return l;
2869 }
2870 
2871 /* Called in response to some event where we want to change the current layer. */
CVLSelectLayer(CharView * cv,int layer)2872 void CVLSelectLayer(CharView *cv, int layer) {
2873     enum drawmode dm = cv->b.drawmode;
2874 
2875     if ( layer<-1 || layer>=cv->b.sc->layer_cnt )
2876 	return;
2877 
2878     if ( layer==-1 ) {
2879         cv->b.drawmode = dm_grid;
2880         cv->lastselpt = NULL;
2881     } else {
2882         if ( layer==1 ) {
2883             cv->b.drawmode = dm_fore;
2884             cv->lastselpt = NULL;
2885         } else {
2886             cv->b.drawmode = dm_back;
2887             cv->b.layerheads[dm_back] = &cv->b.sc->layers[layer];
2888             cv->lastselpt = NULL;
2889         }
2890 
2891         CVDebugFree(cv->dv);
2892         SplinePointListsFree(cv->b.gridfit); cv->b.gridfit = NULL;
2893         FreeType_FreeRaster(cv->oldraster); cv->oldraster = NULL;
2894         FreeType_FreeRaster(cv->raster); cv->raster = NULL;
2895         cv->show_ft_results = false;
2896     }
2897     layerinfo.active = CVLayer(&cv->b); /* the index of the active layer */
2898 
2899     CVRegenFill(cv);
2900     GDrawRequestExpose(cv->v,NULL,false);
2901     if (cvlayers2) GDrawRequestExpose(cvlayers2,NULL,false);
2902     if (cvlayers)  GDrawRequestExpose(cvlayers,NULL,false);
2903     if ( dm!=cv->b.drawmode )
2904         GDrawRequestExpose(cv->gw,NULL,false); /* the logo (where the scrollbars join) shows what layer we are in */
2905     CVInfoDrawText(cv,cv->gw);
2906 }
2907 
cvlayers_e_h(GWindow gw,GEvent * event)2908 static int cvlayers_e_h(GWindow gw, GEvent *event) {
2909     CharView *cv = (CharView *) GDrawGetUserData(gw);
2910     char *buts[3];
2911     buts[0] = _("_Yes"); buts[1]=_("_No"); buts[2] = NULL;
2912 
2913     if ( event->type==et_destroy && cvlayers == gw )
2914     {
2915 	cvlayers = NULL;
2916 	return( true );
2917     }
2918 
2919     if ( cv==NULL )
2920 	return( true );
2921 
2922     switch ( event->type ) {
2923       case et_close:
2924 	GDrawSetVisible(gw,false);
2925       break;
2926       case et_char: case et_charup:
2927 	if ( event->u.chr.keysym == GK_Return) {
2928 	    CVLRemoveEdit(cv, true);
2929 	} else if ( event->u.chr.keysym == GK_Escape) {
2930 	    CVLRemoveEdit(cv, false);
2931 	} else PostCharToWindow(cv->gw,event);
2932       break;
2933       case et_mousemove: {
2934         int l, col;
2935 
2936         l = CVLScanForItem(event->u.mouse.x,event->u.mouse.y, &col);
2937         if ( l!=layerinfo.mo_layer || col!=layerinfo.mo_col ) {
2938             layerinfo.mo_layer = l;
2939             layerinfo.mo_col = col;
2940             GDrawRequestExpose(cvlayers,NULL,false);
2941         }
2942 
2943 return( true );
2944 
2945       } break;
2946       case et_mousedown: {
2947         if ( layerinfo.rename_active ) CVLRemoveEdit(cv, true);
2948       } break;
2949       case et_mouseup: {
2950         int l, x, cid, h;
2951         GGadget *g;
2952         l = CVLScanForItem(event->u.mouse.x,event->u.mouse.y, &cid);
2953 
2954         if ( cid==CID_EBase && l>=-1 && l<cv->b.sc->layer_cnt )
2955 	{
2956 	    /* Need to check for this BEFORE checking for right click! */
2957             if ( event->u.mouse.button==1 && event->u.mouse.clicks==2 )
2958 	    {
2959 		 /* bring up edit box for layer name */
2960 
2961                 if ( l<2 )
2962 		    return ( true );
2963 
2964                 x = 7+(1+((layerscols&LSHOW_CUBIC)?1:0)+((layerscols&LSHOW_FG)?1:0))*layerinfo.column_width;
2965                 g = GWidgetGetControl(cvlayers,CID_Edit);
2966 		h = 1.5*layer_height;
2967 
2968                 GGadgetResize(g, layerinfo.sb_start-x, h);
2969                 GGadgetMove(g, x,layer_header_height+(l+1.5+layerinfo.offtop)*layer_height-h/2);
2970                 GGadgetSetVisible(g,true);
2971                 /* GGadgetSetTitle8((GTextField*)g, cv->b.sc->parent->layers[l].name); */
2972                 GGadgetSetTitle8(g, cv->b.sc->parent->layers[l].name);
2973 
2974 		layerinfo.active=l;
2975                 layerinfo.rename_active=1;
2976                 return ( true );
2977             }
2978 
2979             CVLSelectLayer(cv, l);
2980         }
2981 
2982          /* right click to pop up menu */
2983 	if ( event->u.mouse.button==3 ) {
2984 	    LayerMenu(cv,event,true);
2985 	    return(true);
2986         }
2987 
2988          /* otherwise, deal with clicking up on the various controls */
2989         if ( l<-1 || l>=cv->b.sc->layer_cnt)
2990 	    return (true);
2991 
2992         if ( cid==CID_QBase) {
2993             if (l>=0) { /* don't try to adjust if calling for guides layer */
2994                 if (cv->b.sc->layers[l].order2)
2995                     SFConvertLayerToOrder3(cv->b.sc->parent, l);
2996                 else
2997                     SFConvertLayerToOrder2(cv->b.sc->parent, l);
2998                 cv->back_img_out_of_date = true;
2999 	        GDrawRequestExpose(cvlayers,NULL,false);
3000                 GDrawRequestExpose(cv->v,NULL,false);
3001             }
3002         } else if ( cid==CID_FBase) {
3003             if (l>1) { /* don't try to adjust if calling guides, default fore or back layer */
3004                 if (cv->b.sc->layers[l].background)
3005                     SFLayerSetBackground(cv->b.sc->parent,l,0);
3006                 else
3007                     SFLayerSetBackground(cv->b.sc->parent,l,1);
3008 	        GDrawRequestExpose(cvlayers,NULL,false);
3009                 GDrawRequestExpose(cv->v,NULL,false);
3010             }
3011         }
3012       } break; /* case et_mouseup */
3013       case et_expose:
3014 	LayersExpose(cv,gw,event);
3015       break;
3016       case et_resize:
3017         if ( event->u.resize.sized ) {
3018             CVLCheckLayerCount(cv,false); /* update widget existence, but do not resize */
3019         }
3020       break;
3021       case et_controlevent:
3022 	if ( event->u.control.subtype == et_buttonactivate ) {
3023 	    int cid = GGadgetGetCid(event->u.control.g);
3024 	    int layer;
3025 
3026 	    switch( cid ) {
3027 	      case CID_AddLayer: {
3028                 SplineChar *sc = cv->b.sc;
3029 
3030 		 /* This adds a new layer to the end of the current layers list.
3031 		  * Somehow it is created as an invisible layer. */
3032 		SFAddLayer(cv->b.sc->parent, /* font of the glyph in the charview */
3033 				UniqueLayerName(sc,_("Back")),     /* Name */
3034 				0,         /* 0=cubic, 1=quad */
3035 				1);       /* 1=back,  0=fore */
3036 
3037 		layer=cv->b.sc->parent->layer_cnt-1;
3038 
3039 		cv->showback[layer>>5] |=  (1<<(layer&31)); /* make it visible */
3040 		CVLCheckLayerCount(cv,true); /* update widget existence */
3041 		CVLayersSet(cv);       /* update widget state     */
3042               } break;
3043 	      case CID_RemoveLayer:
3044 		layer = CVLayer((CharViewBase *) cv); /* the index of the active layer */
3045                 if (layer==ly_fore || layer==ly_back || layer==ly_grid)
3046 return ( true );
3047 	        if ( gwwv_ask(_("Cannot Be Undone"),(const char **) buts,0,1,_("This operation cannot be undone, do it anyway?"))==1 )
3048 return ( true );
3049                 SFRemoveLayer(cv->b.sc->parent, layer);
3050                 CVLCheckLayerCount(cv,true); /* update widget existence */
3051                 CVLayersSet(cv);       /* update widget state     */
3052 	      break;
3053 	      case CID_RenameLayer: {
3054 		/* *** */
3055                 int x = 7+(1+((layerscols&LSHOW_CUBIC)?1:0)+((layerscols&LSHOW_FG)?1:0))*layerinfo.column_width;
3056                 GGadget *g = GWidgetGetControl(cvlayers,CID_Edit);
3057 		layer = CVLayer((CharViewBase *) cv); /* the index of the active layer */
3058 		/* layer = layerinfo.active */ /* the index of the active layer */
3059 
3060                 GGadgetResize(g, layerinfo.sb_start-x,1.5*layer_height);
3061                 GGadgetMove(g, x,layer_header_height+(layer+1+layerinfo.offtop)*layer_height);
3062                 GGadgetSetVisible(g,true);
3063                 GGadgetSetTitle8(g, cv->b.sc->parent->layers[layer].name);
3064 
3065                 layerinfo.rename_active=1;
3066 
3067 		CVLCheckLayerCount(cv,true); /* update widget existence */
3068 		CVLayersSet(cv);       /* update widget state     */
3069 		GDrawRequestExpose(cvtools,NULL,false);
3070 
3071               } break;
3072 	    }
3073         } else if ( event->u.control.subtype == et_radiochanged ) {
3074 	    enum drawmode dm = cv->b.drawmode;
3075 	    int cid = GGadgetGetCid(event->u.control.g);
3076 
3077 	    switch( cid ) {
3078 	      case CID_VFore:
3079 		CVShows.showfore = cv->showfore = GGadgetIsChecked(event->u.control.g);
3080                 GDrawRequestExpose(cv->v,NULL,false);
3081 	      break;
3082 	      case CID_VBack:
3083 		CVShows.showback = GGadgetIsChecked(event->u.control.g);
3084 		if ( CVShows.showback )
3085 		    cv->showback[0] |= 1;
3086 		else
3087 		    cv->showback[0] &= ~1;
3088 		cv->back_img_out_of_date = true;
3089                 GDrawRequestExpose(cv->v,NULL,false);
3090 	      break;
3091 	      case CID_VGrid:
3092 		CVShows.showgrids = cv->showgrids = GGadgetIsChecked(event->u.control.g);
3093                 GDrawRequestExpose(cv->v,NULL,false);
3094 	      break;
3095 	      case CID_EFore:
3096 		cv->b.drawmode = dm_fore;
3097 		cv->lastselpt = NULL;
3098 
3099 		CVDebugFree(cv->dv);
3100 		SplinePointListsFree(cv->b.gridfit); cv->b.gridfit = NULL;
3101 		FreeType_FreeRaster(cv->oldraster); cv->oldraster = NULL;
3102 		FreeType_FreeRaster(cv->raster); cv->raster = NULL;
3103 		cv->show_ft_results = false;
3104 	      break;
3105 	      case CID_EBack:
3106 		cv->b.drawmode = dm_back;
3107 		cv->b.layerheads[dm_back] = &cv->b.sc->layers[ly_back];
3108 		cv->lastselpt = NULL;
3109 
3110 		CVDebugFree(cv->dv);
3111 		SplinePointListsFree(cv->b.gridfit); cv->b.gridfit = NULL;
3112 		FreeType_FreeRaster(cv->oldraster); cv->oldraster = NULL;
3113 		FreeType_FreeRaster(cv->raster); cv->raster = NULL;
3114 		cv->show_ft_results = false;
3115 	      break;
3116 	      case CID_EGrid:
3117 		cv->b.drawmode = dm_grid;
3118 		cv->lastselpt = NULL;
3119 	      break;
3120 	      default:
3121                 if ( cid>=CID_VBase-1 && cid<CID_VBase+999) {
3122                     cid -= CID_VBase;
3123                     if ( GGadgetIsChecked(event->u.control.g))
3124                         cv->showback[cid>>5] |=  (1<<(cid&31));
3125                     else
3126                         cv->showback[cid>>5] &= ~(1<<(cid&31));
3127                     cv->back_img_out_of_date = true;
3128 
3129                     GDrawRequestExpose(cv->v,NULL,false);
3130                     if ( dm!=cv->b.drawmode )
3131                         GDrawRequestExpose(cv->gw,NULL,false);	/* the logo (where the scrollbars join) shows what layer we are in */
3132                 }
3133             }
3134 
3135         } else if ( event->u.control.subtype == et_scrollbarchange ) {
3136 	    LayerScroll(cv,event);
3137 
3138 	}
3139       break; /* case et_controlevent */
3140       default: {
3141       } break;
3142     } /* switch ( event->type ) */
3143 return( true );
3144 }
3145 
3146 /* Set to true the editable field for the current layer, and false for the other layers. */
CVSetLayer(CharView * cv,int layer)3147 void CVSetLayer(CharView *cv,int layer) {
3148 
3149      /* Update the drawmode of cv */
3150     if ( layer == ly_grid )
3151 	cv->b.drawmode = dm_grid;
3152     else if (layer == ly_fore )
3153 	cv->b.drawmode = dm_fore;
3154     else {
3155 	cv->b.drawmode = dm_back;
3156 	cv->b.layerheads[dm_back] = &cv->b.sc->layers[layer];
3157     }
3158     if ( cvlayers!=NULL && GDrawGetUserData(cvlayers)==cv )
3159 	GDrawRequestExpose(cvlayers,NULL,false);
3160 }
3161 
3162 /* Check if a key press corresponds to a mnemonic the palette knows about. */
CVPaletteMnemonicCheck(GEvent * event)3163 int CVPaletteMnemonicCheck(GEvent *event) {
3164     static struct strmatch { char *str; int cid; } strmatch[] = {
3165 /* GT: Foreground, make it short */
3166 	{ N_("F_ore"), CID_EFore },
3167 /* GT: Background, make it short */
3168 	{ N_("_Back"), CID_EBack },
3169 /* GT: Guide layer, make it short */
3170 	{ N_("_Guide"), CID_EGrid },
3171 	{ NULL, 0 }
3172     };
3173     unichar_t mn, mnc;
3174     int j, i, ch;
3175     char *foo;
3176     GEvent fake;
3177     GGadget *g;
3178     CharView *cv;
3179     SplineFont *parent;
3180     int curlayer;
3181 
3182     if ( cvtools==NULL )
3183 return( false );
3184     cv = GDrawGetUserData(cvtools);
3185     parent = cv->b.sc->parent;
3186     curlayer = CVLayer(&cv->b); /* the index of the active layer */
3187 
3188     if ( isdigit(event->u.chr.keysym) ) {
3189 	int off = event->u.chr.keysym - '0';
3190 
3191 	g = GWidgetGetControl(cvlayers, CID_EBase+off-1);
3192 	if ( off-1<parent->layer_cnt && off!=curlayer ) {
3193             CVLSelectLayer(cv, off);
3194 	    if ( cv->b.sc->parent->multilayer )
3195 	    	GDrawRequestExpose(cvlayers2,NULL,false);
3196 	    else
3197 return( true );
3198 	}
3199     }
3200 
3201      /* mnemonic is encoded in the layer name */
3202     for ( j=0; j<2; ++j ) {
3203 	for ( i=0; j==0 ? i<parent->layer_cnt : strmatch[i].str!=NULL; ++i ) {
3204 	    for ( foo = j==0 ? parent->layers[i].name : _(strmatch[i].str);
3205 		    (ch=utf8_ildb((const char **) &foo))!=0; )
3206 		if ( ch=='_' )
3207 	    break;
3208 	    if ( ch=='_' )
3209 		mnc = utf8_ildb((const char **) &foo);
3210 	    else
3211 		mnc = 0;
3212 	    mn = mnc;
3213 	    if ( islower(mn)) mnc = toupper(mn);
3214 	    else if ( isupper(mn)) mnc = tolower(mn);
3215 	    if ( event->u.chr.chars[0]==mn || event->u.chr.chars[0]==mnc ) {
3216 		if ( cv->b.sc->parent->multilayer ) {
3217 		    fake.type = et_mousedown;
3218 		    fake.w = cvlayers;
3219 		    fake.u.mouse.x = 40;
3220 		    if ( strmatch[i].cid==CID_EGrid ) {
3221 			fake.u.mouse.y = layer2.header_height+12;
3222 		    } else if ( strmatch[i].cid==CID_EBack ) {
3223 			fake.u.mouse.y = layer2.header_height+12+CV_LAYERS2_LINE_HEIGHT;
3224 		    } else {
3225 			fake.u.mouse.y = layer2.header_height+12+2*CV_LAYERS2_LINE_HEIGHT;
3226 		    }
3227 		    cvlayers2_e_h(cvlayers2,&fake);
3228 		} else {
3229             	    CVLSelectLayer(cv, i);
3230 	    	    GDrawRequestExpose(cvlayers,NULL,false);
3231 		}
3232     return( true );
3233 	    }
3234 	}
3235     }
3236 return( false );
3237 }
3238 
3239 /* This is used for fonts other than Type 3 fonts. CVMakeLayers2() is used for Type 3.
3240  * Only the basics of the palette are set up here, with the widgets for the default fore, back,
3241  * and guides layers. The palette is updated to actual character views in CVLCheckLayerCount(). */
CVMakeLayers(CharView * cv)3242 GWindow CVMakeLayers(CharView *cv) {
3243     GRect r,size;
3244     GWindowAttrs wattrs;
3245     GGadgetCreateData gcd[25];
3246     GTextInfo label[25];
3247     GGadget *gadget;
3248     FontRequest rq;
3249     extern int _GScrollBar_Width;
3250     int i=0;
3251     int viscol=0;
3252 
3253     if ( cvlayers!=NULL )
3254 return( cvlayers );
3255 
3256      /* Initialize layerinfo */
3257     if ( layerinfo.clut==NULL )
3258 	layerinfo.clut = _BDFClut(4);
3259     if ( layersfont==NULL ) {
3260 	memset(&rq,'\0',sizeof(rq));
3261 	rq.utf8_family_name = SANS_UI_FAMILIES;
3262 	rq.point_size = -12;
3263 	rq.weight = 400;
3264 	layersfont = GDrawInstanciateFont(cvlayers2,&rq);
3265 	layersfont = GResourceFindFont("LayersPalette.Font",layersfont);
3266     }
3267     layerinfo.font = layersfont;
3268 
3269      /* Initialize palette window */
3270     memset(&wattrs,0,sizeof(wattrs));
3271     wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_positioned|wam_isdlg;
3272     wattrs.event_masks = -1;
3273     wattrs.cursor = ct_mypointer;
3274     wattrs.positioned = true;
3275     wattrs.is_dlg = true;
3276     wattrs.utf8_window_title = _("Layers");
3277 
3278     r.width = GGadgetScale(104); r.height = CV_LAYERS_HEIGHT;
3279     if ( cvlayersoff.x==-9999 ) {
3280 	 /* Offset of window on screen, by default make it sit just below the tools palette */
3281 	cvlayersoff.x = -r.width-6;
3282 	cvlayersoff.y = cv->mbh+getToolbarHeight(cv)+45/*25*/; /* 45 is right if there's decor, 25 when none. twm gives none, kde gives decor */
3283     }
3284     r.x = cvlayersoff.x; r.y = cvlayersoff.y;
3285     if ( palettes_docked ) { r.x = 0; r.y=getToolbarHeight(cv)+2; }
3286     cvlayers = CreatePalette( cv->gw, &r, cvlayers_e_h, NULL, &wattrs, cv->v );
3287 
3288     memset(&label,0,sizeof(label));
3289     memset(&gcd,0,sizeof(gcd));
3290 
3291     int32 plusw = GDrawGetText8Width(cv->gw,  _("+"), -1);
3292     int32 plush = GDrawGetText8Height(cv->gw, _("+"), -1);
3293     plusw = GDrawPointsToPixels(NULL,plusw+4);
3294     plush = GDrawPointsToPixels(NULL,plush+4);
3295     plush = MAX( plush, plusw ); // make it square.
3296 
3297      /* Remove Layer button */
3298     label[0].text = (unichar_t *) _("-");
3299     label[0].text_is_1byte = true;
3300     gcd[i].gd.label = &label[0];
3301     gcd[i].gd.pos.x = 7; gcd[i].gd.pos.y = 5;
3302     gcd[i].gd.pos.width  = plusw; gcd[i].gd.pos.height = plush;
3303     gcd[i].gd.flags = gg_enabled|gg_visible|gg_pos_in_pixels;
3304     gcd[i].gd.cid = CID_RemoveLayer;
3305     gcd[i].gd.popup_msg = _("Delete the current layer");
3306     gcd[i].creator = GButtonCreate;
3307     ++i;
3308 
3309      /* Add Layer button */
3310     label[1].text = (unichar_t *) _("+");
3311     label[1].text_is_1byte = true;
3312     gcd[i].gd.label = &label[1];
3313     gcd[i].gd.pos.x = 30; gcd[i].gd.pos.y = 5;
3314     gcd[i].gd.pos.width  = plusw; gcd[i].gd.pos.height = plush;
3315     gcd[i].gd.flags = gg_enabled|gg_visible|gg_pos_in_pixels;
3316     gcd[i].gd.cid = CID_AddLayer;
3317     gcd[i].gd.popup_msg = _("Add a new layer");
3318     gcd[i].creator = GButtonCreate;
3319     ++i;
3320 
3321      /* "Layers" label next to the add and remove buttons */
3322     label[2].text = (unichar_t *) "";
3323     label[2].text_is_1byte = true;
3324     gcd[i].gd.label = &label[2];
3325     gcd[i].gd.pos.x = 47; gcd[i].gd.pos.y = 5;
3326     gcd[i].gd.flags = gg_enabled|gg_visible|gg_pos_in_pixels;
3327     gcd[i].gd.cid = CID_LayersMenu;
3328     /* gcd[i].gd.popup_msg = _("Rename the current layer"); */
3329     gcd[i].creator = GLabelCreate;
3330     ++i;
3331 
3332      /* Default visibility toggles for Fore, Back, and Guides */
3333     gcd[i].gd.pos.x = viscol; gcd[i].gd.pos.y = 38;
3334     gcd[i].gd.flags = gg_enabled|gg_visible|gg_dontcopybox|gg_pos_in_pixels;
3335     if ( cv->showgrids ) gcd[i].gd.flags |= gg_cb_on;
3336     gcd[i].gd.cid = CID_VGrid;
3337     gcd[i].gd.popup_msg = _("Is Layer Visible?");
3338     gcd[i].creator = GVisibilityBoxCreate;
3339     ++i;
3340 
3341     gcd[i].gd.pos.x = viscol; gcd[i].gd.pos.y = 38;
3342     gcd[i].gd.flags = gg_enabled|gg_visible|gg_dontcopybox|gg_pos_in_pixels;
3343     if ( cv->showback[0]&1 ) gcd[i].gd.flags |= gg_cb_on;
3344     gcd[i].gd.cid = CID_VBack;
3345     gcd[i].gd.popup_msg = _("Is Layer Visible?");
3346     gcd[i].creator = GVisibilityBoxCreate;
3347     ++i;
3348 
3349     gcd[i].gd.pos.x = viscol; gcd[i].gd.pos.y = 21;
3350     gcd[i].gd.flags = gg_enabled|gg_visible|gg_dontcopybox|gg_pos_in_pixels;
3351     if ( cv->showfore ) gcd[i].gd.flags |= gg_cb_on;
3352     gcd[i].gd.cid = CID_VFore;
3353     gcd[i].gd.popup_msg = _("Is Layer Visible?");
3354     gcd[i].creator = GVisibilityBoxCreate;
3355     ++i;
3356 
3357 
3358      /* Scroll bar */
3359     gcd[i].gd.pos.width = GDrawPointsToPixels(cv->gw,_GScrollBar_Width);
3360     gcd[i].gd.pos.x = 0; /* <- these get updated to real values later */
3361     gcd[i].gd.pos.y = 0;
3362     gcd[i].gd.pos.height = 50;
3363     gcd[i].gd.flags = gg_enabled|gg_pos_in_pixels|gg_sb_vert;
3364     gcd[i].gd.cid = CID_SB;
3365     gcd[i].creator = GScrollBarCreate;
3366     layerinfo.sb_start = gcd[i].gd.pos.x;
3367     ++i;
3368 
3369      /* Edit box for in place layer rename */
3370     gcd[i].gd.pos.width=gcd[i].gd.pos.height=1;
3371     gcd[i].gd.flags = gg_enabled|gg_pos_in_pixels;
3372     gcd[i].gd.cid = CID_Edit;
3373     gcd[i].gd.popup_msg = _("Type in new layer name");
3374     gcd[i].creator = GTextFieldCreate;
3375     ++i;
3376 
3377     GGadgetsCreate(cvlayers,gcd);
3378     if ( cvvisible[0] )
3379 	GDrawSetVisible(cvlayers,true);
3380     layers_max=2;
3381 
3382     gadget=GWidgetGetControl(cvlayers,CID_AddLayer);
3383     GGadgetGetSize(gadget,&size);
3384     layer_header_height = 0;
3385     layer_footer_height = size.y + size.height;
3386 
3387     GGadgetGetSize(GWidgetGetControl(cvlayers,CID_VGrid),&size);
3388     layer_height = size.height;
3389     int32 w = GDrawGetText8Width(cvlayers, "W", -1);
3390     layerinfo.column_width = w+6;
3391 
3392     layerinfo.active = CVLayer(&cv->b); /* the index of the active layer */
3393     layerinfo.mo_col   = -2; /* -2 forces this variable to be updated. afterwords it will be -1 for nothing, or >=0 */
3394     layerinfo.mo_layer = -2;
3395     layerinfo.offtop   = 0;
3396     layerinfo.rename_active = 0;
3397 
3398     GVisibilityBoxSetToMinWH(GWidgetGetControl(cvlayers,CID_VGrid));
3399     GVisibilityBoxSetToMinWH(GWidgetGetControl(cvlayers,CID_VBack));
3400     GVisibilityBoxSetToMinWH(GWidgetGetControl(cvlayers,CID_VFore));
3401 
3402 return( cvlayers );
3403 }
3404 
3405 
3406 /* ***************** CVTools and other common palette functions follow ************ */
3407 
CVPopupInvoked(GWindow v,GMenuItem * mi,GEvent * e)3408 static void CVPopupInvoked(GWindow v, GMenuItem *mi, GEvent *e) {
3409     CharView *cv = (CharView *) GDrawGetUserData(v);
3410     int pos;
3411 
3412     pos = mi->mid;
3413     if ( pos==cvt_spiro ) {
3414 	CVChangeSpiroMode(cv);
3415     } else if ( cv->had_control ) {
3416 	if ( cv->cb1_tool!=pos ) {
3417 	    cv->cb1_tool = cv_cb1_tool = pos;
3418 	    GDrawRequestExpose(cvtools,NULL,false);
3419 	}
3420     } else {
3421 	if ( cv->b1_tool!=pos ) {
3422 	    cv->b1_tool = cv_b1_tool = pos;
3423 	    GDrawRequestExpose(cvtools,NULL,false);
3424 	}
3425     }
3426     CVToolsSetCursor(cv,cv->had_control?ksm_control:0,NULL);
3427 }
3428 
CVPopupLayerInvoked(GWindow v,GMenuItem * mi,GEvent * e)3429 static void CVPopupLayerInvoked(GWindow v, GMenuItem *mi, GEvent *e) {
3430     CharView *cv = (CharView *) GDrawGetUserData(v);
3431     int layer = mi->mid==0 ? 1 : mi->mid==1 ? 0 : -1;
3432 
3433     if ( layerinfo.active!=layer )
3434         CVLSelectLayer(cv, layer);
3435 }
3436 
CVPopupSelectInvoked(GWindow v,GMenuItem * mi,GEvent * e)3437 static void CVPopupSelectInvoked(GWindow v, GMenuItem *mi, GEvent *e) {
3438     CharView *cv = (CharView *) GDrawGetUserData(v);
3439 
3440     switch ( mi->mid ) {
3441       case 0:
3442 	CVPGetInfo(cv);
3443       break;
3444       case 1:
3445 	if ( cv->p.ref!=NULL )
3446 	    CharViewCreate(cv->p.ref->sc,(FontView *) (cv->b.fv),-1);
3447       break;
3448       case 2:
3449 	CVAddAnchor(cv);
3450       break;
3451       case 3:
3452 	CVMakeClipPath(cv);
3453       break;
3454     case MIDL_MakeLine: {
3455 	_CVMenuMakeLine((CharViewBase *) cv,mi->mid==MIDL_MakeArc, e!=NULL && (e->u.mouse.state&ksm_meta));
3456 	break;
3457     }
3458     case MIDL_MakeArc: {
3459 	_CVMenuMakeLine((CharViewBase *) cv,mi->mid==MIDL_MakeArc, e!=NULL && (e->u.mouse.state&ksm_meta));
3460 	break;
3461     }
3462     case MIDL_InsertPtOnSplineAt: {
3463 	_CVMenuInsertPt( cv );
3464 	break;
3465     }
3466     case MIDL_NamePoint: {
3467 	if ( cv->p.sp )
3468 	    _CVMenuNamePoint( cv, cv->p.sp );
3469 	break;
3470     }
3471     case MIDL_NameContour: {
3472 	_CVMenuNameContour( cv );
3473 	break;
3474     }
3475 
3476     }
3477 }
3478 
CVToolsPopup(CharView * cv,GEvent * event)3479 void CVToolsPopup(CharView *cv, GEvent *event) {
3480     GMenuItem mi[125];
3481     int i=0;
3482     int j=0;
3483     int anysel=0;
3484     static char *selectables[] = { N_("Get Info..."), N_("Open Reference"), N_("Add Anchor"), NULL };
3485 
3486     memset(mi,'\0',sizeof(mi));
3487     anysel = CVTestSelectFromEvent(cv,event);
3488 
3489     if( anysel )
3490     {
3491         if ( cv->b.sc->inspiro && hasspiro()) {
3492             mi[i].ti.text = (unichar_t *) _("G4 Curve");
3493             mi[i].ti.text_is_1byte = true;
3494             mi[i].ti.fg = COLOR_DEFAULT;
3495             mi[i].ti.bg = COLOR_DEFAULT;
3496             mi[i].mid = MID_SpiroG4;
3497             mi[i].invoke = CVMenuPointType;
3498             i++;
3499             mi[i].ti.text = (unichar_t *) _("G2 Curve");
3500             mi[i].ti.text_is_1byte = true;
3501             mi[i].ti.fg = COLOR_DEFAULT;
3502             mi[i].ti.bg = COLOR_DEFAULT;
3503             mi[i].mid = MID_SpiroG2;
3504             mi[i].invoke = CVMenuPointType;
3505             i++;
3506             mi[i].ti.text = (unichar_t *) _("Corner");
3507             mi[i].ti.text_is_1byte = true;
3508             mi[i].ti.fg = COLOR_DEFAULT;
3509             mi[i].ti.bg = COLOR_DEFAULT;
3510             mi[i].mid = MID_SpiroCorner;
3511             mi[i].invoke = CVMenuPointType;
3512             i++;
3513             mi[i].ti.text = (unichar_t *) _("Left Constraint");
3514             mi[i].ti.text_is_1byte = true;
3515             mi[i].ti.fg = COLOR_DEFAULT;
3516             mi[i].ti.bg = COLOR_DEFAULT;
3517             mi[i].mid = MID_SpiroLeft;
3518             mi[i].invoke = CVMenuPointType;
3519             i++;
3520             mi[i].ti.text = (unichar_t *) _("Right Constraint");
3521             mi[i].ti.text_is_1byte = true;
3522             mi[i].ti.fg = COLOR_DEFAULT;
3523             mi[i].ti.bg = COLOR_DEFAULT;
3524             mi[i].mid = MID_SpiroRight;
3525             mi[i].invoke = CVMenuPointType;
3526             i++;
3527         } else {
3528             mi[i].ti.text = (unichar_t *) _("Curve");
3529             mi[i].ti.text_is_1byte = true;
3530             mi[i].ti.fg = COLOR_DEFAULT;
3531             mi[i].ti.bg = COLOR_DEFAULT;
3532             mi[i].mid = MID_Curve;
3533             mi[i].invoke = CVMenuPointType;
3534             i++;
3535             mi[i].ti.text = (unichar_t *) _("HVCurve");
3536             mi[i].ti.text_is_1byte = true;
3537             mi[i].ti.fg = COLOR_DEFAULT;
3538             mi[i].ti.bg = COLOR_DEFAULT;
3539             mi[i].mid = MID_HVCurve;
3540             mi[i].invoke = CVMenuPointType;
3541             i++;
3542             mi[i].ti.text = (unichar_t *) _("Corner");
3543             mi[i].ti.text_is_1byte = true;
3544             mi[i].ti.fg = COLOR_DEFAULT;
3545             mi[i].ti.bg = COLOR_DEFAULT;
3546             mi[i].mid = MID_Corner;
3547             mi[i].invoke = CVMenuPointType;
3548             i++;
3549             mi[i].ti.text = (unichar_t *) _("Tangent");
3550             mi[i].ti.text_is_1byte = true;
3551             mi[i].ti.fg = COLOR_DEFAULT;
3552             mi[i].ti.bg = COLOR_DEFAULT;
3553             mi[i].mid = MID_Tangent;
3554             mi[i].invoke = CVMenuPointType;
3555             i++;
3556         }
3557 
3558 	    mi[i].ti.line = true;
3559 	    mi[i].ti.fg = COLOR_DEFAULT;
3560 	    mi[i].ti.bg = COLOR_DEFAULT;
3561 	    i++;
3562 
3563 	    mi[i].ti.text = (unichar_t *) _("Merge");
3564 	    mi[i].ti.text_is_1byte = true;
3565 	    mi[i].ti.fg = COLOR_DEFAULT;
3566 	    mi[i].ti.bg = COLOR_DEFAULT;
3567 	    mi[i].mid = MID_Merge;
3568 	    mi[i].invoke = CVMerge;
3569 	    i++;
3570 	    mi[i].ti.text = (unichar_t *) _("Merge to Line");
3571 	    mi[i].ti.text_is_1byte = true;
3572 	    mi[i].ti.fg = COLOR_DEFAULT;
3573 	    mi[i].ti.bg = COLOR_DEFAULT;
3574 	    mi[i].mid = MID_MergeToLine;
3575 	    mi[i].invoke = CVMergeToLine;
3576 	    i++;
3577 
3578 	    mi[i].ti.text = (unichar_t *) _("Align Points");
3579 	    mi[i].ti.text_is_1byte = true;
3580 	    mi[i].ti.fg = COLOR_DEFAULT;
3581 	    mi[i].ti.bg = COLOR_DEFAULT;
3582 	    mi[i].mid = MID_Average;
3583 	    mi[i].invoke = CVMenuConstrain;
3584 	    i++;
3585 
3586     }
3587 
3588 
3589     if( !anysel )
3590     {
3591 	for ( i=0;i<=cvt_skew; ++i ) {
3592 	    char *msg = _(popupsres[i]);
3593 	    if ( cv->b.sc->inspiro && hasspiro()) {
3594 		if ( i==cvt_spirog2 )
3595 		    msg = _("Add a g2 curve point");
3596 		else if ( i==cvt_spiroleft )
3597 		    msg = _("Add a left \"tangent\" point");
3598 		else if ( i==cvt_spiroright )
3599 		    msg = _("Add a right \"tangent\" point");
3600 	    }
3601 	    mi[i].ti.text = (unichar_t *) msg;
3602 	    mi[i].ti.text_is_1byte = true;
3603 	    mi[i].ti.fg = COLOR_DEFAULT;
3604 	    mi[i].ti.bg = COLOR_DEFAULT;
3605 	    mi[i].mid = i;
3606 	    mi[i].invoke = CVPopupInvoked;
3607 	}
3608     }
3609 
3610     if( !anysel )
3611     {
3612 	if ( cvlayers!=NULL && !cv->b.sc->parent->multilayer ) {
3613 	    mi[i].ti.line = true;
3614 	    mi[i].ti.fg = COLOR_DEFAULT;
3615 	    mi[i++].ti.bg = COLOR_DEFAULT;
3616 	    for ( j=0;j<3; ++j, ++i ) {
3617 		mi[i].ti.text = (unichar_t *) _(editablelayers[j]);
3618 		mi[i].ti.text_in_resource = true;
3619 		mi[i].ti.text_is_1byte = true;
3620 		mi[i].ti.fg = COLOR_DEFAULT;
3621 		mi[i].ti.bg = COLOR_DEFAULT;
3622 		mi[i].mid = j;
3623 		mi[i].invoke = CVPopupLayerInvoked;
3624 	    }
3625 	}
3626     }
3627 
3628     if( i > 0 ) {
3629 	mi[i].ti.line = true;
3630 	mi[i].ti.fg = COLOR_DEFAULT;
3631 	mi[i++].ti.bg = COLOR_DEFAULT;
3632     }
3633 
3634     for ( j=0; selectables[j]!=0; ++j )
3635     {
3636 	if ( (!anysel && j!=2 ) ||
3637 		( j==0 && cv->p.spline ) ||
3638 		( j==1 && !cv->p.ref ))
3639 	{
3640 	    // don't show them a disabled item
3641 	    continue;
3642 
3643 	    // or, if the above "continue;" is commented then keep the entry
3644 	    // but don't let them select it
3645 	    mi[i].ti.disabled = true;
3646 	}
3647 	mi[i].ti.text = (unichar_t *) _(selectables[j]);
3648 	mi[i].ti.text_is_1byte = true;
3649 	mi[i].ti.fg = COLOR_DEFAULT;
3650 	mi[i].ti.bg = COLOR_DEFAULT;
3651 	mi[i].mid = j;
3652 	mi[i].invoke = CVPopupSelectInvoked;
3653 	i++;
3654     }
3655 
3656     if ( anysel ) {
3657 	mi[i].ti.text = (unichar_t *)_("Name Point...");
3658 	mi[i].ti.text_is_1byte = true;
3659 	mi[i].ti.fg = COLOR_DEFAULT;
3660 	mi[i].ti.bg = COLOR_DEFAULT;
3661 	mi[i].mid = MIDL_NamePoint;
3662 	mi[i].invoke = CVPopupSelectInvoked;
3663 	i++;
3664     }
3665 
3666     if ( cv->b.sc->parent->multilayer ) {
3667 	mi[i].ti.text = (unichar_t *) _("Make Clip Path");
3668 	mi[i].ti.text_is_1byte = true;
3669 	mi[i].ti.fg = COLOR_DEFAULT;
3670 	mi[i].ti.bg = COLOR_DEFAULT;
3671 	mi[i].mid = j;
3672 	mi[i].invoke = CVPopupSelectInvoked;
3673 	i++;
3674     }
3675 
3676     int cnt = CVCountSelectedPoints(cv);
3677 //    printf(".... count:%d\n", cnt );
3678     if( cnt > 1 ) {
3679 	mi[i].ti.text = (unichar_t *) _("Make Line");
3680 	mi[i].ti.text_is_1byte = true;
3681 	mi[i].ti.fg = COLOR_DEFAULT;
3682 	mi[i].ti.bg = COLOR_DEFAULT;
3683 	mi[i].mid = MIDL_MakeLine;
3684 	mi[i].invoke = CVPopupSelectInvoked;
3685 	i++;
3686 
3687 	mi[i].ti.text = (unichar_t *) _("Make Arc");
3688 	mi[i].ti.text_is_1byte = true;
3689 	mi[i].ti.fg = COLOR_DEFAULT;
3690 	mi[i].ti.bg = COLOR_DEFAULT;
3691 	mi[i].mid = MIDL_MakeArc;
3692 	mi[i].invoke = CVPopupSelectInvoked;
3693 	i++;
3694 
3695 	mi[i].ti.text = (unichar_t *) _("Insert Point On Spline At...");
3696 	mi[i].ti.text_is_1byte = true;
3697 	mi[i].ti.fg = COLOR_DEFAULT;
3698 	mi[i].ti.bg = COLOR_DEFAULT;
3699 	mi[i].mid = MIDL_InsertPtOnSplineAt;
3700 	mi[i].invoke = CVPopupSelectInvoked;
3701 	i++;
3702 
3703 	mi[i].ti.text = (unichar_t *) _("Name Point");
3704 	mi[i].ti.text_is_1byte = true;
3705 	mi[i].ti.fg = COLOR_DEFAULT;
3706 	mi[i].ti.bg = COLOR_DEFAULT;
3707 	mi[i].mid = MIDL_NamePoint;
3708 	mi[i].invoke = CVPopupSelectInvoked;
3709 	i++;
3710 
3711 	mi[i].ti.text = (unichar_t *) _("Name Contour");
3712 	mi[i].ti.text_is_1byte = true;
3713 	mi[i].ti.fg = COLOR_DEFAULT;
3714 	mi[i].ti.bg = COLOR_DEFAULT;
3715 	mi[i].mid = MIDL_NameContour;
3716 	mi[i].invoke = CVPopupSelectInvoked;
3717 	i++;
3718     }
3719 
3720     cv->had_control = (event->u.mouse.state&ksm_control)?1:0;
3721     GMenuCreatePopupMenuWithName(cv->v,event, "Popup", mi);
3722 }
3723 
CVPaletteCheck(CharView * cv)3724 static void CVPaletteCheck(CharView *cv) {
3725     if ( cvtools==NULL ) {
3726 	if ( palettes_fixed ) {
3727 	    cvtoolsoff.x = 0; cvtoolsoff.y = 0;
3728 	}
3729 	CVMakeTools(cv);
3730     }
3731     if ( cv->b.sc->parent->multilayer && cvlayers2==NULL ) {
3732 	if ( palettes_fixed ) {
3733 	    cvlayersoff.x = 0; cvlayersoff.y = getToolbarHeight(cv)+45/*25*/;	/* 45 is right if there's decor, 25 when none. twm gives none, kde gives decor */
3734 	}
3735 	CVMakeLayers2(cv);
3736     } else if ( !cv->b.sc->parent->multilayer && cvlayers==NULL ) {
3737 	if ( palettes_fixed ) {
3738 	    cvlayersoff.x = 0; cvlayersoff.y = getToolbarHeight(cv)+45/*25*/;	/* 45 is right if there's decor, 25 when none. twm gives none, kde gives decor */
3739 	}
3740 	CVMakeLayers(cv);
3741     }
3742 }
3743 
CVPaletteIsVisible(CharView * cv,int which)3744 int CVPaletteIsVisible(CharView *cv,int which) {
3745     CVPaletteCheck(cv);
3746     if ( which==1 )
3747 return( cvtools!=NULL && GDrawIsVisible(cvtools) );
3748 
3749     if ( cv->b.sc->parent->multilayer )
3750 return( cvlayers2!=NULL && GDrawIsVisible(cvlayers2));
3751 
3752 return( cvlayers!=NULL && GDrawIsVisible(cvlayers) );
3753 }
3754 
CVPaletteSetVisible(CharView * cv,int which,int visible)3755 void CVPaletteSetVisible(CharView *cv,int which,int visible) {
3756     CVPaletteCheck(cv);
3757     if ( which==1 && cvtools!=NULL)
3758 	GDrawSetVisible(cvtools,visible );
3759     else if ( which==0 && cv->b.sc->parent->multilayer && cvlayers2!=NULL )
3760 	GDrawSetVisible(cvlayers2,visible );
3761     else if ( which==0 && cvlayers!=NULL )
3762 	GDrawSetVisible(cvlayers,visible );
3763     cvvisible[which] = visible;
3764     SavePrefs(true);
3765 }
3766 
CVPalettesRaise(CharView * cv)3767 void CVPalettesRaise(CharView *cv) {
3768     if ( cvtools!=NULL && GDrawIsVisible(cvtools))
3769 	GDrawRaise(cvtools);
3770     if ( cvlayers!=NULL && GDrawIsVisible(cvlayers))
3771 	GDrawRaise(cvlayers);
3772     if ( cvlayers2!=NULL && GDrawIsVisible(cvlayers2))
3773 	GDrawRaise(cvlayers2);
3774 }
3775 
_CVPaletteActivate(CharView * cv,int force,int docking_changed)3776 void _CVPaletteActivate(CharView *cv, int force, int docking_changed) {
3777     CharView *old;
3778 
3779     CVPaletteCheck(cv);
3780     if ( layers2_active!=-1 && layers2_active!=cv->b.sc->parent->multilayer ) {
3781 	if ( !cvvisible[0] ) {
3782 	    if ( cvlayers2!=NULL ) GDrawSetVisible(cvlayers2,false);
3783 	    if ( cvlayers !=NULL ) GDrawSetVisible(cvlayers,false);
3784 	} else if ( layers2_active && cvlayers!=NULL ) {
3785 	    if ( cvlayers2!=NULL ) GDrawSetVisible(cvlayers2,false);
3786 	    GDrawSetVisible(cvlayers,true);
3787 	} else if ( !layers2_active && cvlayers2!=NULL ) {
3788 	    if ( cvlayers !=NULL ) GDrawSetVisible(cvlayers,false);
3789 	    GDrawSetVisible(cvlayers2,true);
3790 	}
3791     }
3792     layers2_active = cv->b.sc->parent->multilayer;
3793     if ( (old = GDrawGetUserData(cvtools))!=cv || force) {
3794 	if ( old!=NULL ) {
3795 	    SaveOffsets(old->gw,cvtools,&cvtoolsoff);
3796 	    if ( old->b.sc->parent->multilayer )
3797 		SaveOffsets(old->gw,cvlayers2,&cvlayersoff);
3798 	    else
3799 		SaveOffsets(old->gw,cvlayers,&cvlayersoff);
3800 	}
3801 
3802     if ((palettes_docked && old != cv) || docking_changed) {
3803         // When docked, we need to recreate the palettes
3804         // Because they were created as a child of the old charview
3805         GDrawDestroyWindow(cvtools);
3806 
3807         if (cvlayers != NULL)
3808             GDrawDestroyWindow(cvlayers);
3809         if (cvlayers2 != NULL)
3810             GDrawDestroyWindow(cvlayers2);
3811 
3812         cvtools = cvlayers = cvlayers2 = NULL;
3813         CVPaletteCheck(cv);
3814     }
3815 
3816     GDrawSetUserData(cvtools,cv);
3817 
3818 	if ( cv->b.sc->parent->multilayer ) {
3819 	    LayersSwitch(cv);
3820 	    GDrawSetUserData(cvlayers2,cv);
3821 	} else {
3822 	    GDrawSetUserData(cvlayers,cv);
3823             CVLCheckLayerCount(cv,true);
3824 	}
3825     if (palettes_docked) {
3826         if (cvvisible[1])
3827             GDrawRequestExpose(cvtools, NULL, false);
3828         if (cvvisible[0]) {
3829             if (cv->b.sc->parent->multilayer)
3830                 GDrawRequestExpose(cvlayers2, NULL, false);
3831             else
3832                 GDrawRequestExpose(cvlayers, NULL, false);
3833         }
3834     } else {
3835 	    if ( cvvisible[0]) {
3836 		if ( cv->b.sc->parent->multilayer )
3837 		    RestoreOffsets(cv->gw,cvlayers2,&cvlayersoff);
3838 		else
3839 		    RestoreOffsets(cv->gw,cvlayers,&cvlayersoff);
3840 	    }
3841 	    if ( cvvisible[1])
3842 		RestoreOffsets(cv->gw,cvtools,&cvtoolsoff);
3843 	}
3844 	GDrawSetVisible(cvtools,cvvisible[1]);
3845 	if ( cv->b.sc->parent->multilayer )
3846 	    GDrawSetVisible(cvlayers2,cvvisible[0]);
3847 	else
3848 	    GDrawSetVisible(cvlayers,cvvisible[0]);
3849 	if ( cvvisible[1]) {
3850 	    cv->showing_tool = cvt_none;
3851 	    CVToolsSetCursor(cv,0,NULL);
3852 	    GDrawRequestExpose(cvtools,NULL,false);
3853 	}
3854 	if ( cvvisible[0])
3855 	    CVLayersSet(cv);
3856     }
3857     if ( bvtools!=NULL ) {
3858 	BitmapView *bv = GDrawGetUserData(bvtools);
3859 	if ( bv!=NULL ) {
3860 	    SaveOffsets(bv->gw,bvtools,&bvtoolsoff);
3861 	    SaveOffsets(bv->gw,bvlayers,&bvlayersoff);
3862 	    if ( !bv->shades_hidden )
3863 		SaveOffsets(bv->gw,bvshades,&bvshadesoff);
3864 	    GDrawSetUserData(bvtools,NULL);
3865 	    GDrawSetUserData(bvlayers,NULL);
3866 	    GDrawSetUserData(bvshades,NULL);
3867 	}
3868 	GDrawSetVisible(bvtools,false);
3869 	GDrawSetVisible(bvlayers,false);
3870 	GDrawSetVisible(bvshades,false);
3871     }
3872 }
3873 
CVPaletteActivate(CharView * cv)3874 void CVPaletteActivate(CharView *cv) {
3875     _CVPaletteActivate(cv,false,false);
3876 }
3877 
CV_LayerPaletteCheck(SplineFont * sf)3878 void CV_LayerPaletteCheck(SplineFont *sf) {
3879     CharView *old;
3880 
3881     if ( cvlayers!=NULL ) {
3882 	if ( (old = GDrawGetUserData(cvlayers))!=NULL ) {
3883 	    if ( old->b.sc->parent==sf )
3884 		_CVPaletteActivate(old,true,false);
3885 	}
3886     }
3887 }
3888 
3889 /* make the charview point to the correct layer heads for the specified glyph */
SFLayerChange(SplineFont * sf)3890 void SFLayerChange(SplineFont *sf) {
3891     CharView *old, *cv;
3892     int i;
3893 
3894     for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
3895 	SplineChar *sc = sf->glyphs[i];
3896 	for ( cv=(CharView *) (sc->views); cv!=NULL; cv=(CharView *) (cv->b.next) ) {
3897 	    cv->b.layerheads[dm_back] = &sc->layers[ly_back];
3898 	    cv->b.layerheads[dm_fore] = &sc->layers[ly_fore];
3899 	    cv->b.layerheads[dm_grid] = &sf->grid;
3900 	}
3901     }
3902 
3903     if ( cvtools==NULL )
3904 return;					/* No charviews open */
3905     old = GDrawGetUserData(cvtools);
3906     if ( old==NULL || old->b.sc->parent!=sf )	/* Irrelevant */
3907 return;
3908     _CVPaletteActivate(old,true,false);
3909 }
3910 
CVPalettesHideIfMine(CharView * cv)3911 void CVPalettesHideIfMine(CharView *cv) {
3912     if ( cvtools==NULL )
3913 return;
3914     if ( GDrawGetUserData(cvtools)==cv ) {
3915 	SaveOffsets(cv->gw,cvtools,&cvtoolsoff);
3916 	GDrawSetVisible(cvtools,false);
3917 	GDrawSetUserData(cvtools,NULL);
3918 	if ( cv->b.sc->parent->multilayer && cvlayers2!=NULL ) {
3919 	    SaveOffsets(cv->gw,cvlayers2,&cvlayersoff);
3920 	    GDrawSetVisible(cvlayers2,false);
3921 	    GDrawSetUserData(cvlayers2,NULL);
3922 	} else {
3923 	    SaveOffsets(cv->gw,cvlayers,&cvlayersoff);
3924 	    GDrawSetVisible(cvlayers,false);
3925 	    GDrawSetUserData(cvlayers,NULL);
3926 	}
3927     }
3928 }
3929 
CVPalettesWidth(void)3930 int CVPalettesWidth(void) {
3931 return( GGadgetScale(CV_LAYERS2_WIDTH));
3932 }
3933 
3934 /* ************************************************************************** */
3935 /* **************************** Bitmap Palettes ***************************** */
3936 /* ************************************************************************** */
3937 
BVLayersSet(BitmapView * bv)3938 static void BVLayersSet(BitmapView *bv) {
3939     GGadgetSetChecked(GWidgetGetControl(bvlayers,CID_VFore),bv->showfore);
3940     GGadgetSetChecked(GWidgetGetControl(bvlayers,CID_VBack),bv->showoutline);
3941     GGadgetSetChecked(GWidgetGetControl(bvlayers,CID_VGrid),bv->showgrid);
3942 }
3943 
bvlayers_e_h(GWindow gw,GEvent * event)3944 static int bvlayers_e_h(GWindow gw, GEvent *event) {
3945     BitmapView *bv = (BitmapView *) GDrawGetUserData(gw);
3946 
3947     if ( event->type==et_destroy && bvlayers == gw ) {
3948 	bvlayers = NULL;
3949 return( true );
3950     }
3951 
3952     if ( bv==NULL )
3953 return( true );
3954 
3955     switch ( event->type ) {
3956       case et_close:
3957 	GDrawSetVisible(gw,false);
3958       break;
3959       case et_char: case et_charup:
3960 	PostCharToWindow(bv->gw,event);
3961       break;
3962       case et_controlevent:
3963 	if ( event->u.control.subtype == et_radiochanged ) {
3964 	    switch(GGadgetGetCid(event->u.control.g)) {
3965 	      case CID_VFore:
3966 		BVShows.showfore = bv->showfore = GGadgetIsChecked(event->u.control.g);
3967 	      break;
3968 	      case CID_VBack:
3969 		BVShows.showoutline = bv->showoutline = GGadgetIsChecked(event->u.control.g);
3970 	      break;
3971 	      case CID_VGrid:
3972 		BVShows.showgrid = bv->showgrid = GGadgetIsChecked(event->u.control.g);
3973 	      break;
3974 	    }
3975 	    GDrawRequestExpose(bv->v,NULL,false);
3976 	}
3977       break;
3978     }
3979 return( true );
3980 }
3981 
BVMakeLayers(BitmapView * bv)3982 GWindow BVMakeLayers(BitmapView *bv) {
3983     GRect r;
3984     GWindowAttrs wattrs;
3985     GGadgetCreateData gcd[8], boxes[2], *hvarray[5][3];
3986     GTextInfo label[8];
3987     static GBox radio_box = { bt_none, bs_rect, 0, 0, 0, 0, 0, 0, 0, 0, COLOR_DEFAULT, COLOR_DEFAULT, 0, 0, 0, 0, 0, 0, 0 };
3988     FontRequest rq;
3989     int i;
3990 
3991     if ( bvlayers!=NULL )
3992 return(bvlayers);
3993     memset(&wattrs,0,sizeof(wattrs));
3994     wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_positioned|wam_isdlg;
3995     wattrs.event_masks = -1;
3996     wattrs.cursor = ct_mypointer;
3997     wattrs.positioned = true;
3998     wattrs.is_dlg = true;
3999     wattrs.utf8_window_title = _("Layers");
4000 
4001     r.width = GGadgetScale(BV_LAYERS_WIDTH); r.height = BV_LAYERS_HEIGHT;
4002     r.x = -r.width-6; r.y = bv->mbh+BV_TOOLS_HEIGHT+45/*25*/;	/* 45 is right if there's decor, is in kde, not in twm. Sigh */
4003     if ( palettes_docked ) {
4004 	r.x = 0; r.y = BV_TOOLS_HEIGHT+4;
4005     } else if ( palettes_fixed ) {
4006 	r.x = 0; r.y = BV_TOOLS_HEIGHT+45;
4007     }
4008     bvlayers = CreatePalette( bv->gw, &r, bvlayers_e_h, bv, &wattrs, bv->v );
4009 
4010     memset(&label,0,sizeof(label));
4011     memset(&gcd,0,sizeof(gcd));
4012     memset(&boxes,0,sizeof(boxes));
4013 
4014     if ( layersfont==NULL ) {
4015 	memset(&rq,'\0',sizeof(rq));
4016 	rq.utf8_family_name = SANS_UI_FAMILIES;
4017 	rq.point_size = -12;
4018 	rq.weight = 400;
4019 	layersfont = GDrawInstanciateFont(cvlayers2,&rq);
4020 	layersfont = GResourceFindFont("LayersPalette.Font",layersfont);
4021     }
4022     for ( i=0; i<sizeof(label)/sizeof(label[0]); ++i )
4023 	label[i].font = layersfont;
4024 
4025 /* GT: Abbreviation for "Visible" */
4026     label[0].text = (unichar_t *) _("V");
4027     label[0].text_is_1byte = true;
4028     gcd[0].gd.label = &label[0];
4029     gcd[0].gd.pos.x = 7; gcd[0].gd.pos.y = 5;
4030     gcd[0].gd.flags = gg_enabled|gg_visible|gg_pos_in_pixels;
4031     gcd[0].gd.popup_msg = _("Is Layer Visible?");
4032     gcd[0].creator = GLabelCreate;
4033 
4034     label[1].text = (unichar_t *) "Layer";
4035     label[1].text_is_1byte = true;
4036     gcd[1].gd.label = &label[1];
4037     gcd[1].gd.pos.x = 23; gcd[1].gd.pos.y = 5;
4038     gcd[1].gd.flags = gg_enabled|gg_visible|gg_pos_in_pixels;
4039     gcd[1].gd.popup_msg = _("Is Layer Visible?");
4040     gcd[1].creator = GLabelCreate;
4041     hvarray[0][0] = &gcd[0]; hvarray[0][1] = &gcd[1]; hvarray[0][2] = NULL;
4042 
4043     gcd[2].gd.pos.x = 5; gcd[2].gd.pos.y = 21;
4044     gcd[2].gd.flags = gg_enabled|gg_visible|gg_dontcopybox|gg_pos_in_pixels;
4045     gcd[2].gd.cid = CID_VFore;
4046     gcd[2].gd.popup_msg = _("Is Layer Visible?");
4047     gcd[2].gd.box = &radio_box;
4048     gcd[2].creator = GCheckBoxCreate;
4049     label[2].text = (unichar_t *) _("Bitmap");
4050     label[2].text_is_1byte = true;
4051     gcd[2].gd.label = &label[2];
4052     hvarray[1][0] = &gcd[2]; hvarray[1][1] = GCD_ColSpan; hvarray[1][2] = NULL;
4053 
4054     gcd[3].gd.pos.x = 5; gcd[3].gd.pos.y = 37;
4055     gcd[3].gd.flags = gg_enabled|gg_visible|gg_dontcopybox|gg_pos_in_pixels;
4056     gcd[3].gd.cid = CID_VBack;
4057     gcd[3].gd.popup_msg = _("Is Layer Visible?");
4058     gcd[3].gd.box = &radio_box;
4059     gcd[3].creator = GCheckBoxCreate;
4060     label[3].text = (unichar_t *) _("Outline");
4061     label[3].text_is_1byte = true;
4062     gcd[3].gd.label = &label[3];
4063     hvarray[2][0] = &gcd[3]; hvarray[2][1] = GCD_ColSpan; hvarray[2][2] = NULL;
4064 
4065     gcd[4].gd.pos.x = 5; gcd[4].gd.pos.y = 53;
4066     gcd[4].gd.flags = gg_enabled|gg_visible|gg_dontcopybox|gg_pos_in_pixels;
4067     gcd[4].gd.cid = CID_VGrid;
4068     gcd[4].gd.popup_msg = _("Is Layer Visible?");
4069     gcd[4].gd.box = &radio_box;
4070     gcd[4].creator = GCheckBoxCreate;
4071     label[4].text = (unichar_t *) _("_Guide");
4072     label[4].text_is_1byte = true;
4073     label[4].text_in_resource = true;
4074     gcd[4].gd.label = &label[4];
4075     hvarray[3][0] = &gcd[4]; hvarray[3][1] = GCD_ColSpan; hvarray[3][2] = NULL;
4076     hvarray[4][0] = NULL;
4077 
4078     if ( bv->showfore ) gcd[2].gd.flags |= gg_cb_on;
4079     if ( bv->showoutline ) gcd[3].gd.flags |= gg_cb_on;
4080     if ( bv->showgrid ) gcd[4].gd.flags |= gg_cb_on;
4081 
4082     boxes[0].gd.pos.x = boxes[0].gd.pos.y = 2;
4083     boxes[0].gd.flags = gg_enabled|gg_visible;
4084     boxes[0].gd.u.boxelements = hvarray[0];
4085     boxes[0].creator = GHVGroupCreate;
4086 
4087     GGadgetsCreate(bvlayers,boxes);
4088     GHVBoxFitWindow(boxes[0].ret);
4089 
4090     if ( bvvisible[0] )
4091 	GDrawSetVisible(bvlayers,true);
4092 return( bvlayers );
4093 }
4094 
4095 struct shades_layout {
4096     int depth;
4097     int div;
4098     int cnt;		/* linear number of squares */
4099     int size;
4100 };
4101 
BVShadesDecompose(BitmapView * bv,struct shades_layout * lay)4102 static void BVShadesDecompose(BitmapView *bv, struct shades_layout *lay) {
4103     GRect r;
4104     int temp;
4105 
4106     GDrawGetSize(bvshades,&r);
4107     lay->depth = BDFDepth(bv->bdf);
4108     lay->div = 255/((1<<lay->depth)-1);
4109     lay->cnt = lay->depth==8 ? 16 : lay->depth;
4110     temp = r.width>r.height ? r.height : r.width;
4111     lay->size = (temp-8+1)/lay->cnt - 1;
4112 }
4113 
BVShadesExpose(GWindow pixmap,BitmapView * bv,GRect * r)4114 static void BVShadesExpose(GWindow pixmap, BitmapView *bv, GRect *r) {
4115     struct shades_layout lay;
4116     GRect old;
4117     int i,j,index;
4118     GRect block;
4119     Color bg = default_background;
4120     int greybg = (3*COLOR_RED(bg)+6*COLOR_GREEN(bg)+COLOR_BLUE(bg))/10;
4121 
4122     GDrawSetLineWidth(pixmap,0);
4123     BVShadesDecompose(bv,&lay);
4124     GDrawPushClip(pixmap,r,&old);
4125     for ( i=0; i<=lay.cnt; ++i ) {
4126 	int p = 3+i*(lay.size+1);
4127 	int m = 8+lay.cnt*(lay.size+1);
4128 	GDrawDrawLine(pixmap,p,0,p,m,bg);
4129 	GDrawDrawLine(pixmap,0,p,m,p,bg);
4130     }
4131     block.width = block.height = lay.size;
4132     for ( i=0; i<lay.cnt; ++i ) {
4133 	block.y = 4 + i*(lay.size+1);
4134 	for ( j=0; j<lay.cnt; ++j ) {
4135 	    block.x = 4 + j*(lay.size+1);
4136 	    index = (i*lay.cnt+j)*lay.div;
4137 	    if (( bv->color >= index - lay.div/2 &&
4138 			bv->color <= index + lay.div/2 ) ||
4139 		 ( bv->color_under_cursor >= index - lay.div/2 &&
4140 		    bv->color_under_cursor <= index + lay.div/2 )) {
4141 		GRect outline;
4142 		outline.x = block.x-1; outline.y = block.y-1;
4143 		outline.width = block.width+1; outline.height = block.height+1;
4144 		GDrawDrawRect(pixmap,&outline,
4145 		    ( bv->color >= index - lay.div/2 &&
4146 			bv->color <= index + lay.div/2 )?0x00ff00:0xffffff);
4147 	    }
4148 	    index = (255-index) * greybg / 255;
4149 	    GDrawFillRect(pixmap,&block,0x010101*index);
4150 	}
4151     }
4152 }
4153 
BVShadesMouse(BitmapView * bv,GEvent * event)4154 static void BVShadesMouse(BitmapView *bv, GEvent *event) {
4155     struct shades_layout lay;
4156     int i, j;
4157 
4158     GGadgetEndPopup();
4159     if ( event->type == et_mousemove && !bv->shades_down )
4160 return;
4161     BVShadesDecompose(bv,&lay);
4162     if ( event->u.mouse.x<4 || event->u.mouse.y<4 ||
4163 	    event->u.mouse.x>=4+lay.cnt*(lay.size+1) ||
4164 	    event->u.mouse.y>=4+lay.cnt*(lay.size+1) )
4165 return;
4166     i = (event->u.mouse.y-4)/(lay.size+1);
4167     j = (event->u.mouse.x-4)/(lay.size+1);
4168     if ( bv->color != (i*lay.cnt + j)*lay.div ) {
4169 	bv->color = (i*lay.cnt + j)*lay.div;
4170 	GDrawRequestExpose(bvshades,NULL,false);
4171     }
4172     if ( event->type == et_mousedown ) bv->shades_down = true;
4173     else if ( event->type == et_mouseup ) bv->shades_down = false;
4174     if ( event->type == et_mouseup )
4175 	GDrawRequestExpose(bv->gw,NULL,false);
4176 }
4177 
bvshades_e_h(GWindow gw,GEvent * event)4178 static int bvshades_e_h(GWindow gw, GEvent *event) {
4179     BitmapView *bv = (BitmapView *) GDrawGetUserData(gw);
4180 
4181     if ( event->type==et_destroy && bvshades == gw ) {
4182 	bvshades = NULL;
4183 return( true );
4184     }
4185 
4186     if ( bv==NULL )
4187 return( true );
4188 
4189     switch ( event->type ) {
4190       case et_expose:
4191 	BVShadesExpose(gw,bv,&event->u.expose.rect);
4192       break;
4193       case et_mousemove:
4194       case et_mouseup:
4195       case et_mousedown:
4196 	BVShadesMouse(bv,event);
4197       break;
4198       case et_char: case et_charup:
4199 	PostCharToWindow(bv->gw,event);
4200       break;
4201       case et_destroy:
4202       break;
4203       case et_close:
4204 	GDrawSetVisible(gw,false);
4205       break;
4206     }
4207 return( true );
4208 }
4209 
BVMakeShades(BitmapView * bv)4210 static GWindow BVMakeShades(BitmapView *bv) {
4211     GRect r;
4212     GWindowAttrs wattrs;
4213 
4214     if ( bvshades!=NULL )
4215 return( bvshades );
4216     memset(&wattrs,0,sizeof(wattrs));
4217     wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_positioned|wam_isdlg/*|wam_backcol*/;
4218     wattrs.event_masks = -1;
4219     wattrs.cursor = ct_eyedropper;
4220     wattrs.positioned = true;
4221     wattrs.is_dlg = true;
4222     wattrs.background_color = 0xffffff;
4223     wattrs.utf8_window_title = _("Shades");
4224 
4225     r.width = BV_SHADES_HEIGHT; r.height = r.width;
4226     r.x = -r.width-6; r.y = bv->mbh+225;
4227     if ( palettes_docked ) {
4228 	r.x = 0; r.y = BV_TOOLS_HEIGHT+BV_LAYERS_HEIGHT+4;
4229     } else if ( palettes_fixed ) {
4230 	r.x = 0; r.y = BV_TOOLS_HEIGHT+BV_LAYERS_HEIGHT+90;
4231     }
4232     bvshades = CreatePalette( bv->gw, &r, bvshades_e_h, bv, &wattrs, bv->v );
4233     bv->shades_hidden = BDFDepth(bv->bdf)==1;
4234     if ( bvvisible[2] && !bv->shades_hidden )
4235 	GDrawSetVisible(bvshades,true);
4236 return( bvshades );
4237 }
4238 
4239 static char *bvpopups[] = { N_("Pointer"), N_("Magnify (Minify with alt)"),
4240 				    N_("Set/Clear Pixels"), N_("Draw a Line"),
4241 			            N_("Shift Entire Bitmap"), N_("Scroll Bitmap") };
4242 
BVToolsExpose(GWindow pixmap,BitmapView * bv,GRect * r)4243 static void BVToolsExpose(GWindow pixmap, BitmapView *bv, GRect *r) {
4244     GRect old;
4245     /* Note: If you change this ordering, change enum bvtools */
4246     static GImage *buttons[][2] = { { &GIcon_pointer, &GIcon_magnify },
4247 				    { &GIcon_pencil, &GIcon_line },
4248 			            { &GIcon_shift, &GIcon_hand }};
4249     int i,j,norm;
4250     int tool = bv->cntrldown?bv->cb1_tool:bv->b1_tool;
4251     int dither = GDrawSetDither(NULL,false);
4252 
4253     GDrawPushClip(pixmap,r,&old);
4254     GDrawFillRect(pixmap,r,GDrawGetDefaultBackground(NULL));
4255     GDrawSetLineWidth(pixmap,0);
4256     for ( i=0; i<sizeof(buttons)/sizeof(buttons[0]); ++i ) for ( j=0; j<2; ++j ) {
4257 	GDrawDrawImage(pixmap,buttons[i][j],NULL,j*27+1,i*27+1);
4258 	norm = (i*2+j!=tool);
4259 	GDrawDrawLine(pixmap,j*27,i*27,j*27+25,i*27,norm?0xe0e0e0:0x707070);
4260 	GDrawDrawLine(pixmap,j*27,i*27,j*27,i*27+25,norm?0xe0e0e0:0x707070);
4261 	GDrawDrawLine(pixmap,j*27,i*27+25,j*27+25,i*27+25,norm?0x707070:0xe0e0e0);
4262 	GDrawDrawLine(pixmap,j*27+25,i*27,j*27+25,i*27+25,norm?0x707070:0xe0e0e0);
4263     }
4264     GDrawPopClip(pixmap,&old);
4265     GDrawSetDither(NULL,dither);
4266 }
4267 
BVToolsSetCursor(BitmapView * bv,int state,char * device)4268 void BVToolsSetCursor(BitmapView *bv, int state,char *device) {
4269     int shouldshow;
4270     static enum bvtools tools[bvt_max2+1] = { bvt_none };
4271     int cntrl;
4272 
4273     if ( tools[0] == bvt_none ) {
4274 	tools[bvt_pointer] = ct_mypointer;
4275 	tools[bvt_magnify] = ct_magplus;
4276 	tools[bvt_pencil] = ct_pencil;
4277 	tools[bvt_line] = ct_line;
4278 	tools[bvt_shift] = ct_shift;
4279 	tools[bvt_hand] = ct_myhand;
4280 	tools[bvt_minify] = ct_magminus;
4281 	tools[bvt_eyedropper] = ct_eyedropper;
4282 	tools[bvt_setwidth] = ct_setwidth;
4283 	tools[bvt_setvwidth] = ct_updown;
4284 	tools[bvt_rect] = ct_rect;
4285 	tools[bvt_filledrect] = ct_filledrect;
4286 	tools[bvt_elipse] = ct_elipse;
4287 	tools[bvt_filledelipse] = ct_filledelipse;
4288     }
4289 
4290     shouldshow = bvt_none;
4291     if ( bv->active_tool!=bvt_none )
4292 	shouldshow = bv->active_tool;
4293     else if ( bv->pressed_display!=bvt_none )
4294 	shouldshow = bv->pressed_display;
4295     else if ( device==NULL || strcmp(device,"Mouse1")==0 ) {
4296 	if ( (state&(ksm_shift|ksm_control)) && (state&ksm_button4))
4297 	    shouldshow = bvt_magnify;
4298 	else if ( (state&(ksm_shift|ksm_control)) && (state&ksm_button5))
4299 	    shouldshow = bvt_minify;
4300 	else if ( (state&ksm_control) && (state&(ksm_button2|ksm_super)) )
4301 	    shouldshow = bv->cb2_tool;
4302 	else if ( (state&(ksm_button2|ksm_super)) )
4303 	    shouldshow = bv->b2_tool;
4304 	else if ( (state&ksm_control) )
4305 	    shouldshow = bv->cb1_tool;
4306 	else
4307 	    shouldshow = bv->b1_tool;
4308     } else if ( strcmp(device,"eraser")==0 )
4309 	shouldshow = bv->er_tool;
4310     else if ( strcmp(device,"stylus")==0 ) {
4311 	if ( (state&(ksm_button2|ksm_control|ksm_super)) )
4312 	    shouldshow = bv->s2_tool;
4313 	else
4314 	    shouldshow = bv->s1_tool;
4315     }
4316 
4317     if ( shouldshow==bvt_magnify && (state&ksm_meta))
4318 	shouldshow = bvt_minify;
4319     if ( (shouldshow==bvt_pencil || shouldshow==bvt_line) && (state&ksm_meta) && bv->bdf->clut!=NULL )
4320 	shouldshow = bvt_eyedropper;
4321     if ( shouldshow!=bvt_none && shouldshow!=bv->showing_tool ) {
4322 	GDrawSetCursor(bv->v,tools[shouldshow]);
4323 	if ( bvtools != NULL )
4324 	    GDrawSetCursor(bvtools,tools[shouldshow]);
4325 	bv->showing_tool = shouldshow;
4326     }
4327 
4328     if ( device==NULL || strcmp(device,"stylus")==0 ) {
4329 	cntrl = (state&ksm_control)?1:0;
4330 	if ( device!=NULL && (state&ksm_button2))
4331 	    cntrl = true;
4332 	if ( cntrl != bv->cntrldown ) {
4333 	    bv->cntrldown = cntrl;
4334 	    GDrawRequestExpose(bvtools,NULL,false);
4335 	}
4336     }
4337 }
4338 
BVToolsMouse(BitmapView * bv,GEvent * event)4339 static void BVToolsMouse(BitmapView *bv, GEvent *event) {
4340     int i = (event->u.mouse.y/27), j = (event->u.mouse.x/27);
4341     int pos;
4342     int isstylus = event->u.mouse.device!=NULL && strcmp(event->u.mouse.device,"stylus")==0;
4343     int styluscntl = isstylus && (event->u.mouse.state&0x200);
4344 
4345     if(j >= 2)
4346 return;			/* If the wm gave me a window the wrong size */
4347 
4348     pos = i*2 + j;
4349     GGadgetEndPopup();
4350     if ( pos<0 || pos>=bvt_max )
4351 	pos = bvt_none;
4352     if ( event->type == et_mousedown ) {
4353         if ( isstylus && event->u.mouse.button==2 )
4354             /* Not a real button press, only touch counts. This is a modifier */;
4355 	else {
4356 	    bv->pressed_tool = bv->pressed_display = pos;
4357 	    bv->had_control = ((event->u.mouse.state&ksm_control) || styluscntl)?1:0;
4358 	    event->u.chr.state |= (1<<(7+event->u.mouse.button));
4359 	}
4360     } else if ( event->type == et_mousemove ) {
4361 	if ( bv->pressed_tool==bvt_none && pos!=bvt_none ) {
4362 	    /* Not pressed */
4363 	    if ( !bv->shades_hidden && strcmp(bvpopups[pos],"Set/Clear Pixels")==0 )
4364 		GGadgetPreparePopup8(bvtools,_("Set/Clear Pixels\n(Eyedropper with alt)"));
4365 	    else
4366 		GGadgetPreparePopup8(bvtools,_(bvpopups[pos]));
4367 	} else if ( pos!=bv->pressed_tool || bv->had_control != (((event->u.mouse.state&ksm_control)||styluscntl)?1:0) )
4368 	    bv->pressed_display = bvt_none;
4369 	else
4370 	    bv->pressed_display = bv->pressed_tool;
4371     } else if ( event->type == et_mouseup ) {
4372 	if ( pos!=bv->pressed_tool || bv->had_control != (((event->u.mouse.state&ksm_control)||styluscntl)?1:0) )
4373 	    bv->pressed_tool = bv->pressed_display = bvt_none;
4374 	else {
4375 	    if ( event->u.mouse.device!=NULL && strcmp(event->u.mouse.device,"eraser")==0 )
4376 		bv->er_tool = pos;
4377 	    else if ( isstylus ) {
4378 	        if ( event->u.mouse.button==2 )
4379 		    /* Only thing that matters is touch which maps to button 1 */;
4380 		else if ( bv->had_control )
4381 		    bv->s2_tool = pos;
4382 		else
4383 		    bv->s1_tool = pos;
4384 	    } else if ( bv->had_control && event->u.mouse.button==2 )
4385 		bv->cb2_tool = pos;
4386 	    else if ( event->u.mouse.button==2 )
4387 		bv->b2_tool = pos;
4388 	    else if ( bv->had_control ) {
4389 		if ( bv->cb1_tool!=pos ) {
4390 		    bv->cb1_tool = pos;
4391 		    GDrawRequestExpose(bvtools,NULL,false);
4392 		}
4393 	    } else {
4394 		if ( bv->b1_tool!=pos ) {
4395 		    bv->b1_tool = pos;
4396 		    GDrawRequestExpose(bvtools,NULL,false);
4397 		}
4398 	    }
4399 	    bv->pressed_tool = bv->pressed_display = bvt_none;
4400 	}
4401 	event->u.mouse.state &= ~(1<<(7+event->u.mouse.button));
4402     }
4403     BVToolsSetCursor(bv,event->u.mouse.state,event->u.mouse.device);
4404 }
4405 
bvtools_e_h(GWindow gw,GEvent * event)4406 static int bvtools_e_h(GWindow gw, GEvent *event) {
4407     BitmapView *bv = (BitmapView *) GDrawGetUserData(gw);
4408 
4409     if ( event->type==et_destroy && bvtools == gw ) {
4410 	bvtools = NULL;
4411 return( true );
4412     }
4413 
4414     if ( bv==NULL )
4415 return( true );
4416 
4417     switch ( event->type ) {
4418       case et_expose:
4419 	BVToolsExpose(gw,bv,&event->u.expose.rect);
4420       break;
4421       case et_mousedown:
4422 	BVToolsMouse(bv,event);
4423       break;
4424       case et_mousemove:
4425 	BVToolsMouse(bv,event);
4426       break;
4427       case et_mouseup:
4428 	BVToolsMouse(bv,event);
4429       break;
4430       case et_crossing:
4431 	bv->pressed_display = bvt_none;
4432 	BVToolsSetCursor(bv,event->u.mouse.state,event->u.mouse.device);
4433       break;
4434       case et_char: case et_charup:
4435 	if ( bv->had_control != ((event->u.chr.state&ksm_control)?1:0) )
4436 	    bv->pressed_display = bvt_none;
4437 	PostCharToWindow(bv->gw,event);
4438       break;
4439       case et_close:
4440 	GDrawSetVisible(gw,false);
4441       break;
4442     }
4443 return( true );
4444 }
4445 
BVMakeTools(BitmapView * bv)4446 GWindow BVMakeTools(BitmapView *bv) {
4447     GRect r;
4448     GWindowAttrs wattrs;
4449 
4450     if ( bvtools!=NULL )
4451 return( bvtools );
4452     memset(&wattrs,0,sizeof(wattrs));
4453     wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_positioned|wam_isdlg;
4454     wattrs.event_masks = -1;
4455     wattrs.cursor = ct_mypointer;
4456     wattrs.positioned = true;
4457     wattrs.is_dlg = true;
4458     wattrs.utf8_window_title = _("Tools");
4459 
4460     r.width = BV_TOOLS_WIDTH; r.height = BV_TOOLS_HEIGHT;
4461     r.x = -r.width-6; r.y = bv->mbh+20;
4462     if ( palettes_fixed || palettes_docked ) {
4463 	r.x = 0; r.y = 0;
4464     }
4465     bvtools = CreatePalette( bv->gw, &r, bvtools_e_h, bv, &wattrs, bv->v );
4466     if ( bvvisible[1] )
4467 	GDrawSetVisible(bvtools,true);
4468 return( bvtools );
4469 }
4470 
BVPopupInvoked(GWindow v,GMenuItem * mi,GEvent * e)4471 static void BVPopupInvoked(GWindow v, GMenuItem *mi,GEvent *e) {
4472     BitmapView *bv = (BitmapView *) GDrawGetUserData(v);
4473     int pos;
4474 
4475     pos = mi->mid;
4476     if ( bv->had_control ) {
4477 	if ( bv->cb1_tool!=pos ) {
4478 	    bv->cb1_tool = pos;
4479 	    GDrawRequestExpose(bvtools,NULL,false);
4480 	}
4481     } else {
4482 	if ( bv->b1_tool!=pos ) {
4483 	    bv->b1_tool = pos;
4484 	    GDrawRequestExpose(bvtools,NULL,false);
4485 	}
4486     }
4487     BVToolsSetCursor(bv,bv->had_control?ksm_control:0,NULL);
4488 }
4489 
BVToolsPopup(BitmapView * bv,GEvent * event)4490 void BVToolsPopup(BitmapView *bv, GEvent *event) {
4491     GMenuItem mi[21];
4492     int i, j;
4493 
4494     memset(mi,'\0',sizeof(mi));
4495     for ( i=0;i<6; ++i ) {
4496 	mi[i].ti.text = (unichar_t *) _(bvpopups[i]);
4497 	mi[i].ti.text_is_1byte = true;
4498 	mi[i].ti.fg = COLOR_DEFAULT;
4499 	mi[i].ti.bg = COLOR_DEFAULT;
4500 	mi[i].mid = i;
4501 	mi[i].invoke = BVPopupInvoked;
4502     }
4503 
4504     mi[i].ti.text = (unichar_t *) _("Rectangle");
4505     mi[i].ti.text_is_1byte = true;
4506     mi[i].ti.fg = COLOR_DEFAULT;
4507     mi[i].ti.bg = COLOR_DEFAULT;
4508     mi[i].mid = bvt_rect;
4509     mi[i++].invoke = BVPopupInvoked;
4510     mi[i].ti.text = (unichar_t *) _("Filled Rectangle"); mi[i].ti.text_is_1byte = true;
4511     mi[i].ti.fg = COLOR_DEFAULT;
4512     mi[i].ti.bg = COLOR_DEFAULT;
4513     mi[i].mid = bvt_filledrect;
4514     mi[i++].invoke = BVPopupInvoked;
4515     mi[i].ti.text = (unichar_t *) _("Ellipse"); mi[i].ti.text_is_1byte = true;
4516     mi[i].ti.fg = COLOR_DEFAULT;
4517     mi[i].ti.bg = COLOR_DEFAULT;
4518     mi[i].mid = bvt_elipse;
4519     mi[i++].invoke = BVPopupInvoked;
4520     mi[i].ti.text = (unichar_t *) _("Filled Ellipse"); mi[i].ti.text_is_1byte = true;
4521     mi[i].ti.fg = COLOR_DEFAULT;
4522     mi[i].ti.bg = COLOR_DEFAULT;
4523     mi[i].mid = bvt_filledelipse;
4524     mi[i++].invoke = BVPopupInvoked;
4525 
4526     mi[i].ti.fg = COLOR_DEFAULT;
4527     mi[i].ti.bg = COLOR_DEFAULT;
4528     mi[i++].ti.line = true;
4529     for ( j=0; j<6; ++j, ++i ) {
4530 	mi[i].ti.text = (unichar_t *) BVFlipNames[j];
4531 	mi[i].ti.text_is_1byte = true;
4532 	mi[i].ti.fg = COLOR_DEFAULT;
4533 	mi[i].ti.bg = COLOR_DEFAULT;
4534 	mi[i].mid = j;
4535 	mi[i].invoke = BVMenuRotateInvoked;
4536     }
4537     if ( bv->fv->b.sf->onlybitmaps ) {
4538 	mi[i].ti.fg = COLOR_DEFAULT;
4539 	mi[i].ti.bg = COLOR_DEFAULT;
4540 	mi[i++].ti.line = true;
4541 	mi[i].ti.text = (unichar_t *) _("Set _Width...");
4542 	mi[i].ti.text_is_1byte = true;
4543 	mi[i].ti.text_in_resource = true;
4544 	mi[i].ti.fg = COLOR_DEFAULT;
4545 	mi[i].ti.bg = COLOR_DEFAULT;
4546 	mi[i].mid = bvt_setwidth;
4547 	mi[i].invoke = BVPopupInvoked;
4548     }
4549     bv->had_control = (event->u.mouse.state&ksm_control)?1:0;
4550     GMenuCreatePopupMenu(bv->v,event, mi);
4551 }
4552 
BVPaletteCheck(BitmapView * bv)4553 static void BVPaletteCheck(BitmapView *bv) {
4554     if ( bvtools==NULL ) {
4555 	BVMakeTools(bv);
4556 	BVMakeLayers(bv);
4557 	BVMakeShades(bv);
4558     }
4559 }
4560 
BVPaletteIsVisible(BitmapView * bv,int which)4561 int BVPaletteIsVisible(BitmapView *bv,int which) {
4562     BVPaletteCheck(bv);
4563     if ( which==1 )
4564 return( bvtools!=NULL && GDrawIsVisible(bvtools) );
4565     if ( which==2 )
4566 return( bvshades!=NULL && GDrawIsVisible(bvshades) );
4567 
4568 return( bvlayers!=NULL && GDrawIsVisible(bvlayers) );
4569 }
4570 
BVPaletteSetVisible(BitmapView * bv,int which,int visible)4571 void BVPaletteSetVisible(BitmapView *bv,int which,int visible) {
4572     BVPaletteCheck(bv);
4573     if ( which==1 && bvtools!=NULL)
4574 	GDrawSetVisible(bvtools,visible );
4575     else if ( which==2 && bvshades!=NULL)
4576 	GDrawSetVisible(bvshades,visible );
4577     else if ( which==0 && bvlayers!=NULL )
4578 	GDrawSetVisible(bvlayers,visible );
4579     bvvisible[which] = visible;
4580     SavePrefs(true);
4581 }
4582 
_BVPaletteActivate(BitmapView * bv,int force,int docking_changed)4583 static void _BVPaletteActivate(BitmapView *bv, int force, int docking_changed) {
4584     BitmapView *old;
4585 
4586     BVPaletteCheck(bv);
4587     if ( ((old = GDrawGetUserData(bvtools)) != bv) || force ) {
4588 	if ( old!=NULL ) {
4589 	    SaveOffsets(old->gw,bvtools,&bvtoolsoff);
4590 	    SaveOffsets(old->gw,bvlayers,&bvlayersoff);
4591 	    SaveOffsets(old->gw,bvshades,&bvshadesoff);
4592 	}
4593 
4594     if ((palettes_docked && old != bv) || docking_changed) {
4595         // Recreate the bvtools if docked, similar to cvtools
4596         GDrawDestroyWindow(bvtools);
4597         GDrawDestroyWindow(bvlayers);
4598         GDrawDestroyWindow(bvshades);
4599         bvtools = bvlayers = bvshades = NULL;
4600         BVPaletteCheck(bv);
4601     }
4602 
4603 	GDrawSetUserData(bvtools,bv);
4604 	GDrawSetUserData(bvlayers,bv);
4605 	GDrawSetUserData(bvshades,bv);
4606 
4607     if (palettes_docked) {
4608         if (bvvisible[0])
4609             GDrawRequestExpose(bvlayers, NULL, false);
4610         if (bvvisible[1])
4611             GDrawRequestExpose(bvtools, NULL, false);
4612         if (bvvisible[2])
4613             GDrawRequestExpose(bvshades, NULL, false);
4614     } else {
4615 	    if ( bvvisible[0])
4616 		RestoreOffsets(bv->gw,bvlayers,&bvlayersoff);
4617 	    if ( bvvisible[1])
4618 		RestoreOffsets(bv->gw,bvtools,&bvtoolsoff);
4619 	    if ( bvvisible[2] && !bv->shades_hidden )
4620 		RestoreOffsets(bv->gw,bvshades,&bvshadesoff);
4621 	}
4622 	GDrawSetVisible(bvtools,bvvisible[1]);
4623 	GDrawSetVisible(bvlayers,bvvisible[0]);
4624 	GDrawSetVisible(bvshades,bvvisible[2] && bv->bdf->clut!=NULL);
4625 	if ( bvvisible[1]) {
4626 	    bv->showing_tool = bvt_none;
4627 	    BVToolsSetCursor(bv,0,NULL);
4628 	    GDrawRequestExpose(bvtools,NULL,false);
4629 	}
4630 	if ( bvvisible[0])
4631 	    BVLayersSet(bv);
4632 	if ( bvvisible[2] && !bv->shades_hidden )
4633 	    GDrawRequestExpose(bvtools,NULL,false);
4634     }
4635     if ( cvtools!=NULL ) {
4636 	CharView *cv = GDrawGetUserData(cvtools);
4637 	if ( cv!=NULL ) {
4638 	    SaveOffsets(cv->gw,cvtools,&cvtoolsoff);
4639 	    SaveOffsets(cv->gw,cvlayers,&cvlayersoff);
4640 	    GDrawSetUserData(cvtools,NULL);
4641 	    if ( cvlayers!=NULL )
4642 		GDrawSetUserData(cvlayers,NULL);
4643 	    if ( cvlayers2!=NULL )
4644 		GDrawSetUserData(cvlayers2,NULL);
4645 	}
4646 	GDrawSetVisible(cvtools,false);
4647 	if ( cvlayers!=NULL )
4648 	    GDrawSetVisible(cvlayers,false);
4649 	if ( cvlayers2!=NULL )
4650 	    GDrawSetVisible(cvlayers2,false);
4651     }
4652 }
4653 
BVPaletteActivate(BitmapView * bv)4654 void BVPaletteActivate(BitmapView *bv) {
4655     _BVPaletteActivate(bv, false, false);
4656 }
4657 
BVPalettesHideIfMine(BitmapView * bv)4658 void BVPalettesHideIfMine(BitmapView *bv) {
4659     if ( bvtools==NULL )
4660 return;
4661     if ( GDrawGetUserData(bvtools)==bv ) {
4662 	SaveOffsets(bv->gw,bvtools,&bvtoolsoff);
4663 	SaveOffsets(bv->gw,bvlayers,&bvlayersoff);
4664 	SaveOffsets(bv->gw,bvshades,&bvshadesoff);
4665 	GDrawSetVisible(bvtools,false);
4666 	GDrawSetVisible(bvlayers,false);
4667 	GDrawSetVisible(bvshades,false);
4668 	GDrawSetUserData(bvtools,NULL);
4669 	GDrawSetUserData(bvlayers,NULL);
4670 	GDrawSetUserData(bvshades,NULL);
4671     }
4672 }
4673 
CVPaletteDeactivate(void)4674 void CVPaletteDeactivate(void) {
4675     if ( cvtools!=NULL ) {
4676 	CharView *cv = GDrawGetUserData(cvtools);
4677 	if ( cv!=NULL ) {
4678 	    SaveOffsets(cv->gw,cvtools,&cvtoolsoff);
4679 	    GDrawSetUserData(cvtools,NULL);
4680 	    if ( cv->b.sc->parent->multilayer && cvlayers2!=NULL ) {
4681 		SaveOffsets(cv->gw,cvlayers2,&cvlayersoff);
4682 		GDrawSetUserData(cvlayers2,NULL);
4683 	    } else if ( cvlayers!=NULL ) {
4684 		SaveOffsets(cv->gw,cvlayers,&cvlayersoff);
4685 		GDrawSetUserData(cvlayers,NULL);
4686 	    }
4687 	}
4688 	GDrawSetVisible(cvtools,false);
4689 	if ( cvlayers!=NULL )
4690 	    GDrawSetVisible(cvlayers,false);
4691 	if ( cvlayers2!=NULL )
4692 	    GDrawSetVisible(cvlayers2,false);
4693     }
4694     if ( bvtools!=NULL ) {
4695 	BitmapView *bv = GDrawGetUserData(bvtools);
4696 	if ( bv!=NULL ) {
4697 	    SaveOffsets(bv->gw,bvtools,&bvtoolsoff);
4698 	    SaveOffsets(bv->gw,bvlayers,&bvlayersoff);
4699 	    SaveOffsets(bv->gw,bvshades,&bvshadesoff);
4700 	    GDrawSetUserData(bvtools,NULL);
4701 	    GDrawSetUserData(bvlayers,NULL);
4702 	    GDrawSetUserData(bvshades,NULL);
4703 	}
4704 	GDrawSetVisible(bvtools,false);
4705 	GDrawSetVisible(bvlayers,false);
4706 	GDrawSetVisible(bvshades,false);
4707     }
4708 }
4709 
BVPaletteColorChange(BitmapView * bv)4710 void BVPaletteColorChange(BitmapView *bv) {
4711     if ( bvshades!=NULL )
4712 	GDrawRequestExpose(bvshades,NULL,false);
4713     GDrawRequestExpose(bv->gw,NULL,false);
4714 }
4715 
BVPaletteColorUnderChange(BitmapView * bv,int color_under)4716 void BVPaletteColorUnderChange(BitmapView *bv,int color_under) {
4717     if ( bvshades!=NULL && color_under!=bv->color_under_cursor ) {
4718 	bv->color_under_cursor = color_under;
4719 	GDrawRequestExpose(bvshades,NULL,false);
4720     }
4721 }
4722 
BVPaletteChangedChar(BitmapView * bv)4723 void BVPaletteChangedChar(BitmapView *bv) {
4724     if ( bvshades!=NULL && bvvisible[2]) {
4725 	int hidden = bv->bdf->clut==NULL;
4726 	if ( hidden!=bv->shades_hidden ) {
4727 	    GDrawSetVisible(bvshades,!hidden);
4728 	    bv->shades_hidden = hidden;
4729 	    GDrawRequestExpose(bv->gw,NULL,false);
4730 	} else
4731 	    GDrawRequestExpose(bvshades,NULL,false);
4732     }
4733 }
4734 
PalettesChangeDocking()4735 void PalettesChangeDocking() {
4736     palettes_docked = !palettes_docked;
4737 
4738     if (cvtools != NULL)
4739         _CVPaletteActivate((CharView*)GDrawGetUserData(cvtools), true, true);
4740     if (bvtools != NULL)
4741         _BVPaletteActivate((BitmapView*)GDrawGetUserData(bvtools), true, true);
4742 
4743     SavePrefs(true);
4744 }
4745 
BVPalettesWidth(void)4746 int BVPalettesWidth(void) {
4747 return( GGadgetScale(BV_LAYERS_WIDTH));
4748 }
4749