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