1 /*
2  *  xnec2c - GTK2-based version of nec2c, the C translation of NEC2
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU Library General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  */
18 
19 /* geom_edit.c
20  *
21  * Structure/Geometry editor functions for xnec2c
22  */
23 
24 #include "geom_edit.h"
25 #include "shared.h"
26 
27 /*------------------------------------------------------------------------*/
28 
29 /* Wire_Editor()
30  *
31  * Handles all actions of the wire editor window
32  */
33   void
Wire_Editor(int action)34 Wire_Editor( int action )
35 {
36   /* For looking up spinbuttons */
37   GtkSpinButton *spin;
38 
39   /* Frame of tapered wire data */
40   GtkWidget *frame;
41 
42   /* For reading/writing to GW & GC rows */
43   static GtkTreeIter
44 	iter_gw,
45 	iter_gc;
46 
47   int idx, idi;
48 
49   static gboolean
50 		   load   = FALSE, /* Enable wire loading (conductivity specified) */
51 		   taper  = FALSE, /* Editing a tapered wire */
52 		   save   = FALSE, /* Enable saving of editor data */
53 		   busy   = FALSE, /* Block callbacks. Must be a better way to do this? */
54 		   newpcl = TRUE,  /* New percent-of-lambda value */
55 		   newrdm = TRUE,  /* New diameter ratio value */
56 		   newwln = TRUE;  /* New wire length value */
57 
58   /* Float type data, wire conductivity */
59   static gdouble fv[14], s = 0.0;
60 
61   /* Integer type data */
62   static gint iv[4];
63 
64   /* Wire's projection on xyz axes */
65   gdouble dx, dy, dz;
66 
67   /* Card (row) name */
68   gchar name[3];
69 
70   /* Spin button names, int & float data */
71   gchar *ispin[2] =
72   {
73 	"wire_tagnum_spinbutton",
74 	"wire_numseg_spinbutton"
75   };
76 
77   gchar *fspin[14] =
78   {
79 	"wire_x1_spinbutton",
80 	"wire_y1_spinbutton",
81 	"wire_z1_spinbutton",
82 	"wire_x2_spinbutton",
83 	"wire_y2_spinbutton",
84 	"wire_z2_spinbutton",
85 	"wire_dia_spinbutton",
86 	"wire_rlen_spinbutton",
87 	"wire_dia1_spinbutton",
88 	"wire_dian_spinbutton",
89 	"wire_rdia_spinbutton",
90 	"wire_pcl_spinbutton",
91 	"wire_len_spinbutton",
92 	"wire_res_spinbutton"
93   };
94 
95 
96   /* Block callbacks. (Should be a better way to do this) */
97   if( Give_Up( &busy, wire_editor) ) return;
98 
99   /* Save data to nec2 editor if appropriate */
100   if( (action & EDITOR_SAVE) && save )
101   {
102 	/* Clear data not used in GC card */
103 	iv[SPIN_COL_I3] = iv[SPIN_COL_I4] = 0;
104 	for( idx = WIRE_RDIA; idx <= WIRE_RES; idx++ )
105 	  fv[idx] = 0.0;
106 
107 	/* Set GW data to treeview */
108 	Set_Geometry_Data( geom_store, &iter_gw, iv, fv );
109 
110 	/* Set GC card data to treeview if taper */
111 	if( taper )
112 	  Set_Geometry_Data( geom_store, &iter_gc,
113 		  &iv[SPIN_COL_I3], &fv[WIRE_RLEN] );
114 
115 	/* Set wire conductivity (loading card) */
116 	if( load )
117 	  Set_Wire_Conductivity( iv[SPIN_COL_I1], s, cmnd_store );
118 
119 	save = load = FALSE;
120   } /* if( (action & EDITOR_SAVE) && save ) */
121 
122   /* Read int data from the wire editor */
123   for( idi = SPIN_COL_I1; idi <= SPIN_COL_I2; idi++ )
124   {
125 	spin = GTK_SPIN_BUTTON( lookup_widget(wire_editor, ispin[idi]) );
126 	iv[idi] = gtk_spin_button_get_value_as_int( spin );
127   }
128 
129   /* Read float data from the wire editor */
130   for( idx = WIRE_X1; idx <= WIRE_RES; idx++ )
131   {
132 	spin = GTK_SPIN_BUTTON( lookup_widget(wire_editor, fspin[idx]) );
133 	fv[idx] = gtk_spin_button_get_value( spin );
134   }
135   fv[WIRE_DIA]  /= 2.0;
136   fv[WIRE_DIA1] /= 2.0;
137   fv[WIRE_DIAN] /= 2.0;
138 
139   /* Respond to user action */
140   switch( action )
141   {
142 	case EDITOR_NEW: /* New wire row(s) to create */
143 	  /* Insert a default GE card if list is empty */
144 	  Insert_GE_Card( geom_store, &iter_gw );
145 
146 	  /* Insert a new blank GW row after a selected row,
147 	   * if any, otherwise before the last (GE) row */
148 	  Insert_Blank_Geometry_Row(
149 		  geom_treeview, geom_store, &iter_gw, "GW" );
150 
151 	  /* Some default values */
152 	  iv[SPIN_COL_I1] = ++gbl_tag_num;
153 	  iv[SPIN_COL_I3] = iv[SPIN_COL_I4] = 0;
154 
155 	  if( taper )
156 	  {
157 		/* Insert a new blank GC row if tapered wire */
158 		Insert_Blank_Geometry_Row(
159 			geom_treeview, geom_store, &iter_gc, "GC" );
160 		fv[WIRE_DIA]  = 0.0;
161 	  }
162 
163 	  /* Scroll tree view to bottom */
164 	  gtk_adjustment_set_value(
165 		  geom_adjustment, geom_adjustment->upper );
166 	  break;
167 
168 	case EDITOR_EDIT:  /* Edit a wire row (GW/GC) */
169 	  /* Get selected row */
170 	  Get_Selected_Row(
171 		  geom_treeview, geom_store, &iter_gw, name );
172 	  iter_gc = iter_gw;
173 
174 	  /*** Editing a GC card ***/
175 	  if( strcmp(name, "GC") == 0 )
176 	  {
177 		taper = TRUE;
178 
179 		/* Get tapered wire data from tree view */
180 		Get_Geometry_Data( geom_store, &iter_gc,
181 			&iv[SPIN_COL_I3], &fv[WIRE_RLEN] );
182 		fv[WIRE_RDIA] = fv[WIRE_RLEN];
183 
184 		/* Check for a preceding GW card.
185 		 * If card is GW, get wire data */
186 		if( Check_Card_Name(geom_store, &iter_gw, PREVIOUS, "GW") )
187 		{
188 		  Get_Geometry_Data( geom_store, &iter_gw, iv, fv );
189 
190 		  /* Warn user if wire radius not 0 */
191 		  if( fv[WIRE_DIA] != 0.0 )
192 			stop( _("GC card preceded by GW card\n"\
193 				  "with non-zero wire radius"), ERR_OK );
194 
195 		} /* if( strcmp(name, "GC") == 0 ) */
196 		else stop( _("No GW card before GC card"), ERR_OK );
197 	  }
198 	  else /*** Editing a GW card ***/
199 	  {
200 		taper = FALSE;
201 
202 		/* Get wire data from tree view */
203 		Get_Geometry_Data( geom_store, &iter_gw, iv, fv );
204 
205 		/* Get wire conductivity if specified in LD card */
206 		Get_Wire_Conductivity(iv[SPIN_COL_I1], &s, cmnd_store);
207 		fv[WIRE_RES] = s;
208 
209 		/*** Get tapered wire data if dia = 0 ***/
210 		if( fv[WIRE_DIA] == 0.0 )
211 		{
212 		  /* If next card is GC, get data */
213 		  if( Check_Card_Name(geom_store, &iter_gc, NEXT, "GC") )
214 		  {
215 			taper = TRUE;
216 
217 			/* Get wire taper data from tree view */
218 			Get_Geometry_Data( geom_store, &iter_gc,
219 				&iv[SPIN_COL_I3], &fv[WIRE_RLEN] );
220 			fv[WIRE_RDIA] = fv[WIRE_RLEN];
221 		  }
222 		  else stop( _("No GC card after a GW card\n"\
223 				"with a zero wire radius"), ERR_OK );
224 
225 		} /* if( fv[WIRE_DIA] == 0.0 ) */
226 		/* If radius != 0, next card should not be GC */
227 		else if( Check_Card_Name(geom_store, &iter_gc, NEXT, "GC") )
228 		  stop( _("GC card follows a GW card\n"\
229 				"with non-zero wire radius"), ERR_OK );
230 
231 	  } /* if( strcmp(name, "GC") == 0 ) */
232 	  break;
233 
234 	case WIRE_EDITOR_TAPR: /* Show taper wire data if button checked */
235 	  {
236 		/* Wire diameter */
237 		static double diam;
238 
239 		/* Read tapered wire checkbutton */
240 		taper = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(
241 			  lookup_widget(wire_editor, "wire_taper_checkbutton")) );
242 		if( taper )
243 		{
244 		  /* Set wire dia to 0 */
245 		  diam = fv[WIRE_DIA];
246 		  fv[WIRE_DIA] = 0.0;
247 
248 		  /* Insert GC card if valid GW iteration */
249 		  if( gtk_list_store_iter_is_valid(geom_store, &iter_gw) )
250 			Insert_Blank_Geometry_Row(
251 				geom_treeview, geom_store, &iter_gc, "GC");
252 		}
253 		else
254 		{
255 		  /* Restore wire diam */
256 		  fv[WIRE_DIA] = diam;
257 
258 		  /* Remove GC card if valid */
259 		  Remove_Row( geom_store, &iter_gc );
260 		} /* if( taper ) */
261 	  }
262 	  save = TRUE;
263 	  break;
264 
265 	case EDITOR_CANCEL: /* Cancel wire editor */
266 	  /* Remove cards */
267 	  Remove_Row( geom_store, &iter_gw );
268 	  if( taper )
269 		Remove_Row( geom_store, &iter_gc );
270 	  save = busy = FALSE;
271 	  return;
272 
273 	case EDITOR_DATA: /* Some data changed in editor window */
274 	  save = TRUE;
275 	  break;
276 
277 	case EDITOR_LOAD: /* Wire conductivity specified */
278 	  spin = GTK_SPIN_BUTTON( lookup_widget(
279 			wire_editor, fspin[WIRE_RES]) );
280 	  s = gtk_spin_button_get_value( spin );
281 	  if( s > 0.0 )
282 	  {
283 		save = TRUE;
284 		load = TRUE;
285 	  }
286 	  else load = FALSE;
287 	  break;
288 
289 	case EDITOR_TAGNUM: /* Tag number edited by user */
290 	  gbl_tag_num = iv[SPIN_COL_I1];
291 	  save = TRUE;
292 	  if( s > 0.0 ) load = TRUE;
293 	  break;
294 
295 	case EDITOR_SEGPC: /* Segment length as % of smallest wavelength */
296 	  /* Calculate num of segs for given % of lambda */
297 	  if( calc_data.mxfrq != 0.0 )
298 	  {
299 		if( taper && ( fv[WIRE_RLEN] != 1.0) ) /* Taper ratio < 1 */
300 		{
301 		  double cnt = 1.0 / (fv[WIRE_PCL]/100.0) * (1.0-fv[WIRE_RLEN]);
302 		  if( cnt < 1.0 )
303 		  {
304 			double i = ceil( log(1.0-cnt) / log(fv[WIRE_RLEN]) );
305 			iv[SPIN_COL_I2] = (gint)i;
306 		  }
307 		}
308 		else
309 		{
310 		  double i = ceil( 100.0 * (fv[WIRE_LEN]/fv[WIRE_PCL]) /
311 			  ((double)CVEL/calc_data.mxfrq) );
312 		  iv[SPIN_COL_I2] = (gint)i;
313 		}
314 	  }
315 	  newpcl = FALSE;
316 	  save = TRUE;
317 	  break;
318 
319 	  /* Calculate new wire end points on length change */
320 	case WIRE_EDITOR_WLEN:
321 	  {
322 		double l, dl;
323 
324 		/* Length of wire's projection on axes */
325 		dx = fv[WIRE_X2]-fv[WIRE_X1];
326 		dy = fv[WIRE_Y2]-fv[WIRE_Y1];
327 		dz = fv[WIRE_Z2]-fv[WIRE_Z1];
328 
329 		/* Wire's length */
330 		l = (gdouble)sqrt( dx*dx + dy*dy + dz*dz );
331 
332 		/* 1/2 of change in wire's length / length */
333 		dl = fv[WIRE_LEN] - l; dl /= 2.0 * l;
334 
335 		/* Corresponding change in wire end co-ordinates */
336 		dx *= dl; dy *= dl; dz *= dl;
337 		fv[WIRE_X1] -= dx; fv[WIRE_X2] += dx;
338 		fv[WIRE_Y1] -= dy; fv[WIRE_Y2] += dy;
339 		fv[WIRE_Z1] -= dz; fv[WIRE_Z2] += dz;
340 	  }
341 	  newwln = FALSE;
342 	  save = TRUE;
343 	  break;
344 
345 	case WIRE_EDITOR_RLEN: /* Length taper ratio changed */
346 	  fv[WIRE_DIAN] = fv[WIRE_DIA1] *
347 		pow(fv[WIRE_RLEN], (double)(iv[SPIN_COL_I2]-1)); /* Nth seg dia */
348 	  break;
349 
350 	case WIRE_EDITOR_RDIA: /* New diameter taper ratio */
351 	  fv[WIRE_DIAN] = fv[WIRE_DIA1] *
352 		pow(fv[WIRE_RDIA], (double)(iv[SPIN_COL_I2]-1)); /* Nth seg dia */
353 	  newrdm = FALSE;
354 	  save = TRUE;
355 
356   } /* switch( action ) */
357 
358   /* Frame of tapered wire data */
359   frame = lookup_widget(wire_editor, "wire_taperframe");
360   /* Show taper data if appropriate */
361   if( taper )
362   {
363 	gtk_widget_show( frame );
364 	gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(
365 		  lookup_widget(wire_editor,
366 			"wire_taper_checkbutton")), TRUE );
367   }
368   else
369   {
370 	gtk_widget_hide( frame );
371 	gtk_window_resize( GTK_WINDOW(wire_editor), 10, 10 );
372 	gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(
373 		  lookup_widget(wire_editor,
374 			"wire_taper_checkbutton")), FALSE );
375   }
376 
377   /*** Calculate wire length ***/
378   if( newwln )
379   {
380 	/* Length of wire's projection on axes */
381 	dx = fv[WIRE_X2]-fv[WIRE_X1];
382 	dy = fv[WIRE_Y2]-fv[WIRE_Y1];
383 	dz = fv[WIRE_Z2]-fv[WIRE_Z1];
384 	/* Wire's length */
385 	fv[WIRE_LEN] = (gdouble)sqrt( dx*dx + dy*dy + dz*dz );
386   }
387   else newwln = TRUE;
388 
389   /*** Calculate seg length as % of smallest wavelength ***/
390   if( (calc_data.mxfrq != 0.0) && newpcl )
391   {
392 	if( taper && (fv[WIRE_RLEN] != 1.0) )
393 	  fv[WIRE_PCL] =
394 		100.0 * fv[WIRE_LEN] * (1.0-fv[WIRE_RLEN]) /
395 		(1.0-(gdouble)pow(fv[WIRE_RLEN], (gdouble)iv[SPIN_COL_I2])) /
396 		((gdouble)CVEL/calc_data.mxfrq);
397 	else
398 	  fv[WIRE_PCL] = 100.0 * (fv[WIRE_LEN] /
399 		  (gdouble)iv[SPIN_COL_I2]) / ((gdouble)CVEL/calc_data.mxfrq);
400   }
401   else newpcl = TRUE;
402 
403   /*** Calculate radius taper ratio ***/
404   if( (iv[SPIN_COL_I2] > 1) && newrdm )
405 	fv[WIRE_RDIA] = pow( fv[WIRE_DIAN]/fv[WIRE_DIA1],
406 		1.0/(double)(iv[SPIN_COL_I2]-1) );
407   else newrdm = TRUE;
408 
409   /* Write int data to the wire editor */
410   for( idi = SPIN_COL_I1; idi <= SPIN_COL_I2; idi++ )
411   {
412 	spin = GTK_SPIN_BUTTON(
413 		lookup_widget(wire_editor, ispin[idi]) );
414 	gtk_spin_button_set_value( spin, iv[idi] );
415   }
416 
417   /* Write float data to the wire editor (F1 to F7 and taper) */
418   fv[WIRE_DIA] *= 2.0; fv[WIRE_DIA1] *= 2.0; fv[WIRE_DIAN] *= 2.0;
419   for( idx = WIRE_X1; idx <= WIRE_RES; idx++ )
420   {
421 	spin = GTK_SPIN_BUTTON(
422 		lookup_widget(wire_editor, fspin[idx]) );
423 	gtk_spin_button_set_value( spin, fv[idx] );
424   }
425   fv[WIRE_DIA] /= 2.0; fv[WIRE_DIA1] /= 2.0; fv[WIRE_DIAN] /= 2.0;
426 
427   /* Wait for GTK to complete its tasks */
428   while( g_main_context_iteration(NULL, FALSE) );
429   busy = FALSE;
430 
431 } /* Wire_Editor() */
432 
433 /*------------------------------------------------------------------------*/
434 
435 /* Patch_Editor()
436  *
437  * Handles all actions of the patch editor window
438  */
439   void
Patch_Editor(int action)440 Patch_Editor( int action )
441 {
442   /* For looking up spinbuttons */
443   GtkSpinButton *spin;
444 
445   /* For reading/writing to SP/SM & SC rows */
446   static GtkTreeIter
447 	iter_sp,
448 	iter_sc;
449 
450   int idx, idi;
451 
452   /* Patch type */
453   static int ptype = PATCH_ARBT;
454 
455   /* Integer type data */
456   static gint iv[4];
457 
458   /* Float type data */
459   static gdouble fv[14];
460 
461   /* Card (row) name */
462   static gchar name[3] = "SP";
463 
464   /* Spin button names, int data */
465   gchar *ispin[2] =
466   {
467 	"patch_nx_spinbutton",
468 	"patch_ny_spinbutton",
469   };
470 
471   /* Spin button names, float data */
472   gchar *fspin[12] =
473   {
474 	"patch_x1_spinbutton",
475 	"patch_y1_spinbutton",
476 	"patch_z1_spinbutton",
477 	"patch_x2_spinbutton",
478 	"patch_y2_spinbutton",
479 	"patch_z2_spinbutton",
480 	"patch_x3_spinbutton",
481 	"patch_y3_spinbutton",
482 	"patch_z3_spinbutton",
483 	"patch_x4_spinbutton",
484 	"patch_y4_spinbutton",
485 	"patch_z4_spinbutton",
486   };
487 
488   gchar *rbutton[5] =
489   {
490 	"patch_arbitrary_radiobutton",
491 	"patch_rectangular_radiobutton",
492 	"patch_triangular_radiobutton",
493 	"patch_quadrilateral_radiobutton",
494 	"patch_surface_radiobutton"
495   };
496 
497   static gboolean
498 	save  = FALSE,	/* Enable saving of editor data */
499 		  busy  = FALSE,	/* Block callbacks. Must be a better way to do this? */
500 		  ptset = FALSE;	/* Set patch type radio buttons */
501 
502 
503   /* Block callbacks. (Should be a better way to do this) */
504   if( Give_Up( &busy, patch_editor) ) return;
505 
506   /* Save data to nec2 editor if appropriate */
507   if( (action & EDITOR_SAVE) && save )
508   {
509 	/* Clear data not used in SC card */
510 	iv[SPIN_COL_I3]  = iv[SPIN_COL_I4]  = 0;
511 	fv[UNUSED_F1] = fv[UNUSED_F2] = 0.0;
512 
513 	/* Set SP data to treeview */
514 	Set_Geometry_Data( geom_store, &iter_sp, iv, fv );
515 
516 	/* Set SC card data to treeview if non arbitrary */
517 	if( ptype != PATCH_ARBT )
518 	  Set_Geometry_Data(geom_store,
519 		  &iter_sc, &iv[SPIN_COL_I3], &fv[PATCH_X3]);
520 
521 	save = FALSE;
522   } /* if( (action & EDITOR_SAVE) && save ) */
523 
524   /* Set int data from the patch editor (SP card) */
525   if( ptype != PATCH_SURF )
526   {
527 	iv[SPIN_COL_I1] = 0; 	  /* Not used in SP */
528 	iv[SPIN_COL_I2] = ptype; /* Patch type */
529   }
530   /* Read int data from the patch editor (SM card) */
531   else for( idi = SPIN_COL_I1; idi <= SPIN_COL_I2; idi++ )
532   {
533 	spin = GTK_SPIN_BUTTON(
534 		lookup_widget(patch_editor, ispin[idi]) );
535 	double i = gtk_spin_button_get_value( spin );
536 	iv[idi] = (gint)i;
537   }
538 
539   /* Read float data from the patch editor */
540   for( idx = PATCH_X1; idx <= PATCH_Z2; idx++ )
541   {
542 	spin = GTK_SPIN_BUTTON(
543 		lookup_widget(patch_editor, fspin[idx]) );
544 	fv[idx] = gtk_spin_button_get_value( spin );
545   }
546   for( idx = PATCH_X3; idx <= PATCH_Z4; idx++ )
547   {
548 	spin = GTK_SPIN_BUTTON(
549 		lookup_widget(patch_editor, fspin[idx-1]) );
550 	fv[idx] = gtk_spin_button_get_value( spin );
551   }
552 
553   /* Respond to user action */
554   switch( action )
555   {
556 	case EDITOR_NEW: /* New patch to edit, enter some default data */
557 	  /* Insert a default GE card if list is empty */
558 	  Insert_GE_Card( geom_store, &iter_sp );
559 
560 	  /* Insert a new blank SP row after a selected row,
561 	   * if any, otherwise before the last (GE) row */
562 	  Insert_Blank_Geometry_Row(
563 		  geom_treeview, geom_store, &iter_sp, name );
564 
565 	  /* Insert an SC card for non-arbitrary patch */
566 	  if( ptype != PATCH_ARBT )
567 		Insert_Blank_Geometry_Row(
568 			geom_treeview, geom_store, &iter_sc, "SC" );
569 
570 	  /* Scroll tree view to bottom */
571 	  gtk_adjustment_set_value(
572 		  geom_adjustment, geom_adjustment->upper );
573 	  ptset = TRUE;
574 	  break;
575 
576 	case EDITOR_EDIT:  /* Edit a selected geometry row */
577 	  /* Get selected row */
578 	  Get_Selected_Row(
579 		  geom_treeview, geom_store, &iter_sp, name );
580 	  iter_sc = iter_sp;
581 
582 	  /*** Editing an SC card ***/
583 	  if( strcmp(name, "SC") == 0 )
584 	  {
585 		/* Get patch data from SC row in tree view */
586 		Get_Geometry_Data( geom_store, &iter_sc,
587 			&iv[SPIN_COL_I3], &fv[PATCH_X3] );
588 
589 		/* Check for a preceding SP | SM card.
590 		 * If card is SP, get patch data */
591 		if( Check_Card_Name(geom_store, &iter_sp, PREVIOUS, "SP") )
592 		{
593 		  Get_Geometry_Data( geom_store, &iter_sp, iv, fv );
594 		  ptype = iv[SPIN_COL_I2];
595 
596 		  /* Warn user if SP card with arbitrary
597 		   * patch is followed by an SC card */
598 		  if( ptype == PATCH_ARBT )
599 			stop( _("SC card preceded by SP card\n"\
600 				  "with arbitrary patch type"), ERR_OK );
601 
602 		} /* if( Check_Card_Name(geom_store, &iter_sp, PREVIOUS, "SP") ) */
603 		else /* Look for a previous SM card */
604 		{
605 		  iter_sp = iter_sc;
606 		  if( Check_Card_Name(geom_store, &iter_sp, PREVIOUS, "SM") )
607 		  {
608 			Get_Geometry_Data( geom_store, &iter_sp, iv, fv );
609 			ptype = PATCH_SURF;
610 		  }
611 		  else stop( _("No SP or SM card before SC card"), ERR_OK );
612 		}
613 	  } /* if( strcmp(name, "SC") == 0 ) */
614 	  /*** Editing an SP|SM card ***/
615 	  else if( strcmp(name, "SP") == 0 )
616 	  {
617 		/* Get patch data from treeview */
618 		Get_Geometry_Data( geom_store, &iter_sp, iv, fv );
619 		ptype = iv[SPIN_COL_I2];
620 
621 		/*** Get SC card data if patch type non-arbitrary ***/
622 		if( ptype != PATCH_ARBT )
623 		{
624 		  /* If next card is SC, get data */
625 		  if( Check_Card_Name(geom_store, &iter_sc, NEXT, "SC") )
626 			Get_Geometry_Data( geom_store, &iter_sc,
627 				&iv[SPIN_COL_I3], &fv[PATCH_X3] );
628 		  else
629 		  {
630 			ptype = PATCH_ARBT;
631 			stop( _("No SC card after an SP card\n"\
632 				  "with non-arbitrary patch type"), ERR_OK );
633 		  }
634 
635 		} /* if( ptype != PATCH_ARBT ) */
636 		/* If patch type arbitrary, no SC card should follow */
637 		else if( Check_Card_Name(geom_store, &iter_sc, NEXT, "SC") )
638 		  stop( _("SC card follows an SP card\n"\
639 				"with arbitrary patch type"), ERR_OK );
640 	  } /* if( strcmp(name, "SP") == 0 ) */
641 	  else /* SM card */
642 	  {
643 		/* Get patch data from treeview */
644 		Get_Geometry_Data( geom_store, &iter_sp, iv, fv );
645 		ptype = PATCH_SURF;
646 
647 		/* If next card is SC, get data */
648 		if( Check_Card_Name(geom_store, &iter_sc, NEXT, "SC") )
649 		  Get_Geometry_Data( geom_store, &iter_sc,
650 			  &iv[SPIN_COL_I3], &fv[PATCH_X3] );
651 		else stop( _("No SC card after an SM card"), ERR_OK );
652 
653 	  } /* if( strcmp(name, "SP") == 0 ) */
654 
655 	  ptset = TRUE;
656 	  break;
657 
658 	case EDITOR_CANCEL: /* Cancel patch editor */
659 	  /* Remove cards */
660 	  Remove_Row( geom_store, &iter_sp );
661 	  if( ptype != PATCH_ARBT )
662 		Remove_Row( geom_store, &iter_sc );
663 	  save = busy = FALSE;
664 	  return;
665 
666 	case EDITOR_DATA: /* Some editor data changed */
667 	  save = TRUE;
668 	  break;
669 
670 	case PATCH_EDITOR_ARBT: /* Arbitary-shaped patch */
671 	  ptype = PATCH_ARBT;
672 	  ptset = FALSE;
673 	  save  = TRUE;
674 	  for( idx = PATCH_X3; idx <= UNUSED_F2; idx++ )
675 		fv[idx] = 0.0;
676 
677 	  /* Remove SC card */
678 	  Remove_Row( geom_store, &iter_sc );
679 	  break;
680 
681 	case PATCH_EDITOR_RECT: /* Rectangular patch */
682 	  ptype = PATCH_RECT;
683 	  ptset = FALSE;
684 	  save  = TRUE;
685 	  for( idx = PATCH_X4; idx <= UNUSED_F2; idx++ )
686 		fv[idx] = 0.0;
687 	  break;
688 
689 	case PATCH_EDITOR_TRIA: /* Triangular patch */
690 	  ptype = PATCH_TRIA;
691 	  ptset = FALSE;
692 	  save  = TRUE;
693 	  for( idx = PATCH_X4; idx <= UNUSED_F2; idx++ )
694 		fv[idx] = 0.0;
695 	  break;
696 
697 	case PATCH_EDITOR_QUAD: /* Quadrilateral patch */
698 	  ptype = PATCH_QUAD;
699 	  ptset = FALSE;
700 	  save  = TRUE;
701 	  break;
702 
703 	case PATCH_EDITOR_SURF: /* Multi-patch surface */
704 	  iv[SPIN_COL_I1] = iv[SPIN_COL_I2] = 8;
705 	  ptype = PATCH_SURF;
706 	  ptset  = FALSE;
707 	  save   = TRUE;
708 	  break;
709 
710 	case PATCH_EDITOR_SCCD: /* Insert SC card (non-arbitrary patch case) */
711 	  if( gtk_list_store_iter_is_valid( geom_store, &iter_sp) )
712 		Insert_Blank_Geometry_Row(
713 			geom_treeview, geom_store, &iter_sc, "SC");
714 
715   } /* switch( action ) */
716 
717   /* Change labels as needed */
718   if( ptype == PATCH_ARBT )
719   {
720 	gtk_label_set_text( GTK_LABEL(
721 		  lookup_widget(patch_editor, "patch_x1_label")), _("Center - X") );
722 	gtk_label_set_text( GTK_LABEL(
723 		  lookup_widget(patch_editor, "patch_y1_label")), _("Center - Y") );
724 	gtk_label_set_text( GTK_LABEL(
725 		  lookup_widget(patch_editor, "patch_z1_label")), _("Center - Z") );
726 	gtk_label_set_text( GTK_LABEL(
727 		  lookup_widget(patch_editor, "patch_x2_label")), _("Normal - Elev.") );
728 	gtk_label_set_text( GTK_LABEL(
729 		  lookup_widget(patch_editor, "patch_y2_label")), _("Normal - Azim.") );
730 	gtk_label_set_text( GTK_LABEL(
731 		  lookup_widget(patch_editor, "patch_z2_label")), _("Patch Area") );
732   }
733   else
734   {
735 	gtk_label_set_text( GTK_LABEL(
736 		  lookup_widget(patch_editor, "patch_x1_label")), _("Corner 1 - X") );
737 	gtk_label_set_text( GTK_LABEL(
738 		  lookup_widget(patch_editor, "patch_y1_label")), _("Corner 1 - Y") );
739 	gtk_label_set_text( GTK_LABEL(
740 		  lookup_widget(patch_editor, "patch_z1_label")), _("Corner 1 - Z") );
741 	gtk_label_set_text( GTK_LABEL(
742 		  lookup_widget(patch_editor, "patch_x2_label")), _("Corner 2 - X") );
743 	gtk_label_set_text( GTK_LABEL(
744 		  lookup_widget(patch_editor, "patch_y2_label")), _("Corner 2 - Y") );
745 	gtk_label_set_text( GTK_LABEL(
746 		  lookup_widget(patch_editor, "patch_z2_label")), _("Corner 2 - Z") );
747   }
748 
749   /* Hide/Show parts of window as needed */
750   switch( ptype )
751   {
752 	case PATCH_ARBT: /* Arbitary shaped patch */
753 	  gtk_widget_hide( lookup_widget(patch_editor, "patch_sc_frame") );
754 	  gtk_widget_hide( lookup_widget(patch_editor, "patch_sm_frame") );
755 	  gtk_window_resize( GTK_WINDOW(patch_editor), 10, 10 );
756 	  break;
757 
758 	case PATCH_RECT: /* Rectangular patch */
759 	  gtk_widget_show( lookup_widget(patch_editor, "patch_sc_frame") );
760 	  gtk_widget_hide( lookup_widget(patch_editor, "patch_sc_table") );
761 	  gtk_widget_hide( lookup_widget(patch_editor, "patch_sm_frame") );
762 	  gtk_window_resize( GTK_WINDOW(patch_editor), 10, 10 );
763 	  break;
764 
765 	case PATCH_TRIA: /* Triangular patch */
766 	  gtk_widget_show( lookup_widget(patch_editor, "patch_sc_frame") );
767 	  gtk_widget_hide( lookup_widget(patch_editor, "patch_sc_table") );
768 	  gtk_widget_hide( lookup_widget(patch_editor, "patch_sm_frame") );
769 	  gtk_window_resize( GTK_WINDOW(patch_editor), 10, 10 );
770 	  break;
771 
772 	case PATCH_QUAD: /* Quadrilateral patch */
773 	  gtk_widget_show( lookup_widget(patch_editor, "patch_sc_frame") );
774 	  gtk_widget_show( lookup_widget(patch_editor, "patch_sc_table") );
775 	  gtk_widget_hide( lookup_widget(patch_editor, "patch_sm_frame") );
776 	  gtk_window_resize( GTK_WINDOW(patch_editor), 10, 10 );
777 	  break;
778 
779 	case PATCH_SURF: /* Multi-patch surface */
780 	  gtk_widget_show( lookup_widget(patch_editor, "patch_sm_frame") );
781 	  gtk_widget_show( lookup_widget(patch_editor, "patch_sc_frame") );
782 	  gtk_widget_hide( lookup_widget(patch_editor, "patch_sc_table") );
783 	  gtk_window_resize( GTK_WINDOW(patch_editor), 10, 10 );
784 
785   } /* switch( ptype ) */
786 
787   /* Set patch type radio button */
788   if( ptset )
789   {
790 	ptset = FALSE;
791 	gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(
792 		  lookup_widget(patch_editor, rbutton[ptype])), TRUE );
793   }
794 
795   /* Set card name */
796   Strlcpy( name, (ptype == PATCH_SURF ? "SM" : "SP"), sizeof(name) );
797   if( gtk_list_store_iter_is_valid(geom_store, &iter_sp) && save )
798 	gtk_list_store_set( geom_store, &iter_sp, GEOM_COL_NAME, name, -1 );
799 
800   /* Write int data for SM card */
801   if( ptype == PATCH_SURF )
802 	for( idi = SPIN_COL_I1; idi <= SPIN_COL_I2; idi++ )
803 	{
804 	  spin = GTK_SPIN_BUTTON( lookup_widget(patch_editor, ispin[idi]) );
805 	  gtk_spin_button_set_value( spin, iv[idi] );
806 	}
807 
808   /* Write float data to the patch editor */
809   for( idx = PATCH_X1; idx <= PATCH_Z2; idx++ )
810   {
811 	spin = GTK_SPIN_BUTTON( lookup_widget(patch_editor, fspin[idx]) );
812 	gtk_spin_button_set_value( spin, fv[idx] );
813   }
814   for( idx = PATCH_X3; idx <= PATCH_Z4; idx++ )
815   {
816 	spin = GTK_SPIN_BUTTON( lookup_widget(patch_editor, fspin[idx-1]) );
817 	gtk_spin_button_set_value( spin, fv[idx] );
818   }
819 
820   /* Wait for GTK to complete its tasks */
821   while( g_main_context_iteration(NULL, FALSE) );
822   busy = FALSE;
823 
824 } /* Patch_Editor() */
825 
826 /*------------------------------------------------------------------------*/
827 
828 /* Arc_Editor()
829  *
830  * Handles all actions of the arc editor window
831  */
832 
833   void
Arc_Editor(int action)834 Arc_Editor( int action )
835 {
836   /* For looking up spinbuttons */
837   GtkSpinButton *spin;
838 
839   /* For reading/writing to GA rows */
840   static GtkTreeIter iter_ga;
841 
842   int idx, idi;
843 
844   static gboolean
845 		   load   = FALSE, /* Enable wire loading (conductivity specified) */
846 		   newpcl = TRUE,  /* New percent-of-lambda value  */
847 		   save   = FALSE, /* Enable saving of editor data */
848 		   busy   = FALSE; /* Block callbacks. Must be a better way to do this? */
849 
850   /* Float type data */
851   static gdouble fv[7] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
852 
853   /* Wire conductivity */
854   static gdouble s = 0.0;
855 
856   /* Integer type data */
857   static gint iv[2];
858 
859   /* Card (row) name */
860   gchar name[3];
861 
862   /* Spin button names, int & float data */
863   gchar *ispin[2] =
864   {
865 	"arc_tagnum_spinbutton",
866 	"arc_numseg_spinbutton"
867   };
868 
869   gchar *fspin[6] =
870   {
871 	"arc_rad_spinbutton",
872 	"arc_end1_spinbutton",
873 	"arc_end2_spinbutton",
874 	"arc_dia_spinbutton",
875 	"arc_pcl_spinbutton",
876 	"arc_res_spinbutton"
877   };
878 
879 
880   /* Block callbacks. (Should be a better way to do this) */
881   if( Give_Up( &busy, arc_editor) ) return;
882 
883   /* Save data to nec2 editor if appropriate */
884   if( (action & EDITOR_SAVE) && save )
885   {
886 	Set_Geometry_Data( geom_store, &iter_ga, iv, fv );
887 
888 	/* Set wire conductivity (loading card) */
889 	if( load )
890 	  Set_Wire_Conductivity( iv[SPIN_COL_I1], s, cmnd_store );
891 
892 	save = load = FALSE;
893   } /* if( (action & EDITOR_SAVE) && save ) */
894 
895   /* Read int data from the arc editor */
896   for( idi = SPIN_COL_I1; idi <= SPIN_COL_I2; idi++ )
897   {
898 	spin = GTK_SPIN_BUTTON( lookup_widget(arc_editor, ispin[idi]) );
899 	iv[idi] = gtk_spin_button_get_value_as_int( spin );
900   }
901 
902   /* Read float data from the arc editor */
903   for( idx = ARC_RAD; idx <= ARC_PCL; idx++ )
904   {
905 	spin = GTK_SPIN_BUTTON( lookup_widget(arc_editor, fspin[idx]) );
906 	fv[idx] = gtk_spin_button_get_value( spin );
907   }
908   fv[ARC_DIA] /= 2.0;
909 
910   /* Get wire conductivity */
911   spin = GTK_SPIN_BUTTON( lookup_widget(arc_editor, fspin[idx]) );
912   s = gtk_spin_button_get_value( spin );
913 
914   /* Respond to user action */
915   switch( action )
916   {
917 	case EDITOR_NEW: /* New arc row to create */
918 	  /* Insert a default GE card if list is empty */
919 	  Insert_GE_Card( geom_store, &iter_ga );
920 
921 	  /* Insert a new blank GA row after a selected row,
922 	   * if any, otherwise before the last (GE) row */
923 	  Insert_Blank_Geometry_Row(
924 		  geom_treeview, geom_store, &iter_ga, "GA");
925 
926 	  /* Some default values */
927 	  iv[SPIN_COL_I1] = ++gbl_tag_num;
928 	  spin = GTK_SPIN_BUTTON(
929 		  lookup_widget(arc_editor, ispin[SPIN_COL_I1]));
930 	  gtk_spin_button_set_value( spin, iv[SPIN_COL_I1] );
931 
932 	  /* Scroll tree view to bottom */
933 	  gtk_adjustment_set_value(
934 		  geom_adjustment, geom_adjustment->upper);
935 	  break;
936 
937 	case EDITOR_EDIT:  /* Edit an arc row (GA) selected in treeview */
938 	  /* Get selected row */
939 	  Get_Selected_Row(
940 		  geom_treeview, geom_store, &iter_ga, name );
941 
942 	  /* Get arc data from tree view */
943 	  Get_Geometry_Data(
944 		  geom_store, &iter_ga, iv, fv );
945 
946 	  /* Get wire conductivity if specified in LD card */
947 	  Get_Wire_Conductivity(iv[SPIN_COL_I1], &s, cmnd_store);
948 	  break;
949 
950 	case EDITOR_CANCEL: /* Cancel arc editor */
951 	  /* Remove cards */
952 	  Remove_Row( geom_store, &iter_ga );
953 	  save = busy = FALSE;
954 	  return;
955 
956 	case EDITOR_DATA: /* Some data changed in editor window */
957 	  save = TRUE;
958 	  break;
959 
960 	case EDITOR_LOAD: /* Wire conductivity specified */
961 	  spin = GTK_SPIN_BUTTON( lookup_widget(
962 			arc_editor, fspin[SPIN_COL_F6]) );
963 	  s = gtk_spin_button_get_value( spin );
964 	  if( s > 0.0 )
965 	  {
966 		save = TRUE;
967 		load = TRUE;
968 	  }
969 	  else load = FALSE;
970 	  break;
971 
972 	case EDITOR_TAGNUM: /* Tag number edited by user */
973 	  gbl_tag_num = iv[SPIN_COL_I1];
974 	  save = TRUE;
975 	  if( s > 0.0 )	load = TRUE;
976 	  break;
977 
978 	case EDITOR_SEGPC: /* Segment length as % of smallest wavelength */
979 	  /* Calculate num of segs for given % of lambda */
980 	  if( calc_data.mxfrq != 0.0 )
981 	  {
982 		gdouble len = fv[ARC_RAD] *
983 		  (gdouble)fabs( fv[ARC_END1]-fv[ARC_END2] )/(gdouble)TD;
984 		double i = ceil(100.0 / fv[ARC_PCL] *
985 			len /((gdouble)CVEL/(gdouble)calc_data.mxfrq));
986 		iv[SPIN_COL_I2] = (gint)i;
987 	  }
988 	  newpcl = FALSE;
989 	  save = TRUE;
990 
991   } /* switch( action ) */
992 
993   /*** Calculate seg length as % of smallest wavelength ***/
994   if( (calc_data.mxfrq != 0.0) && newpcl )
995   {
996 	gdouble len = fv[ARC_RAD] *
997 	  (gdouble)fabs( fv[ARC_END1]-fv[ARC_END2] )/(gdouble)TD;
998 	fv[ARC_PCL] = 100.0 * (len/(gdouble)iv[SPIN_COL_I2]) /
999 	  ((gdouble)CVEL/(gdouble)calc_data.mxfrq);
1000   }
1001   else newpcl = TRUE;
1002 
1003   /* Write int data to the arc editor */
1004   for( idi = SPIN_COL_I1; idi <= SPIN_COL_I2; idi++ )
1005   {
1006 	spin = GTK_SPIN_BUTTON(
1007 		lookup_widget(arc_editor, ispin[idi]) );
1008 	gtk_spin_button_set_value( spin, iv[idi] );
1009   }
1010 
1011   /* Write float data to the arc editor (F1 to F4 & pcl/resistance) */
1012   fv[ARC_DIA] *= 2.0;
1013   for( idx = ARC_RAD; idx <= ARC_PCL; idx++ )
1014   {
1015 	spin = GTK_SPIN_BUTTON(
1016 		lookup_widget(arc_editor, fspin[idx]) );
1017 	gtk_spin_button_set_value( spin, fv[idx] );
1018   }
1019   fv[ARC_DIA] /= 2.0;
1020 
1021   spin = GTK_SPIN_BUTTON(
1022 	  lookup_widget(arc_editor, fspin[idx]) );
1023   gtk_spin_button_set_value( spin, s );
1024 
1025   /* Wait for GTK to complete its tasks */
1026   while( g_main_context_iteration(NULL, FALSE) );
1027   busy = FALSE;
1028 
1029 } /* Arc_Editor() */
1030 
1031 /*------------------------------------------------------------------------*/
1032 
1033 /* Helix_Editor()
1034  *
1035  * Handles all actions of the helix editor window
1036  */
1037 
1038   void
Helix_Editor(int action)1039 Helix_Editor( int action )
1040 {
1041   /* For looking up spinbuttons */
1042   GtkSpinButton *spin;
1043 
1044   /* For reading/writing to GH rows */
1045   static GtkTreeIter iter_gh;
1046 
1047   gint idx, idi;
1048   gdouble ftmp;
1049 
1050   static gboolean
1051 			load    = FALSE, /* Enable wire loading (conductivity specified) */
1052 			linkall = TRUE,  /* Link all radius spinbuttons  */
1053 			linkzo  = FALSE, /* Link X, Y @ Z=0 spinbuttons  */
1054 			linkzhl = FALSE, /* Link X, Y @ Z=HL spinbuttons */
1055 			helixlh = FALSE, /* Specify a left hand helix */
1056 			newpcl  = TRUE,  /* New percent-of-lambda value  */
1057 			newspc  = TRUE,  /* New percent-of-lambda value  */
1058 			save    = FALSE, /* Enable saving of editor data */
1059 			busy    = FALSE; /* Block callbacks. Must be a better way to do this? */
1060 
1061   /* Float type data, wire conductivity */
1062   static gdouble fv[10], s = 0.0;
1063 
1064   /* Integer type data */
1065   static gint iv[2];
1066 
1067   /* Card (row) name */
1068   gchar name[3];
1069 
1070   /* Spin button names, int & float data */
1071   gchar *ispin[2] =
1072   {
1073 	"helix_tagnum_spinbutton",
1074 	"helix_numseg_spinbutton"
1075   };
1076 
1077   gchar *fspin[10] =
1078   {
1079 	"helix_tspace_spinbutton",
1080 	"helix_len_spinbutton",
1081 	"helix_radxzo_spinbutton",
1082 	"helix_radyzo_spinbutton",
1083 	"helix_radxzhl_spinbutton",
1084 	"helix_radyzhl_spinbutton",
1085 	"helix_dia_spinbutton",
1086 	"helix_pcl_spinbutton",
1087 	"helix_nturns_spinbutton",
1088 	"helix_res_spinbutton"
1089   };
1090 
1091 
1092   /* Block callbacks. (Should be a better way to do this) */
1093   if( Give_Up( &busy, helix_editor) ) return;
1094 
1095   /* Save data to nec2 editor if appropriate */
1096   if( (action & EDITOR_SAVE) && save )
1097   {
1098 	/* Change seg/turn to total number of segs */
1099 	gint tmp = iv[SPIN_COL_I2];
1100 	double i = ceil( (gdouble)iv[SPIN_COL_I2] * fv[HELIX_NTURN] );
1101 	iv[SPIN_COL_I2] = (gint)i;
1102 
1103 	/* Change to left hand helix */
1104 	if( helixlh )
1105 	  fv[HELIX_LEN] = -fv[HELIX_LEN];
1106 
1107 	Set_Geometry_Data( geom_store, &iter_gh, iv, fv );
1108 
1109 	/* Change back */
1110 	iv[SPIN_COL_I2] = tmp;
1111 	fv[HELIX_LEN] = fabs( fv[HELIX_LEN] );
1112 
1113 	/* Set wire conductivity (loading card) */
1114 	if( load )
1115 	  Set_Wire_Conductivity( iv[SPIN_COL_I1], s, cmnd_store );
1116 
1117 	save = load = FALSE;
1118   } /* if( (action & EDITOR_SAVE) && save ) */
1119 
1120   /* Read int data from the helix editor */
1121   for( idi = SPIN_COL_I1; idi <= SPIN_COL_I2; idi++ )
1122   {
1123 	spin = GTK_SPIN_BUTTON(
1124 		lookup_widget(helix_editor, ispin[idi]) );
1125 	iv[idi] = gtk_spin_button_get_value_as_int( spin );
1126   }
1127   /* Read float data from the helix editor */
1128   for( idx = HELIX_TSPACE; idx <= HELIX_RES; idx++ )
1129   {
1130 	spin = GTK_SPIN_BUTTON(
1131 		lookup_widget(helix_editor, fspin[idx]) );
1132 	fv[idx] = gtk_spin_button_get_value( spin );
1133   }
1134   fv[HELIX_DIA] /= 2.0;
1135 
1136   /* Link all radius spinbuttons to X @ Z=0 */
1137   if( linkall )
1138 	fv[HELIX_RYZO] = fv[HELIX_RXZHL] = fv[HELIX_RYZHL] = fv[HELIX_RXZO];
1139 
1140   /* Link X, Y @ Z=0 spinbuttons */
1141   if( linkzo )
1142 	fv[HELIX_RYZO] = fv[HELIX_RXZO];
1143 
1144   /* Link X, Y @ Z=0 spinbuttons */
1145   if( linkzhl )
1146 	fv[HELIX_RYZHL] = fv[HELIX_RXZHL];
1147 
1148   /* Respond to user action */
1149   switch( action )
1150   {
1151 	case EDITOR_NEW: /* New helix row to create */
1152 	  /* Insert a default GE card if list is empty */
1153 	  Insert_GE_Card( geom_store, &iter_gh );
1154 
1155 	  /* Insert a new blank GH row after a selected row,
1156 	   * if any, otherwise before the last (GE) row */
1157 	  Insert_Blank_Geometry_Row(
1158 		  geom_treeview, geom_store, &iter_gh, "GH");
1159 
1160 	  /* Some default values */
1161 	  iv[SPIN_COL_I1] = ++gbl_tag_num;
1162 	  spin = GTK_SPIN_BUTTON( lookup_widget(
1163 			helix_editor, ispin[SPIN_COL_I1]) );
1164 	  gtk_spin_button_set_value( spin, iv[SPIN_COL_I1] );
1165 
1166 	  /* Scroll tree view to bottom */
1167 	  gtk_adjustment_set_value(
1168 		  geom_adjustment, geom_adjustment->upper);
1169 	  break;
1170 
1171 	case EDITOR_EDIT:  /* Edit a helix row (GH) */
1172 	  /* Get selected row */
1173 	  Get_Selected_Row( geom_treeview, geom_store, &iter_gh, name );
1174 
1175 	  /* Get helix data from tree view */
1176 	  Get_Geometry_Data( geom_store, &iter_gh, iv, fv );
1177 
1178 	  /* Get wire conductivity if specified in LD card */
1179 	  Get_Wire_Conductivity(iv[SPIN_COL_I1], &s, cmnd_store);
1180 	  fv[HELIX_RES] = s;
1181 
1182 	  /* Set LH/RH helix check button */
1183 	  {
1184 		GtkToggleButton *toggle =
1185 		  GTK_TOGGLE_BUTTON( lookup_widget(
1186 				helix_editor, "helix_lh_checkbutton") );
1187 		if( fv[HELIX_LEN] < 0.0 )
1188 		  gtk_toggle_button_set_active( toggle, TRUE );
1189 		else
1190 		  gtk_toggle_button_set_active( toggle, FALSE );
1191 	  }
1192 
1193 	  /* If left hand helix */
1194 	  fv[HELIX_LEN] = fabs( fv[HELIX_LEN] );
1195 
1196 	  /* Change to number of segs/turn */
1197 	  fv[HELIX_NTURN] = fv[HELIX_LEN] / fv[HELIX_TSPACE];
1198 	  iv[SPIN_COL_I2] =
1199 		(gint)((gdouble)iv[SPIN_COL_I2] / fv[HELIX_NTURN]);
1200 	  break;
1201 
1202 	case EDITOR_CANCEL: /* Cancel helix editor */
1203 	  /* Remove cards */
1204 	  Remove_Row( geom_store, &iter_gh );
1205 	  save = busy = FALSE;
1206 	  return;
1207 
1208 	case EDITOR_DATA: /* Some data changed in editor window */
1209 	  save = TRUE;
1210 	  break;
1211 
1212 	case EDITOR_LOAD: /* Wire conductivity specified */
1213 	  spin = GTK_SPIN_BUTTON(lookup_widget(
1214 			helix_editor, fspin[HELIX_RES]));
1215 	  s = gtk_spin_button_get_value( spin );
1216 	  if( s > 0.0 )
1217 	  {
1218 		save = TRUE;
1219 		load = TRUE;
1220 	  }
1221 	  else load = FALSE;
1222 	  break;
1223 
1224 	case EDITOR_TAGNUM: /* Tag number edited by user */
1225 	  gbl_tag_num = iv[SPIN_COL_I1];
1226 	  save = TRUE;
1227 	  if( s > 0.0 )	load = TRUE;
1228 	  break;
1229 
1230 	case HELIX_EDITOR_LH: /* Left hand helix */
1231 	  helixlh = TRUE;
1232 	  save = TRUE;
1233 	  break;
1234 
1235 	case HELIX_EDITOR_RH: /* Right hand helix */
1236 	  helixlh = FALSE;
1237 	  save = TRUE;
1238 	  break;
1239 
1240 	case HELIX_EDITOR_LINKALL: /* Link all radius spinbuttons */
1241 	  linkall = TRUE;
1242 	  linkzo  = linkzhl = FALSE;
1243 	  break;
1244 
1245 	case HELIX_EDITOR_LINKZO: /* Link X, Y @ Z=0 spinbuttons */
1246 	  linkzo = TRUE;
1247 	  linkall = linkzhl = FALSE;
1248 	  break;
1249 
1250 	case HELIX_EDITOR_LINKZHL: /* Link X, Y @ Z=HL spinbuttons */
1251 	  linkzhl = TRUE;
1252 	  linkzo  = linkall = FALSE;
1253 	  break;
1254 
1255 	case HELIX_EDITOR_NTURN: /* New number of turns */
1256 	  fv[HELIX_TSPACE] = fv[HELIX_LEN] / fv[HELIX_NTURN];
1257 	  newspc = FALSE;
1258 	  save = TRUE;
1259 	  break;
1260 
1261 	case EDITOR_SEGPC: /* Segment length as % of smallest wavelength */
1262 	  /* Calculate num of segs for given % of lambda */
1263 	  if( calc_data.mxfrq != 0.0 )
1264 	  {
1265 		gdouble len, f;
1266 
1267 		/* Pitch angle of helix, assumes untapered helix */
1268 		f = asin( fv[HELIX_TSPACE] / (gdouble)TP / fv[HELIX_RXZO] );
1269 
1270 		/* Helix turn length */
1271 		len = (gdouble)TP * fv[HELIX_RXZO] / (gdouble)cos( f );
1272 
1273 		/* New number of segments */
1274 		double i = ceil(100.0 / fv[HELIX_PCL]*len /
1275 			((gdouble)CVEL / (gdouble)calc_data.mxfrq) );
1276 		iv[SPIN_COL_I2] = (gint)i;
1277 	  }
1278 	  newpcl = FALSE;
1279 	  save = TRUE;
1280 
1281   } /* switch( action ) */
1282 
1283   /*** Calculate seg length as % of smallest wavelength ***/
1284   if( (calc_data.mxfrq != 0.0) && newpcl )
1285   {
1286 	gdouble len, f;
1287 
1288 	/* Pitch angle of helix, assumes untapered helix */
1289 	f = asin( fv[HELIX_TSPACE]/(gdouble)TP/fv[HELIX_RXZO] );
1290 
1291 	/* Helix turn length */
1292 	len = (gdouble)TP * fv[HELIX_RXZO] / (gdouble)cos( f );
1293 
1294 	fv[HELIX_PCL] = 100.0 * (len/(gdouble)iv[SPIN_COL_I2]) /
1295 	  ((gdouble)CVEL / (gdouble)calc_data.mxfrq);
1296   }
1297   else newpcl = TRUE;
1298 
1299   /* Calculate new turn spacing */
1300   if( newspc )
1301 	fv[HELIX_NTURN] = fv[HELIX_LEN] / fv[HELIX_TSPACE];
1302   else
1303 	newspc = TRUE;
1304 
1305   /* Write int data to the helix editor */
1306   for( idi = SPIN_COL_I1; idi <= SPIN_COL_I2; idi++ )
1307   {
1308 	spin = GTK_SPIN_BUTTON( lookup_widget(
1309 		  helix_editor, ispin[idi]) );
1310 	gtk_spin_button_set_value( spin, iv[idi] );
1311   }
1312 
1313   /* Write float data to the helix editor */
1314   ftmp = fv[HELIX_DIA];
1315   fv[HELIX_DIA] *= 2.0;
1316   for( idx = HELIX_TSPACE; idx <= HELIX_RES; idx++ )
1317   {
1318 	spin = GTK_SPIN_BUTTON( lookup_widget(
1319 		  helix_editor, fspin[idx]) );
1320 	gtk_spin_button_set_value( spin, fv[idx] );
1321   }
1322   fv[HELIX_DIA] = ftmp;
1323 
1324   /* Wait for GTK to complete its tasks */
1325   while( g_main_context_iteration(NULL, FALSE) );
1326   busy = FALSE;
1327 
1328 } /* Helix_Editor() */
1329 
1330 /*------------------------------------------------------------------------*/
1331 
1332 /* Reflect_Editor()
1333  *
1334  * Handles all actions of the reflect editor window
1335  */
1336   void
Reflect_Editor(int action)1337 Reflect_Editor( int action )
1338 {
1339   /* For looking up spinbuttons/checkbuttons */
1340   GtkSpinButton *spin;
1341   GtkToggleButton *toggle;
1342 
1343   /* For reading/writing to GX row */
1344   static GtkTreeIter iter_gx;
1345 
1346   int idx, ck;
1347 
1348   /* Integer type data */
1349   static gint iv[2];
1350 
1351   /* Check button names */
1352   gchar *ckbutton[3] =
1353   {
1354 	"reflect_z_checkbutton",
1355 	"reflect_y_checkbutton",
1356 	"reflect_x_checkbutton"
1357   };
1358 
1359   /* Card (row) name */
1360   gchar name[3];
1361 
1362   static gboolean
1363 	save = FALSE, /* Enable saving of editor data */
1364 		 busy = FALSE; /* Block callbacks. Must be a better way to do this? */
1365 
1366 
1367   /* Block callbacks. (Should be a better way to do this) */
1368   if( Give_Up( &busy, reflect_editor) ) return;
1369 
1370   /* Save data to nec2 editor if appropriate */
1371   if( (action & EDITOR_SAVE) && save )
1372   {
1373 	Set_Geometry_Int_Data( geom_store, &iter_gx, iv );
1374 	save = FALSE;
1375   } /* if( (action & EDITOR_SAVE) && save ) */
1376 
1377   /* Respond to user action */
1378   switch( action )
1379   {
1380 	case EDITOR_NEW: /* New reflect row to create */
1381 	  /* Insert a default GE card if list is empty */
1382 	  Insert_GE_Card( geom_store, &iter_gx );
1383 
1384 	  /* Insert a new blank GX row after a selected row,
1385 	   * if any, otherwise before the last (GE) row */
1386 	  Insert_Blank_Geometry_Row(
1387 		  geom_treeview, geom_store, &iter_gx, "GX");
1388 
1389 	  /* Scroll tree view to bottom */
1390 	  gtk_adjustment_set_value(
1391 		  geom_adjustment, geom_adjustment->upper);
1392 	  break;
1393 
1394 	case EDITOR_EDIT:  /* Edit a reflect row (GX) selected in treeview */
1395 	  /* Get selected row */
1396 	  Get_Selected_Row(
1397 		  geom_treeview, geom_store, &iter_gx, name );
1398 
1399 	  /* Get reflect data from tree view */
1400 	  Get_Geometry_Int_Data( geom_store, &iter_gx, iv );
1401 
1402 	  /* Set reflection axes check buttons */
1403 	  {
1404 		ck = iv[SPIN_COL_I2];
1405 
1406 		for( idx = 0; idx < 3; idx++ )
1407 		{
1408 		  toggle = GTK_TOGGLE_BUTTON(
1409 			  lookup_widget(reflect_editor, ckbutton[idx]) );
1410 		  if( ck & 1 )
1411 			gtk_toggle_button_set_active( toggle, TRUE );
1412 		  else
1413 			gtk_toggle_button_set_active( toggle, FALSE );
1414 		  ck /= 10;
1415 		}
1416 	  }
1417 
1418 	  /* Set tag num increment */
1419 	  spin = GTK_SPIN_BUTTON(
1420 		  lookup_widget(reflect_editor, "reflect_taginc_spinbutton") );
1421 	  gtk_spin_button_set_value( spin, iv[SPIN_COL_I1] );
1422 	  break;
1423 
1424 	case EDITOR_CANCEL: /* Cancel reflect editor */
1425 	  /* Remove cards */
1426 	  Remove_Row( geom_store, &iter_gx );
1427 	  save = busy = FALSE;
1428 	  return;
1429 
1430 	case REFLECT_EDITOR_TOGGLE: /* Reflect button toggled */
1431 	  save = TRUE;
1432 	  break;
1433 
1434 	case EDITOR_DATA: /* Some data changed in editor window */
1435 	  save = TRUE;
1436 
1437   } /* switch( action ) */
1438 
1439   /* Work out the I2 value needed by GX card */
1440   ck = 1;  iv[SPIN_COL_I2] = 0;
1441   for( idx = 0; idx < 3; idx++ )
1442   {
1443 	toggle = GTK_TOGGLE_BUTTON(
1444 		lookup_widget(reflect_editor, ckbutton[idx]) );
1445 	if( gtk_toggle_button_get_active(toggle) )
1446 	  iv[SPIN_COL_I2] += ck;
1447 	ck *= 10;
1448   }
1449 
1450   /* Read tag inc from the reflect editor */
1451   spin = GTK_SPIN_BUTTON(
1452 	  lookup_widget(reflect_editor,
1453 		"reflect_taginc_spinbutton") );
1454   iv[SPIN_COL_I1] = gtk_spin_button_get_value_as_int( spin );
1455 
1456   /* Wait for GTK to complete its tasks */
1457   while( g_main_context_iteration(NULL, FALSE) );
1458   busy = FALSE;
1459 
1460 } /* Reflection_Editor() */
1461 
1462 /*------------------------------------------------------------------------*/
1463 
1464 /* Scale_Editor()
1465  *
1466  * Handles all actions of the scale editor window
1467  */
1468   void
Scale_Editor(int action)1469 Scale_Editor( int action )
1470 {
1471   /* For looking up spinbuttons */
1472   GtkSpinButton *spin;
1473 
1474   /* For reading/writing to GS row */
1475   static GtkTreeIter iter_gs;
1476 
1477   /* Integer type data */
1478   static gint iv[2];
1479 
1480   /* Spin button names, int data */
1481   gchar *ispin[2] =
1482   {
1483 	"scale_from_spinbutton",
1484 	"scale_to_spinbutton"
1485   };
1486 
1487   int idx, idi;
1488 
1489   /* Scale factor */
1490   static gdouble scale = 1.0;
1491 
1492   /* Card (row) name, strings for convertions */
1493   gchar name[3], sf[13], *str;
1494 
1495   static gboolean
1496 	save = FALSE, /* Enable saving of editor data */
1497 		 busy = FALSE; /* Block callbacks. Must be a better way to do this? */
1498 
1499 
1500   /* Block callbacks. (Should be a better way to do this) */
1501   if( Give_Up( &busy, scale_editor) ) return;
1502 
1503   /* Save data to nec2 editor if appropriate */
1504   if( (action & EDITOR_SAVE) && save )
1505   {
1506 	/* Clear all GS columns */
1507 	for( idx = GEOM_COL_I1; idx <= GEOM_COL_F7; idx++ )
1508 	  gtk_list_store_set( geom_store, &iter_gs, idx, "0", -1 );
1509 
1510 	/* Enter tag from-to data */
1511 	Set_Geometry_Int_Data( geom_store, &iter_gs, iv );
1512 
1513 	/* Enter scale factor */
1514 	snprintf( sf, sizeof(sf), "%12.5E", scale );
1515 	gtk_list_store_set(
1516 		geom_store, &iter_gs, GEOM_COL_F1, sf, -1 );
1517 
1518 	save = FALSE;
1519   } /* if( (action & EDITOR_SAVE) && save ) */
1520 
1521   /* Respond to user action */
1522   switch( action )
1523   {
1524 	case EDITOR_NEW: /* New scale row to create */
1525 	  /* Insert a default GE card if list is empty */
1526 	  Insert_GE_Card( geom_store, &iter_gs );
1527 
1528 	  /* Insert a new blank GS row after a selected row,
1529 	   * if any, otherwise before the last (GE) row */
1530 	  Insert_Blank_Geometry_Row(
1531 		  geom_treeview, geom_store, &iter_gs, "GS");
1532 
1533 	  /* Scroll tree view to bottom */
1534 	  gtk_adjustment_set_value(
1535 		  geom_adjustment, geom_adjustment->upper);
1536 	  save = FALSE;
1537 	  break;
1538 
1539 	case EDITOR_EDIT:  /* Edit a scale row (GS) selected in treeview */
1540 	  /* Get selected row */
1541 	  Get_Selected_Row(
1542 		  geom_treeview, geom_store, &iter_gs, name );
1543 
1544 	  /* Get tag from-to data from tree view */
1545 	  Get_Geometry_Int_Data( geom_store, &iter_gs, iv );
1546 
1547 	  /* Get scale data from tree view */
1548 	  if( gtk_list_store_iter_is_valid(geom_store, &iter_gs) )
1549 	  {
1550 		gtk_tree_model_get(	GTK_TREE_MODEL(geom_store),
1551 			&iter_gs, GEOM_COL_F1, &str, -1);
1552 		scale = Strtod( str, NULL );
1553 		g_free( str );
1554 	  }
1555 	  else
1556 		stop( _("Error reading row data\n"\
1557 			    "Invalid list iterator"), ERR_OK );
1558 
1559 	  /* Enter tag from-to data to scale editor */
1560 	  for( idi = SPIN_COL_I1; idi <= SPIN_COL_I2; idi++ )
1561 	  {
1562 		spin = GTK_SPIN_BUTTON(
1563 			lookup_widget(scale_editor, ispin[idi]) );
1564 		gtk_spin_button_set_value( spin, iv[idi] );
1565 	  }
1566 
1567 	  /* Set scale factor to scale editor */
1568 	  spin = GTK_SPIN_BUTTON(
1569 		  lookup_widget(scale_editor, "scale_factor_spinbutton") );
1570 	  gtk_spin_button_set_value( spin, scale );
1571 	  break;
1572 
1573 	case EDITOR_CANCEL: /* Cancel scale editor */
1574 	  /* Remove cards */
1575 	  Remove_Row( geom_store, &iter_gs );
1576 	  save = busy = FALSE;
1577 	  return;
1578 
1579 	case EDITOR_DATA: /* Some data changed in editor window */
1580 	  /* Read int data from the scale editor */
1581 	  for( idi = SPIN_COL_I1; idi <= SPIN_COL_I2; idi++ )
1582 	  {
1583 		spin = GTK_SPIN_BUTTON(
1584 			lookup_widget(scale_editor, ispin[idi]) );
1585 		iv[idi] = gtk_spin_button_get_value_as_int( spin );
1586 	  }
1587 
1588 	  /* Read scale from the scale editor */
1589 	  spin = GTK_SPIN_BUTTON(
1590 		  lookup_widget(scale_editor, "scale_factor_spinbutton") );
1591 	  scale = gtk_spin_button_get_value( spin );
1592 	  save = TRUE;
1593 
1594   } /* switch( action ) */
1595 
1596   /* Wait for GTK to complete its tasks */
1597   while( g_main_context_iteration(NULL, FALSE) );
1598   busy = FALSE;
1599 
1600 } /* Scale_Editor() */
1601 
1602 /*------------------------------------------------------------------------*/
1603 
1604 /* Cylinder_Editor()
1605  *
1606  * Handles all actions of the cylinder editor window
1607  */
1608   void
Cylinder_Editor(int action)1609 Cylinder_Editor( int action )
1610 {
1611   /* For looking up spinbuttons */
1612   GtkSpinButton *spin;
1613 
1614   /* For reading/writing to GR row */
1615   static GtkTreeIter iter_gr;
1616 
1617   int idi;
1618 
1619   /* Integer data (I1 & I2) */
1620   static gint iv[2];
1621 
1622   /* Cylinder data spinbuttons */
1623   static gchar *ispin[2] =
1624   {
1625 	"cylinder_taginc_spinbutton",
1626 	"cylinder_total_spinbutton"
1627   };
1628 
1629   /* Card (row) name, strings for convertions */
1630   gchar name[3];
1631 
1632   static gboolean
1633 	save = FALSE, /* Enable saving of editor data */
1634 		 busy = FALSE; /* Block callbacks. Must be a better way to do this? */
1635 
1636 
1637   /* Block callbacks. (Should be a better way to do this) */
1638   if( Give_Up( &busy, cylinder_editor) ) return;
1639 
1640   /* Save data to nec2 editor if appropriate */
1641   if( (action & EDITOR_SAVE) && save )
1642   {
1643 	Set_Geometry_Int_Data( geom_store, &iter_gr, iv );
1644 	save = FALSE;
1645   } /* if( (action & EDITOR_SAVE) && save ) */
1646 
1647   /* Respond to user action */
1648   switch( action )
1649   {
1650 	case EDITOR_NEW: /* New cylinder row to create */
1651 	  /* Insert a default GE card if list is empty */
1652 	  Insert_GE_Card( geom_store, &iter_gr );
1653 
1654 	  /* Insert a new blank GR row after a selected row,
1655 	   * if any, otherwise before the last (GE) row */
1656 	  Insert_Blank_Geometry_Row(
1657 		  geom_treeview, geom_store, &iter_gr, "GR");
1658 
1659 	  /* Scroll tree view to bottom */
1660 	  gtk_adjustment_set_value(
1661 		  geom_adjustment, geom_adjustment->upper);
1662 	  save = TRUE;
1663 	  break;
1664 
1665 	case EDITOR_EDIT:  /* Edit a cylinder row (GR) selected in treeview */
1666 	  /* Get selected row */
1667 	  Get_Selected_Row(
1668 		  geom_treeview, geom_store, &iter_gr, name);
1669 
1670 	  /* Get integer data from cylinder editor */
1671 	  Get_Geometry_Int_Data( geom_store, &iter_gr, iv );
1672 
1673 	  /* Write int data to the cylinder editor */
1674 	  for( idi = SPIN_COL_I1; idi <= SPIN_COL_I2; idi++ )
1675 	  {
1676 		spin = GTK_SPIN_BUTTON(
1677 			lookup_widget(cylinder_editor, ispin[idi]));
1678 		gtk_spin_button_set_value( spin, iv[idi] );
1679 	  }
1680 	  break;
1681 
1682 	case EDITOR_CANCEL: /* Cancel cylinder editor */
1683 	  /* Remove cards */
1684 	  Remove_Row( geom_store, &iter_gr );
1685 	  save = busy = FALSE;
1686 	  return;
1687 
1688 	case EDITOR_DATA: /* Some data changed in editor window */
1689 	  save = TRUE;
1690 
1691   } /* switch( action ) */
1692 
1693   /* Read int data from the cylinder editor */
1694   for( idi = SPIN_COL_I1; idi <= SPIN_COL_I2; idi++ )
1695   {
1696 	spin = GTK_SPIN_BUTTON(
1697 		lookup_widget(cylinder_editor, ispin[idi]));
1698 	iv[idi] = gtk_spin_button_get_value_as_int( spin );
1699   }
1700 
1701   /* Wait for GTK to complete its tasks */
1702   while( g_main_context_iteration(NULL, FALSE) );
1703   busy = FALSE;
1704 
1705 } /* Cylinder_Editor() */
1706 
1707 /*------------------------------------------------------------------------*/
1708 
1709 /* Transform_Editor()
1710  *
1711  * Handles all actions of the transform editor window
1712  */
1713   void
Transform_Editor(int action)1714 Transform_Editor( int action )
1715 {
1716   /* For looking up spinbuttons */
1717   GtkSpinButton *spin;
1718 
1719   /* For reading/writing to GM row */
1720   static GtkTreeIter iter_gm;
1721 
1722   int idx, idi, idf;
1723 
1724   /* Integer data (I1 to I3) */
1725   static gint iv[3];
1726 
1727   /* Float data (F1 to F7) */
1728   static gdouble fv[7];
1729 
1730   /* Transform int data spinbuttons */
1731   static gchar *ispin[3] =
1732   {
1733 	"transform_taginc_spinbutton",
1734 	"transform_new_spinbutton",
1735 	"transform_start_spinbutton"
1736   };
1737 
1738   /* Transform float data spinbuttons */
1739   static gchar *fspin[6] =
1740   {
1741 	"transform_rx_spinbutton",
1742 	"transform_ry_spinbutton",
1743 	"transform_rz_spinbutton",
1744 	"transform_mx_spinbutton",
1745 	"transform_my_spinbutton",
1746 	"transform_mz_spinbutton"
1747   };
1748 
1749   /* Card (row) name, strings for convertions */
1750   gchar name[3];
1751 
1752   static gboolean
1753 	save = FALSE, /* Enable saving of editor data */
1754 	busy = FALSE; /* Block callbacks. Must be a better way to do this? */
1755 
1756 
1757   /* Block callbacks. (Should be a better way to do this) */
1758   if( Give_Up( &busy, transform_editor) ) return;
1759 
1760   /* Save data to nec2 editor if appropriate */
1761   if( (action & EDITOR_SAVE) && save )
1762   {
1763 	Set_Geometry_Data( geom_store, &iter_gm, iv, fv );
1764 	save = FALSE;
1765   } /* if( (action & EDITOR_SAVE) && save ) */
1766 
1767   /* Respond to user action */
1768   switch( action )
1769   {
1770 	case EDITOR_NEW: /* New transform row to create */
1771 	  /* Insert a default GE card if list is empty */
1772 	  Insert_GE_Card( geom_store, &iter_gm );
1773 
1774 	  /* Insert a new blank GM row after a selected row,
1775 	   * if any, otherwise before the last (GE) row */
1776 	  Insert_Blank_Geometry_Row(
1777 		  geom_treeview, geom_store, &iter_gm, "GM");
1778 
1779 	  /* Scroll tree view to bottom */
1780 	  gtk_adjustment_set_value(
1781 		  geom_adjustment, geom_adjustment->upper);
1782 	  break;
1783 
1784 	case EDITOR_EDIT:  /* Edit transform row (GM) selected in treeview */
1785 	  /* Get selected row */
1786 	  Get_Selected_Row(geom_treeview, geom_store, &iter_gm, name);
1787 
1788 	  /* Get integer data from transform editor */
1789 	  Get_Geometry_Data( geom_store, &iter_gm, iv, fv );
1790 
1791 	  /* Write int data to the transform editor */
1792 	  iv[SPIN_COL_I3] = (gint)fv[SPIN_COL_F7];
1793 	  for( idi = SPIN_COL_I1; idi <= SPIN_COL_I3; idi++ )
1794 	  {
1795 		spin = GTK_SPIN_BUTTON(
1796 			lookup_widget(transform_editor, ispin[idi]));
1797 		gtk_spin_button_set_value( spin, iv[idi] );
1798 	  }
1799 	  /* Write float data to the transform editor */
1800 	  for( idf = SPIN_COL_F1; idf <= SPIN_COL_F6; idf++ )
1801 	  {
1802 		spin = GTK_SPIN_BUTTON(
1803 			lookup_widget(transform_editor, fspin[idf]));
1804 		gtk_spin_button_set_value( spin, fv[idf] );
1805 	  }
1806 	  break;
1807 
1808 	case EDITOR_CANCEL: /* Cancel transform editor */
1809 	  /* Remove cards */
1810 	  Remove_Row( geom_store, &iter_gm );
1811 	  save = busy = FALSE;
1812 	  return;
1813 
1814 	case EDITOR_DATA: /* Some data changed in editor window */
1815 	  save = TRUE;
1816 
1817   } /* switch( action ) */
1818 
1819   /* Read int data from the transform editor */
1820   for( idi = SPIN_COL_I1; idi <= SPIN_COL_I3; idi++ )
1821   {
1822 	spin = GTK_SPIN_BUTTON(
1823 		lookup_widget(transform_editor, ispin[idi]));
1824 	iv[idi] = gtk_spin_button_get_value_as_int( spin );
1825   }
1826   /* Read float data from the transform editor */
1827   for( idx = 0; idx < 6; idx++ )
1828   {
1829 	spin = GTK_SPIN_BUTTON(
1830 		lookup_widget(transform_editor, fspin[idx]));
1831 	fv[idx] = gtk_spin_button_get_value( spin );
1832   }
1833   fv[SPIN_COL_F7] = (gdouble)iv[SPIN_COL_I3];
1834 
1835   /* Wait for GTK to complete its tasks */
1836   while( g_main_context_iteration(NULL, FALSE) );
1837   busy = FALSE;
1838 
1839 } /* Transform_Editor() */
1840 
1841 /*------------------------------------------------------------------------*/
1842 
1843 /* Gend_Editor()
1844  *
1845  * Edits the GE card
1846  */
1847 
1848   void
Gend_Editor(int action)1849 Gend_Editor( int action )
1850 {
1851   /* For reading/writing to GE row */
1852   static GtkTreeIter iter_ge;
1853 
1854   /* For checking radio buttons */
1855   GtkToggleButton *toggle;
1856 
1857   /* Ground type radio buttons */
1858 #define GE_RDBTN 3
1859   static gchar *rdbutton[GE_RDBTN] =
1860   {
1861 	"gend_noimg_radiobutton",
1862 	"gend_nognd_radiobutton",
1863 	"gend_img_radiobutton"
1864   };
1865 
1866   /* Card (row) name, strings for convertions */
1867   gchar name[3], *sv;
1868   static gchar si[6];
1869 
1870   int idx;
1871 
1872   static gboolean
1873 	save = FALSE, /* Enable saving of editor data */
1874 		 busy = FALSE; /* Block callbacks. Must be a better way to do this? */
1875 
1876 
1877   /* Block callbacks. (Should be a better way to do this) */
1878   if( Give_Up( &busy, gend_editor) ) return;
1879 
1880   /* Save data to nec2 editor if appropriate */
1881   if( (action & EDITOR_SAVE) && save &&
1882 	  gtk_list_store_iter_is_valid(geom_store, &iter_ge))
1883   {
1884 	gtk_list_store_set(
1885 		geom_store, &iter_ge, GEOM_COL_I1, si, -1 );
1886 	save = FALSE;
1887   } /* if( (action & EDITOR_SAVE) && save ) */
1888 
1889   /* Respond to user action */
1890   switch( action )
1891   {
1892 	case EDITOR_EDIT:  /* Edit geom end row (GE) */
1893 	  /* Open GE Editor */
1894 	  if( gend_editor == NULL )
1895 	  {
1896 		gend_editor = create_gend_editor();
1897 		gtk_widget_show( gend_editor );
1898 	  }
1899 
1900 	  /* Get selected row */
1901 	  Get_Selected_Row( geom_treeview, geom_store, &iter_ge, name );
1902 
1903 	  /* Get integer data from transform editor */
1904 	  if( gtk_list_store_iter_is_valid(geom_store, &iter_ge) )
1905 	  {
1906 		gtk_tree_model_get( GTK_TREE_MODEL(geom_store),
1907 			&iter_ge, GEOM_COL_I1, &sv, -1 );
1908 		idx = atoi(sv) + 1;
1909 		g_free(sv);
1910 		toggle = GTK_TOGGLE_BUTTON( lookup_widget(
1911 			  gend_editor, rdbutton[idx]) );
1912 		gtk_toggle_button_set_active( toggle, TRUE );
1913 	  }
1914 	  else stop( _("Error reading row data\n"\
1915 			"Invalid list iterator"), ERR_OK );
1916 	  break;
1917 
1918 	case EDITOR_CANCEL: /* Cancel transform editor */
1919 	  /* Remove card */
1920 	  Remove_Row( geom_store, &iter_ge );
1921 	  save = busy = FALSE;
1922 	  return;
1923 
1924 	case EDITOR_RDBUTTON: /* Radio button toggled in editor window */
1925 	  /* Test radio buttons */
1926 	  for( idx = 0; idx < GE_RDBTN; idx++ )
1927 	  {
1928 		toggle = GTK_TOGGLE_BUTTON( lookup_widget(
1929 			  gend_editor, rdbutton[idx]) );
1930 		if( gtk_toggle_button_get_active(toggle) )
1931 		  break;
1932 	  }
1933 	  snprintf( si, sizeof(si), "%5d", idx-1 );
1934 	  save = TRUE;
1935 
1936   } /* switch( action ) */
1937 
1938   /* Wait for GTK to complete its tasks */
1939   while( g_main_context_iteration(NULL, FALSE) );
1940   busy = FALSE;
1941 
1942 } /* Gend_Editor() */
1943 
1944 /*------------------------------------------------------------------------*/
1945 
1946 /* Insert_GE_Card()
1947  *
1948  * Inserts a default GE card if missing
1949  */
1950 
1951   void
Insert_GE_Card(GtkListStore * store,GtkTreeIter * iter)1952 Insert_GE_Card( GtkListStore *store, GtkTreeIter *iter )
1953 {
1954   gint idx, idi;
1955 
1956   /* Insert default GE card if list is clear */
1957   idx = gtk_tree_model_iter_n_children(
1958 	  GTK_TREE_MODEL(store), NULL );
1959   if( !idx )
1960   {
1961 	gtk_list_store_append( store, iter );
1962 	gtk_list_store_set( store, iter, GEOM_COL_NAME, "GE", -1 );
1963 	for( idi = GEOM_COL_I1; idi < GEOM_NUM_COLS; idi++ )
1964 	  gtk_list_store_set( store, iter, idi, "0", -1 );
1965   }
1966 
1967 } /* Insert_GE_Card() */
1968 
1969 /*------------------------------------------------------------------------*/
1970 
1971 /* Get_Geometry_Data()
1972  *
1973  * Gets geometry data from a treeview row
1974  */
1975 
1976   void
Get_Geometry_Data(GtkListStore * store,GtkTreeIter * iter,int * iv,double * fv)1977 Get_Geometry_Data(
1978 	GtkListStore *store,
1979 	GtkTreeIter *iter,
1980 	int *iv, double *fv )
1981 {
1982   gint idi, idf;
1983   gchar *sv;
1984 
1985   /* Get data from tree view (I1,I2, F1-F7)*/
1986   if( gtk_list_store_iter_is_valid(store, iter) )
1987   {
1988 	for( idi = GEOM_COL_I1; idi <= GEOM_COL_I2; idi++ )
1989 	{
1990 	  gtk_tree_model_get(
1991 		  GTK_TREE_MODEL(store), iter, idi, &sv, -1);
1992 	  iv[idi-GEOM_COL_I1] = atoi(sv);
1993 	  g_free(sv);
1994 	}
1995 	for( idf = GEOM_COL_F1; idf <= GEOM_COL_F7; idf++ )
1996 	{
1997 	  gtk_tree_model_get(
1998 		  GTK_TREE_MODEL(store), iter, idf, &sv, -1);
1999 	  fv[idf-GEOM_COL_F1] = Strtod( sv, NULL );
2000 	  g_free(sv);
2001 	}
2002   }
2003   else stop( _("Error reading row data\n"\
2004 		"Invalid list iterator"), ERR_OK );
2005 
2006 } /* Get_Geometry_Data() */
2007 
2008 /*------------------------------------------------------------------------*/
2009 
2010 /* Get_Geometry_Int_Data()
2011  *
2012  * Gets integer (I1, I2) geometry data from a treeview row
2013  */
2014 
2015   void
Get_Geometry_Int_Data(GtkListStore * store,GtkTreeIter * iter,int * iv)2016 Get_Geometry_Int_Data( GtkListStore *store, GtkTreeIter *iter, int *iv )
2017 {
2018   gint idi;
2019   gchar *sv;
2020 
2021   /* Get data from tree view (I1, I2) */
2022   if( gtk_list_store_iter_is_valid(store, iter) )
2023   {
2024 	for( idi = GEOM_COL_I1; idi <= GEOM_COL_I2; idi++ )
2025 	{
2026 	  gtk_tree_model_get(
2027 		  GTK_TREE_MODEL(store), iter, idi, &sv, -1);
2028 	  iv[idi-GEOM_COL_I1] = atoi(sv);
2029 	  g_free(sv);
2030 	}
2031   }
2032   else stop( _("Error reading row data\n"\
2033 		"Invalid list iterator"), ERR_OK );
2034 
2035 } /* Get_Geometry_Int_Data() */
2036 
2037 /*------------------------------------------------------------------------*/
2038 
2039 /* Set_Geometry_Data()
2040  *
2041  * Sets data into a geometry row
2042  */
2043 
2044   void
Set_Geometry_Data(GtkListStore * store,GtkTreeIter * iter,int * iv,double * fv)2045 Set_Geometry_Data(
2046 	GtkListStore *store,
2047 	GtkTreeIter *iter,
2048 	int *iv, double *fv )
2049 {
2050   gchar str[13];
2051   gint idi, idf;
2052 
2053   /* Format and set editor data to treeview (I1, I2 & F1-F7) */
2054   if( gtk_list_store_iter_is_valid(store, iter) )
2055   {
2056 	for( idi = GEOM_COL_I1; idi <= GEOM_COL_I2; idi++ )
2057 	{
2058 	  snprintf( str, 6, "%5d", iv[idi-GEOM_COL_I1] );
2059 	  gtk_list_store_set( store, iter, idi, str, -1 );
2060 	}
2061 
2062 	for( idf = GEOM_COL_F1; idf <= GEOM_COL_F7; idf++ )
2063 	{
2064 	  snprintf( str, 13, "%12.5E", fv[idf-GEOM_COL_F1] );
2065 	  gtk_list_store_set( store, iter, idf, str, -1 );
2066 	}
2067   }
2068   else stop( _("Error writing row data\n"\
2069 		"Please re-select row"), ERR_OK );
2070 
2071   SetFlag( NEC2_EDIT_SAVE );
2072 
2073 } /* Set_Geometry_Data() */
2074 
2075 /*------------------------------------------------------------------------*/
2076 
2077 /* Set_Geometry_Int_Data()
2078  *
2079  * Sets integer (I1, I2) data into a geometry row
2080  */
2081 
2082   void
Set_Geometry_Int_Data(GtkListStore * store,GtkTreeIter * iter,int * iv)2083 Set_Geometry_Int_Data( GtkListStore *store, GtkTreeIter *iter, int *iv )
2084 {
2085   gchar str[6];
2086   gint idi, idf;
2087 
2088   /* Format and set editor data to treeview (I1, I2) */
2089   if( gtk_list_store_iter_is_valid(store, iter) )
2090   {
2091 	for( idi = GEOM_COL_I1; idi <= GEOM_COL_I2; idi++ )
2092 	{
2093 	  snprintf( str, sizeof(str), "%5d", iv[idi-GEOM_COL_I1] );
2094 	  gtk_list_store_set( store, iter, idi, str, -1 );
2095 	}
2096 
2097 	/* Clear unused float columns */
2098 	for( idf = GEOM_COL_F1; idf <= GEOM_COL_F7; idf++ )
2099 	  gtk_list_store_set( store, iter, idf, "0.0", -1 );
2100   }
2101   else stop( _("Error writing row data\n"\
2102 		"Please re-select row"), ERR_OK );
2103 
2104   SetFlag( NEC2_EDIT_SAVE );
2105 
2106 } /* Set_Geometry_Int_Data() */
2107 
2108 /*------------------------------------------------------------------------*/
2109 
2110 /* Check_Card_Name()
2111  *
2112  * Checks previous or next card's name, returns TRUE on match
2113  */
2114 
2115   gboolean
Check_Card_Name(GtkListStore * store,GtkTreeIter * iter,gboolean next,const gchar * name)2116 Check_Card_Name(
2117 	GtkListStore *store,
2118 	GtkTreeIter *iter,
2119 	gboolean next,
2120 	const gchar *name )
2121 {
2122   gboolean retv;
2123   char *str;
2124 
2125   retv = FALSE;
2126   if( gtk_list_store_iter_is_valid(store, iter) )
2127   {
2128 	if( next )
2129 	{
2130 	  if( gtk_tree_model_iter_next(GTK_TREE_MODEL(store), iter) )
2131 	  {
2132 		gtk_tree_model_get( GTK_TREE_MODEL(store),
2133 			iter, GEOM_COL_NAME, &str, -1);
2134 		if( strcmp(name, str) == 0 ) retv = TRUE;
2135 		g_free(str);
2136 	  }
2137 	}
2138 	else
2139 	{
2140 	  if( gtk_tree_model_iter_previous(GTK_TREE_MODEL(store), iter) )
2141 	  {
2142 		gtk_tree_model_get( GTK_TREE_MODEL(store), iter,
2143 			GEOM_COL_NAME, &str, -1);
2144 		if( strcmp(name, str) == 0 ) retv = TRUE;
2145 		g_free(str);
2146 	  }
2147 	}
2148   }
2149 
2150   return( retv );
2151 
2152 } /* Check_Card_Name() */
2153 
2154 /*------------------------------------------------------------------------*/
2155 
2156 /* Give_Up()
2157  *
2158  * Signals functon to abort if busy or no NEC2 editor window
2159  */
2160 
2161   gboolean
Give_Up(int * busy,GtkWidget * widget)2162 Give_Up( int *busy, GtkWidget *widget )
2163 {
2164   /* Block callbacks. (Should be a better way to do this) */
2165   if( *busy ) return( TRUE );
2166   *busy = TRUE;
2167 
2168   /* Abort if NEC2 editor window is closed */
2169   if( nec2_edit_window == NULL )
2170   {
2171 	stop( _("NEC2 editor window not open"), ERR_OK );
2172 	gtk_widget_destroy( widget );
2173 	*busy = FALSE;
2174 	return( TRUE );
2175   }
2176 
2177   return( FALSE );
2178 
2179 } /* Give_Up() */
2180 
2181 /*------------------------------------------------------------------------*/
2182 
2183 /* Insert_Blank_Geometry_Row()
2184  *
2185  * Inserts a blank row in a tree view with only its name (GW ... )
2186  */
2187 
2188   void
Insert_Blank_Geometry_Row(GtkTreeView * view,GtkListStore * store,GtkTreeIter * iter,const gchar * name)2189 Insert_Blank_Geometry_Row(
2190 	GtkTreeView *view, GtkListStore *store,
2191 	GtkTreeIter *iter, const gchar *name )
2192 {
2193   GtkTreeSelection *selection;
2194   gboolean retv;
2195   gint n;
2196   gchar *str;
2197 
2198   if( nec2_edit_window == NULL )
2199 	return;
2200 
2201   /* Get selected row, if any */
2202   selection = gtk_tree_view_get_selection( view );
2203   retv = gtk_tree_selection_get_selected(
2204 	  selection, NULL, iter );
2205 
2206   /* If no selected row, insert new row into list
2207    * store before last row, else after the selected row,
2208    * but if this is a GE row, then insert before it */
2209   if( !retv )
2210   {
2211 	n = gtk_tree_model_iter_n_children(
2212 		GTK_TREE_MODEL(store), NULL );
2213 	gtk_tree_model_iter_nth_child(
2214 		GTK_TREE_MODEL(store), iter, NULL, n-1 );
2215 	gtk_list_store_insert_before( store, iter, iter );
2216   }
2217   else
2218   {
2219 	gtk_tree_model_get( GTK_TREE_MODEL(store),
2220 		iter, GEOM_COL_NAME, &str, -1 );
2221 	if( strcmp(str, "GE") == 0 )
2222 	  gtk_list_store_insert_before( store, iter, iter );
2223 	else
2224 	  gtk_list_store_insert_after( store, iter, iter );
2225 	g_free(str);
2226   }
2227 
2228   gtk_list_store_set( store, iter, GEOM_COL_NAME, name, -1 );
2229   for( n = GEOM_COL_I1; n < GEOM_NUM_COLS; n++ )
2230 	gtk_list_store_set( store, iter, n, "--", -1 );
2231   gtk_tree_selection_select_iter( selection, iter );
2232 
2233 } /* Insert_Blank_Geometry_Row() */
2234 
2235 /*------------------------------------------------------------------------*/
2236 
2237 /* Remove_Row()
2238  *
2239  * Removes a row and selects previous or next row
2240  */
2241 
2242   void
Remove_Row(GtkListStore * store,GtkTreeIter * iter)2243 Remove_Row( GtkListStore *store, GtkTreeIter *iter )
2244 {
2245   if( gtk_list_store_iter_is_valid(store, iter) )
2246 	gtk_list_store_remove( store, iter );
2247 
2248 } /* Remove_Row() */
2249 
2250 /*------------------------------------------------------------------------*/
2251 
2252 /* Get_Selected_Row()
2253  *
2254  * Gets the selected row in a tree view
2255  */
2256 
2257   gboolean
Get_Selected_Row(GtkTreeView * view,GtkListStore * store,GtkTreeIter * iter,gchar * name)2258 Get_Selected_Row(
2259 	GtkTreeView *view,
2260 	GtkListStore *store,
2261 	GtkTreeIter *iter,
2262 	gchar *name )
2263 {
2264   gchar *str;
2265   GtkTreeSelection *selection;
2266 
2267   /* Get selected row, if any */
2268   selection = gtk_tree_view_get_selection( view );
2269   if( !gtk_tree_selection_get_selected(selection, NULL, iter) )
2270 	return( FALSE );
2271 
2272   /* Get row name */
2273   gtk_tree_model_get(
2274 	  GTK_TREE_MODEL(store), iter, GEOM_COL_NAME, &str, -1);
2275   Strlcpy( name, str, 3 );
2276   g_free( str );
2277 
2278   return( TRUE );
2279 
2280 } /* Get_Selected_Row() */
2281 
2282 /*------------------------------------------------------------------------*/
2283 
2284 /* Set_Wire_Conductivity()
2285  *
2286  * Sets the wire conductivity specified in a geometry editor
2287  * (wire, arc, helix) to a loading card (LD row) in commands treview
2288  */
2289 
2290   void
Set_Wire_Conductivity(int tag,double s,GtkListStore * store)2291 Set_Wire_Conductivity( int tag, double s, GtkListStore *store )
2292 {
2293   int idx, idi, nchld;
2294   GtkTreeIter iter_ld;
2295   gchar *str, sv[13];
2296 
2297   /* Find num of rows and first iter, abort if tree empty */
2298   nchld = gtk_tree_model_iter_n_children(
2299 	  GTK_TREE_MODEL(store), NULL);
2300   if(!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter_ld))
2301 	return;
2302 
2303   /* Look for an LD card with tag number = tag */
2304   for( idx = 0; idx < nchld; )
2305   {
2306 	gtk_tree_model_get( GTK_TREE_MODEL(store),
2307 		&iter_ld, GEOM_COL_NAME, &str, -1 );
2308 
2309 	if( strcmp(str, "LD") == 0 )
2310 	{
2311 	  g_free( str );
2312 	  gtk_tree_model_get( GTK_TREE_MODEL(store),
2313 		  &iter_ld, GEOM_COL_I2, &str, -1 );
2314 	  if( atoi( str ) == tag )
2315 	  {
2316 		g_free( str );
2317 		break;
2318 	  }
2319 	  else g_free( str );
2320 	}
2321 	else g_free( str );
2322 
2323 	idx++;
2324 	if( !gtk_tree_model_iter_next(
2325 		  GTK_TREE_MODEL(store), &iter_ld) )
2326 	  break;
2327 
2328   } /* for( idx = 0; idx < nchld; idx++ ) */
2329 
2330   /* If not found LD card with tagnum = tag, insert new */
2331   if( idx >= nchld )
2332   {
2333 	gtk_tree_model_iter_nth_child(
2334 		GTK_TREE_MODEL(store), &iter_ld, NULL, nchld-1 );
2335 	gtk_list_store_insert_before( store, &iter_ld, &iter_ld );
2336 	gtk_list_store_set(
2337 		store, &iter_ld, CMND_COL_NAME, "LD", -1 );
2338 
2339 	/* Clear rest of LD row */
2340 	for( idi = CMND_COL_I1; idi <= CMND_COL_F6; idi++ )
2341 	  gtk_list_store_set( store, &iter_ld, idi, "0", -1 );
2342   }
2343 
2344   /* Set LD card parameters */
2345   gtk_list_store_set( store, &iter_ld, CMND_COL_I1, "5", -1 );
2346   snprintf( sv, 6, "%5d", tag );
2347   gtk_list_store_set( store, &iter_ld, CMND_COL_I2, sv, -1 );
2348   snprintf( sv, 13, "%12.5E", s );
2349   gtk_list_store_set( store, &iter_ld, CMND_COL_F1, sv, -1 );
2350 
2351   /* Scroll tree view to bottom */
2352   gtk_adjustment_set_value(
2353 	  cmnd_adjustment, cmnd_adjustment->upper );
2354 
2355 } /* Set_Wire_Conductivity() */
2356 
2357 /*------------------------------------------------------------------------*/
2358 
2359 /* Get_Wire_Conductivity()
2360  *
2361  * Gets the wire conductivity specified in a loading
2362  * card (LD row) in commands treview for a given tag #
2363  */
2364 
2365   gboolean
Get_Wire_Conductivity(int tag,double * s,GtkListStore * store)2366 Get_Wire_Conductivity( int tag, double *s, GtkListStore *store )
2367 {
2368   int idx, type, nchld;
2369   GtkTreeIter iter_ld;
2370   gchar *str;
2371   static int t = -1;
2372 
2373   /* Find num of rows and first iter, abort if tree empty */
2374   nchld = gtk_tree_model_iter_n_children(
2375 	  GTK_TREE_MODEL(store), NULL );
2376   if( !gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter_ld) )
2377 	return( FALSE );
2378 
2379   /* Look for an LD card with tag number = tag */
2380   for( idx = 0; idx < nchld; )
2381   {
2382 	gtk_tree_model_get( GTK_TREE_MODEL(store),
2383 		&iter_ld, GEOM_COL_NAME, &str, -1 );
2384 
2385 	if( strcmp(str, "LD") == 0 )
2386 	{
2387 	  g_free( str );
2388 	  gtk_tree_model_get( GTK_TREE_MODEL(store),
2389 		  &iter_ld, GEOM_COL_I2, &str, -1 );
2390 	  if( atoi(str) == tag )
2391 	  {
2392 		g_free( str );
2393 		break;
2394 	  }
2395 	  else g_free( str );
2396 	}
2397 	else g_free( str );
2398 
2399 	idx++;
2400 	if( !gtk_tree_model_iter_next(
2401 		  GTK_TREE_MODEL(store), &iter_ld) )
2402 	  break;
2403 
2404   } /* for( idx = 0; idx < nchld; idx++ ) */
2405 
2406   /* If not found LD card with tagnum = tag, return s=0 */
2407   if( idx >= nchld )
2408   {
2409 	*s = 0.0;
2410 	t = tag;
2411 	return( FALSE );
2412   }
2413 
2414   /* If LD card for given tag is already read, abort */
2415   if( t == tag ) return( FALSE );
2416   else t = tag;
2417 
2418   /* Get the loading type (we want LDTYP 5) */
2419   gtk_tree_model_get( GTK_TREE_MODEL(store),
2420 	  &iter_ld, GEOM_COL_I1, &str, -1 );
2421   type = atoi( str );
2422   g_free( str );
2423   if( type != 5 ) return( FALSE );
2424 
2425   /* Get the wire conductivity S/m */
2426   gtk_tree_model_get( GTK_TREE_MODEL(store),
2427 	  &iter_ld, CMND_COL_F1, &str, -1 );
2428   *s = Strtod( str, NULL );
2429   g_free( str );
2430 
2431   return( TRUE );
2432 } /* Get_Wire_Conductivity() */
2433 
2434 /*------------------------------------------------------------------------*/
2435 
2436