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