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