1 /* XNECVIEW - a program for visualizing NEC2 input and output data
2 *
3 * Copyright (C) 1998-2006,2011, Pieter-Tjerk de Boer -- pa3fwm@amsat.org
4 *
5 * Distributed on the conditions of version 2 of the GPL: see the files
6 * README and COPYING, which accompany this source file.
7 *
8 * This module contains all X-windows related stuff; this includes all
9 * event handlers, and thus most of the interaction with the user.
10 */
11
12
13 #include <math.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <gtk/gtk.h>
17 #include <gdk/gdkkeysyms.h>
18
19 #ifdef HAVE_LIBPNG
20 #include <png.h>
21 #endif
22
23 #include "xnecview.h"
24
25 #include "icon.xbm"
26
27
28
29 /* note: gdraw2, ggc2, etc. refer to the second window, i.e., the window containing the plots of SWR etc. vs. frequency */
30 GtkWidget *gdraw1=NULL,*gdraw2=NULL;
31 GtkWidget *vbox1; /* the (GTK) vertical box for window 1, containing the top row of buttons, the drawing itself, and the bottom row of buttons */
32 GtkWidget *botrow_curr; /* the (GTK) bottom row of buttons in window 1 for settings of the currents display */
33 GtkWidget *botrow_anim; /* the (GTK) bottom row of buttons in window 1 for settings of the (animated) near field display */
34 GdkGC *ggc,*ggc2;
35 GdkFont *gfont;
36
37 GdkPixmap *gbackg=NULL; /* picture buffer used for double buffering code; it will serve as the background pixmap for the window */
38 GtkLabel *msgwidget; /* label widget in top right corner, used for several messages */
39 int fontheight;
40 GdkPixmap *gbackg2=NULL; /* for window2, we draw into this pixmap */
41 GdkColormap *gcm;
42 int depth;
43
44 int redraw=1; /* flag which signifies need for redrawing of struct/gain plot */
45 int dragging=0; /* flag to indicate that user is dragging the struct/gain plot */
46 int quick; /* flag to indicate that drawing should be rough but quick */
47 int quit=0; /* flag to indicate that the user wants to quit */
48 int redraw2=1; /* flag which signifies need for redrawing of frequency plots; extra for speedup: if it ==2, then only the vgain plot needs to be redrawn */
49 int animbusy=0; /* flag to indicate that we're still busy processing the previous animation picture, to slow down the animation sufficiently on slow machines and/or complicated models */
50
51 double old_animfreq=0; /* storage for animation frequency when animation is temporarily suspended using the 'z' key */
52
53 Outdev *out=NULL;
54
55
56 /* color values for several items: */
57 GdkColor col[NC];
58 GdkColor gcol[NC];
59
60
61 /* -------------------- X windows stuff: drawing ---------------------------------------- */
62
X_SetLineAttributes(unsigned int a,int b,int c,int d)63 void X_SetLineAttributes(unsigned int a,int b,int c,int d)
64 {
65 gdk_gc_set_line_attributes(ggc, a,b,c,d);
66 }
67
X_DrawLine(double a,double b,double c,double d)68 void X_DrawLine(double a,double b,double c,double d)
69 {
70 #if 0
71 if (a>32000 || a<-32000
72 || b>32000 || b<-32000
73 || c>32000 || c<-32000
74 || d>32000 || d<-32000
75 )
76 #endif
77 if (a>winsizex || a<0
78 || b>winsizey || b<0
79 || c>winsizex || c<0
80 || d>winsizey || d<0
81 )
82 {
83 /* clipping is needed, otherwise we run into problems when feeding these extremely large coordinates to the X server; apparently, the X11 protocol uses only 16 bits for the coordinates */
84 double h;
85
86 if (a>winsizex && c>winsizex) return;
87 if (a<0 && c<0) return;
88 if (b>winsizey && d>winsizey) return;
89 if (b<0 && d<0) return;
90
91 if (c<a) { h=a; a=c; c=h; h=b; b=d; d=h; }
92 if (a<0) {
93 b -= (d-b)*a/(c-a);
94 a=0;
95 }
96 if (c>winsizex) {
97 d -= (d-b)*(c-winsizex)/(c-a);
98 c=winsizex;
99 }
100
101 if (d<b) { h=a; a=c; c=h; h=b; b=d; d=h; }
102 if (b<0) {
103 a -= (c-a)*b/(d-b);
104 b=0;
105 }
106 if (d>winsizey) {
107 c -= (c-a)*(d-winsizey)/(d-b);
108 d=winsizey;
109 }
110 }
111 gdk_draw_line(gbackg,ggc,(int)(a+0.5),(int)(b+0.5),(int)(c+0.5),(int)(d+0.5));
112 }
113
X_SetForeground(GdkColor * xc)114 void X_SetForeground(GdkColor *xc)
115 {
116 gdk_gc_set_foreground(ggc,xc);
117 }
118
X_ClearWindow()119 void X_ClearWindow()
120 {
121 X_SetForeground(&c_bg);
122 gdk_draw_rectangle(gbackg,ggc,TRUE,0,0,winsizex,winsizey);
123 }
124
125
X_DrawString(double a,double b,char * s,double d,double e)126 void X_DrawString(double a,double b,char *s,double d,double e) /* draw string */
127 {
128 if (d>0) a-=d*gdk_string_width(gfont,s);
129 b += -gfont->descent + e*(gfont->descent+gfont->ascent);
130 gdk_draw_string(gbackg,gfont,ggc,(int)(a+0.5),(int)(b+0.5),s);
131 }
132
133
X_Complete(void)134 void X_Complete(void)
135 {
136 gdk_window_set_back_pixmap(gdraw1->window, gbackg, 0);
137 gdk_window_clear(gdraw1->window);
138 }
139
140 Outdev outX={ X_SetLineAttributes, X_DrawLine, X_SetForeground, X_ClearWindow, X_DrawString, X_Complete, NULL };
141
142
X2_SetLineAttributes(unsigned int a,int b,int c,int d)143 void X2_SetLineAttributes(unsigned int a,int b,int c,int d)
144 {
145 gdk_gc_set_line_attributes(ggc2, a,b,c,d);
146 }
147
X2_DrawLine(double a,double b,double c,double d)148 void X2_DrawLine(double a,double b,double c,double d)
149 {
150 if (b<-32000 || d<-32000 || b>32000 || d>32000) return;
151 gdk_draw_line(gbackg2,ggc2,(int)(a+0.5),(int)(b+0.5),(int)(c+0.5),(int)(d+0.5));
152 }
153
X2_SetForeground(GdkColor * xc)154 void X2_SetForeground(GdkColor *xc)
155 {
156 gdk_gc_set_foreground(ggc2,xc);
157 }
158
X2_SetClipRectangle(double x1,double y1,double x2,double y2)159 void X2_SetClipRectangle(double x1,double y1,double x2,double y2)
160 {
161 GdkRectangle gr;
162 gr.x=(int)(x1+0.5);
163 gr.y=(int)(y1+0.5);
164 gr.width=(int)(x2-gr.x+1.5);
165 gr.height=(int)(y2-gr.y+1.5);
166 gdk_gc_set_clip_rectangle(ggc2,&gr);
167 }
168
X2_ClearWindow()169 void X2_ClearWindow()
170 {
171 X2_SetClipRectangle(0,0,win2sizex,win2sizey);
172 X2_SetForeground(&c_bg);
173 gdk_draw_rectangle(gbackg2,ggc2,TRUE,0,0,win2sizex,win2sizey);
174 }
175
X2_ClearRectangle(double x1,double y1,double x2,double y2)176 void X2_ClearRectangle(double x1,double y1,double x2,double y2)
177 {
178 X2_SetClipRectangle(0,0,win2sizex,win2sizey);
179 X2_SetForeground(&c_bg);
180 gdk_draw_rectangle(gbackg2,ggc2,TRUE, (int)(x1+0.5),(int)(y1+0.5), (int)(x2-x1+1.5),(int)(y2-y1+1.5));
181 }
182
183
X2_DrawString(double a,double b,char * s,double d,double e)184 void X2_DrawString(double a,double b,char *s,double d,double e) /* draw string */
185 {
186 if (d>0) a-=d*gdk_string_width(gfont,s);
187 b += -gfont->descent + e*(gfont->descent+gfont->ascent);
188 gdk_draw_string(gbackg2,gfont,ggc2,(int)(a+0.5),(int)(b+0.5),s);
189 }
190
X2_Complete(void)191 void X2_Complete(void)
192 {
193 gdk_window_set_back_pixmap(gdraw2->window, gbackg2, 0);
194 gdk_window_clear(gdraw2->window);
195 }
196
197 Outdev outX2={
198 X2_SetLineAttributes,
199 X2_DrawLine,
200 X2_SetForeground,
201 X2_ClearWindow,
202 X2_DrawString,
203 X2_Complete,
204 X2_SetClipRectangle,
205 X2_ClearRectangle,
206 };
207
208
209 /* -------------------- support function for querying the image ---------------------------- */
210
211
query_pixmap(GdkPixmap * w,int x,int y)212 int query_pixmap(GdkPixmap *w,int x, int y)
213 /* returns index in phase colours array of colour at (x,y); or -1 if the colour is c_inactive, or -2 if the colour is yet another one */
214 {
215 int i;
216 guint32 u;
217 GdkImage *im;
218 int width,height;
219
220 gdk_window_get_size(w,&width,&height);
221 if (x<0 || y<0 || x>=width || y>=height) return -2;
222
223 im = gdk_image_get(w, x, y, 1, 1);
224 u = gdk_image_get_pixel(im, 0, 0);
225 gdk_image_destroy(im);
226 if (u==c_bg.pixel) return -2; /* most common case first :-) */
227 for (i=0;i<NC_phase;i++)
228 if (c_currents[i].pixel==u) return i;
229 if (u==c_inactive.pixel) return -1;
230 return -2;
231 }
232
233
234
235 /* -------------------- export a widget as a PNG file ---------------------------------------- */
236
237 #ifdef HAVE_LIBPNG
write_png(int which,const char * filename)238 int write_png(int which,const char *filename)
239 {
240 GdkImage *image;
241 GdkWindow *w;
242 FILE *f;
243 int width,height;
244 int x,y;
245 png_structp pp;
246 png_infop ip;
247 unsigned char *buf;
248 png_color pal[NC];
249 int i;
250
251 if (which==1) {
252 if (!out) { out=&outX; draw_all(0); }
253 w=gbackg;
254 } else {
255 if (!out) { out=&outX2; draw_all2(0); }
256 w=gbackg2;
257 }
258 gdk_window_get_size(w,&width,&height);
259
260 f=fopen(filename,"wb");
261 if (!f) return 1;
262
263 image = gdk_image_get(w, 0, 0, width, height);
264 if (!image) {
265 fclose(f);
266 return 1;
267 }
268
269 pp=png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
270 if (!pp) {
271 fclose(f);
272 return 1;
273 }
274 ip=png_create_info_struct(pp);
275 if (!ip) {
276 png_destroy_write_struct(&pp,(png_infopp)NULL);
277 fclose(f);
278 return 1;
279 }
280 if (setjmp(png_jmpbuf(pp))) {
281 png_destroy_write_struct(&pp,&ip);
282 fclose(f);
283 gdk_image_destroy(image);
284 return 1;
285 }
286 png_init_io(pp,f);
287 png_set_IHDR(pp,ip,width,height,8,PNG_COLOR_TYPE_PALETTE,PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_DEFAULT,PNG_FILTER_TYPE_DEFAULT);
288 for (i=0;i<NC;i++) {
289 pal[i].red= (col[i].red>>8);
290 pal[i].green=(col[i].green>>8);
291 pal[i].blue= (col[i].blue>>8);
292 }
293 png_set_PLTE(pp,ip,pal,NC);
294 png_write_info(pp,ip);
295
296 buf=mymalloc(width);
297 for (y=0;y<height;y++) {
298 for (x=0;x<width;x++) {
299 guint32 u;
300 u = gdk_image_get_pixel(image, x, y);
301 for(i=0;i<NC;i++) if (col[i].pixel==u) break;
302 buf[x]=i;
303 }
304 png_write_row(pp,buf);
305 }
306 free(buf);
307
308 png_write_end(pp,NULL);
309 png_destroy_write_struct(&pp,&ip);
310
311 fclose(f);
312 gdk_image_destroy(image);
313 return 0;
314 }
315 #endif
316
317
318
319
320 /* -------------------- event handlers (and their supporting code) for window 1 (struct/gain plot) ---------------------- */
321
322 char GSnumbers[][32]={" 0 -1 -3 -6 -10 dB",
323 " 0 -1 -3 -6 -10 dB",
324 " 0 -3 -10 -20 -30 dB",
325 " 0 -10 -20 -30 dB"};
326
upd_msg(void)327 void upd_msg(void)
328 {
329 char s[32];
330 return;
331 if (scaleplot && (gainplot==GPslice || gainplot==GPframe || gainplot==GPopaque)) {
332 gtk_label_set_text(msgwidget,GSnumbers[gainscale]);
333 } else {
334 sprintf(s,"phi=%g theta=%g",rint(phi),rint(theta));
335 gtk_label_set_text(msgwidget,s);
336 }
337 }
338
339
setrpfreq(void)340 void setrpfreq(void)
341 {
342 int x;
343 redraw=1;
344 process_nec_output(neco+rp_index);
345 if (window2open) {
346 gdk_window_clear(gdraw2->window);
347 gdk_gc_set_foreground(ggc2,&c_back);
348 x=freqx(neco[rp_index].f);
349 gdk_draw_line(gdraw2->window,ggc2,x,0,x,win2sizey);
350 }
351 }
352
353
354
355
resize_event(GtkWidget * w,GdkEventConfigure * ev,gpointer dummy)356 gint resize_event(GtkWidget *w,GdkEventConfigure *ev,gpointer dummy)
357 {
358 if (!gbackg) return TRUE;
359 if (winsizex==ev->width && winsizey==ev->height) return TRUE;
360 winsizex=ev->width;
361 winsizey=ev->height;
362 gdk_pixmap_unref(gbackg);
363 gbackg=gdk_pixmap_new(w->window,winsizex,winsizey,gdk_drawable_get_depth(w->window));
364 calcproj();
365 redraw=1;
366 #if 0
367 w->requisition.width=winsizex;
368 w->requisition.height=winsizey;
369 #endif
370 return TRUE;
371 }
372
373
374 int lastx=0;
375 int lasty=0;
376 int origx=0;
377 int origy=0;
378
buttonpress_event(GtkWidget * w,GdkEventButton * ev,gpointer dummy)379 gint buttonpress_event(GtkWidget *w,GdkEventButton *ev,gpointer dummy)
380 {
381 origx=lastx=ev->x;
382 origy=lasty=ev->y;
383 return TRUE;
384 }
385
386
buttonrelease_event(GtkWidget * w,GdkEventButton * ev,gpointer dummy)387 gint buttonrelease_event(GtkWidget *w,GdkEventButton *ev,gpointer dummy)
388 {
389 if (dragging) {
390 dragging=0;
391 if (quick) {
392 quick=0;
393 redraw=1;
394 }
395 if (structplot==SPcurrents) redraw=1; /* this redraw is needed to grab a correct copy of the phaseplot */
396 return TRUE;
397 }
398
399 if (ev->button==1) {
400 zoom*=1.4142;
401 trx-=(double)(ev->x-winsizex/2)/zoom/winsize;
402 try-=(double)(ev->y-winsizey/2)/zoom/winsize;
403 calcproj();
404 redraw=1;
405 calc_vgain();
406 if (plot2_vgain && redraw2==0) redraw2=2;
407 }
408
409 if (ev->button==2) {
410 zoom=ini_zoom;
411 phi=ini_phi;
412 theta=ini_theta;
413 scaleplot=0;
414 trx=ini_trx;
415 try=ini_try;
416 upd_msg();
417 calcproj();
418 redraw=1;
419 calc_vgain();
420 if (plot2_vgain && redraw2==0) redraw2=2;
421 }
422
423 if (ev->button==3) {
424 zoom/=1.4142;
425 calcproj();
426 redraw=1;
427 calc_vgain();
428 if (plot2_vgain && redraw2==0) redraw2=2;
429 }
430 return TRUE;
431 }
432
433
motion_event(GtkWidget * w,GdkEventMotion * ev,gpointer dummy)434 gint motion_event(GtkWidget *w,GdkEventMotion *ev,gpointer dummy)
435 {
436 int dx,dy;
437 int pos_x,pos_y;
438 unsigned int keys_buttons;
439
440 /* Get the pointer position*/
441 gdk_window_get_pointer(w->window, &pos_x, &pos_y, &keys_buttons);
442
443 /* if we have a currents display, try to find the phase of the point under the cursor */
444 if (structplot==SPcurrents && !dragging) {
445 int i;
446 double phase;
447 int r,xc,yc,x,y;
448 r=winsize/10;
449 xc=yc=r+r/2+1;
450 i=query_pixmap(gbackg,pos_x,pos_y);
451 if (i>=0) {
452 phase=((i*360.0/NC_phase)-phaseoffset)*M_PI/180.0;
453 x=xc+r*cos(phase);
454 y=yc+r*sin(phase);
455 gdk_window_clear(gdraw1->window);
456 gdk_gc_set_foreground(ggc,&c_axis); /* black */
457 gdk_draw_line(gdraw1->window,ggc,xc,yc,x,y);
458 } else if (i==-1) {
459 gdk_window_clear(gdraw1->window);
460 }
461 }
462
463 /* Don't allow motion which is too small*/
464 if (abs(pos_x-origx)+abs(pos_y-origy)<2) return TRUE;
465
466 /* Calculate motion vector */
467 dx=pos_x-lastx;
468 dy=pos_y-lasty;
469
470 if (ev->state & GDK_BUTTON1_MASK) {
471 /* drag with button1: rotate */
472 theta-=180.*(double)dy/(double)winsizey;
473 if (theta<0) theta=0;
474 if (theta>180) theta=180;
475 phi-=180.*(double)dx/(double)winsizex;
476 scaleplot=0;
477 calc_vgain();
478 if (plot2_vgain && redraw2==0) redraw2=2;
479 } else if (ev->state & GDK_BUTTON2_MASK) {
480 /* drag with button2: zoom in/out */
481 double z;
482 z=5*(double)(dx-dy)/winsize;
483 zoom*=z+1;
484 trx-=(double)(origx-winsizex/2)/winsize*z/zoom;
485 try-=(double)(origy-winsizey/2)/winsize*z/zoom;
486 } else if (ev->state & GDK_BUTTON3_MASK) {
487 /* drag with button3: translate */
488 trx+=(double)(dx)/zoom/winsize;
489 try+=(double)(dy)/zoom/winsize;
490 } else return TRUE;
491
492 quick=(ev->state&GDK_CONTROL_MASK);
493 upd_msg();
494 calcproj();
495 redraw=1;
496
497 dragging=1;
498
499 lastx=pos_x;
500 lasty=pos_y;
501
502 return TRUE;
503 }
504
505
keypress_event(GtkWidget * w,GdkEventKey * ev,gpointer dummy)506 gint keypress_event(GtkWidget *w,GdkEventKey *ev,gpointer dummy)
507 {
508 int i;
509
510 switch (ev->keyval) {
511 case GDK_Up:
512 case GDK_KP_Up:
513 theta+=5;
514 if (theta>180) theta=180;
515 upd_msg();
516 calcproj();
517 redraw=1;
518 calc_vgain();
519 if (plot2_vgain && redraw2==0) redraw2=2;
520 break;
521 case GDK_Down:
522 case GDK_KP_Down:
523 theta-=5;
524 if (theta<0) theta=0;
525 upd_msg();
526 calcproj();
527 redraw=1;
528 calc_vgain();
529 if (plot2_vgain && redraw2==0) redraw2=2;
530 break;
531 case GDK_Left:
532 case GDK_KP_Left:
533 phi+=5;
534 upd_msg();
535 calcproj();
536 redraw=1;
537 calc_vgain();
538 if (plot2_vgain && redraw2==0) redraw2=2;
539 break;
540 case GDK_Right:
541 case GDK_KP_Right:
542 phi-=5;
543 upd_msg();
544 calcproj();
545 redraw=1;
546 calc_vgain();
547 if (plot2_vgain && redraw2==0) redraw2=2;
548 break;
549 case GDK_Page_Down:
550 case GDK_KP_Page_Down:
551 i=rp_index;
552 do {
553 i--;
554 if (i<0) return TRUE;
555 } while (!neco[i].rp && !neco[i].cu && !neco[i].nf);
556 rp_index=i;
557 setrpfreq();
558 break;
559 case GDK_Page_Up:
560 case GDK_KP_Page_Up:
561 i=rp_index;
562 do {
563 i++;
564 if (i>=numneco) return TRUE;
565 } while (!neco[i].rp && !neco[i].cu && !neco[i].nf);
566 rp_index=i;
567 setrpfreq();
568 break;
569 case '>':
570 animphase+=M_PI/8;
571 redraw=1;
572 break;
573 case '<':
574 animphase-=M_PI/8;
575 redraw=1;
576 break;
577 case 'v':
578 switch (structplot) {
579 case SPstruct: printf(" --struct"); break;
580 case SPtags: printf(" --tags"); break;
581 case SPcurrents: printf(" --currents"); break;
582 case SPanim: printf(" --animation"); break;
583 }
584 switch (gainplot) {
585 case GPnearfield: printf(" --near"); break;
586 case GPslice: printf(" --slice"); break;
587 case GPframe: printf(" --frame"); break;
588 case GPopaque: printf(" --opaque"); break;
589 }
590 if (gainplot==GPslice || gainplot==GPframe || gainplot==GPopaque) switch (gainscale) {
591 case GSlinpower: printf(" --linpower"); break;
592 case GSlinvolt: printf(" --linvolt"); break;
593 case GSlog: printf(" --log"); break;
594 case GSarrl: printf(" --arrl"); break;
595 }
596 if (gainplot==GPslice || gainplot==GPframe || gainplot==GPopaque || structplot==SPcurrents) switch (polarization) {
597 case POLnone: printf(" --pol=total"); break;
598 case POLhor: printf(" --pol=hor"); break;
599 case POLvert: printf(" --pol=vert"); break;
600 case POLlhcp: printf(" --pol=lhcp"); break;
601 case POLrhcp: printf(" --pol=rhcp"); break;
602 case POLcolour: printf(" --pol=colour"); break;
603 }
604 printf("\n");
605 if (structplot!=SPnone || gainplot!=SPnone) printf(" --view=%g,%g,%g,%g,%g",phi,theta,zoom,trx,try);
606 if (numneco>1) printf(" --freq=%g",neco[rp_index].f);
607 printf("\n");
608 if (structplot==SPanim || gainplot==GPnearfield) printf(" --afreq=%g --aphase=%g",animfreq,animphase*180/M_PI);
609 if (gainplot==GPnearfield) printf(" --escale=%g --hscale=%g%s",escale, hscale, show_p?"":" --hidepoynting");
610 if (structplot==SPanim) printf(" --iscale=%g --qscale=%g",iscale, qscale);
611 printf("\n");
612 break;
613 case 'z':
614 if (animfreq==old_animfreq) break;
615 if (animfreq==0) { animfreq=old_animfreq; old_animfreq=0; }
616 else { old_animfreq=animfreq; animfreq=0; }
617 break;
618 default:
619 return FALSE;
620 }
621 return TRUE;
622 }
623
624
625
626
627
cmd_reload(void)628 void cmd_reload(void)
629 {
630 reread();
631 redraw=redraw2=1;
632 gtk_widget_grab_focus(gdraw1);
633 gtk_widget_grab_focus(gdraw2);
634 }
635
cmd_X(void)636 void cmd_X(void)
637 {
638 phi=0; theta=90; redraw=1;
639 scaleplot=1;
640 calcproj();
641 calc_vgain();
642 if (plot2_vgain && redraw2==0) redraw2=2;
643 upd_msg();
644 gtk_widget_grab_focus(gdraw1);
645 }
646
cmd_Y()647 void cmd_Y()
648 {
649 phi=90; theta=90; redraw=1;
650 scaleplot=1;
651 calcproj();
652 calc_vgain();
653 if (plot2_vgain && redraw2==0) redraw2=2;
654 upd_msg();
655 gtk_widget_grab_focus(gdraw1);
656 }
657
cmd_Z()658 void cmd_Z()
659 {
660 phi=0; theta=0; redraw=1;
661 scaleplot=1;
662 calcproj();
663 calc_vgain();
664 if (plot2_vgain && redraw2==0) redraw2=2;
665 upd_msg();
666 gtk_widget_grab_focus(gdraw1);
667 }
668
669 char *GSnames[]={"lin.P","lin.V","arrl","log",NULL};
670
cmd_setgs(char ** p)671 void cmd_setgs(char **p)
672 {
673 gainscale=p-GSnames;
674 mark_gpo_invalid();
675 if (rp_index>=0) {
676 extr/=GAINSIZE;
677 process_nec_output(neco+rp_index);
678 }
679 upd_msg();
680 redraw=1;
681 gtk_widget_grab_focus(gdraw1);
682 }
683
684 char *GPnames[]={"none","slice","frame","opaque","near E/H",NULL};
685
cmd_setgp(char ** p)686 void cmd_setgp(char **p)
687 {
688 int o=gainplot;
689 gainplot=p-GPnames;
690 if (gainplot==GPnearfield) {
691 if (o!=GPnearfield && structplot!=SPanim) {
692 gtk_box_set_child_packing(GTK_BOX(vbox1), gdraw1, FALSE, FALSE, 0, GTK_PACK_START);
693 gtk_widget_show(botrow_anim);
694 gtk_box_set_child_packing(GTK_BOX(vbox1), gdraw1, TRUE, TRUE, 0, GTK_PACK_START);
695 }
696 } else if (o==GPnearfield && structplot!=SPanim) {
697 gtk_box_set_child_packing(GTK_BOX(vbox1), gdraw1, FALSE, FALSE, 0, GTK_PACK_START);
698 gtk_widget_hide(botrow_anim);
699 gtk_box_set_child_packing(GTK_BOX(vbox1), gdraw1, TRUE, TRUE, 0, GTK_PACK_START);
700 }
701 upd_msg();
702 redraw=1;
703 }
704
705 char *SPnames[]={"none","struct","+tags","currents","anim.",NULL};
706
cmd_setsp(char ** p)707 void cmd_setsp(char **p)
708 {
709 int o=structplot;
710 structplot=p-SPnames;
711 if (structplot==SPcurrents) {
712 if (o!=SPcurrents) {
713 gtk_box_set_child_packing(GTK_BOX(vbox1), gdraw1, FALSE, FALSE, 0, GTK_PACK_START);
714 gtk_widget_show(botrow_curr);
715 gtk_box_set_child_packing(GTK_BOX(vbox1), gdraw1, TRUE, TRUE, 0, GTK_PACK_START);
716 }
717 } else if (o==SPcurrents) {
718 gtk_box_set_child_packing(GTK_BOX(vbox1), gdraw1, FALSE, FALSE, 0, GTK_PACK_START);
719 gtk_widget_hide(botrow_curr);
720 gtk_box_set_child_packing(GTK_BOX(vbox1), gdraw1, TRUE, TRUE, 0, GTK_PACK_START);
721 }
722 if (structplot==SPanim) {
723 if (o!=SPanim && gainplot!=GPnearfield) {
724 gtk_box_set_child_packing(GTK_BOX(vbox1), gdraw1, FALSE, FALSE, 0, GTK_PACK_START);
725 gtk_widget_show(botrow_anim);
726 gtk_box_set_child_packing(GTK_BOX(vbox1), gdraw1, TRUE, TRUE, 0, GTK_PACK_START);
727 }
728 } else if (o==SPanim && gainplot!=GPnearfield) {
729 gtk_box_set_child_packing(GTK_BOX(vbox1), gdraw1, FALSE, FALSE, 0, GTK_PACK_START);
730 gtk_widget_hide(botrow_anim);
731 gtk_box_set_child_packing(GTK_BOX(vbox1), gdraw1, TRUE, TRUE, 0, GTK_PACK_START);
732 }
733 redraw=1;
734 }
735
736
cmd_togglelock(GtkWidget * w,gpointer * f)737 void cmd_togglelock(GtkWidget *w, gpointer *f)
738 {
739 phasedirlock = GTK_TOGGLE_BUTTON(w)->active;
740 if (phasedirlock) {
741 phasephi = phi;
742 phasetheta = theta;
743 } else {
744 if (structplot==SPcurrents) {
745 calcproj();
746 redraw=1;
747 }
748 }
749 gtk_widget_grab_focus(gdraw1);
750 }
751
752
753 char *POLnames[]={"total","hor.","vert.","lhcp","rhcp","colour",NULL};
754
cmd_setpol(char ** p)755 void cmd_setpol(char **p)
756 {
757 polarization=p-POLnames;
758 mark_gpo_invalid();
759 if (rp_index>=0) {
760 extr/=GAINSIZE;
761 process_nec_output(neco+rp_index);
762 }
763 redraw=1;
764 calc_vgain();
765 redraw2=1;
766 }
767
768 char *DCnames[]={"no","yes",NULL};
769
cmd_setdc(char ** p)770 void cmd_setdc(char **p)
771 {
772 distcor=p-DCnames;
773 redraw=1;
774 }
775
776
cmd_phaseoffset(GtkAdjustment * adj)777 void cmd_phaseoffset(GtkAdjustment *adj)
778 {
779 phaseoffset=adj->value;
780 redraw=1;
781 gtk_widget_grab_focus(gdraw1);
782 }
783
cmd_maxthickness(GtkAdjustment * adj)784 void cmd_maxthickness(GtkAdjustment *adj)
785 {
786 maxthickness=adj->value;
787 redraw=1;
788 gtk_widget_grab_focus(gdraw1);
789 }
790
cmd_escale(GtkAdjustment * adj)791 void cmd_escale(GtkAdjustment *adj)
792 {
793 escale=adj->value;
794 redraw=1;
795 gtk_widget_grab_focus(gdraw1);
796 }
797
cmd_hscale(GtkAdjustment * adj)798 void cmd_hscale(GtkAdjustment *adj)
799 {
800 hscale=adj->value;
801 redraw=1;
802 gtk_widget_grab_focus(gdraw1);
803 }
804
cmd_qscale(GtkAdjustment * adj)805 void cmd_qscale(GtkAdjustment *adj)
806 {
807 qscale=adj->value;
808 redraw=1;
809 gtk_widget_grab_focus(gdraw1);
810 }
811
cmd_iscale(GtkAdjustment * adj)812 void cmd_iscale(GtkAdjustment *adj)
813 {
814 iscale=adj->value;
815 redraw=1;
816 gtk_widget_grab_focus(gdraw1);
817 }
818
cmd_animfreq(GtkAdjustment * adj)819 void cmd_animfreq(GtkAdjustment *adj)
820 {
821 animfreq=adj->value;
822 gtk_widget_grab_focus(gdraw1);
823 }
824
825
cmd_export_eps_ok(GtkWidget * w,GtkFileSelection * fs)826 void cmd_export_eps_ok(GtkWidget *w, GtkFileSelection *fs)
827 {
828 const char *s;
829 s=gtk_file_selection_get_filename(fs);
830 if (write_postscript(s,draw_all,winsizex,winsizey)) fprintf(stderr,"Error writing postscript\n");
831 gtk_widget_destroy(GTK_WIDGET(fs));
832 }
833
834 #ifdef HAVE_LIBPNG
cmd_export_png_ok(GtkWidget * w,GtkFileSelection * fs)835 void cmd_export_png_ok(GtkWidget *w, GtkFileSelection *fs)
836 {
837 const char *s;
838 s=gtk_file_selection_get_filename(fs);
839 if (write_png(1,s)) fprintf(stderr,"Error writing PNG\n");
840 gtk_widget_destroy(GTK_WIDGET(fs));
841 }
842 #endif
843
844
do_animation(void)845 int do_animation(void)
846 {
847 if (animfreq==0) return 1;
848 if (animbusy) return 1;
849 if (structplot!=SPanim && gainplot!=GPnearfield) return 1;
850 animphase+=0.002*anim_update_interval*M_PI*animfreq;
851 if (animphase>2*M_PI) animphase-=2*M_PI;
852 redraw=1;
853 animbusy=1;
854 return 1;
855 }
856
857
858 /* -------------------- event handlers (and their supporting code) for window 2 (frequency plot) ---------------------- */
859
860
expose_event2(GtkWidget * w,GdkEventExpose * ev,gpointer dummy)861 gint expose_event2(GtkWidget *w,GdkEventExpose *ev,gpointer dummy)
862 {
863 int x;
864 if(ev->count != 0) return TRUE;
865 if (rp_index<0) return TRUE;
866 x=freqx(neco[rp_index].f);
867 gdk_gc_set_foreground(ggc2,&c_back);
868 gdk_draw_line(gdraw2->window,ggc2,x,0,x,win2sizey);
869 return TRUE;
870 }
871
872
resize_event2(GtkWidget * w,GdkEventConfigure * ev,gpointer dummy)873 gint resize_event2(GtkWidget *w,GdkEventConfigure *ev,gpointer dummy)
874 {
875 if (!gbackg2) return FALSE;
876 win2sizex=ev->width;
877 win2sizey=ev->height;
878 gdk_pixmap_unref(gbackg2);
879 gbackg2=gdk_pixmap_new(w->window,win2sizex,win2sizey,gdk_drawable_get_depth(w->window));
880
881 redraw2=1;
882 return TRUE;
883 }
884
885
886
buttonpress_event2(GtkWidget * w,GdkEventButton * ev,gpointer dummy)887 gint buttonpress_event2(GtkWidget *w,GdkEventButton *ev,gpointer dummy)
888 {
889 int i;
890 i=freqindex(xfreq(ev->x));
891 if (i<0) return TRUE;
892 if (rp_index==i) return TRUE;
893 rp_index=i;
894 setrpfreq();
895 return TRUE;
896 }
897
898
899
motion_event2(GtkWidget * w,GdkEventMotion * ev,gpointer dummy)900 gint motion_event2(GtkWidget *w,GdkEventMotion *ev,gpointer dummy)
901 {
902 int pos_x,pos_y;
903 unsigned int keys_buttons;
904
905 /* Get the pointer position*/
906 gdk_window_get_pointer(w->window, &pos_x, &pos_y, &keys_buttons);
907
908 ev->x = pos_x;
909 ev->y = pos_y;
910 buttonpress_event2(w,(GdkEventButton*)ev,dummy);
911 return TRUE;
912 }
913
914
keypress_event2(GtkWidget * w,GdkEventKey * ev,gpointer dummy)915 gint keypress_event2(GtkWidget *w,GdkEventKey *ev,gpointer dummy)
916 {
917 int i;
918
919 switch (ev->keyval) {
920 case GDK_Page_Down:
921 case GDK_KP_Page_Down:
922 case GDK_Down:
923 case GDK_KP_Down:
924 case GDK_Left:
925 case GDK_KP_Left:
926 i=rp_index;
927 do {
928 i--;
929 if (i<0) return TRUE;
930 } while (neco[i].rp==NULL);
931 rp_index=i;
932 setrpfreq();
933 break;
934 case GDK_Page_Up:
935 case GDK_KP_Page_Up:
936 case GDK_Up:
937 case GDK_KP_Up:
938 case GDK_Right:
939 case GDK_KP_Right:
940 i=rp_index;
941 do {
942 i++;
943 if (i>=numneco) return TRUE;
944 } while (neco[i].rp==NULL);
945 rp_index=i;
946 setrpfreq();
947 break;
948 default:
949 return FALSE;
950 }
951 return TRUE;
952 }
953
954
955
cmd_export2_eps_ok(GtkWidget * w,GtkFileSelection * fs)956 void cmd_export2_eps_ok(GtkWidget *w, GtkFileSelection *fs)
957 {
958 const char *s;
959 s=gtk_file_selection_get_filename(fs);
960 if (write_postscript(s,draw_all2,win2sizex,win2sizey)) fprintf(stderr,"Error writing postscript\n");
961 gtk_widget_destroy(GTK_WIDGET(fs));
962 }
963
964 #ifdef HAVE_LIBPNG
cmd_export2_png_ok(GtkWidget * w,GtkFileSelection * fs)965 void cmd_export2_png_ok(GtkWidget *w, GtkFileSelection *fs)
966 {
967 const char *s;
968 s=gtk_file_selection_get_filename(fs);
969 if (write_png(2,s)) fprintf(stderr,"Error writing PNG\n");
970 gtk_widget_destroy(GTK_WIDGET(fs));
971 }
972 #endif
973
cmd_export(GtkWidget * ww,void (* f)(),char * ext)974 void cmd_export(GtkWidget *ww,void(*f)(),char *ext)
975 {
976 GtkWidget *w;
977 char *s,*p;
978
979 w=gtk_file_selection_new("Export PostScript");
980 gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION (w)->ok_button), "clicked",
981 (GtkSignalFunc) f, w);
982 gtk_signal_connect_object(GTK_OBJECT(GTK_FILE_SELECTION (w)->cancel_button), "clicked",
983 (GtkSignalFunc) gtk_widget_destroy, GTK_OBJECT(w));
984
985 s=mymalloc(strlen(inputfilename)+8);
986 strcpy(s,inputfilename);
987 p=strrchr(s,'.');
988 if (!p) p=s+strlen(s);
989 strcpy(p,ext);
990 gtk_file_selection_set_filename(GTK_FILE_SELECTION(w),s);
991 free(s);
992
993 gtk_widget_show(w);
994 gtk_widget_grab_focus(gdraw1);
995 gtk_widget_grab_focus(gdraw2);
996 }
997
cmd_export_eps(GtkWidget * ww,void (* f)())998 void cmd_export_eps(GtkWidget *ww,void(*f)())
999 {
1000 cmd_export(ww,f,".eps");
1001 }
1002
1003 #ifdef HAVE_LIBPNG
cmd_export_png(GtkWidget * ww,void (* f)())1004 void cmd_export_png(GtkWidget *ww,void(*f)())
1005 {
1006 cmd_export(ww,f,".png");
1007 }
1008 #endif
1009
1010
1011
cmd_setZ0(GtkEntry * w)1012 void cmd_setZ0(GtkEntry *w)
1013 {
1014 double r;
1015 const char *q,*p;
1016 char s[20];
1017
1018 q=gtk_entry_get_text(w);
1019 p=strchr(q,'=');
1020 if (p) p++;
1021 else p=q;
1022 r=atof(p);
1023 if (r>0) {
1024 int i;
1025 r0=r;
1026 for (i=0;i<numneco;i++) calcswr(neco+i);
1027 if (plot2_swr) redraw2=1;
1028 }
1029 sprintf(s,"Z0=%g",r0);
1030 gtk_entry_set_text(w,s);
1031 }
1032
1033
1034 /* -------------------- X and GTK initialisation ------------------------------------------------ */
1035
getcolor(char * name,GdkColor * xc)1036 void getcolor(char *name,GdkColor *xc)
1037 {
1038 if (depth==1) { /* on 1bpp displays, choose black for everything except the background */
1039 if (strcmp(name,C_BG)) name="black";
1040 else name="white";
1041 }
1042 gdk_color_parse(name,xc);
1043 if (!gdk_colormap_alloc_color(gcm,xc,TRUE,FALSE)) {
1044 /* if allocation failed, use black */
1045 gdk_color_black(gcm,xc);
1046 }
1047 }
1048
1049
1050 /* Function for conversion from hue/lightness/saturation to red/green/blue.
1051 This function has been copied literally from GTK+ (gtkstyle.c).
1052 However, I doubt that this has the property of "perceptual uniformity";
1053 see e.g. Poynton's Color FAQ at
1054 http://www.inforamp.net/~poynton/notes/colour_and_gamma/ColorFAQ.html .
1055 */
1056 static void
hls_to_rgb(gdouble * h,gdouble * l,gdouble * s)1057 hls_to_rgb (gdouble *h,
1058 gdouble *l,
1059 gdouble *s)
1060 {
1061 gdouble hue;
1062 gdouble lightness;
1063 gdouble saturation;
1064 gdouble m1, m2;
1065 gdouble r, g, b;
1066
1067 lightness = *l;
1068 saturation = *s;
1069
1070 if (lightness <= 0.5)
1071 m2 = lightness * (1 + saturation);
1072 else
1073 m2 = lightness + saturation - lightness * saturation;
1074 m1 = 2 * lightness - m2;
1075
1076 if (saturation == 0)
1077 {
1078 *h = lightness;
1079 *l = lightness;
1080 *s = lightness;
1081 }
1082 else
1083 {
1084 hue = *h + 120;
1085 while (hue > 360)
1086 hue -= 360;
1087 while (hue < 0)
1088 hue += 360;
1089
1090 if (hue < 60)
1091 r = m1 + (m2 - m1) * hue / 60;
1092 else if (hue < 180)
1093 r = m2;
1094 else if (hue < 240)
1095 r = m1 + (m2 - m1) * (240 - hue) / 60;
1096 else
1097 r = m1;
1098
1099 hue = *h;
1100 while (hue > 360)
1101 hue -= 360;
1102 while (hue < 0)
1103 hue += 360;
1104
1105 if (hue < 60)
1106 g = m1 + (m2 - m1) * hue / 60;
1107 else if (hue < 180)
1108 g = m2;
1109 else if (hue < 240)
1110 g = m1 + (m2 - m1) * (240 - hue) / 60;
1111 else
1112 g = m1;
1113
1114 hue = *h - 120;
1115 while (hue > 360)
1116 hue -= 360;
1117 while (hue < 0)
1118 hue += 360;
1119
1120 if (hue < 60)
1121 b = m1 + (m2 - m1) * hue / 60;
1122 else if (hue < 180)
1123 b = m2;
1124 else if (hue < 240)
1125 b = m1 + (m2 - m1) * (240 - hue) / 60;
1126 else
1127 b = m1;
1128
1129 *h = r;
1130 *l = g;
1131 *s = b;
1132 }
1133 }
1134
get_currents_colors(void)1135 void get_currents_colors(void)
1136 {
1137 int i;
1138 double r,g,b;
1139
1140 for (i=0;i<NC_phase;i++) {
1141 r=i*360./NC_phase;
1142 g=0.5;
1143 b=1;
1144 hls_to_rgb(&r,&g,&b);
1145 c_currents[i].red=r*65535;
1146 c_currents[i].green=g*65535;
1147 c_currents[i].blue=b*65535;
1148 gdk_colormap_alloc_color(gcm,c_currents+i,TRUE,TRUE);
1149 }
1150 }
1151
1152
make_option_menu(char ** list,void (* f)(char **),int v)1153 GtkWidget *make_option_menu(char **list,void (*f)(char **),int v)
1154 {
1155 GtkWidget *menu, *button;
1156 GtkWidget *w;
1157 char **p;
1158
1159 menu=gtk_menu_new();
1160 p=list;
1161 while (*p) {
1162 w=gtk_menu_item_new_with_label(*p);
1163 gtk_menu_append(GTK_MENU(menu), w);
1164 gtk_widget_show(w);
1165 gtk_signal_connect_object(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(f), (gpointer)(p));
1166 p++;
1167 }
1168 gtk_menu_set_active(GTK_MENU(menu),v);
1169
1170 button=gtk_option_menu_new();
1171 gtk_option_menu_set_menu(GTK_OPTION_MENU(button),menu);
1172
1173 return button;
1174 }
1175
cmd_quit(GtkWidget * w,gpointer * dummy)1176 void cmd_quit(GtkWidget *w,gpointer *dummy)
1177 {
1178 redraw=redraw2=0;
1179 quit=1;
1180 }
1181
toggle1helper(GtkWidget * w,gpointer * f)1182 void toggle1helper(GtkWidget *w, gpointer *f)
1183 {
1184 *(int*)f = GTK_TOGGLE_BUTTON(w)->active;
1185 redraw=1;
1186 gtk_widget_grab_focus(gdraw1);
1187 }
1188
toggle2helper(GtkWidget * w,gpointer * f)1189 void toggle2helper(GtkWidget *w, gpointer *f)
1190 {
1191 *(int*)f = GTK_TOGGLE_BUTTON(w)->active;
1192 redraw2=1;
1193 gtk_widget_grab_focus(gdraw2);
1194 }
1195
1196
maininitX(int really)1197 void maininitX(int really)
1198 {
1199 GtkWidget *win1, *win2;
1200 GtkWidget *vbox, *toprow;
1201 GtkWidget *w;
1202 GtkAccelGroup *acc;
1203 GdkBitmap *icon;
1204 GtkTooltips *tt;
1205 GtkObject *adj;
1206
1207 tt=gtk_tooltips_new();
1208 #define SET_TT(s) gtk_tooltips_set_tip(tt,w,s,NULL)
1209
1210 {
1211 GdkVisual *vi;
1212 vi = gdk_visual_get_best();
1213 depth=vi->depth;
1214 gcm=gdk_colormap_new(vi,FALSE);
1215 }
1216
1217 /* ----------- initialize window 1 (struct/gain plot) ------------------------------------------------------------- */
1218
1219 if (window1open) {
1220
1221 win1=gtk_window_new(GTK_WINDOW_TOPLEVEL);
1222 gtk_window_set_title(GTK_WINDOW(win1),"Xnecview");
1223 gtk_signal_connect(GTK_OBJECT(win1), "delete_event", GTK_SIGNAL_FUNC(cmd_quit), NULL);
1224 gtk_window_set_policy(GTK_WINDOW(win1),TRUE,TRUE,TRUE);
1225
1226 acc=gtk_accel_group_new();
1227
1228 /* ----- create the top row of buttons ----- */
1229
1230 toprow=gtk_hbox_new(FALSE,0);
1231
1232 w=gtk_button_new_with_label("quit"); gtk_box_pack_start(GTK_BOX(toprow), w, FALSE, FALSE, 0); gtk_widget_show(w);
1233 gtk_signal_connect(GTK_OBJECT(w), "clicked", GTK_SIGNAL_FUNC(cmd_quit), (gpointer)NULL);
1234 gtk_widget_add_accelerator(w, "clicked", acc, GDK_Q, 0,0);
1235 SET_TT("Quit the program");
1236
1237 w=gtk_button_new_with_label("reload"); gtk_box_pack_start(GTK_BOX(toprow), w, FALSE, FALSE, 0); gtk_widget_show(w);
1238 gtk_signal_connect(GTK_OBJECT(w), "clicked", GTK_SIGNAL_FUNC(cmd_reload), (gpointer)NULL);
1239 gtk_widget_add_accelerator(w, "clicked", acc, GDK_R, 0,0);
1240 gtk_widget_add_accelerator(w, "clicked", acc, GDK_period, 0,0);
1241 SET_TT("Reread the data files");
1242
1243 {
1244 /* create the 'export' menu; and to get that one into the top bar, we need to create a menu_bar too */
1245 GtkWidget *m,*v;
1246
1247 v=gtk_menu_item_new_with_label("export"); gtk_widget_show(v);
1248 m=gtk_menu_new(); gtk_menu_item_set_submenu(GTK_MENU_ITEM(v),m); gtk_widget_show(m);
1249 w=gtk_menu_item_new_with_label("PostScript"); gtk_menu_append(GTK_MENU(m),w); gtk_widget_show(w);
1250 gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(cmd_export_eps), (gpointer)cmd_export_eps_ok);
1251 #ifdef HAVE_LIBPNG
1252 w=gtk_menu_item_new_with_label("PNG"); gtk_menu_append(GTK_MENU(m),w); gtk_widget_show(w);
1253 gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(cmd_export_png), (gpointer)cmd_export_png_ok);
1254 #endif
1255 w=gtk_menu_bar_new(); gtk_box_pack_start(GTK_BOX(toprow), w, FALSE, FALSE, 0); gtk_widget_show(w);
1256 gtk_menu_bar_append(GTK_MENU_BAR(w),v);
1257 }
1258
1259 w=make_option_menu(SPnames,cmd_setsp,structplot); gtk_box_pack_start(GTK_BOX(toprow), w, FALSE, FALSE, 0); gtk_widget_show(w);
1260 SET_TT("Choose type of antenna structure display");
1261
1262 w=make_option_menu(GPnames,cmd_setgp,gainplot); gtk_box_pack_start(GTK_BOX(toprow), w, FALSE, FALSE, 0); gtk_widget_show(w);
1263 SET_TT("Choose type of radiation pattern display");
1264
1265 w=make_option_menu(GSnames,cmd_setgs,gainscale); gtk_box_pack_start(GTK_BOX(toprow), w, FALSE, FALSE, 0); gtk_widget_show(w);
1266 SET_TT("Choose gain scale");
1267
1268 w=make_option_menu(POLnames,cmd_setpol,polarization); gtk_box_pack_start(GTK_BOX(toprow), w, FALSE, FALSE, 0); gtk_widget_show(w);
1269 SET_TT("Choose polarisation");
1270
1271 w=gtk_button_new_with_label("X"); gtk_box_pack_start(GTK_BOX(toprow), w, FALSE, FALSE, 0); gtk_widget_show(w);
1272 gtk_signal_connect(GTK_OBJECT(w), "clicked", GTK_SIGNAL_FUNC(cmd_X), (gpointer)NULL);
1273 SET_TT("View along X axis");
1274
1275 w=gtk_button_new_with_label("Y"); gtk_box_pack_start(GTK_BOX(toprow), w, FALSE, FALSE, 0); gtk_widget_show(w);
1276 gtk_signal_connect(GTK_OBJECT(w), "clicked", GTK_SIGNAL_FUNC(cmd_Y), (gpointer)NULL);
1277 SET_TT("View along Y axis");
1278
1279 w=gtk_button_new_with_label("Z"); gtk_box_pack_start(GTK_BOX(toprow), w, FALSE, FALSE, 0); gtk_widget_show(w);
1280 gtk_signal_connect(GTK_OBJECT(w), "clicked", GTK_SIGNAL_FUNC(cmd_Z), (gpointer)NULL);
1281 SET_TT("View along Z axis");
1282
1283 w=gtk_label_new(""); gtk_box_pack_start(GTK_BOX(toprow), w, TRUE, TRUE, 0); gtk_widget_show(w);
1284 msgwidget=GTK_LABEL(w);
1285
1286 /* ----- create the bottom row of buttons for the currents display ----- */
1287
1288 botrow_curr=gtk_hbox_new(FALSE,0);
1289
1290 w=make_option_menu(DCnames,cmd_setdc,distcor); gtk_box_pack_start(GTK_BOX(botrow_curr), w, FALSE, FALSE, 0); gtk_widget_show(w);
1291 SET_TT("Toggle distance compensation");
1292
1293 w=gtk_toggle_button_new_with_label("lock"); gtk_box_pack_start(GTK_BOX(botrow_curr), w, FALSE, FALSE, 0); gtk_widget_show(w);
1294 gtk_signal_connect(GTK_OBJECT(w), "toggled", GTK_SIGNAL_FUNC(cmd_togglelock), (gpointer)&phasedirlock);
1295 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), phasedirlock);
1296 SET_TT("(Un)Lock direction for phase");
1297
1298 adj = gtk_adjustment_new( phaseoffset, -180.0, 180.0, 0.0, 0.0, 0.0 );
1299 gtk_signal_connect(adj, "value_changed", GTK_SIGNAL_FUNC(cmd_phaseoffset), (gpointer)NULL);
1300 w = gtk_hscale_new(GTK_ADJUSTMENT(adj)); gtk_box_pack_start(GTK_BOX(botrow_curr), w, TRUE, TRUE, 0); gtk_widget_show(w);
1301 SET_TT("Set phase offset");
1302
1303 adj = gtk_adjustment_new( maxthickness, 0.0, 50.0, 0.0, 0.0, 0.0 );
1304 gtk_signal_connect(adj, "value_changed", GTK_SIGNAL_FUNC(cmd_maxthickness), (gpointer)NULL);
1305 w = gtk_hscale_new(GTK_ADJUSTMENT(adj)); gtk_box_pack_start(GTK_BOX(botrow_curr), w, TRUE, TRUE, 0); gtk_widget_show(w);
1306 SET_TT("Set thickness");
1307
1308 botrow_curr->requisition.width=10; /* make sure that the window can later be resized to something "too" small, if the user wishes so */
1309
1310 /* ----- create the bottom row of buttons for the animated displays of currents, charges and near field ----- */
1311
1312 botrow_anim=gtk_hbox_new(FALSE,0);
1313
1314 adj = gtk_adjustment_new( iscale, 0.0, 10.0, 0.0, 0.0, 0.0 );
1315 gtk_signal_connect(adj, "value_changed", GTK_SIGNAL_FUNC(cmd_iscale), (gpointer)NULL);
1316 w = gtk_hscale_new(GTK_ADJUSTMENT(adj)); gtk_box_pack_start(GTK_BOX(botrow_anim), w, TRUE, TRUE, 0); gtk_widget_show(w);
1317 SET_TT("Set scale factor for currents");
1318
1319 adj = gtk_adjustment_new( qscale, 0.0, 25.0, 0.0, 0.0, 0.0 );
1320 gtk_signal_connect(adj, "value_changed", GTK_SIGNAL_FUNC(cmd_qscale), (gpointer)NULL);
1321 w = gtk_hscale_new(GTK_ADJUSTMENT(adj)); gtk_box_pack_start(GTK_BOX(botrow_anim), w, TRUE, TRUE, 0); gtk_widget_show(w);
1322 SET_TT("Set scale factor for charges");
1323
1324 adj = gtk_adjustment_new( escale, 0.0, 25.0, 0.0, 0.0, 0.0 );
1325 gtk_signal_connect(adj, "value_changed", GTK_SIGNAL_FUNC(cmd_escale), (gpointer)NULL);
1326 w = gtk_hscale_new(GTK_ADJUSTMENT(adj)); gtk_box_pack_start(GTK_BOX(botrow_anim), w, TRUE, TRUE, 0); gtk_widget_show(w);
1327 SET_TT("Set electric field scale factor");
1328
1329 adj = gtk_adjustment_new( hscale, 0.0, 25.0, 0.0, 0.0, 0.0 );
1330 gtk_signal_connect(adj, "value_changed", GTK_SIGNAL_FUNC(cmd_hscale), (gpointer)NULL);
1331 w = gtk_hscale_new(GTK_ADJUSTMENT(adj)); gtk_box_pack_start(GTK_BOX(botrow_anim), w, TRUE, TRUE, 0); gtk_widget_show(w);
1332 SET_TT("Set magnetic field scale factor");
1333
1334 #define ADDTOGGLE1anim(label,p,s) \
1335 w=gtk_toggle_button_new_with_label(label); gtk_box_pack_start(GTK_BOX(botrow_anim), w, FALSE, FALSE, 0); gtk_widget_show(w); \
1336 gtk_signal_connect(GTK_OBJECT(w), "toggled", GTK_SIGNAL_FUNC(toggle1helper), (gpointer)p); \
1337 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), *p); \
1338 SET_TT(s);
1339
1340 gdraw1=w; /* necessary since in the following toggle1helper() will be called, so gdraw1 should be valid */
1341 ADDTOGGLE1anim("P", &show_p, "Toggle display of Poynting vector");
1342
1343 adj = gtk_adjustment_new( animfreq, 0.0, 2.0, 0.0, 0.0, 0.0 );
1344 gtk_signal_connect(adj, "value_changed", GTK_SIGNAL_FUNC(cmd_animfreq), (gpointer)NULL);
1345 w = gtk_hscale_new(GTK_ADJUSTMENT(adj)); gtk_box_pack_start(GTK_BOX(botrow_anim), w, TRUE, TRUE, 0); gtk_widget_show(w);
1346 SET_TT("Set animation frequency");
1347
1348
1349
1350 /* ----- create vbox containing everything ----- */
1351
1352 vbox1=gtk_vbox_new(FALSE,0);
1353 gtk_box_pack_start(GTK_BOX(vbox1), toprow, FALSE, FALSE, 0);
1354 gtk_box_pack_end(GTK_BOX(vbox1), botrow_curr, FALSE, FALSE, 0);
1355 gtk_box_pack_end(GTK_BOX(vbox1), botrow_anim, FALSE, FALSE, 0);
1356 gdraw1=w=gtk_drawing_area_new();
1357 gtk_drawing_area_size(GTK_DRAWING_AREA(w),winsizex,winsizey);
1358 gtk_box_pack_start(GTK_BOX(vbox1), w, TRUE, TRUE, 0);
1359 gtk_widget_show(w);
1360
1361 gtk_signal_connect( GTK_OBJECT(w), "configure_event", GTK_SIGNAL_FUNC(resize_event), NULL);
1362 gtk_signal_connect( GTK_OBJECT(w), "button_press_event", GTK_SIGNAL_FUNC(buttonpress_event), NULL);
1363 gtk_signal_connect( GTK_OBJECT(w), "button_release_event", GTK_SIGNAL_FUNC(buttonrelease_event), NULL);
1364 gtk_signal_connect( GTK_OBJECT(w), "motion_notify_event", GTK_SIGNAL_FUNC(motion_event), NULL);
1365 gtk_signal_connect_after( GTK_OBJECT(w), "key_press_event", GTK_SIGNAL_FUNC(keypress_event), NULL);
1366 gtk_widget_set_events( w, GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK |
1367 GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
1368 GDK_KEY_PRESS_MASK );
1369 GTK_WIDGET_SET_FLAGS(w, GTK_CAN_FOCUS);
1370
1371 gtk_container_add(GTK_CONTAINER(win1), vbox1);
1372 gtk_widget_show(toprow);
1373 if (structplot==SPcurrents) gtk_widget_show(botrow_curr);
1374 if (gainplot==GPnearfield || structplot==SPanim) gtk_widget_show(botrow_anim);
1375 gtk_widget_show(vbox1);
1376 if (really) gtk_widget_show(win1);
1377 else gtk_widget_realize(gdraw1);
1378
1379 gtk_widget_grab_focus(gdraw1);
1380
1381 gtk_window_add_accel_group(GTK_WINDOW(win1), acc);
1382
1383 ggc = gdk_gc_new(w->window);
1384
1385 if (toprow->requisition.width>winsizex) {
1386 winsizex=toprow->requisition.width;
1387 calcproj();
1388 }
1389 gbackg=gdk_pixmap_new(w->window,winsizex,winsizey,gdk_drawable_get_depth(w->window));
1390
1391 upd_msg();
1392
1393 icon=gdk_bitmap_create_from_data(win1->window,icon_bits,icon_width,icon_height);
1394 gdk_window_set_icon(win1->window, NULL, icon, NULL);
1395 }
1396
1397 /* ----------- initialize window 2 (plots of gain, SWR etc. vs frequency) ----------------------------------------------- */
1398
1399 if (window2open) {
1400 win2=gtk_window_new(GTK_WINDOW_TOPLEVEL);
1401 gtk_window_set_title(GTK_WINDOW(win2),"Xnecview");
1402 gtk_signal_connect(GTK_OBJECT(win2), "delete_event", GTK_SIGNAL_FUNC(cmd_quit), NULL);
1403 gtk_window_set_policy(GTK_WINDOW(win2),TRUE,TRUE,FALSE);
1404
1405 acc=gtk_accel_group_new();
1406
1407 toprow=gtk_hbox_new(FALSE,0);
1408
1409 w=gtk_button_new_with_label("quit"); gtk_box_pack_start(GTK_BOX(toprow), w, FALSE, FALSE, 0); gtk_widget_show(w);
1410 gtk_signal_connect(GTK_OBJECT(w), "clicked", GTK_SIGNAL_FUNC(cmd_quit), (gpointer)NULL);
1411 gtk_widget_add_accelerator(w, "clicked", acc, GDK_Q, 0,0);
1412 SET_TT("Quit the program");
1413
1414 w=gtk_button_new_with_label("reload"); gtk_box_pack_start(GTK_BOX(toprow), w, FALSE, FALSE, 0); gtk_widget_show(w);
1415 gtk_signal_connect(GTK_OBJECT(w), "clicked", GTK_SIGNAL_FUNC(cmd_reload), (gpointer)NULL);
1416 gtk_widget_add_accelerator(w, "clicked", acc, GDK_R, 0,0);
1417 gtk_widget_add_accelerator(w, "clicked", acc, GDK_period, 0,0);
1418 SET_TT("Reread the data files");
1419
1420 {
1421 /* create the 'export' menu; and to get that one into the top bar, we need to create a menu_bar too */
1422 GtkWidget *m,*v;
1423
1424 v=gtk_menu_item_new_with_label("export"); gtk_widget_show(v);
1425 m=gtk_menu_new(); gtk_menu_item_set_submenu(GTK_MENU_ITEM(v),m); gtk_widget_show(m);
1426 w=gtk_menu_item_new_with_label("PostScript"); gtk_menu_append(GTK_MENU(m),w); gtk_widget_show(w);
1427 gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(cmd_export_eps), (gpointer)cmd_export2_eps_ok);
1428 #ifdef HAVE_LIBPNG
1429 w=gtk_menu_item_new_with_label("PNG"); gtk_menu_append(GTK_MENU(m),w); gtk_widget_show(w);
1430 gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(cmd_export_png), (gpointer)cmd_export2_png_ok);
1431 #endif
1432 w=gtk_menu_bar_new(); gtk_box_pack_start(GTK_BOX(toprow), w, FALSE, FALSE, 0); gtk_widget_show(w);
1433 gtk_menu_bar_append(GTK_MENU_BAR(w),v);
1434 }
1435
1436 w=gtk_entry_new_with_max_length(7); gtk_box_pack_start(GTK_BOX(toprow), w, TRUE, TRUE, 0); gtk_widget_show(w);
1437 gtk_widget_set_usize(w,70,0);
1438 gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(cmd_setZ0), (gpointer)NULL);
1439 gtk_signal_connect(GTK_OBJECT(w), "leave_notify_event", GTK_SIGNAL_FUNC(cmd_setZ0), NULL);
1440 cmd_setZ0(GTK_ENTRY(w));
1441 SET_TT("Reference impedance for SWR");
1442
1443 #define ADDTOGGLE2(label,p,s) \
1444 w=gtk_toggle_button_new_with_label(label); gtk_box_pack_start(GTK_BOX(toprow), w, FALSE, FALSE, 0); gtk_widget_show(w); \
1445 gtk_signal_connect(GTK_OBJECT(w), "toggled", GTK_SIGNAL_FUNC(toggle2helper), (gpointer)p); \
1446 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), *p); \
1447 SET_TT(s);
1448
1449 gdraw2=w; /* necessary since in the following toggle2helper() will be called, so gdraw2 should be valid */
1450 ADDTOGGLE2("vgain", &plot2_vgain, "Toggle plot of gain toward viewer");
1451 ADDTOGGLE2("maxgain", &plot2_maxgain, "Toggle plot of maximum gain");
1452 ADDTOGGLE2("dir", &plot2_dir, "Toggle plot of direction of maximum gain");
1453 ADDTOGGLE2("SWR", &plot2_swr, "Toggle plot of SWR");
1454 ADDTOGGLE2("Re/Im", &plot2_z, "Toggle plot of impedance (Re/Im)");
1455 ADDTOGGLE2("phi/abs", &plot2_z2, "Toggle plot of impedance (phi/abs)");
1456
1457 vbox=gtk_vbox_new(FALSE,0);
1458 gtk_box_pack_start(GTK_BOX(vbox), toprow, FALSE, FALSE, 0);
1459 gdraw2=w=gtk_drawing_area_new();
1460 gtk_drawing_area_size(GTK_DRAWING_AREA(w),win2sizex,win2sizey);
1461 gtk_box_pack_start(GTK_BOX(vbox), w, TRUE, TRUE, 0);
1462 gtk_widget_show(w);
1463 GTK_WIDGET_SET_FLAGS(w, GTK_CAN_FOCUS);
1464
1465 gtk_signal_connect( GTK_OBJECT(w), "configure_event", GTK_SIGNAL_FUNC(resize_event2), NULL);
1466 gtk_signal_connect( GTK_OBJECT(w), "button_press_event", GTK_SIGNAL_FUNC(buttonpress_event2), NULL);
1467 gtk_signal_connect( GTK_OBJECT(w), "motion_notify_event", GTK_SIGNAL_FUNC(motion_event2), NULL);
1468 gtk_signal_connect_after( GTK_OBJECT(w), "key_press_event", GTK_SIGNAL_FUNC(keypress_event2), NULL);
1469 gtk_widget_set_events( w, GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK |
1470 GDK_BUTTON_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
1471 GDK_KEY_PRESS_MASK );
1472
1473 gtk_container_add(GTK_CONTAINER(win2), vbox);
1474 gtk_widget_show(toprow);
1475 gtk_widget_show(vbox);
1476 if (really) gtk_widget_show(win2);
1477 else gtk_widget_realize(gdraw2);
1478
1479 gtk_widget_grab_focus(gdraw2);
1480
1481 gtk_window_add_accel_group(GTK_WINDOW(win2), acc);
1482
1483 ggc2 = gdk_gc_new(w->window);
1484
1485 gbackg2=gdk_pixmap_new(w->window,win2sizex,win2sizey,gdk_drawable_get_depth(w->window));
1486
1487 gtk_signal_connect( GTK_OBJECT(w), "expose_event", GTK_SIGNAL_FUNC(expose_event2), NULL);
1488
1489 icon=gdk_bitmap_create_from_data(win2->window,icon_bits,icon_width,icon_height);
1490 gdk_window_set_icon(win2->window, NULL, icon, NULL);
1491 }
1492
1493
1494 /* ----------- initialize some variables etc. that are needed for direct Xlib drawing ------------ */
1495
1496 getcolor("white",&c_bg);
1497 getcolor(C_AXIS,&c_axis);
1498 getcolor(C_WIRE,&c_wire);
1499 getcolor(C_SURF,&c_surf);
1500 getcolor(C_BACK,&c_back);
1501 getcolor(C_GAIN,&c_gain);
1502 getcolor(C_SCALE,&c_scale);
1503 getcolor(C_EXCI,&c_exci);
1504 getcolor(C_LOAD,&c_load);
1505 getcolor(C_NETW,&c_netw);
1506 getcolor(C_INACTIVE,&c_inactive);
1507 getcolor(C_EFIELD,&c_efield);
1508 getcolor(C_HFIELD,&c_hfield);
1509 getcolor(C_POYNTING,&c_poynting);
1510 getcolor(C_QPOS,&c_qpos);
1511 getcolor(C_QNEG,&c_qneg);
1512 getcolor(C_GAIN_LIN,&c_gain_lin);
1513 getcolor(C_GAIN_LHCP,&c_gain_lhcp);
1514 getcolor(C_GAIN_RHCP,&c_gain_rhcp);
1515 get_currents_colors();
1516
1517 gfont=gdk_font_load(XFONT);
1518 if (!gfont) gfont=gdk_font_load("fixed");
1519 if (!gfont) { fprintf(stderr,"Can't load fonts '%s' or 'fixed'.\n",XFONT); exit(1); }
1520 fontheight=gfont->ascent+gfont->descent;
1521
1522 if (window1open) gdk_gc_set_font(ggc,gfont);
1523 if (window2open) gdk_gc_set_font(ggc2,gfont);
1524
1525 if (gdraw1==NULL) gdraw1=gdraw2;
1526 else if (gdraw2==NULL) gdraw2=gdraw1;
1527
1528 g_timeout_add( anim_update_interval, (GtkFunction) do_animation, NULL);
1529 }
1530
1531
1532 /* -------------------- main loop (wait for event, process event, redisplay) ------------ */
1533
1534 int *present_redraw=NULL;
1535
Pending(void)1536 int Pending(void)
1537 {
1538 if (present_redraw==NULL) return 0;
1539 gtk_main_iteration_do(FALSE);
1540 return *present_redraw | quit;
1541 }
1542
1543
mainX(int really)1544 void mainX(int really)
1545 {
1546 maininitX(really);
1547 if (!really) return;
1548 while (!quit) {
1549 if (window1open && redraw) {
1550 present_redraw = &redraw;
1551 redraw=0;
1552 out = &outX;
1553 draw_all(1);
1554 }
1555 if (window2open && redraw2) {
1556 int r=redraw2;
1557 present_redraw = &redraw2;
1558 redraw2=0;
1559 out = &outX2;
1560 draw_all2(r==2);
1561 if (rp_index>=0) {
1562 int x;
1563 x=freqx(neco[rp_index].f);
1564 gdk_gc_set_foreground(ggc2,&c_back);
1565 gdk_draw_line(gdraw2->window,ggc2,x,0,x,win2sizey);
1566 }
1567 }
1568 animbusy=0;
1569 gtk_main_iteration_do(!( (window1open && redraw) || (window2open && redraw2) ));
1570 }
1571 }
1572
initX(int * argcp,char ** argv)1573 void initX(int *argcp,char **argv)
1574 {
1575 gtk_init(argcp,&argv);
1576 winsize=winsizex=winsizey=ini_winsize;
1577 win2sizex=win2sizey=ini_winsize;
1578 }
1579
1580