1 /****************************************************************************
2
3 EDITSS: A shipshape editor for XPilot shipshapes V2.1
4 Copyright (C) 1994 Ronald In 't Velt
5
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
21 Right now, it is impossible to reach me via E-Mail. When I will have
22 an account again somewhere, I will post a notice in alt.games.xpilot (or
23 rec.games.xpilot in case this newgroup is accepted into rec.).
24
25
26 EDITSS.C: main module
27 ****************************************************************************/
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <fcntl.h>
33 #include <time.h>
34 #include <ctype.h>
35 #include <sys/param.h>
36 #include <pwd.h>
37 #include <unistd.h>
38 #include <X11/Intrinsic.h>
39 #include <X11/StringDefs.h>
40 #include <X11/Xaw/Command.h>
41 #include <X11/Xaw/Viewport.h>
42 #include <X11/Xaw/Box.h>
43 #include <X11/Xaw/Toggle.h>
44 #include <X11/Xaw/AsciiText.h>
45 #include <X11/Xaw/AsciiSrc.h>
46 #include <X11/Xaw/AsciiSink.h>
47 #include <X11/Xaw/Label.h>
48 #include <X11/Xaw/List.h>
49 #include <X11/Xaw/Form.h>
50 #include <X11/Xaw/Scrollbar.h>
51 #include <X11/Xaw/Dialog.h>
52 #include <X11/Xaw/Porthole.h>
53 #include <X11/Xaw/Paned.h>
54
55 #include "const.h"
56 #include "types.h"
57
58
59 #include "pship.h"
60 #include "editss.h"
61 #include "xstuff.h"
62
63 /*****************************************************************************
64 * The following vars are global *
65 *****************************************************************************/
66 XtAppContext app_context;
67 Widget toplevel, mainw; /* main windows */
68 Widget b_quit, b_draw, b_kill; /* The widgets */
69 Widget b_split, b_write;
70 Widget area, small, b_print, b_shipname, b_shipaut;
71 Widget sn_source, sn_sink, l_sn, b_default;
72 Widget sa_source, sa_sink;
73 Widget shipview, shipbm, b_clear, sl_source;
74 Widget sl_sink, b_shiplib, l_sl;
75 Widget l_size, l_sizeok, b_box, l_prob, b_psout;
76 Widget b_mg, b_lg, b_rg, b_ll, b_rl, b_mr, b_en;
77
78 Pixmap pm_area, pm_small, pm_ships; /* drawing areas */
79 Pixmap pm_kill, pm_split, pm_nose, pm_rear; /* pointer pixmaps */
80 Pixmap pm_eng, pm_mis;
81
82 Cursor cur_nose, cur_rear, cur_draw, cur_kill, cur_split;/* pointers */
83 Cursor cur_eng, cur_mis;
84
85 int bb_bor, va_bor; /* border widths */
86 Pixel bb_b, bb_f, nl_b, nl_f; /* widget colors */
87 Pixel st_b, st_f, bh_b, bh_f, bt_b, bt_f, ba_b, ba_f;
88 Pixel pmc, plc, prc;
89 XColor col_black, col_white;
90 int scr_num, scr_depth; /* number and depth of screen */
91 char bb_fs[30], bb_bs[30]; /* names of widget colors */
92 char nl_fs[30], nl_bs[30], st_fs[30], st_bs[30];
93 char bh_fs[30], bh_bs[30], ba_fs[30], ba_bs[30];
94 char bt_fs[30], bt_bs[30];
95 char mc[30], lc[30], rc[30];
96 int f_w, f_h; /* width & height of font */
97
98 int isdefault, colorok; /* default file / colors exist? */
99 Dimension pm_area_w, pm_area_h, pm_small_w, pm_small_h;
100 GC gc_draw, gc_clear, gc_grid, gc_xor, gc_ship, gc_main, gc_left, gc_right;
101 XFontStruct *font_small; /* smaller font */
102 XFontStruct *font;
103 char fontname[MAXLINELEN], shipname[MAXLINELEN], shipaut[MAXLINELEN];
104 char shiplib[MAXLINELEN]; /* names of stuff */
105
106 int xo, yo, nrships; /* nr of ships in lib */
107 int drawmode, dragpoint, dragmode; /* current drawmodes */
108 int rcformat; /* is format in .xpilotrd format? */
109 char dr_val[] = {'D', 'K', 'S', '8', '7', '9', '1', '3', '5', '2'};
110 /* value array for radiobuttons */
111
112 Time tl; /* timer for double-click */
113 ship sh_ed; /* current ship to be edited */
114
115 int callfrom=FALSE; /* called from XXPMS */
116
117 shiplist *sl;
118 /****************************************************************************/
Free_Shiplist(shiplist * sl)119 void Free_Shiplist(shiplist *sl)
120 {
121 if (sl!=NULL) {
122 if (sl->s!=NULL) free(sl->s);
123 free(sl);
124 }
125 }
126
Alloc_Shiplist(void)127 shiplist *Alloc_Shiplist(void)
128 {
129 return (shiplist *)malloc(sizeof(shiplist));
130 }
131
132
133 /* Remove all cr's from string s */
killcr(char * s)134 void killcr(char *s)
135 {
136 char *b;
137 b=strchr(s,'\n');
138 if (b!=NULL) {
139 *b='\0';
140 if (*(b+1)!='\0') strcat(s, b+1);
141 }
142 }
143
144
145 /* Kill trailing spaces and tabs from string s */
killsp(char * s)146 void killsp(char *s)
147 {
148 int i;
149 i=strlen(s)-1;
150 while ((i>=0)&&( ((s[i]==' ')||(s[i]=='\t')) )) {
151 s[i]='\0';
152 i-=1;
153 }
154 }
155
156
157 /* Get shiblib string from widget ans clean up */
getshiplib(void)158 void getshiplib(void)
159 {
160 char *s;
161 XtVaGetValues(b_shiplib, XtNstring, &s, NULL);
162 strcpy(shiplib,s);
163 killcr(shiplib);
164 killsp(shiplib);
165 }
166
167
168 /* Get shibname string from widget ans clean up */
getshipname(void)169 void getshipname(void)
170 {
171 char *s;
172 XtVaGetValues(b_shipname, XtNstring, &s, NULL);
173 strcpy(shipname,s);
174 killcr(shipname);
175 killsp(shipname);
176 strcpy(sh_ed.name, shipname);
177 }
178
179
getshipaut(void)180 void getshipaut(void)
181 {
182 char *s;
183 XtVaGetValues(b_shipaut, XtNstring, &s, NULL);
184 strcpy(shipaut,s);
185 killcr(shipaut);
186 killsp(shipaut);
187 strcpy(sh_ed.author, shipaut);
188 }
189
190
191
192 /* Determine home directory of the user */
userpath(void)193 char *userpath(void)
194 {
195 static char res[MAXLINELEN], *h;
196 struct passwd *pwd;
197 res[0]='\0';
198 h=getenv("HOME");
199 if (h!=NULL) strcpy(res,h);
200 if ((strlen(res)==0)&&(access(h,0)!=-1)) strcpy(res,h);
201 if (strlen(res)==0) {
202 pwd=getpwuid(getuid());
203 if (pwd!=NULL) strcpy(res,pwd->pw_dir);
204 }
205 return res;
206 }
207
208 /* Get a ship from the shiplib file. Name into sname, ship into sship */
209 /* if same=TRUE, file will not reset, close on subsequent calls */
getoneshipdef(char * sship,FILE * fin)210 int getoneshipdef(char *sship, FILE *fin)
211 {
212 char *sd;
213 static char c[MAXSHIPLEN], d[MAXSHIPLEN];
214
215 getshiplib();
216 if ((fin==NULL)||(feof(fin))) return FALSE;
217 sship[0]='\0';
218 fscanf(fin,"%[^\n]",c);
219 fscanf(fin,"%*[\n]");
220 sd=strchr(c,'\\');
221 while (sd!=NULL) {
222 *sd='\0';
223 fscanf(fin,"%[^\n]",d);
224 fscanf(fin,"%*[\n]");
225 strcat(c, d);
226 sd=strchr(c,'\\');
227 }
228 strcpy(sship, c);
229 return TRUE;
230 }
231
232
233
234 /* Find the closest line to px, py in the editship */
findline(int px,int py)235 int findline(int px, int py)
236 {
237 int dx, dy, b, i, np, mindist, minpnt;
238 float slope;
239 if (sh_ed.n<2) return -1;
240 mindist=9999; minpnt=-1;
241 for (i=0; i<sh_ed.n; i++) {
242 if (i==sh_ed.n-1) np=0; else np=i+1;
243 dx=cx(sh_ed.p[np].x)-cx(sh_ed.p[i].x);
244 dy=cy(sh_ed.p[np].y)-cy(sh_ed.p[i].y);
245 b=0;
246 if (abs(dx)>abs(dy)) {
247 slope=(float)dy/(float)dx;
248 b=cx(sh_ed.p[i].x)-px;
249 if (((b<0)&&(dx>0))||((b>0)&&(dx<=0))) {
250 b=px-cx(sh_ed.p[np].x);
251 if (((b<0)&&(dx>0))||((b>0)&&(dx<=0))) b=0;
252 }
253 if (b<0) b=-b;
254 if (b<(pm_area_w-20)/60)
255 b=abs(py-(cy(sh_ed.p[i].y)+(int)(slope*(px-cx(sh_ed.p[i].x)))));
256 } else {
257 /* BUGFIX BG: Don't divide by zero. core dumper. */
258 if (dy == 0)
259 slope = 0;
260 else
261 slope=(float)dx/(float)dy;
262 b=cy(sh_ed.p[i].y)-py;
263 if (((b<0)&&(dy>0))||((b>0)&&(dy<=0))) {
264 b=py-cy(sh_ed.p[np].y);
265 if (((b<0)&&(dy>0))||((b>0)&&(dy<=0))) b=0;
266 }
267 if (b<0) b=-b;
268 if (b<(pm_area_h-20)/60)
269 b=abs(px-(cx(sh_ed.p[i].x)+(int)(slope*(py-cy(sh_ed.p[i].y)))));
270 }
271 if ((b<(pm_area_w-20)/60)&&(b<mindist)) {
272 mindist=b;
273 minpnt=i;
274 }
275 }
276 return minpnt;
277 }
278
279
280 /* Coordinate conversion */
cx(int x)281 int cx(int x)
282 {
283 int i;
284 i=x+15;
285 i=(int)(i*(pm_area_w-20)/30)+10;
286 return i;
287 }
288
289 /* Coordinate conversion */
cy(int y)290 int cy(int y)
291 {
292 int i;
293 i=-y+15;
294 i=(int)(i*(pm_area_h-20)/30)+10;
295 return i;
296 }
297
298 /* Coordinate conversion */
rx(int x)299 int rx(int x)
300 {
301 int i;
302 i=x-5;
303 i=(int)(i*30/(pm_area_w-20))-15;
304 if (i<-15) i=-15;
305 if (i>15) i=15;
306 return i;
307 }
308
309 /* Coordinate conversion */
ry(int y)310 int ry(int y)
311 {
312 int i;
313 i=y-5;
314 i=(int)(i*30/(pm_area_h-20))-15;
315 if (i<-15) i=-15;
316 if (i>15) i=15;
317 return -i;
318 }
319
320 /* Coordinate conversion */
rs(int i)321 int rs(int i)
322 {
323 float f=(SPM_SIZE/40.0);
324 return (int)((i+20)*f);
325 }
326
327
stringupp(char * s)328 char * stringupp(char *s) /* make a string uppercase */
329 {
330 static char kaas[1000];
331 char *c;
332
333 strncpy(kaas, s, sizeof(kaas));
334 kaas[sizeof(kaas) - 1] = '\0';
335 c = kaas;
336 while(*c) {
337 *c = toupper(*c);
338 c+=1;
339 }
340 return kaas;
341 }
342
343
344 /* Parse value in s into definition p */
fillin(char * s,fileinfo p)345 void fillin(char *s, fileinfo p)
346 {
347 int di; /* dummy's */
348 float df;
349 if (strstr(p.parse,"%S")!=NULL) { /* capitalize string */
350 strcpy(p.varad,stringupp(s));
351 return;
352 }
353 if (strstr(p.parse,"%s")!=NULL) { /* string */
354 strcpy(p.varad,s);
355 return;
356 }
357 if (strstr(p.parse,"%>s")!=NULL) { /* append string */
358 strcat(p.varad,p.def);
359 strcat(p.varad,s);
360 strcat(p.varad,"\n");
361 return;
362 }
363 if (strstr(p.parse,"%>S")!=NULL) { /* append capit. string */
364 strcat(p.varad,p.def);
365 strcat(p.varad,stringupp(s));
366 strcat(p.varad,"\n");
367 return;
368 }
369 if (strstr(p.parse,"%b")!=NULL) { /* handle boolean */
370 if ((!strcasecmp(s,"true"))||(!strcasecmp(s,"on"))||(!strcasecmp(s,"yes")))
371 *(int *)p.varad=1;
372 else
373 *(int *)p.varad=0;
374 return;
375 }
376 if (strstr(p.parse,"%t")!=NULL) { /* handle troolean */
377 if ((!strcasecmp(s,"true"))||(!strcasecmp(s,"on"))||(!strcasecmp(s,"yes")))
378 *(int *)p.varad=1;
379 else
380 if (!strcasecmp(s,"none")) *(int *)p.varad=NONE;
381 else *(int *)p.varad=0;
382 return;
383 }
384 if (strstr(p.parse,"%i")!=NULL) { /* handle int */
385 di=atoi(s);
386 *(int *)p.varad=di;
387 }
388 if (strstr(p.parse,"%f")!=NULL) { /* handle float */
389 df=atoi(s);
390 *(float *)p.varad=df;
391 }
392 }
393
394
395 /* parse file f and p */
parsefile(char * f,fileinfo * p)396 int parsefile(char *f, fileinfo *p)
397 {
398 int i=0;
399 FILE *fin;
400 char a1[1000], a2[1000], a3[1000], a4[1000];
401 char *b1;
402
403 fin=fopen(f,"r"); /* open the default file */
404 /* else change to defaults first! */
405
406 while (p[i].parse!=NULL) {
407 if (strstr(p[i].parse,"%>")!=NULL) strcpy(p[i].varad,"\0");
408 else fillin(p[i].def,p[i]);
409 i++;
410 }
411 if (fin==NULL) return FALSE; /* do nothing if no file */
412
413 while (!feof(fin)) { /* read the entire file! */
414 a2[0]='\0';
415 fscanf(fin,"%[^\n]%[\n]",a1,a4); /* read to EOL */
416 sscanf(a1,"%[^:#*\t ]%[:*\t ]%[^*\t]",a2,a4,a3); /* strings */
417 a4[0]='\0';
418 sscanf(&a3[1],"%[^#]",a4);
419 a3[1]='\0';
420 strcat(a3,a4);
421 b1=&a3[strlen(a3)-1]; /* strip last spaces */
422 i=FALSE;
423 while ((b1!=a3)&&(*b1==' ')) {
424 b1--;
425 i=TRUE;
426 }
427 if (i) {
428 b1++;
429 if (*b1==' ') *b1='\0';
430 }
431 i=0;
432 while ((p[i].parse!=NULL)&&(strcasecmp(p[i].key,a2))) i++;
433 if (p[i].parse!=NULL) {
434 fillin(a3, p[i]);
435 }
436 }
437 fclose (fin);
438 return TRUE;
439 }
440
441
loaddefs(void)442 void loaddefs(void) /* load defaults */
443 {
444 char a[100],b[100]; /* dummy strings */
445 static fileinfo parray[] = {
446 {"%i","buttonbox_border",&bb_bor,"1"},
447 {"%i","value_border",&va_bor,"0"},
448 {"%s","buttonbox_b",&bb_bs,"white"},
449 {"%s","buttonbox_f",&bb_fs,"black"},
450 {"%s","namelist_b",&nl_bs,"white"},
451 {"%s","namelist_f",&nl_fs,"black"},
452 {"%s","status_b",&st_bs,"white"},
453 {"%s","status_f",&st_fs,"black"},
454 {"%s","button_high_b",&bh_bs,"white"},
455 {"%s","button_high_f",&bh_fs,"black"},
456 {"%s","button_toggle_b",&bt_bs,"white"},
457 {"%s","button_toggle_f",&bt_fs,"black"},
458 {"%s","button_action_b",&ba_bs,"white"},
459 {"%s","button_action_f",&ba_fs,"black"},
460 {"%s","smallfont",&fontname,"8x13"},
461 {"%s","shiplib",&shiplib,".xpilotrc"},
462 {"%s","maincol",&mc,"black"},
463 {"%s","leftcol",&lc,"black"},
464 {"%s","rightcol",&rc,"black"},
465 {NULL,NULL,NULL,NULL}
466 };
467
468 a[0]='\0';
469 b[0]='\0';
470 strcpy(b,userpath());
471 strcat(b,"/.editssrc");
472 isdefault=parsefile(b,parray);
473 }
474
475
476 /* Read ships from shiplib, display them */
getdir(void)477 void getdir(void)
478 {
479 char a[MAXSHIPLEN], b[MAXLINELEN];
480 int i1, i;
481 Dimension x, y;
482 ship *sh;
483 shiplist *slp, *slpp;
484 FILE *fin;
485
486 while (sl!=NULL) {
487 /* BUGFIX BG: Don't access memory after free(). core dumper. */
488 slp = sl->n;
489 sl->n = NULL;
490 Free_Shiplist(sl);
491 sl = slp;
492 }
493
494 strcpy(b,userpath());
495 if (strlen(b)==0) printf("WARNING! Cannot determine home directory\n");
496 strcat(b,"/");
497 strcat(b,shiplib);
498 fin=fopen(b,"r");
499
500 if (pm_ships>0) {
501 XFillRectangle(XtDisplay(toplevel),pm_ships,gc_draw,0,0,SPM_SIZE,SPM_SIZE*nrships);
502 XCopyArea(XtDisplay(shipbm), pm_ships, XtWindow(shipbm),
503 DefaultGCOfScreen(XtScreen(toplevel)), 0, 0,
504 SPM_SIZE, SPM_SIZE*nrships, 0,0);
505 XFreePixmap(XtDisplay(toplevel),pm_ships);
506 }
507 nrships=0;
508 while (getoneshipdef(a,fin)) {
509 nrships+=1;
510 }
511 if (fin!=NULL) fclose(fin);
512 if (nrships<1) i1=1; else i1=nrships;
513
514 a[0]='\0';
515 pm_ships = XCreatePixmap(XtDisplay(toplevel), RootWindowOfScreen(XtScreen(toplevel)),
516 SPM_SIZE,SPM_SIZE*i1,scr_depth);
517 XtResizeWidget(shipbm, SPM_SIZE,SPM_SIZE*i1, 0);
518 XFillRectangle(XtDisplay(toplevel),pm_ships,gc_draw,0,0,SPM_SIZE,SPM_SIZE*i1);
519
520 fin=fopen(b,"r");
521
522
523 nrships=0;
524 a[0]='\0';
525 b[0]='\0';
526 slp = NULL;
527 while(getoneshipdef(a, fin)) {
528 sh=Convert_shape_str(strchr(a,'('));
529 if (sh!=NULL) {
530 if (sl == NULL) {
531 sl = Alloc_Shiplist();
532 slp = sl;
533 } else {
534 slp->n = Alloc_Shiplist();
535 slp = slp->n;
536 }
537 slp->s = sh;
538 for (i=0; i<sh->n; i++) {
539 if (i<sh->n-1)
540 XDrawLine(XtDisplay(toplevel),pm_ships,gc_clear,rs(sh->p[i].x),rs(-sh->p[i].y)+nrships*SPM_SIZE,rs(sh->p[i+1].x),rs(-sh->p[i+1].y)+nrships*SPM_SIZE);
541 else
542 XDrawLine(XtDisplay(toplevel),pm_ships,gc_clear,rs(sh->p[i].x),rs(-sh->p[i].y)+nrships*SPM_SIZE,rs(sh->p[0].x),rs(-sh->p[0].y)+nrships*SPM_SIZE);
543 }
544 nrships+=1;
545 }
546 }
547 if (slp!=NULL) slp->n = NULL;
548 XCopyArea(XtDisplay(shipbm), pm_ships, XtWindow(shipbm),
549 DefaultGCOfScreen(XtScreen(toplevel)), 0, 0,
550 SPM_SIZE, SPM_SIZE*i1, 0,0);
551 XtVaGetValues(shipview, XtNwidth, &x, XtNheight, &y, NULL);
552 XtResizeWidget(shipview, x, y+1, 1);
553 XtResizeWidget(shipview, x, y, 1);
554
555 if (fin) fclose(fin);
556 XtSetSensitive(b_psout, (nrships>0));
557 }
558
559
560 /* The main */
main(int argc,char ** argv)561 int main(int argc, char **argv)
562 {
563 ship *newship;
564 sl = NULL;
565 printf("%s (c) 1994 R. In 't Velt \n",VERSION);
566 loaddefs();
567 cleanship(&sh_ed);
568 shipname[0]='\0';
569 x_init(argc, argv);
570 drawmode=DM_NONE;
571 if ((argc>=2)&&(strchr(argv[1],'(')!=NULL)) {
572 newship=Convert_shape_str(argv[1]);
573 cpyship(&sh_ed, newship);
574 Free_ship_shape(newship);
575 }
576 XtAppMainLoop(app_context);
577
578 return 0;
579 }
580
581