1 /*
2  *
3  * XASTIR, Amateur Station Tracking and Information Reporting
4  * Copyright (C) 1999,2000  Frank Giannandrea
5  * Copyright (C) 2000-2019 The Xastir Group
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20  *
21  * Look at the README for more information on the program.
22  */
23 
24 
25 #ifdef HAVE_CONFIG_H
26   #include "config.h"
27 #endif  // HAVE_CONFIG_H
28 
29 #include "snprintf.h"
30 
31 #include <stdint.h>
32 #include <ctype.h>
33 #include <math.h>
34 
35 #if TIME_WITH_SYS_TIME
36   #include <sys/time.h>
37   #include <time.h>
38 #else   // TIME_WITH_SYS_TIME
39   #if HAVE_SYS_TIME_H
40     #include <sys/time.h>
41   #else  // HAVE_SYS_TIME_H
42     #include <time.h>
43   #endif // HAVE_SYS_TIME_H
44 #endif  // TIME_WITH_SYS_TIME
45 
46 #include "xastir.h"
47 #include "draw_symbols.h"
48 #include "main.h"
49 #include "xa_config.h"
50 #include "maps.h"
51 #include "interface.h"
52 #include "objects.h"
53 
54 void move_station_time(DataRow *p_curr, DataRow *p_time);
55 
56 #include <Xm/XmAll.h>
57 #include <X11/cursorfont.h>
58 
59 // Must be last include file
60 #include "leak_detection.h"
61 
62 
63 extern XmFontList fontlist1;    // Menu/System fontlist
64 
65 // lesstif (at least as of version 0.94 in 2008), doesn't
66 // have full implementation of combo boxes.
67 #ifndef USE_COMBO_BOX
68   #if (XmVERSION >= 2 && !defined(LESSTIF_VERSION))
69     #define USE_COMBO_BOX 1
70   #endif
71 #endif  // USE_COMBO_BOX
72 
73 
74 // ---------------------------- object -------------------------------
75 Widget object_dialog = (Widget)NULL;
76 Widget df_object_dialog = (Widget)NULL;
77 Widget object_name_data,
78        object_lat_data_deg, object_lat_data_min, object_lat_data_ns,
79        object_lon_data_deg, object_lon_data_min, object_lon_data_ew,
80        object_group_data, object_symbol_data, object_icon,
81        object_comment_data, ob_frame, ob_group, ob_symbol,
82        ob_option_frame,
83        signpost_frame, area_frame, area_toggle, signpost_toggle,
84        df_bearing_toggle, map_view_toggle, probabilities_toggle,
85        ob_bearing_data, frameomni, framebeam,
86        ob_speed, ob_speed_data, ob_course, ob_course_data,
87        ob_comment,
88        ob_altitude, ob_altitude_data, signpost_data,
89        probability_data_min, probability_data_max,
90        open_filled_toggle, ob_lat_offset_data, ob_lon_offset_data,
91        ob_corridor, ob_corridor_data, ob_corridor_miles,
92        omni_antenna_toggle, beam_antenna_toggle;
93 Pixmap Ob_icon0, Ob_icon;
94 void Set_Del_Object(Widget w, XtPointer clientData, XtPointer calldata);
95 // Array to hold predefined objects to display on Create/Move popup menu.
96 predefinedObject predefinedObjects[MAX_NUMBER_OF_PREDEFINED_OBJECTS];
97 void Populate_predefined_objects(predefinedObject *predefinedObjects);
98 int number_of_predefined_objects;
99 char predefined_object_definition_filename[256] = "predefined_SAR.sys";
100 int predefined_menu_from_file = 0;
101 
102 int Area_object_enabled = 0;
103 int Map_View_object_enabled = 0;
104 int Area_type = 0;
105 char Area_color[3] = "/0";
106 int Area_bright = 0;
107 int Area_filled = 0;
108 int Signpost_object_enabled = 0;
109 int Probability_circles_enabled = 0;
110 int DF_object_enabled = 0;
111 int Omni_antenna_enabled = 0;
112 int Beam_antenna_enabled = 0;
113 char object_shgd[5] = "0000\0";
114 char object_NRQ[4] = "960\0";
115 XtPointer global_parameter1 = (XtPointer)NULL;
116 XtPointer global_parameter2 = (XtPointer)NULL;
117 
118 int polygon_last_x = -1;        // Draw CAD Objects functions
119 int polygon_last_y = -1;        // Draw CAD Objects functions
120 
121 int doing_move_operation = 0;
122 
123 Widget draw_CAD_objects_dialog = (Widget)NULL;
124 Widget cad_dialog = (Widget)NULL;
125 Widget cad_label_data,
126        cad_comment_data,
127        cad_probability_data,
128        cad_line_style_data;
129 // Values entered in the cad_dialog
130 int draw_CAD_objects_flag = 0;
131 void Draw_All_CAD_Objects(Widget w);
132 void Save_CAD_Objects_to_file(void);
133 Widget cad_erase_dialog;
134 Widget list_of_existing_CAD_objects = (Widget)NULL;
135 Widget cad_list_dialog = (Widget)NULL;
136 Widget list_of_existing_CAD_objects_edit = (Widget)NULL;
137 void Format_area_for_output(double *area_km2, char *area_description, int sizeof_area_description);
138 void Update_CAD_objects_list_dialog(void);
139 void CAD_object_set_raw_probability(CADRow *object_ptr, float probability, int as_percent);
140 int CAD_draw_objects = TRUE;
141 int CAD_show_label = TRUE;
142 int CAD_show_raw_probability = TRUE;
143 int CAD_show_comment = TRUE;
144 int CAD_show_area = TRUE;
145 void Draw_CAD_Objects_erase_dialog_close(Widget w, XtPointer clientData, XtPointer callData);
146 void Draw_CAD_Objects_list_dialog_close(Widget w, XtPointer clientData, XtPointer callData);
147 #ifndef USE_COMBO_BOX
148   int clsd_value;  // replacement value for cad line type combo box
149 #endif // !USE_COMBO_BOX
150 
151 
152 ////////////////////////////////////////////////////////////////////////////////////////////////////
153 
154 // Init values for Objects dialog
155 char last_object[9+1];
156 char last_obj_grp;
157 char last_obj_sym;
158 char last_obj_overlay;
159 char last_obj_comment[34+1];
160 
161 
162 
163 /////////////////////////////////////////////////////////////////////////
164 
165 
166 
167 /*
168  *  Check for a valid object name
169  */
valid_object(char * name)170 int valid_object(char *name)
171 {
172   int len, i;
173 
174   // max 9 printable ASCII characters, case sensitive   [APRS
175   // Reference]
176   len = (int)strlen(name);
177   if (len > 9 || len == 0)
178   {
179     return(0);  // wrong size
180   }
181 
182   for (i=0; i<len; i++)
183     if (!isprint((int)name[i]))
184     {
185       return(0);  // not printable
186     }
187 
188   return(1);
189 }
190 
191 
192 
193 
194 
195 /*
196  *  Check for a valid item name (3-9 chars, any printable ASCII
197  *  except '!' or '_')
198  */
valid_item(char * name)199 int valid_item(char *name)
200 {
201   int len, i;
202 
203   // min 3, max 9 printable ASCII characters, case sensitive
204   // [APRS Reference]
205   len = (int)strlen(name);
206   if (len > 9 || len < 3)
207   {
208     return(0);  // Wrong size
209   }
210 
211   for (i=0; i<len; i++)
212   {
213     if (!isprint((int)name[i]))
214     {
215       return(0);                  // Not printable
216     }
217     if ( (name[i] == '!') || (name[i] == '_') )
218     {
219       return(0);                  // Contains '!' or '_'
220     }
221   }
222 
223   return(1);
224 }
225 
226 
227 
228 
229 
230 /*
231  *  Clear out object/item history log file
232  */
Object_History_Clear(Widget UNUSED (w),XtPointer UNUSED (clientData),XtPointer UNUSED (callData))233 void Object_History_Clear( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) )
234 {
235   char *file;
236   FILE *f;
237   char temp_file_path[MAX_VALUE];
238 
239   file = get_user_base_dir("config/object.log", temp_file_path, sizeof(temp_file_path));
240 
241   f=fopen(file,"w");
242   if (f!=NULL)
243   {
244     (void)fclose(f);
245 
246     if (debug_level & 1)
247     {
248       fprintf(stderr,"Clearing Object/Item history file...\n");
249     }
250   }
251   else
252   {
253     fprintf(stderr,"Couldn't open file for writing: %s\n", file);
254   }
255 }
256 
257 
258 
259 
260 
261 /*
262  *  Re-read object/item history log file
263  */
Object_History_Refresh(Widget UNUSED (w),XtPointer UNUSED (clientData),XtPointer UNUSED (callData))264 void Object_History_Refresh( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) )
265 {
266 
267   // Reload saved objects and items from previous runs.
268   reload_object_item();
269 }
270 
271 
272 
273 
274 
275 // We have a lot of code duplication between Setup_object_data,
276 // Setup_item_data, and Create_object_item_tx_string.
277 //
278 // Make sure to look at the "transmit_compressed_objects_items"
279 // variable
280 // to decide whether to send a compressed packet.
281 /*
282  *  Create the transmit string for Objects/Items.
283  *  Input is a DataRow struct, output is both an integer that says
284  *  whether it completed successfully, and a char* that has the
285  *  output tx string in it.
286  *
287  *  Returns 0 if there's a problem.
288  */
Create_object_item_tx_string(DataRow * p_station,char * line,int line_length)289 int Create_object_item_tx_string(DataRow *p_station, char *line, int line_length)
290 {
291   int i, done;
292   char lat_str[MAX_LAT];
293   char lon_str[MAX_LONG];
294   char comment[43+1];                 // max 43 characters of comment
295   char comment2[43+1];
296   char time[7+1];
297   struct tm *day_time;
298   time_t sec;
299   char complete_area_color[3];
300   int complete_area_type;
301   int lat_offset, lon_offset;
302   char complete_corridor[6];
303   char altitude[10];
304   char speed_course[8];
305   int speed;
306   int course;
307   int temp;
308   long temp2;
309   char signpost[6];
310   int bearing;
311   char tempstr[50];
312   char object_group;
313   char object_symbol;
314   int killed = 0;
315 
316 
317   (void)remove_trailing_spaces(p_station->call_sign);
318   //(void)to_upper(p_station->call_sign);     Not per spec.  Don't
319   //use this.
320 
321   if ((p_station->flag & ST_OBJECT) != 0)     // We have an object
322   {
323     if (!valid_object(p_station->call_sign))
324     {
325       line[0] = '\0';
326       return(0);
327     }
328   }
329   else if ((p_station->flag & ST_ITEM) != 0)      // We have an item
330   {
331     xastir_snprintf(tempstr,
332                     sizeof(tempstr),
333                     "%s",
334                     p_station->call_sign);
335 
336     if (strlen(tempstr) == 1)   // Add two spaces (to make 3 minimum chars)
337     {
338       strcpy(p_station->call_sign, tempstr);
339       p_station->call_sign[sizeof(p_station->call_sign)-1] = '\0';  // Terminate string
340       strcat(p_station->call_sign, "  ");
341       p_station->call_sign[sizeof(p_station->call_sign)-1] = '\0';  // Terminate string
342     }
343     else if (strlen(tempstr) == 2)   // Add one space (to make 3 minimum chars)
344     {
345       strcpy(p_station->call_sign, tempstr);
346       p_station->call_sign[sizeof(p_station->call_sign)-1] = '\0';  // Terminate string
347       strcat(p_station->call_sign, " ");
348       p_station->call_sign[sizeof(p_station->call_sign)-1] = '\0';  // Terminate string
349     }
350 
351     if (!valid_item(p_station->call_sign))
352     {
353       line[0] = '\0';
354       return(0);
355     }
356   }
357   else    // Not an item or an object, what are we doing here!
358   {
359     line[0] = '\0';
360     return(0);
361   }
362 
363   // Lat/lon are in Xastir coordinates, so we need to convert
364   // them to APRS string format here.
365   convert_lat_l2s(p_station->coord_lat, lat_str, sizeof(lat_str), CONVERT_LP_NOSP);
366   convert_lon_l2s(p_station->coord_lon, lon_str, sizeof(lon_str), CONVERT_LP_NOSP);
367 
368   // Check for an overlay character.  Replace the group character
369   // (table char) with the overlay if present.
370   if (p_station->aprs_symbol.special_overlay != '\0')
371   {
372     // Overlay character found
373     object_group = p_station->aprs_symbol.special_overlay;
374     if ( (object_group >= '0' && object_group <= '9')
375          || (object_group >= 'A' && object_group <= 'Z') )
376     {
377       // Valid overlay character, use what we have
378     }
379     else
380     {
381       // Bad overlay character, throw it away
382       object_group = '\\';
383     }
384   }
385   else      // No overlay character
386   {
387     object_group = p_station->aprs_symbol.aprs_type;
388   }
389 
390   object_symbol = p_station->aprs_symbol.aprs_symbol;
391 
392   // In this case we grab only the first comment field (if it
393   // exists) for the object/item
394   if ( (p_station->comment_data != NULL)
395        && (p_station->comment_data->text_ptr != NULL) )
396   {
397     xastir_snprintf(comment,
398                     sizeof(comment),
399                     "%s",
400                     p_station->comment_data->text_ptr);
401   }
402   else
403   {
404     comment[0] = '\0';  // Empty string
405   }
406 
407   if ( (p_station->probability_min[0] != '\0')
408        || (p_station->probability_max[0] != '\0') )
409   {
410 
411     if (p_station->probability_max[0] == '\0')
412     {
413       // Only have probability_min
414       strcpy(comment2, "Pmin");
415       comment2[sizeof(comment2)-1] = '\0';  // Terminate string
416       strcat(comment2, p_station->probability_min);
417       comment2[sizeof(comment2)-1] = '\0';  // Terminate string
418       strcat(comment2, ",");
419       comment2[sizeof(comment2)-1] = '\0';  // Terminate string
420       strcat(comment2, comment);
421       comment2[sizeof(comment2)-1] = '\0';  // Terminate string
422     }
423     else if (p_station->probability_min[0] == '\0')
424     {
425       // Only have probability_max
426       strcpy(comment2, "Pmax");
427       comment2[sizeof(comment2)-1] = '\0';  // Terminate string
428       strcat(comment2, p_station->probability_max);
429       comment2[sizeof(comment2)-1] = '\0';  // Terminate string
430       strcat(comment2, ",");
431       comment2[sizeof(comment2)-1] = '\0';  // Terminate string
432       strcat(comment2, comment);
433       comment2[sizeof(comment2)-1] = '\0';  // Terminate string
434     }
435     else    // Have both
436     {
437       strcpy(comment2, "Pmin");
438       comment2[sizeof(comment2)-1] = '\0';  // Terminate string
439       strcat(comment2, p_station->probability_min);
440       comment2[sizeof(comment2)-1] = '\0';  // Terminate string
441       strcat(comment2, ",Pmax");
442       comment2[sizeof(comment2)-1] = '\0';  // Terminate string
443       strcat(comment2, p_station->probability_max);
444       comment2[sizeof(comment2)-1] = '\0';  // Terminate string
445       strcat(comment2, ",");
446       comment2[sizeof(comment2)-1] = '\0';  // Terminate string
447       strcat(comment2, comment);
448       comment2[sizeof(comment2)-1] = '\0';  // Terminate string
449     }
450     xastir_snprintf(comment,sizeof(comment), "%s", comment2);
451   }
452 
453 
454   // Put RNG or PHG at the beginning of the comment
455   strcpy(comment2, p_station->power_gain);
456   comment2[sizeof(comment2)-1] = '\0';  // Terminate string
457   strcat(comment2, comment);
458   comment2[sizeof(comment2)-1] = '\0';  // Terminate string
459 
460   xastir_snprintf(comment,
461                   sizeof(comment),
462                   "%s",
463                   comment2);
464 
465 
466   (void)remove_trailing_spaces(comment);
467 
468 
469   // This is for objects only, not items.  Uses current time but
470   // should use the transmitted time from the DataRow struct.
471   // Which time field in the struct would that be?  Have to find
472   // out
473   // from the extract_?? code.
474   if ((p_station->flag & ST_OBJECT) != 0)
475   {
476     sec = sec_now();
477     day_time = gmtime(&sec);
478     xastir_snprintf(time,
479                     sizeof(time),
480                     "%02d%02d%02dz",
481                     day_time->tm_mday,
482                     day_time->tm_hour,
483                     day_time->tm_min);
484   }
485 
486 
487 // Handle Generic Options
488 
489 
490   // Speed/Course Fields
491   xastir_snprintf(speed_course, sizeof(speed_course), ".../"); // Start with invalid-data string
492   course = 0;
493   if (strlen(p_station->course) != 0)      // Course was entered
494   {
495     // Need to check for 1 to three digits only, and 001-360
496     // degrees)
497     temp = atoi(p_station->course);
498     if ( (temp >= 1) && (temp <= 360) )
499     {
500       xastir_snprintf(speed_course, sizeof(speed_course), "%03d/",temp);
501       course = temp;
502     }
503     else if (temp == 0)     // Spec says 001 to 360 degrees...
504     {
505       xastir_snprintf(speed_course, sizeof(speed_course), "360/");
506     }
507   }
508   speed = 0;
509   if (strlen(p_station->speed) != 0)   // Speed was entered (we only handle knots currently)
510   {
511     // Need to check for 1 to three digits, no alpha characters
512     temp = atoi(p_station->speed);
513     if ( (temp >= 0) && (temp <= 999) )
514     {
515       long x_long, y_lat;
516 
517       xastir_snprintf(tempstr, sizeof(tempstr), "%03d",temp);
518       strncat(speed_course,
519               tempstr,
520               sizeof(speed_course) - 1 - strlen(speed_course));
521       speed = temp;
522 
523       // Speed is non-zero.  Compute the current dead-reckoned
524       // position and use that instead.
525       compute_current_DR_position(p_station,
526                                   &x_long,
527                                   &y_lat);
528 
529       // Lat/lon are in Xastir coordinates, so we need to
530       // convert them to APRS string format here.
531       //
532       convert_lat_l2s(y_lat,
533                       lat_str,
534                       sizeof(lat_str),
535                       CONVERT_LP_NOSP);
536 
537       convert_lon_l2s(x_long,
538                       lon_str,
539                       sizeof(lon_str),
540                       CONVERT_LP_NOSP);
541 
542 //fprintf(stderr,"\t%s  %s\n", lat_str, lon_str);
543 
544     }
545     else
546     {
547       strncat(speed_course,
548               "...",
549               sizeof(speed_course) - 1 - strlen(speed_course));
550     }
551   }
552   else    // No speed entered, blank it out
553   {
554     strncat(speed_course,
555             "...",
556             sizeof(speed_course) - 1 - strlen(speed_course));
557   }
558   if ( (speed_course[0] == '.') && (speed_course[4] == '.') )
559   {
560     speed_course[0] = '\0'; // No speed or course entered, so blank it
561   }
562   if (p_station->aprs_symbol.area_object.type != AREA_NONE)    // It's an area object
563   {
564     speed_course[0] = '\0'; // Course/Speed not allowed if Area Object
565   }
566 
567   // Altitude Field
568   altitude[0] = '\0'; // Start with empty string
569   if (strlen(p_station->altitude) != 0)     // Altitude was entered (we only handle feet currently)
570   {
571     // Need to check for all digits, and 1 to 6 digits
572     if (isdigit((int)p_station->altitude[0]))
573     {
574       // Must convert from meters to feet before transmitting
575       temp2 = (int)( (atof(p_station->altitude) / 0.3048) + 0.5);
576       if ( (temp2 >= 0) && (temp2 <= 99999l) )
577       {
578         char temp_alt[20];
579         xastir_snprintf(temp_alt, sizeof(temp_alt), "/A=%06ld",temp2);
580         memcpy(altitude, temp_alt, sizeof(altitude) - 1);
581         altitude[sizeof(altitude)-1] = '\0';  // Terminate string
582       }
583     }
584   }
585 
586 
587 // Handle Specific Options
588 
589 
590   // Area Objects
591   if (p_station->aprs_symbol.area_object.type != AREA_NONE)   // It's an area object
592   {
593 
594     // Note that transmitted color consists of two characters,
595     // from "/0" to "15"
596     xastir_snprintf(complete_area_color, sizeof(complete_area_color), "%02d", p_station->aprs_symbol.area_object.color);
597     if (complete_area_color[0] == '0')
598     {
599       complete_area_color[0] = '/';
600     }
601 
602     complete_area_type = p_station->aprs_symbol.area_object.type;
603 
604     lat_offset = p_station->aprs_symbol.area_object.sqrt_lat_off;
605     lon_offset = p_station->aprs_symbol.area_object.sqrt_lon_off;
606 
607     // Corridor
608     complete_corridor[0] = '\0';
609     if ( (complete_area_type == 1) || (complete_area_type == 6))
610     {
611       if (p_station->aprs_symbol.area_object.corridor_width > 0)
612       {
613         char temp_corridor[10];
614         xastir_snprintf(temp_corridor, sizeof(temp_corridor), "{%d}",
615                         p_station->aprs_symbol.area_object.corridor_width);
616         memcpy(complete_corridor, temp_corridor, sizeof(complete_corridor) - 1);
617         complete_corridor[sizeof(complete_corridor)-1] = '\0';  // Terminate string
618       }
619     }
620 
621     if ((p_station->flag & ST_OBJECT) != 0)     // It's an object
622     {
623 
624       if (transmit_compressed_objects_items)
625       {
626         char temp_group = object_group;
627         long x_long, y_lat;
628 
629         // If we have a numeric overlay, we need to convert
630         // it to 'a-j' for compressed objects.
631         if (temp_group >= '0' && temp_group <= '9')
632         {
633           temp_group = temp_group + 'a';
634         }
635 
636         if (speed == 0)
637         {
638           x_long = p_station->coord_lon;
639           y_lat  = p_station->coord_lat;
640         }
641         else
642         {
643           // Speed is non-zero.  Compute the current
644           // dead-reckoned position and use that instead.
645           compute_current_DR_position(p_station,
646                                       &x_long,
647                                       &y_lat);
648         }
649 
650         // We need higher precision lat/lon strings than
651         // those created above.
652         convert_lat_l2s(y_lat, lat_str, sizeof(lat_str), CONVERT_HP_NOSP);
653         convert_lon_l2s(x_long, lon_str, sizeof(lon_str), CONVERT_HP_NOSP);
654 
655         xastir_snprintf(line, line_length, ";%-9s*%s%s%1d%02d%2s%02d%s%s%s",
656                         p_station->call_sign,
657                         time,
658                         compress_posit(lat_str,
659                                        temp_group,
660                                        lon_str,
661                                        object_symbol,
662                                        course,
663                                        speed,  // In knots
664                                        ""),    // PHG, must be blank
665                         complete_area_type,
666                         lat_offset,
667                         complete_area_color,
668                         lon_offset,
669                         speed_course,
670                         complete_corridor,
671                         altitude);
672 
673       }
674       else    // Non-compressed posit object
675       {
676 
677         xastir_snprintf(line, line_length, ";%-9s*%s%s%c%s%c%1d%02d%2s%02d%s%s%s",
678                         p_station->call_sign,
679                         time,
680                         lat_str,
681                         object_group,
682                         lon_str,
683                         object_symbol,
684                         complete_area_type,
685                         lat_offset,
686                         complete_area_color,
687                         lon_offset,
688                         speed_course,
689                         complete_corridor,
690                         altitude);
691       }
692     }
693     else        // It's an item
694     {
695 
696       if (transmit_compressed_objects_items)
697       {
698         char temp_group = object_group;
699         long x_long, y_lat;
700 
701         // If we have a numeric overlay, we need to convert
702         // it to 'a-j' for compressed objects.
703         if (temp_group >= '0' && temp_group <= '9')
704         {
705           temp_group = temp_group + 'a';
706         }
707 
708         if (speed == 0)
709         {
710           x_long = p_station->coord_lon;
711           y_lat  = p_station->coord_lat;
712         }
713         else
714         {
715           // Speed is non-zero.  Compute the current
716           // dead-reckoned position and use that instead.
717           compute_current_DR_position(p_station,
718                                       &x_long,
719                                       &y_lat);
720         }
721 
722         // We need higher precision lat/lon strings than
723         // those created above.
724         convert_lat_l2s(y_lat, lat_str, sizeof(lat_str), CONVERT_HP_NOSP);
725         convert_lon_l2s(x_long, lon_str, sizeof(lon_str), CONVERT_HP_NOSP);
726 
727         xastir_snprintf(line, line_length, ")%s!%s%1d%02d%2s%02d%s%s%s",
728                         p_station->call_sign,
729                         compress_posit(lat_str,
730                                        temp_group,
731                                        lon_str,
732                                        object_symbol,
733                                        course,
734                                        speed,  // In knots
735                                        ""),    // PHG, must be blank
736                         complete_area_type,
737                         lat_offset,
738                         complete_area_color,
739                         lon_offset,
740                         speed_course,
741                         complete_corridor,
742                         altitude);
743       }
744       else    // Non-compressed item
745       {
746 
747         xastir_snprintf(line, line_length, ")%s!%s%c%s%c%1d%02d%2s%02d%s%s%s",
748                         p_station->call_sign,
749                         lat_str,
750                         object_group,
751                         lon_str,
752                         object_symbol,
753                         complete_area_type,
754                         lat_offset,
755                         complete_area_color,
756                         lon_offset,
757                         speed_course,
758                         complete_corridor,
759                         altitude);
760       }
761     }
762   }
763 
764   else if ( (p_station->aprs_symbol.aprs_type == '\\') // We have a signpost object
765             && (p_station->aprs_symbol.aprs_symbol == 'm' ) )
766   {
767     if (strlen(p_station->signpost) > 0)
768     {
769       char temp_sign[10];
770       xastir_snprintf(temp_sign, sizeof(temp_sign), "{%s}", p_station->signpost);
771       memcpy(signpost, temp_sign, sizeof(signpost));
772       signpost[sizeof(signpost)-1] = '\0';  // Terminate string
773     }
774     else    // No signpost data entered, blank it out
775     {
776       signpost[0] = '\0';
777     }
778     if ((p_station->flag & ST_OBJECT) != 0)     // It's an object
779     {
780 
781       if (transmit_compressed_objects_items)
782       {
783         char temp_group = object_group;
784         long x_long, y_lat;
785 
786         // If we have a numeric overlay, we need to convert
787         // it to 'a-j' for compressed objects.
788         if (temp_group >= '0' && temp_group <= '9')
789         {
790           temp_group = temp_group + 'a';
791         }
792 
793         if (speed == 0)
794         {
795           x_long = p_station->coord_lon;
796           y_lat  = p_station->coord_lat;
797         }
798         else
799         {
800           // Speed is non-zero.  Compute the current
801           // dead-reckoned position and use that instead.
802           compute_current_DR_position(p_station,
803                                       &x_long,
804                                       &y_lat);
805         }
806 
807         // We need higher precision lat/lon strings than
808         // those created above.
809         convert_lat_l2s(y_lat, lat_str, sizeof(lat_str), CONVERT_HP_NOSP);
810         convert_lon_l2s(x_long, lon_str, sizeof(lon_str), CONVERT_HP_NOSP);
811 
812         xastir_snprintf(line, line_length, ";%-9s*%s%s%s%s",
813                         p_station->call_sign,
814                         time,
815                         compress_posit(lat_str,
816                                        temp_group,
817                                        lon_str,
818                                        object_symbol,
819                                        course,
820                                        speed,  // In knots
821                                        ""),    // PHG, must be blank
822                         altitude,
823                         signpost);
824       }
825       else    // Non-compressed posit object
826       {
827 
828         xastir_snprintf(line, line_length, ";%-9s*%s%s%c%s%c%s%s%s",
829                         p_station->call_sign,
830                         time,
831                         lat_str,
832                         object_group,
833                         lon_str,
834                         object_symbol,
835                         speed_course,
836                         altitude,
837                         signpost);
838       }
839     }
840     else    // It's an item
841     {
842 
843       if (transmit_compressed_objects_items)
844       {
845         char temp_group = object_group;
846         long x_long, y_lat;
847 
848         // If we have a numeric overlay, we need to convert
849         // it to 'a-j' for compressed objects.
850         if (temp_group >= '0' && temp_group <= '9')
851         {
852           temp_group = temp_group + 'a';
853         }
854 
855         if (speed == 0)
856         {
857           x_long = p_station->coord_lon;
858           y_lat  = p_station->coord_lat;
859         }
860         else
861         {
862           // Speed is non-zero.  Compute the current
863           // dead-reckoned position and use that instead.
864           compute_current_DR_position(p_station,
865                                       &x_long,
866                                       &y_lat);
867         }
868 
869         // We need higher precision lat/lon strings than
870         // those created above.
871         convert_lat_l2s(y_lat, lat_str, sizeof(lat_str), CONVERT_HP_NOSP);
872         convert_lon_l2s(x_long, lon_str, sizeof(lon_str), CONVERT_HP_NOSP);
873 
874         xastir_snprintf(line, line_length, ")%s!%s%s%s",
875                         p_station->call_sign,
876                         compress_posit(lat_str,
877                                        temp_group,
878                                        lon_str,
879                                        object_symbol,
880                                        course,
881                                        speed,  // In knots
882                                        ""),    // PHG, must be blank
883                         altitude,
884                         signpost);
885       }
886       else    // Non-compressed item
887       {
888 
889         xastir_snprintf(line, line_length, ")%s!%s%c%s%c%s%s%s",
890                         p_station->call_sign,
891                         lat_str,
892                         object_group,
893                         lon_str,
894                         object_symbol,
895                         speed_course,
896                         altitude,
897                         signpost);
898       }
899     }
900   }
901 
902   else if (p_station->signal_gain[0] != '\0')   // Must be an Omni-DF object/item
903   {
904 
905     if ((p_station->flag & ST_OBJECT) != 0)     // It's an object
906     {
907 
908       if (transmit_compressed_objects_items)
909       {
910         char temp_group = object_group;
911         long x_long, y_lat;
912 
913         // If we have a numeric overlay, we need to convert
914         // it to 'a-j' for compressed objects.
915         if (temp_group >= '0' && temp_group <= '9')
916         {
917           temp_group = temp_group + 'a';
918         }
919 
920         if (speed == 0)
921         {
922           x_long = p_station->coord_lon;
923           y_lat  = p_station->coord_lat;
924         }
925         else
926         {
927           // Speed is non-zero.  Compute the current
928           // dead-reckoned position and use that instead.
929           compute_current_DR_position(p_station,
930                                       &x_long,
931                                       &y_lat);
932         }
933 
934         // We need higher precision lat/lon strings than
935         // those created above.
936         convert_lat_l2s(y_lat, lat_str, sizeof(lat_str), CONVERT_HP_NOSP);
937         convert_lon_l2s(x_long, lon_str, sizeof(lon_str), CONVERT_HP_NOSP);
938 
939         xastir_snprintf(line, line_length, ";%-9s*%s%s%s/%s%s",
940                         p_station->call_sign,
941                         time,
942                         compress_posit(lat_str,
943                                        temp_group,
944                                        lon_str,
945                                        object_symbol,
946                                        course,
947                                        speed,  // In knots
948                                        ""),    // PHG, must be blank
949                         p_station->signal_gain,
950                         speed_course,
951                         altitude);
952       }
953       else    // Non-compressed posit object
954       {
955 
956         xastir_snprintf(line, line_length, ";%-9s*%s%s%c%s%c%s/%s%s",
957                         p_station->call_sign,
958                         time,
959                         lat_str,
960                         object_group,
961                         lon_str,
962                         object_symbol,
963                         p_station->signal_gain,
964                         speed_course,
965                         altitude);
966       }
967     }
968     else    // It's an item
969     {
970 
971       if (transmit_compressed_objects_items)
972       {
973         char temp_group = object_group;
974         long x_long, y_lat;
975 
976         // If we have a numeric overlay, we need to convert
977         // it to 'a-j' for compressed objects.
978         if (temp_group >= '0' && temp_group <= '9')
979         {
980           temp_group = temp_group + 'a';
981         }
982 
983         if (speed == 0)
984         {
985           x_long = p_station->coord_lon;
986           y_lat  = p_station->coord_lat;
987         }
988         else
989         {
990           // Speed is non-zero.  Compute the current
991           // dead-reckoned position and use that instead.
992           compute_current_DR_position(p_station,
993                                       &x_long,
994                                       &y_lat);
995         }
996 
997         // We need higher precision lat/lon strings than
998         // those created above.
999         convert_lat_l2s(y_lat, lat_str, sizeof(lat_str), CONVERT_HP_NOSP);
1000         convert_lon_l2s(x_long, lon_str, sizeof(lon_str), CONVERT_HP_NOSP);
1001 
1002         xastir_snprintf(line, line_length, ")%s!%s%s/%s%s",
1003                         p_station->call_sign,
1004                         compress_posit(lat_str,
1005                                        temp_group,
1006                                        lon_str,
1007                                        object_symbol,
1008                                        course,
1009                                        speed,  // In knots
1010                                        ""),    // PHG, must be blank
1011                         p_station->signal_gain,
1012                         speed_course,
1013                         altitude);
1014       }
1015       else    // Non-compressed item
1016       {
1017 
1018         xastir_snprintf(line, line_length, ")%s!%s%c%s%c%s/%s%s",
1019                         p_station->call_sign,
1020                         lat_str,
1021                         object_group,
1022                         lon_str,
1023                         object_symbol,
1024                         p_station->signal_gain,
1025                         speed_course,
1026                         altitude);
1027       }
1028     }
1029   }
1030   else if (p_station->NRQ[0] != 0)    // It's a Beam Heading DFS object/item
1031   {
1032 
1033     if (strlen(speed_course) != 7)
1034       xastir_snprintf(speed_course,
1035                       sizeof(speed_course),
1036                       "000/000");
1037 
1038     bearing = atoi(p_station->bearing);
1039     if ( (bearing < 1) || (bearing > 360) )
1040     {
1041       bearing = 360;
1042     }
1043 
1044     if ((p_station->flag & ST_OBJECT) != 0)     // It's an object
1045     {
1046 
1047       if (transmit_compressed_objects_items)
1048       {
1049         char temp_group = object_group;
1050         long x_long, y_lat;
1051 
1052         // If we have a numeric overlay, we need to convert
1053         // it to 'a-j' for compressed objects.
1054         if (temp_group >= '0' && temp_group <= '9')
1055         {
1056           temp_group = temp_group + 'a';
1057         }
1058 
1059         if (speed == 0)
1060         {
1061           x_long = p_station->coord_lon;
1062           y_lat  = p_station->coord_lat;
1063         }
1064         else
1065         {
1066           // Speed is non-zero.  Compute the current
1067           // dead-reckoned position and use that instead.
1068           compute_current_DR_position(p_station,
1069                                       &x_long,
1070                                       &y_lat);
1071         }
1072 
1073         // We need higher precision lat/lon strings than
1074         // those created above.
1075         convert_lat_l2s(y_lat, lat_str, sizeof(lat_str), CONVERT_HP_NOSP);
1076         convert_lon_l2s(x_long, lon_str, sizeof(lon_str), CONVERT_HP_NOSP);
1077 
1078         xastir_snprintf(line, line_length, ";%-9s*%s%s/%03i/%s%s",
1079                         p_station->call_sign,
1080                         time,
1081                         compress_posit(lat_str,
1082                                        temp_group,
1083                                        lon_str,
1084                                        object_symbol,
1085                                        course,
1086                                        speed,  // In knots
1087                                        ""),    // PHG, must be blank
1088                         bearing,
1089                         p_station->NRQ,
1090                         altitude);
1091       }
1092       else    // Non-compressed posit object
1093       {
1094 
1095         xastir_snprintf(line, line_length, ";%-9s*%s%s%c%s%c%s/%03i/%s%s",
1096                         p_station->call_sign,
1097                         time,
1098                         lat_str,
1099                         object_group,
1100                         lon_str,
1101                         object_symbol,
1102                         speed_course,
1103                         bearing,
1104                         p_station->NRQ,
1105                         altitude);
1106       }
1107     }
1108     else    // It's an item
1109     {
1110 
1111       if (transmit_compressed_objects_items)
1112       {
1113         char temp_group = object_group;
1114         long x_long, y_lat;
1115 
1116         // If we have a numeric overlay, we need to convert
1117         // it to 'a-j' for compressed objects.
1118         if (temp_group >= '0' && temp_group <= '9')
1119         {
1120           temp_group = temp_group + 'a';
1121         }
1122 
1123         if (speed == 0)
1124         {
1125           x_long = p_station->coord_lon;
1126           y_lat  = p_station->coord_lat;
1127         }
1128         else
1129         {
1130           // Speed is non-zero.  Compute the current
1131           // dead-reckoned position and use that instead.
1132           compute_current_DR_position(p_station,
1133                                       &x_long,
1134                                       &y_lat);
1135         }
1136 
1137         // We need higher precision lat/lon strings than
1138         // those created above.
1139         convert_lat_l2s(y_lat, lat_str, sizeof(lat_str), CONVERT_HP_NOSP);
1140         convert_lon_l2s(x_long, lon_str, sizeof(lon_str), CONVERT_HP_NOSP);
1141 
1142         xastir_snprintf(line, line_length, ")%s!%s/%03i/%s%s",
1143                         p_station->call_sign,
1144                         compress_posit(lat_str,
1145                                        temp_group,
1146                                        lon_str,
1147                                        object_symbol,
1148                                        course,
1149                                        speed,  // In knots
1150                                        ""),    // PHG, must be blank
1151                         bearing,
1152                         p_station->NRQ,
1153                         altitude);
1154       }
1155       else    // Non-compressed item
1156       {
1157 
1158         xastir_snprintf(line, line_length, ")%s!%s%c%s%c%s/%03i/%s%s",
1159                         p_station->call_sign,
1160                         lat_str,
1161                         object_group,
1162                         lon_str,
1163                         object_symbol,
1164                         speed_course,
1165                         bearing,
1166                         p_station->NRQ,
1167                         altitude);
1168       }
1169     }
1170   }
1171 
1172   else    // Else it's a normal object/item
1173   {
1174 
1175     if ((p_station->flag & ST_OBJECT) != 0)     // It's an object
1176     {
1177 
1178       if (transmit_compressed_objects_items)
1179       {
1180         char temp_group = object_group;
1181         long x_long, y_lat;
1182 
1183         // If we have a numeric overlay, we need to convert
1184         // it to 'a-j' for compressed objects.
1185         if (temp_group >= '0' && temp_group <= '9')
1186         {
1187           temp_group = temp_group + 'a';
1188         }
1189 
1190         if (speed == 0)
1191         {
1192           x_long = p_station->coord_lon;
1193           y_lat  = p_station->coord_lat;
1194         }
1195         else
1196         {
1197           // Speed is non-zero.  Compute the current
1198           // dead-reckoned position and use that instead.
1199           compute_current_DR_position(p_station,
1200                                       &x_long,
1201                                       &y_lat);
1202         }
1203 
1204         // We need higher precision lat/lon strings than
1205         // those created above.
1206         convert_lat_l2s(y_lat, lat_str, sizeof(lat_str), CONVERT_HP_NOSP);
1207         convert_lon_l2s(x_long, lon_str, sizeof(lon_str), CONVERT_HP_NOSP);
1208 
1209         xastir_snprintf(line, line_length, ";%-9s*%s%s%s",
1210                         p_station->call_sign,
1211                         time,
1212                         compress_posit(lat_str,
1213                                        temp_group,
1214                                        lon_str,
1215                                        object_symbol,
1216                                        course,
1217                                        speed,  // In knots
1218                                        ""),    // PHG, must be blank
1219                         altitude);
1220       }
1221       else    // Non-compressed posit object
1222       {
1223         xastir_snprintf(line, line_length, ";%-9s*%s%s%c%s%c%s%s",
1224                         p_station->call_sign,
1225                         time,
1226                         lat_str,
1227                         object_group,
1228                         lon_str,
1229                         object_symbol,
1230                         speed_course,
1231                         altitude);
1232       }
1233     }
1234     else    // It's an item
1235     {
1236 
1237       if (transmit_compressed_objects_items)
1238       {
1239         char temp_group = object_group;
1240         long x_long, y_lat;
1241 
1242         // If we have a numeric overlay, we need to convert
1243         // it to 'a-j' for compressed objects.
1244         if (temp_group >= '0' && temp_group <= '9')
1245         {
1246           temp_group = temp_group + 'a';
1247         }
1248 
1249         if (speed == 0)
1250         {
1251           x_long = p_station->coord_lon;
1252           y_lat  = p_station->coord_lat;
1253         }
1254         else
1255         {
1256           // Speed is non-zero.  Compute the current
1257           // dead-reckoned position and use that instead.
1258           compute_current_DR_position(p_station,
1259                                       &x_long,
1260                                       &y_lat);
1261         }
1262 
1263         // We need higher precision lat/lon strings than
1264         // those created above.
1265         convert_lat_l2s(y_lat, lat_str, sizeof(lat_str), CONVERT_HP_NOSP);
1266         convert_lon_l2s(x_long, lon_str, sizeof(lon_str), CONVERT_HP_NOSP);
1267 
1268         xastir_snprintf(line, line_length, ")%s!%s%s",
1269                         p_station->call_sign,
1270                         compress_posit(lat_str,
1271                                        temp_group,
1272                                        lon_str,
1273                                        object_symbol,
1274                                        course,
1275                                        speed,  // In knots
1276                                        ""),    // PHG, must be blank
1277                         altitude);
1278       }
1279       else    // Non-compressed item
1280       {
1281         xastir_snprintf(line, line_length, ")%s!%s%c%s%c%s%s",
1282                         p_station->call_sign,
1283                         lat_str,
1284                         object_group,
1285                         lon_str,
1286                         object_symbol,
1287                         speed_course,
1288                         altitude);
1289       }
1290     }
1291   }
1292 
1293   // If it's a "killed" object, change '*' to an '_'
1294   if ((p_station->flag & ST_OBJECT) != 0)                 // It's an object
1295   {
1296     if ((p_station->flag & ST_ACTIVE) != ST_ACTIVE)     // It's been killed
1297     {
1298       line[10] = '_';
1299       killed++;
1300     }
1301   }
1302   // If it's a "killed" item, change '!' to an '_'
1303   else                                                    // It's an item
1304   {
1305     if ((p_station->flag & ST_ACTIVE) != ST_ACTIVE)     // It's been killed
1306     {
1307       killed++;
1308       done = 0;
1309       i = 0;
1310       while ( (!done) && (i < 11) )
1311       {
1312         if (line[i] == '!')
1313         {
1314           line[i] = '_';          // mark as deleted object
1315           done++;                 // Exit from loop
1316         }
1317         i++;
1318       }
1319     }
1320   }
1321 
1322   // Check whether we need to stop transmitting particular killed
1323   // object/items now.
1324   if (killed)
1325   {
1326     // Check whether we should decrement the object_retransmit
1327     // counter so that we will eventually stop sending this
1328     // object/item.
1329     if (p_station->object_retransmit == 0)
1330     {
1331       // We shouldn't be transmitting this killed object/item
1332       // anymore.  We're already done transmitting it.
1333 
1334 //fprintf(stderr, "Done transmitting this object: %s,  %d\n",
1335 //p_station->call_sign,
1336 //p_station->object_retransmit);
1337 
1338       return(0);
1339     }
1340 
1341     // Check whether the timeout has been set yet on this killed
1342     // object/item.  If not, change it from -1 (continuous
1343     // transmit of non-killed objects) to
1344     // MAX_KILLED_OBJECT_RETRANSMIT.
1345     if (p_station->object_retransmit <= -1)
1346     {
1347 
1348 //fprintf(stderr, "Killed object %s, setting retries, %d -> %d\n",
1349 //p_station->call_sign,
1350 //p_station->object_retransmit,
1351 //MAX_KILLED_OBJECT_RETRANSMIT - 1);
1352 
1353       if ((MAX_KILLED_OBJECT_RETRANSMIT - 1) < 0)
1354       {
1355         p_station->object_retransmit = 0;
1356         return(0);  // No retransmits desired
1357       }
1358       else
1359       {
1360         p_station->object_retransmit = MAX_KILLED_OBJECT_RETRANSMIT - 1;
1361       }
1362     }
1363     else
1364     {
1365       // Decrement the timeout if it is a positive number.
1366       if (p_station->object_retransmit > 0)
1367       {
1368 
1369 //fprintf(stderr, "Killed object %s, decrementing retries, %d ->
1370 //%d\n",
1371 //p_station->call_sign,
1372 //p_station->object_retransmit,
1373 //p_station->object_retransmit - 1);
1374 
1375         p_station->object_retransmit--;
1376       }
1377     }
1378   }
1379 
1380   // We need to tack the comment on the end, but need to make
1381   // sure we don't go over the maximum length for an object/item.
1382   if (strlen(comment) != 0)
1383   {
1384     temp = 0;
1385     if ((p_station->flag & ST_OBJECT) != 0)
1386     {
1387       while ( (strlen(line) < 80) && (temp < (int)strlen(comment)) )
1388       {
1389         //fprintf(stderr,"temp: %d->%d\t%c\n", temp,
1390         //strlen(line), comment[temp]);
1391         line[strlen(line) + 1] = '\0';
1392         line[strlen(line)] = comment[temp++];
1393       }
1394     }
1395     else    // It's an item
1396     {
1397       while ( (strlen(line) < (64 + strlen(p_station->call_sign))) && (temp < (int)strlen(comment)) )
1398       {
1399         //fprintf(stderr,"temp: %d->%d\t%c\n", temp,
1400         //strlen(line), comment[temp]);
1401         line[strlen(line) + 1] = '\0';
1402         line[strlen(line)] = comment[temp++];
1403       }
1404     }
1405   }
1406 
1407   //fprintf(stderr,"line: %s\n",line);
1408 
1409 // NOTE:  Compressed mode will be shorter still.  Account
1410 // for that when compressed mode is implemented for objects/items.
1411 
1412   return(1);
1413 }
1414 
1415 
1416 
1417 
1418 
1419 // check_and_transmit_objects_items
1420 //
1421 // This function checks the last_transmit_time for each
1422 // locally-owned object/item.  If it has been at least the
1423 // transmit_time_increment since the last transmit, the increment is
1424 // doubled and the object/item transmitted.
1425 //
1426 // Killed objects/items are transmitted for
1427 // MAX_KILLED_OBJECT_RETRANSMIT times and then transmitting of those
1428 // objects ceases.
1429 //
1430 // This would be a good place to implement auto-expiration of
1431 // objects that's been discussed on the mailing lists.
1432 //
1433 // This function depends on the local loopback that is in
1434 // interface.c.  If we don't hear & decode our own packets, we won't
1435 // have our own objects/items in our list.
1436 //
1437 // We need to check DataRow objects for ST_OBJECT or ST_ITEM types
1438 // that were transmitted by our callsign & SSID.  We might also need
1439 // to modify the remove_time() and check_station_remove functions in
1440 // order not to delete our own objects/items too quickly.
1441 //
1442 // insert_time/remove_time/next_station_time/prev_station_time
1443 //
1444 // It would be nice if the create/modify object dialog and this
1445 // routine went
1446 // through the same functions to create the transmitted packets:
1447 //      objects.c:Setup_object_data
1448 //      objects.c:Setup_item_data
1449 // Unfortunately those routines snag their data directly from the
1450 // dialog.
1451 // In order to make them use the same code we'd have to separate out
1452 // the
1453 // fetch-from-dialog code from the create-transmit-packet code.
1454 //
1455 // This is what aprsDOS does, from Bob's APRS.TXT file:  "a
1456 // fundamental precept is that old data is less important than new
1457 // data."  "Each new packet is transmitted immediately, then 20
1458 // seconds later.  After every transmission, the period is doubled.
1459 // After 20 minutes only six packets have been transmitted.  From
1460 // then on the rate remains at 10 minutes times the number of
1461 // digipeater hops you are using."
1462 // Actually, talking to Bob, he's used a period of 15 seconds as his
1463 // base unit.  We now do the same using the OBJECT_CHECK_RATE define
1464 // to set the initial timing.
1465 
1466 //
1467 // Added these to database.h:DataRow struct:
1468 // time_t last_transmit_time;          // Time we last transmitted
1469 // an object/item.  Used to
1470 //                                     // implement decaying
1471 //                                     transmit time algorithm
1472 // short transmit_time_increment;      // Seconds to add to transmit
1473 // next time around.  Used
1474 //                                     // to implement decaying
1475 //                                     transmit time algorithm
1476 //
1477 // The earlier code here transmitted objects/items at a specified
1478 // rate.  This can cause large transmissions every OBJECT_rate
1479 // seconds, as all objects/items are transmitted at once.  With the
1480 // new code, the objects/items may be spaced a bit from each other
1481 // time-wise, plus they are transmitted less and less often with
1482 // each transmission until they hit the max interval specified by
1483 // the "Object/Item TX Interval" slider.  When they hit that max
1484 // interval, they are transmitted at the constant interval until
1485 // killed.  When they are killed, they are transmitted for
1486 // MAX_KILLED_OBJECT_RETRANSMIT iterations using the decaying
1487 // algorithm, then transmissions cease.
1488 //
check_and_transmit_objects_items(time_t time)1489 void check_and_transmit_objects_items(time_t time)
1490 {
1491   DataRow *p_station;     // pointer to station data
1492   char line[256];
1493   int first = 1;  // Used to output debug message only once
1494   int increment;
1495 
1496 
1497   // Time to re-transmit objects/items?
1498   // Check every OBJECT_CHECK_RATE seconds - 20%.  No faster else
1499   // we'll be running through the station list too often and
1500   // wasting cycles.
1501   if (time < (last_object_check + (int)(4.0 * OBJECT_CHECK_RATE/5.0 + 1.0) ) )
1502   {
1503     return;
1504   }
1505 
1506 //fprintf(stderr,"check_and_transmit_objects_items\n");
1507 
1508   // Set up timer for next go-around
1509   last_object_check = time;
1510 
1511   if (debug_level & 1)
1512   {
1513     fprintf(stderr,"Checking whether to retransmit any objects/items\n");
1514   }
1515 
1516 // We could speed things up quite a bit here by either keeping a
1517 // separate list of our own objects/items, or going through the list
1518 // of stations by time instead of by name (If by time, only check
1519 // backwards from the current time by the max transmit interval plus
1520 // some increment.  Watch out for the user changing the slider).
1521 
1522   for (p_station = n_first; p_station != NULL; p_station = p_station->n_next)
1523   {
1524 
1525     //fprintf(stderr,"%s\t%s\n",p_station->call_sign,p_station->origin);
1526 
1527     // If station is owned by me (Exact match includes SSID)
1528 //        if (is_my_call(p_station->origin,1)) {
1529     // and it's an object or item
1530     if ((p_station->flag & (ST_OBJECT|ST_ITEM)) && is_my_object_item(p_station))
1531     {
1532 
1533       long x_long_save, y_lat_save;
1534 
1535       // If dead-reckoning, we need to send out a new
1536       // position for this object instead of just
1537       // overwriting the old position, which will cause
1538       // the track to skip.  Here we save the old position
1539       // away so we can save it back to the record later.
1540       //
1541       x_long_save = p_station->coord_lon;
1542       y_lat_save = p_station->coord_lat;
1543 
1544       if (debug_level & 1)
1545       {
1546         fprintf(stderr,
1547                 "Found a locally-owned object or item: %s\n",
1548                 p_station->call_sign);
1549       }
1550 
1551       // Call the DR function to compute a new lat/long
1552       // and change the object's lat/long to match so that
1553       // we move the object along each time we transmit
1554       // it.
1555       //
1556 // WE7U
1557 // Here we should log the new position to file if it's not done
1558 // automatically.
1559       //
1560       if (p_station->speed[0] != '\0')
1561       {
1562         long x_long, y_lat;
1563 
1564         compute_current_DR_position(p_station, &x_long, &y_lat);
1565 
1566         // Put the new position into the record
1567         // temporarily so that we can
1568         p_station->coord_lon = x_long;
1569         p_station->coord_lat = y_lat;
1570       }
1571 
1572       // Keep the timestamp current on my own
1573       // objects/items so they don't expire.
1574       p_station->sec_heard = sec_now();
1575       move_station_time(p_station,NULL);
1576 
1577 // Implementing sped-up transmission of new objects, regular
1578 // transmission of old objects (decaying algorithm).  We'll do this
1579 // by keeping a last_transmit_time variable and a
1580 // transmit_time_increment with each DataRow struct.  If the
1581 // last_transmit_time is older than the transmit_time_increment, we
1582 // transmit the object and double the increment variable, until we
1583 // hit the OBJECT_rate limit for the increment.  This will make
1584 // newer objects/items transmit more often, and will also space out
1585 // the transmissions of old objects so they're not transmitted all
1586 // at once in a group.  Each time a new object/item is created that
1587 // is owned by us, it needs to have it's timer set to 20 (seconds).
1588 // If an object/item is touched, it needs to again be set to 20
1589 // seconds.
1590 ///////////////////////////////////
1591 
1592 // Run through the station list.
1593 
1594 // Transmit any objects/items that have equalled or gone past
1595 // (last_transmit_time + transmit_time_increment).  Update the
1596 // last_transmit_time to current time.
1597 //
1598 // Double the transmit_time_increment.  If it has gone beyond
1599 // OBJECT_rate, set it to OBJECT_rate instead.
1600 //
1601 ///////////////////////////////////
1602 
1603 
1604       // Check for the case where the timing slider has
1605       // been reduced and the expire time is too long.
1606       // Reset it to the current max expire time so that
1607       // it'll get transmitted more quickly.
1608       if (p_station->transmit_time_increment > OBJECT_rate)
1609       {
1610         p_station->transmit_time_increment = OBJECT_rate;
1611       }
1612 
1613 
1614       increment = p_station->transmit_time_increment;
1615 
1616       if ( ( p_station->last_transmit_time + increment) <= time )
1617       {
1618         // We should transmit this object/item as it has
1619         // hit its transmit interval.
1620 
1621         float randomize;
1622         int one_fifth_increment;
1623         int new_increment;
1624 
1625 
1626         if (first && !object_tx_disable)      // "Transmitting objects/items"
1627         {
1628           statusline(langcode("BBARSTA042"),1);
1629           first = 0;
1630         }
1631 
1632         // Set up the new doubling increment
1633         increment = increment * 2;
1634         if (increment > OBJECT_rate)
1635         {
1636           increment = OBJECT_rate;
1637         }
1638 
1639         // Randomize the distribution a bit, so that all
1640         // objects are not transmitted at the same time.
1641         // Allow the random number to vary over 20%
1642         // (one-fifth) of the newly computed increment.
1643         one_fifth_increment = (int)((increment / 5) + 0.5);
1644 //fprintf(stderr,"one_fifth_increment: %d\n", one_fifth_increment);
1645 
1646         // Scale the random number from 0.0 to 1.0.
1647         // Must convert at least one of the numbers to a
1648         // float else randomize will be zero every time.
1649         randomize = rand() / (float)RAND_MAX;
1650 //fprintf(stderr,"randomize: %f\n", randomize);
1651 
1652         // Scale it to the range we want (0% to 20% of
1653         // the interval)
1654         randomize = randomize * one_fifth_increment;
1655 //fprintf(stderr,"scaled randomize: %f\n", randomize);
1656 
1657         // Subtract it from the increment, use
1658         // poor-man's rounding to turn the random number
1659         // into an int (so we get the full range).
1660         new_increment = increment - (int)(randomize + 0.5);
1661         p_station->transmit_time_increment = (short)new_increment;
1662 
1663 //fprintf(stderr,"check_and_transmit_objects_items():Setting
1664 //tx_increment to %d:%s\n",
1665 //    new_increment,
1666 //    p_station->call_sign);
1667 
1668         // Set the last transmit time into the object.
1669         // Keep this based off the time the object was
1670         // last created/modified/deleted, so that we
1671         // don't end up with a bunch of them transmitted
1672         // together.
1673         p_station->last_transmit_time = p_station->last_transmit_time + new_increment;
1674 
1675         // Here we need to re-assemble and re-transmit
1676         // the object or item
1677         // Check whether it is a "live" or "killed"
1678         // object and vary the
1679         // number of retransmits accordingly.  Actually
1680         // we should be able
1681         // to keep retransmitting "killed" objects until
1682         // they expire out of
1683         // our station queue with no problems.  If
1684         // someone wants to ressurect
1685         // the object we'll get new info into our struct
1686         // and this function will
1687         // ignore that object from then on, unless we
1688         // again snatch control of
1689         // the object.
1690 
1691         // if signpost, area object, df object, or
1692         // generic object
1693         // check p_station->APRS_Symbol->aprs_type:
1694         //   APRS_OBJECT
1695         //   APRS_ITEM
1696         //   APRS_DF (looks like I didn't use this one
1697         //   when I implemented DF objects)
1698 
1699         //   Whether area, df, signpost.
1700         // Check ->signpost for signpost data.  Check
1701         // ->df_color also.
1702 
1703         // call_sign, sec_heard, coord_lon, coord_lat,
1704         // packet_time, origin,
1705         // aprs_symbol, pos_time, altitude, speed,
1706         // course, bearing, NRQ,
1707         // power_gain, signal_gain, signpost,
1708         // station_time, station_time_type,
1709         // comments, df_color
1710         if (Create_object_item_tx_string(p_station, line, sizeof(line)) )
1711         {
1712 
1713           // Restore the original lat/long before we
1714           // transmit the (possibly) new position.
1715           //
1716           p_station->coord_lon = x_long_save;
1717           p_station->coord_lat = y_lat_save;
1718 
1719 //fprintf(stderr,"Transmitting: %s\n",line);
1720           // Attempt to transmit the object/item again
1721           if (object_tx_disable || transmit_disable)      // Send to loopback only
1722           {
1723             output_my_data(line,-1,0,1,0,NULL); // Local loopback only, not igating
1724           }
1725           else   // Send to all active tx-enabled interfaces
1726           {
1727             output_my_data(line,-1,0,0,0,NULL); // Transmit/loopback object data, not igating
1728           }
1729         }
1730         else
1731         {
1732 //fprintf(stderr,"Create_object_item_tx_string returned a 0\n");
1733           // Don't transmit it.
1734         }
1735       }
1736       else    // Not time to transmit it yet
1737       {
1738 //fprintf(stderr,"Not time to TX yet:
1739 //%s\t%s\t",p_station->call_sign,p_station->origin);
1740 //fprintf(stderr, "%ld secs to go\n", p_station->last_transmit_time
1741 //+ increment - time );
1742       }
1743     }
1744   }
1745 //fprintf(stderr,"Exiting check_and_transmit_objects_items\n");
1746 }
1747 
1748 
1749 
1750 //////////////////// Draw CAD Objects Functions ////////////////////
1751 
1752 
1753 
1754 //#define CAD_DEBUG
1755 
1756 // Allocate a new vertice along the polygon.  If the vertice is very
1757 // close to the first vertice, ask the operator if they wish to
1758 // close the polygon.  If closing, ask for a raw probability?
1759 //
1760 // As each vertice is allocated, write it out to file?  We'd then
1761 // need to edit the file and comment vertices out if we're deleting
1762 // vertices in memory.  We could also write out an entire object
1763 // when we select "Close Polygon".
1764 //
CAD_vertice_allocate(long latitude,long longitude)1765 void CAD_vertice_allocate(long latitude, long longitude)
1766 {
1767 
1768 #ifdef CAD_DEBUG
1769   fprintf(stderr,"Allocating a new vertice\n");
1770 #endif
1771 
1772   // Check whether a line segment will cross another?
1773 
1774   // We use the CAD_list_head variable, as it will be pointing to
1775   // the top of the list, where the current object we're working
1776   // on will be placed.  Check whether that pointer is NULL
1777   // though, just in case.
1778   if (CAD_list_head)     // We have at least one object defined
1779   {
1780     VerticeRow *p_new;
1781 
1782     // Allocate area to hold the vertice
1783     p_new = (VerticeRow *)malloc(sizeof(VerticeRow));
1784 
1785     if (!p_new)
1786     {
1787       fprintf(stderr,"Couldn't allocate memory in CAD_vertice_allocate()\n");
1788       return;
1789     }
1790 
1791     p_new->latitude = latitude;
1792     p_new->longitude = longitude;
1793 
1794     // Link it in at the top of the vertice chain.
1795     p_new->next = CAD_list_head->start;
1796     CAD_list_head->start = p_new;
1797   }
1798 
1799   // Call redraw_symbols outside this function, as
1800   // verticies may be allocated both when loading lots of them from a file
1801   // and when the user is drawing objects in the user interface
1802   // Reload symbols/tracks/CAD objects
1803   //redraw_symbols(da);
1804 }
1805 
1806 
1807 
1808 
1809 
1810 // Allocate a struct for a new object and add one vertice to it.
1811 // When do we name it and place the label?  Assign probability to
1812 // it?  We should keep a pointer to the current polygon we're
1813 // working on, so that we can modify it easily as we draw.
1814 // Actually, it'll be pointed to by CAD_list_head, so we already
1815 // have it!
1816 //
1817 // As each object is allocated, write it out to file?
1818 //
1819 // Compute a default label of date/time?
1820 //
CAD_object_allocate(long latitude,long longitude)1821 void CAD_object_allocate(long latitude, long longitude)
1822 {
1823   CADRow *p_new;
1824 
1825 #ifdef CAD_DEBUG
1826   fprintf(stderr,"Allocating a new CAD object\n");
1827 #endif
1828 
1829   // Allocate memory and link it to the top of the singly-linked
1830   // list of CADRow objects.
1831   p_new = (CADRow *)malloc(sizeof(CADRow));
1832 
1833   if (!p_new)
1834   {
1835     fprintf(stderr,"Couldn't allocate memory in CAD_object_allocate()\n");
1836     return;
1837   }
1838 
1839   // Fill in default values
1840   p_new->creation_time = sec_now();
1841   p_new->start = NULL;
1842   p_new->line_color = colors[0x27];
1843   p_new->line_type = 2;  // LineOnOffDash;
1844   p_new->line_width = 4;
1845   p_new->computed_area = 0;
1846   CAD_object_set_raw_probability(p_new,0.0,FALSE);
1847   p_new->label_latitude = 0l;
1848   p_new->label_longitude = 0l;
1849   p_new->label[0] = '\0';
1850   p_new->comment[0] = '\0';
1851 
1852   // Allocate area to hold the first vertice
1853 
1854 #ifdef CAD_DEBUG
1855   fprintf(stderr,"Allocating a new vertice\n");
1856 #endif
1857 
1858   p_new->start = (VerticeRow *)malloc(sizeof(VerticeRow));
1859   if (!p_new->start)
1860   {
1861     fprintf(stderr,"Couldn't allocate memory in CAD_object_allocate(2)\n");
1862     free(p_new);
1863     return;
1864   }
1865 
1866   p_new->start->next = NULL;
1867   p_new->start->latitude = latitude;
1868   p_new->start->longitude = longitude;
1869 
1870   // Hook it into the linked list of objects
1871   p_new->next = CAD_list_head;
1872   CAD_list_head = p_new;
1873 
1874   /*
1875   //
1876   // Note:  It was too confusing to have these two dialogs close and
1877   // get redrawn when we click on the first vertice.  The net result
1878   // is that we may have two dialogs move on top of the drawing area
1879   // to the spot we're trying to draw.  Commented out this section due
1880   // to that.  We'll get the two dialogs updated when we click on
1881   // either the DONE or CANCEL button on the Close Polygon dialog.
1882   //
1883       // Here we update the erase cad objects dialog if it is up on
1884       // the screen.  We get rid of it and re-establish it, which will
1885       // usually make the dialog move, but this is better than having
1886       // it be out-of-date.
1887       //
1888       if (cad_erase_dialog != NULL) {
1889           Draw_CAD_Objects_erase_dialog_close(da, NULL, NULL);
1890           Draw_CAD_Objects_erase_dialog(da, NULL, NULL);
1891       }
1892 
1893       // Here we update the edit cad objects dialog by getting rid of
1894       // it and then re-establishing it if it is active when we start.
1895       // This will usually make the dialog move, but it's better than
1896       // having it be out-of-date.
1897       //
1898       if (cad_list_dialog!=NULL) {
1899           // Update the Edit CAD Objects list
1900           Draw_CAD_Objects_list_dialog_close(da, NULL, NULL);
1901           Draw_CAD_Objects_list_dialog(da, NULL, NULL);
1902       }
1903   */
1904 }
1905 
1906 
1907 
1908 
1909 
1910 // Delete all vertices associated with a CAD object and free the
1911 // memory.  We really should pass a pointer to the object here
1912 // instead of a vertice, and set the start pointer to NULL when
1913 // done.
1914 //
CAD_vertice_delete_all(VerticeRow * v)1915 void CAD_vertice_delete_all(VerticeRow *v)
1916 {
1917   VerticeRow *tmp;
1918 
1919   // Call CAD_vertice_delete() for each vertice, then unlink this
1920   // CAD object from the linked list and free its memory.
1921 
1922   // Iterate through each vertice, deleting as we go
1923   while (v != NULL)
1924   {
1925     tmp = v;
1926     v = v->next;
1927     free(tmp);
1928 
1929 #ifdef CAD_DEBUG
1930     fprintf(stderr,"Free'ing a vertice\n");
1931 #endif
1932 
1933   }
1934 }
1935 
1936 
1937 
1938 
1939 
1940 // Delete _all_ CAD objects and all associated vertices.  Loop
1941 // through the entire list of CAD objects, calling
1942 // CAD_vertice_delete_all() and then free'ing the CAD object.  When
1943 // done, set the start pointer to NULL.
1944 //
1945 // We also need to wipe the persistent CAD object file.
1946 //
CAD_object_delete_all(void)1947 void CAD_object_delete_all(void)
1948 {
1949   CADRow *p = CAD_list_head;
1950   CADRow *tmp;
1951 
1952   while (p != NULL)
1953   {
1954     VerticeRow *v = p->start;
1955 
1956     // Remove all of the vertices
1957     if (v != NULL)
1958     {
1959 
1960       // Delete/free the vertices
1961       CAD_vertice_delete_all(v);
1962     }
1963 
1964     // Remove the object and free its memory
1965     tmp = p;
1966     p = p->next;
1967     free(tmp);
1968 
1969 #ifdef CAD_DEBUG
1970     fprintf(stderr,"Free'ing an object\n");
1971 #endif
1972 
1973   }
1974 
1975   // Zero the CAD linked list head
1976   CAD_list_head = NULL;
1977 }
1978 
1979 
1980 
1981 
1982 
1983 // Remove a vertice, thereby joining two segments into one?
1984 //
1985 // Recompute the raw probability if need be, or make it an invalid
1986 // value so that we know we need to recompute it.
1987 //
1988 //void CAD_vertice_delete(CADrow *object) {
1989 //    VerticeRow *v = object->start;
1990 
1991 // Unlink the vertice from the linked list and free its memory.
1992 // Allow removing a vertice in the middle or end of a chain.  If
1993 // removing the vertice turns the polygon into an open polygon,
1994 // alert the user of that fact and ask if they wish to close it.
1995 //}
1996 
1997 
1998 
1999 
2000 
2001 /* Test to see if a CAD object of the name (label) provided exists.
2002    Parameter: label, the label text to be checked.
2003    Returns 0 if no CAD object with a name matching the
2004    provided name is found.
2005    Returns 1 if a CAD object with a name matching the
2006    provided name is found.  */
exists_CAD_object_by_label(char * label)2007 int exists_CAD_object_by_label(char *label)
2008 {
2009   CADRow *object_pointer = CAD_list_head;
2010   int result = 0;  // function return value
2011   int done = 0;    // flag to stop loop when a match is found
2012   while (object_pointer != NULL && done==0)
2013   {
2014     if (strcmp(object_pointer->label,label)==0)
2015     {
2016       // a matching name was found
2017       result = 1;
2018       done = 1;
2019     }
2020     object_pointer = object_pointer->next;
2021   }
2022   return result;
2023 }
2024 
2025 
2026 
2027 
2028 
2029 /* Counts to see how many CAD objects of the name (label) provided exist.
2030    Parameter: label, the label text to be checked.
2031    Returns 0 if no CAD object with a name matching the
2032    provided name is found.
2033    Returns count of the number of CAD objects with a matching label if
2034    one or more is found.  */
count_CAD_object_with_matching_label(char * label)2035 int count_CAD_object_with_matching_label(char *label)
2036 {
2037   CADRow *object_pointer = CAD_list_head;
2038   int result = 0;
2039   while (object_pointer != NULL)
2040   {
2041     // iterate through all CAD objects
2042     if (strcmp(object_pointer->label,label)==0)
2043     {
2044       // a matching name was found
2045       result++;
2046       object_pointer = object_pointer->next;
2047     }
2048   }
2049   return result;
2050 }
2051 
2052 
2053 
2054 
2055 
2056 /* Delete one CAD object and all of its vertices. */
CAD_object_delete(CADRow * object)2057 void CAD_object_delete(CADRow *object)
2058 {
2059   CADRow *all_objects_ptr = CAD_list_head;
2060   CADRow *previous_object_ptr = CAD_list_head;
2061   VerticeRow *v = object->start;
2062   int done = 0;
2063 
2064 #ifdef CAD_DEBUG
2065   fprintf(stderr,"Deleting CAD object %s\n",object->label);
2066 #endif
2067   // check to see if the object we were given was the first object
2068   if (object==all_objects_ptr)
2069   {
2070 #ifdef CAD_DEBUG
2071     fprintf(stderr,"Deleting first CAD object %s\n",object->label);
2072 #endif
2073     CAD_vertice_delete_all(v); // Frees the memory also
2074 
2075     // Unlink the object from the chain and free the memory.
2076     CAD_list_head = object->next;  // Unlink
2077     free(object);   // Free the object memory
2078   }
2079   else
2080   {
2081 #ifdef CAD_DEBUG
2082     fprintf(stderr,"Deleting other than first CAD object %s\n",object->label);
2083 #endif
2084     // walk through the list and delete the object when found
2085     while (all_objects_ptr != NULL && done==0)
2086     {
2087       if (object==all_objects_ptr)
2088       {
2089         v = object->start;
2090         CAD_vertice_delete_all(v);
2091         previous_object_ptr->next = object->next;
2092         free(object);
2093         done = 1;
2094       }
2095       else
2096       {
2097         all_objects_ptr = all_objects_ptr->next;
2098       }
2099     }
2100   }
2101 }
2102 
2103 
2104 
2105 
2106 
2107 // Split an existing CAD object into two objects.  Can we trigger
2108 // this by drawing a line across a closed polygon?
CAD_object_split_existing(void)2109 void CAD_object_split_existing(void)
2110 {
2111 }
2112 
2113 // Join two existing polygons into one larger polygon.
CAD_object_join_two(void)2114 void CAD_object_join_two(void)
2115 {
2116 }
2117 
2118 // Move an entire CAD object, with all it's vertices, somewhere
2119 // else.  Move the label along with it as well.
CAD_object_move(void)2120 void CAD_object_move(void)
2121 {
2122 }
2123 
2124 
2125 
2126 
2127 
2128 // Determine if a CAD object is a closed polygon.
2129 //
2130 // Takes a pointer to a CAD object as an argument.
2131 // Returns 1 if the object is closed.
2132 // Returns 0 if the object is not closed.
2133 //
is_CAD_object_open(CADRow * cad_object)2134 int is_CAD_object_open(CADRow *cad_object)
2135 {
2136   VerticeRow *vertex_pointer;
2137   int vertex_count = 0;
2138   int result = 1;
2139   int atleast_one_different = 0;
2140   long start_lat, start_long;
2141   long stop_lat, stop_long;
2142 
2143   vertex_pointer = cad_object->start;
2144   if (vertex_pointer!=NULL)
2145   {
2146     // greater than zero points, get first point.
2147     start_lat = vertex_pointer->latitude;
2148     start_long = vertex_pointer->longitude;
2149     stop_lat = vertex_pointer->latitude;
2150     stop_long = vertex_pointer->longitude;
2151     vertex_pointer = vertex_pointer->next;
2152     while (vertex_pointer != NULL)
2153     {
2154       //greater than one point, get current point.
2155       stop_lat = vertex_pointer->latitude;
2156       stop_long = vertex_pointer->longitude;
2157       if (stop_lat!=start_lat || stop_long!=start_long)
2158       {
2159         atleast_one_different = 1;
2160       }
2161       vertex_pointer = vertex_pointer->next;
2162       vertex_count++;
2163     }
2164     if (vertex_count>2 && start_lat==stop_lat && start_long==stop_long && atleast_one_different > 0)
2165     {
2166       // more than two points, and they aren't in the same place
2167       result = 0;
2168     }
2169   }
2170   return result;
2171 }
2172 
2173 
2174 
2175 
2176 
2177 // Compute the area enclosed by a CAD object.  Check that it is a
2178 // closed, non-intersecting polygon first.
2179 //
CAD_object_compute_area(CADRow * CAD_list_head)2180 double CAD_object_compute_area(CADRow *CAD_list_head)
2181 {
2182   VerticeRow *tmp;
2183   double area;
2184   char temp_course[20];
2185   // Walk the linked list, computing the area of the
2186   // polygon.  Greene's Theorem is how we can compute the area of
2187   // a polygon using the vertices.  We could also compute whether
2188   // we're going clockwise or counter-clockwise around the polygon
2189   // using Greene's Theorem.  In fact I think we do that for
2190   // Shapefile hole polygons.  Remember that here we're walking
2191   // around the vertices backwards due to the ordering of the
2192   // list.  Shouldn't matter for our purposes though.
2193   //
2194   area = 0.0;
2195   tmp = CAD_list_head->start;
2196   if (is_CAD_object_open(CAD_list_head)==0)
2197   {
2198     // Only compute the area if CAD object is a closed polygon,
2199     // that is, not an open polygon.
2200     while (tmp->next != NULL)
2201     {
2202       double dx0, dy0, dx1, dy1;
2203 
2204       // Because lat/long units can vary drastically w.r.t. real
2205       // units, we need to multiply the terms by the real units in
2206       // order to get real area.
2207 
2208       // Compute real distances from a fixed point.  Convert to
2209       // the current measurement units.  We'll use the starting
2210       // vertice as our fixed point.
2211       //
2212       dx0 = calc_distance_course(
2213               CAD_list_head->start->latitude,
2214               CAD_list_head->start->longitude,
2215               CAD_list_head->start->latitude,
2216               tmp->longitude,
2217               temp_course,
2218               sizeof(temp_course));
2219 
2220       if (tmp->longitude < CAD_list_head->start->longitude)
2221       {
2222         dx0 = -dx0;
2223       }
2224 
2225       dy0 = calc_distance_course(
2226               CAD_list_head->start->latitude,
2227               CAD_list_head->start->longitude,
2228               tmp->latitude,
2229               CAD_list_head->start->longitude,
2230               temp_course,
2231               sizeof(temp_course));
2232 
2233       if (tmp->latitude < CAD_list_head->start->latitude)
2234       {
2235         dx0 = -dx0;
2236       }
2237 
2238       dx1 = calc_distance_course(
2239               CAD_list_head->start->latitude,
2240               CAD_list_head->start->longitude,
2241               CAD_list_head->start->latitude,
2242               tmp->next->longitude,
2243               temp_course,
2244               sizeof(temp_course));
2245 
2246       if (tmp->next->longitude < CAD_list_head->start->longitude)
2247       {
2248         dx0 = -dx0;
2249       }
2250 
2251       dy1 = calc_distance_course(
2252               CAD_list_head->start->latitude,
2253               CAD_list_head->start->longitude,
2254               tmp->next->latitude,
2255               CAD_list_head->start->longitude,
2256               temp_course,
2257               sizeof(temp_course));
2258 
2259       // Add the minus signs back in, if any
2260       if (tmp->longitude < CAD_list_head->start->longitude)
2261       {
2262         dx0 = -dx0;
2263       }
2264       if (tmp->latitude < CAD_list_head->start->latitude)
2265       {
2266         dy0 = -dy0;
2267       }
2268       if (tmp->next->longitude < CAD_list_head->start->longitude)
2269       {
2270         dx1 = -dx1;
2271       }
2272       if (tmp->next->latitude < CAD_list_head->start->latitude)
2273       {
2274         dy1 = -dy1;
2275       }
2276 
2277       // Greene's Theorem:  Summation of the following, then
2278       // divide by two:
2279       //
2280       // A = X Y    - X   Y
2281       //  i   i i+1    i+1 i
2282       //
2283       area += (dx0 * dy1) - (dx1 * dy0);
2284 
2285       tmp = tmp->next;
2286     }
2287     area = 0.5 * area;
2288   }
2289 
2290   if (area < 0.0)
2291   {
2292     area = -area;
2293   }
2294 
2295 //fprintf(stderr,"Square nautical miles: %f\n", area);
2296 
2297   return area;
2298 
2299 }
2300 
2301 
2302 
2303 
2304 
2305 // Allocate a label for an object, and place it according to the
2306 // user's requests.  Keep track of where from the origin to place
2307 // the label, font to use, color, etc.
CAD_object_allocate_label(void)2308 void CAD_object_allocate_label(void)
2309 {
2310 }
2311 
2312 
2313 
2314 
2315 
2316 // Set the probability for an object.  We should probably allocate
2317 // the raw probability to small "buckets" within the closed polygon.
2318 // This will allow us to split/join polygons later without messing
2319 // up the probablity assigned to each area originally.  Check that
2320 // it is a closed polygon first.
2321 // if as_percent==TRUE, then probability is treated as a percent
2322 // (expected to be a value between 0 and 100).
2323 // otherwise, then probability is treated as a probability
2324 // (expected to be a value between 0 and 1).
2325 //
CAD_object_set_raw_probability(CADRow * object_ptr,float probability,int as_percent)2326 void CAD_object_set_raw_probability(CADRow *object_ptr, float probability, int as_percent)
2327 {
2328   // initial implementation just assigns a single raw probability to the whole polygon.
2329   // internal storage is as a probability between 0 and 1
2330   // users will usually want to manipulate this as a percent (between 0 and 100)
2331   // thus the get and set functions are aware of both internal storage and
2332   // the user's request and return an appropriately scaled value.
2333   if (as_percent==TRUE)
2334   {
2335     // convert from a percent to a probability between 0 and 1
2336     object_ptr->raw_probability = (probability/100.00);
2337   }
2338   else
2339   {
2340     // treat as in internal storage form
2341     object_ptr->raw_probability = probability;
2342   }
2343 }
2344 
2345 
2346 
2347 
2348 
2349 // Get the raw probability for an object.  Sum up the raw
2350 // probability "buckets" contained within the closed polygon.  Check
2351 // that it _is_ a closed polygon first.
2352 //
CAD_object_get_raw_probability(CADRow * object_ptr,int as_percent)2353 float CAD_object_get_raw_probability(CADRow *object_ptr, int as_percent)
2354 {
2355   float result = 0.0;
2356   // not checking yet for closure
2357   if (object_ptr != NULL)
2358   {
2359     // initial implementation returns just the single raw probability
2360     result = object_ptr->raw_probability;
2361     if (as_percent > 0)
2362     {
2363       // raw probability is a probability between 0 an 1,
2364       // this may be desired as a percent.
2365       result = result * 100;
2366     }
2367   }
2368 #ifdef CAD_DEBUG
2369   fprintf(stderr,"Getting Probability: %01.5f\n",result);
2370 #endif
2371   return result;
2372 }
2373 
2374 
2375 
2376 
2377 
CAD_object_set_line_width(void)2378 void CAD_object_set_line_width(void)
2379 {
2380 }
2381 
2382 
2383 
2384 
2385 
CAD_object_set_color(void)2386 void CAD_object_set_color(void)
2387 {
2388 }
2389 
2390 
2391 
2392 
2393 
CAD_object_set_linetype(void)2394 void CAD_object_set_linetype(void)
2395 {
2396 }
2397 
2398 
2399 
2400 
2401 
2402 // Used to break a line segment into two.  Can then move the vertice
2403 // if needed.  Recompute the raw probability if need be, or make it
2404 // an invalid value so that we know we need to recompute it.
CAD_vertice_insert_new(void)2405 void CAD_vertice_insert_new(void)
2406 {
2407   // Check whether a line segment will cross another?
2408 }
2409 
2410 
2411 
2412 
2413 
2414 // Move an existing vertice.  Recompute the raw probability if need
2415 // be, or make it an invalid value so that we know we need to
2416 // recompute it.
CAD_vertice_move(void)2417 void CAD_vertice_move(void)
2418 {
2419   // Check whether a line segment will cross another?
2420 }
2421 
2422 
2423 
2424 
2425 
2426 // Set the location for drawing the label of an area to the center
2427 // of the area.  Takes a pointer to a CAD object as a parameter.
2428 // Sets the label_latitude and label_longitude attributes of the CAD
2429 // object to the center of the region described by the vertices of
2430 // the object.
2431 //
CAD_object_set_label_at_centroid(CADRow * CAD_object)2432 void CAD_object_set_label_at_centroid(CADRow *CAD_object)
2433 {
2434   // *** current implementation approximates the center as the
2435   // average of the largest and smallest of each of latitude
2436   // and longitude rather than correctly computing the centroid,
2437   // that is, it places the label at the centroid of a bounding
2438   // box for the area.  ***
2439   // We can't use a simple x=sum(x)/n, y=sum(y)/n as the
2440   // points on the outline shouldn't be weighted equally.
2441   // Ideal would be to place the label at the central point within
2442   // the area itslef, apparently this is a hard prbolem.
2443   // alternative would be to use the centroid, which like the
2444   // average of maximum and minimum values may lie outside of
2445   // the area.
2446   VerticeRow *vertex_pointer;
2447   long min_lat, min_long;
2448   long max_lat, max_long;
2449   // Walk the linked list and compute the centroid of the bounding box.
2450   vertex_pointer = CAD_object->start;
2451   min_lat = 0.0;
2452   min_long = 0.0;
2453 
2454   // Set the latitude and longitude of the label to the
2455   // centroid of the bounding box.
2456   // Start by setting lat and long of label to first point.
2457   CAD_object->label_latitude = vertex_pointer->latitude;
2458   CAD_object->label_longitude = vertex_pointer->longitude;
2459   if (vertex_pointer != NULL)
2460   {
2461     // Iterate through the vertices and calculate the center x and y position
2462     // based on an average of the largest and smallest latitudes and longitudes.
2463     min_lat = vertex_pointer->latitude;
2464     min_long = vertex_pointer->longitude;
2465     max_lat = vertex_pointer->latitude;
2466     max_long = vertex_pointer->longitude;
2467     while (vertex_pointer != NULL)
2468     {
2469       if (vertex_pointer->next != NULL)
2470       {
2471         if (vertex_pointer->longitude < min_long )
2472         {
2473           min_long = vertex_pointer->longitude;
2474         }
2475         if (vertex_pointer->latitude < min_lat )
2476         {
2477           min_lat = vertex_pointer->latitude;
2478         }
2479         if (vertex_pointer->longitude > max_long )
2480         {
2481           max_long = vertex_pointer->longitude;
2482         }
2483         if (vertex_pointer->latitude > max_lat )
2484         {
2485           max_lat = vertex_pointer->latitude;
2486         }
2487       }
2488       vertex_pointer = vertex_pointer->next;
2489     }
2490     CAD_object->label_latitude = (max_lat + min_lat)/2.0;
2491     CAD_object->label_longitude = (max_long + min_long)/2.0;
2492   }
2493 }
2494 
2495 
2496 
2497 
2498 
2499 // This is the callback for the CAD objects parameters dialog.  It
2500 // takes the values entered in the dialog and stores them in the
2501 // most recently created object.
2502 //
Set_CAD_object_parameters(Widget widget,XtPointer clientData,XtPointer calldata)2503 void Set_CAD_object_parameters (Widget widget,
2504                                 XtPointer clientData,
2505                                 XtPointer calldata)
2506 {
2507 
2508   float probability = 0.0;
2509   CADRow *target_object = NULL;
2510   int cb_selected;
2511   // need to find out object to edit from clientData rather than
2512   // using the first object in list as the one to edit.
2513   //target_object = CAD_list_head;
2514   target_object = (CADRow *)clientData;
2515 
2516   // set label, comment, and probability for area
2517   xastir_snprintf(target_object->label,
2518                   sizeof(target_object->label),
2519                   "%s", XmTextGetString(cad_label_data)
2520                  );
2521   xastir_snprintf(target_object->comment,
2522                   sizeof(target_object->comment),
2523                   "%s", XmTextGetString(cad_comment_data)
2524                  );
2525   // Is more error checking needed?  atof appears to correctly handle
2526   // empty input, reasonable probability values, and text (0.00).
2527   // User side probabilities are expressed as percent.
2528   probability = atof(XmTextGetString(cad_probability_data));
2529   CAD_object_set_raw_probability(target_object, probability, TRUE);
2530 
2531   // Use the selected line type, default is dashed
2532   cb_selected = FALSE;
2533 
2534 #ifdef USE_COMBO_BOX
2535   XtVaGetValues(cad_line_style_data,
2536                 XmNselectedPosition,
2537                 &cb_selected,
2538                 NULL);
2539 #else
2540   cb_selected = clsd_value;
2541 #endif // USE_COMBO_BOX
2542 
2543   if (cb_selected)
2544   {
2545     target_object->line_type = cb_selected;
2546   }
2547   else
2548   {
2549     target_object->line_type = 2; // LineOnOffDash
2550   }
2551 
2552   if (cad_list_dialog)
2553   {
2554     Update_CAD_objects_list_dialog();
2555   }
2556 
2557   // close object_parameters dialog
2558   XtPopdown(cad_dialog);
2559   XtDestroyWidget(cad_dialog);
2560   cad_dialog = (Widget)NULL;
2561 
2562   Save_CAD_Objects_to_file();
2563   // Reload symbols/tracks/CAD objects so that object name will show on map.
2564   redraw_symbols(da);
2565 
2566   // Here we update the erase cad objects dialog if it is up on
2567   // the screen.  We get rid of it and re-establish it, which will
2568   // usually make the dialog move, but this is better than having
2569   // it be out-of-date.
2570   //
2571   if (cad_erase_dialog != NULL)
2572   {
2573     Draw_CAD_Objects_erase_dialog_close(widget,clientData,calldata);
2574     Draw_CAD_Objects_erase_dialog(widget,clientData,calldata);
2575   }
2576 
2577   // Here we update the edit cad objects dialog by getting rid of
2578   // it and then re-establishing it if it is active when we start.
2579   // This will usually make the dialog move, but it's better than
2580   // having it be out-of-date.
2581   //
2582   if (cad_list_dialog!=NULL)
2583   {
2584     // Update the Edit CAD Objects list
2585     Draw_CAD_Objects_list_dialog_close(widget, clientData, calldata);
2586     Draw_CAD_Objects_list_dialog(widget, clientData, calldata);
2587   }
2588 }
2589 
2590 
2591 
2592 
2593 
2594 // Update the list of existing CAD objects on the cad list dialog to
2595 // reflect the current list of objects.
2596 //
Update_CAD_objects_list_dialog()2597 void Update_CAD_objects_list_dialog()
2598 {
2599   CADRow *object_ptr = CAD_list_head;
2600   int counter = 1;
2601   XmString cb_item;
2602 
2603   if (list_of_existing_CAD_objects_edit!=NULL && cad_list_dialog)
2604   {
2605     XmListDeleteAllItems(list_of_existing_CAD_objects_edit);
2606 
2607     // iterate through list of objects to populate scrolled list
2608     while (object_ptr != NULL)
2609     {
2610 
2611       //  If no label, use the string "<Empty Label>" instead
2612       if (object_ptr->label[0] == '\0')
2613       {
2614         cb_item = XmStringCreateLtoR("<Empty Label>", XmFONTLIST_DEFAULT_TAG);
2615       }
2616       else
2617       {
2618         cb_item = XmStringCreateLtoR(object_ptr->label, XmFONTLIST_DEFAULT_TAG);
2619       }
2620 
2621       XmListAddItem(list_of_existing_CAD_objects_edit,
2622                     cb_item,
2623                     counter);
2624       counter++;
2625       XmStringFree(cb_item);
2626       object_ptr = object_ptr->next;
2627     }
2628   }
2629 }
2630 
2631 
2632 
2633 
2634 
close_object_params_dialog(Widget widget,XtPointer clientData,XtPointer calldata)2635 void close_object_params_dialog(Widget widget, XtPointer clientData, XtPointer calldata)
2636 {
2637   XtPopdown(cad_dialog);
2638   XtDestroyWidget(cad_dialog);
2639   cad_dialog = (Widget)NULL;
2640 
2641   // Here we update the erase cad objects dialog if it is up on
2642   // the screen.  We get rid of it and re-establish it, which will
2643   // usually make the dialog move, but this is better than having
2644   // it be out-of-date.
2645   //
2646   if (cad_erase_dialog != NULL)
2647   {
2648     Draw_CAD_Objects_erase_dialog_close(widget,clientData,calldata);
2649     Draw_CAD_Objects_erase_dialog(widget,clientData,calldata);
2650   }
2651 
2652   // Here we update the edit cad objects dialog by getting rid of
2653   // it and then re-establishing it if it is active when we start.
2654   // This will usually make the dialog move, but it's better than
2655   // having it be out-of-date.
2656   //
2657   if (cad_list_dialog!=NULL)
2658   {
2659     // Update the Edit CAD Objects list
2660     Draw_CAD_Objects_list_dialog_close(widget, clientData, calldata);
2661     Draw_CAD_Objects_list_dialog(widget, clientData, calldata);
2662   }
2663 }
2664 
2665 
2666 #ifndef USE_COMBO_BOX
clsd_menuCallback(Widget widget,XtPointer ptr,XtPointer callData)2667 void clsd_menuCallback(Widget widget, XtPointer ptr, XtPointer callData)
2668 {
2669   //XmPushButtonCallbackStruct *data = (XmPushButtonCallbackStruct *)callData;
2670   XtPointer userData;
2671 
2672   XtVaGetValues(widget, XmNuserData, &userData, NULL);
2673 
2674   //clsd_menu is zero based, cad_line_style_data constants are one based.
2675   clsd_value = (int)userData + 1;
2676   if (debug_level & 1)
2677   {
2678     fprintf(stderr,"Selected value on cad line type pulldown: %d\n",clsd_value);
2679   }
2680 }
2681 #endif  // !USE_COMBO_BOX
2682 
2683 
2684 
2685 // Create a dialog to obtain information about a newly created CAD
2686 // object from the user.  Values of probability, name, and comment
2687 // are initially blank.  Takes as a parameter a string describing
2688 // the area of the object.  There is a single button with a callback
2689 // to Set_CAD_object_parameters, which stores values from the dialog
2690 // in the object's struct.  Should be generalized to allow editing
2691 // of a pre-existing CAD object (except for the name).  Parameter
2692 // should be a pointer to the object.
2693 //
Set_CAD_object_parameters_dialog(char * area_description,CADRow * CAD_object)2694 void Set_CAD_object_parameters_dialog(char *area_description, CADRow *CAD_object)
2695 {
2696   Widget cad_pane, cad_form,
2697          cad_label,
2698          cad_comment,
2699          cad_probability,
2700          cad_line_style,
2701          button_done,
2702          button_cancel;
2703   char   probability_string[5];
2704   int i;  // loop counters
2705   //XmString cb_item;  // used to create picklist of line styles
2706   XmString cb_items[3];
2707 #ifndef USE_COMBO_BOX
2708   Widget clsd_menuPane;
2709   Widget clsd_button;
2710   Widget clsd_buttons[3];
2711   Widget clsd_menu;
2712   char buf[18];
2713   int x;
2714   Arg args[12]; // available for XtSetArguments
2715 #endif // !USE_COMBO_BOX
2716   Widget clsd_widget;
2717 
2718 
2719   if (cad_dialog)
2720   {
2721     (void)XRaiseWindow(XtDisplay(cad_dialog), XtWindow(cad_dialog));
2722   }
2723   else
2724   {
2725 
2726     // Area Object"
2727     cad_dialog = XtVaCreatePopupShell(langcode("CADPUD001"),
2728                                       xmDialogShellWidgetClass,
2729                                       appshell,
2730                                       XmNdeleteResponse,          XmDESTROY,
2731                                       XmNdefaultPosition,         FALSE,
2732                                       XmNfontList, fontlist1,
2733                                       NULL);
2734 
2735     cad_pane = XtVaCreateWidget("Set_Del_Object pane",
2736                                 xmPanedWindowWidgetClass,
2737                                 cad_dialog,
2738                                 MY_FOREGROUND_COLOR,
2739                                 MY_BACKGROUND_COLOR,
2740                                 NULL);
2741 
2742     cad_form =  XtVaCreateWidget("Set_Del_Object ob_form",
2743                                  xmFormWidgetClass,
2744                                  cad_pane,
2745                                  XmNfractionBase,            2,
2746                                  XmNautoUnmanage,            FALSE,
2747                                  XmNshadowThickness,         1,
2748                                  MY_FOREGROUND_COLOR,
2749                                  MY_BACKGROUND_COLOR,
2750                                  NULL);
2751     // Area of polygon, already scaled and internationalized.
2752     cad_label = XtVaCreateManagedWidget(area_description,
2753                                         xmLabelWidgetClass,
2754                                         cad_form,
2755                                         XmNtopAttachment,           XmATTACH_FORM,
2756                                         XmNtopOffset,               10,
2757                                         XmNbottomAttachment,        XmATTACH_NONE,
2758                                         XmNleftAttachment,          XmATTACH_FORM,
2759                                         XmNleftOffset,              10,
2760                                         XmNrightAttachment,         XmATTACH_NONE,
2761                                         MY_FOREGROUND_COLOR,
2762                                         MY_BACKGROUND_COLOR,
2763                                         XmNfontList, fontlist1,
2764                                         NULL);
2765     // "Area Label:"
2766     cad_label = XtVaCreateManagedWidget(langcode("CADPUD002"),
2767                                         xmLabelWidgetClass,
2768                                         cad_form,
2769                                         XmNtopAttachment,           XmATTACH_FORM,
2770                                         XmNtopOffset,               50,
2771                                         XmNbottomAttachment,        XmATTACH_NONE,
2772                                         XmNleftAttachment,          XmATTACH_FORM,
2773                                         XmNleftOffset,              10,
2774                                         XmNrightAttachment,         XmATTACH_NONE,
2775                                         MY_FOREGROUND_COLOR,
2776                                         MY_BACKGROUND_COLOR,
2777                                         XmNfontList, fontlist1,
2778                                         NULL);
2779     // label text field
2780     cad_label_data = XtVaCreateManagedWidget("Set_Del_Object name_data",
2781                      xmTextFieldWidgetClass,
2782                      cad_form,
2783                      XmNeditable,                TRUE,
2784                      XmNcursorPositionVisible,   TRUE,
2785                      XmNsensitive,               TRUE,
2786                      XmNshadowThickness,         1,
2787                      XmNcolumns,                 20,
2788                      XmNmaxLength,               CAD_LABEL_MAX_SIZE - 1,
2789                      XmNtopAttachment,           XmATTACH_FORM,
2790                      XmNtopOffset,               50,
2791                      XmNbottomAttachment,        XmATTACH_NONE,
2792                      XmNleftAttachment,          XmATTACH_WIDGET,
2793                      XmNleftWidget,              cad_label,
2794                      XmNrightAttachment,         XmATTACH_NONE,
2795                      XmNbackground,              colors[0x0f],
2796                      XmNfontList, fontlist1,
2797                      NULL);
2798     // "Comment"
2799     cad_comment = XtVaCreateManagedWidget(langcode("CADPUD003"),
2800                                           xmLabelWidgetClass,
2801                                           cad_form,
2802                                           XmNtopAttachment,           XmATTACH_FORM,
2803                                           XmNtopOffset,               90,
2804                                           XmNbottomAttachment,        XmATTACH_NONE,
2805                                           XmNleftAttachment,          XmATTACH_FORM,
2806                                           XmNleftOffset,              10,
2807                                           XmNrightAttachment,         XmATTACH_NONE,
2808                                           MY_FOREGROUND_COLOR,
2809                                           MY_BACKGROUND_COLOR,
2810                                           XmNfontList, fontlist1,
2811                                           NULL);
2812     // comment text field
2813     cad_comment_data = XtVaCreateManagedWidget("Set_Del_Object name_data",
2814                        xmTextFieldWidgetClass,
2815                        cad_form,
2816                        XmNeditable,                TRUE,
2817                        XmNcursorPositionVisible,   TRUE,
2818                        XmNsensitive,               TRUE,
2819                        XmNshadowThickness,         1,
2820                        XmNcolumns,                 40,
2821                        XmNmaxLength,               CAD_COMMENT_MAX_SIZE - 1,
2822                        XmNtopAttachment,           XmATTACH_FORM,
2823                        XmNtopOffset,               90,
2824                        XmNbottomAttachment,        XmATTACH_NONE,
2825                        XmNleftAttachment,          XmATTACH_WIDGET,
2826                        XmNleftWidget,              cad_comment,
2827                        XmNrightAttachment,         XmATTACH_NONE,
2828                        XmNbackground,              colors[0x0f],
2829                        XmNfontList, fontlist1,
2830                        NULL);
2831     // "Probability (as %)"
2832     cad_probability = XtVaCreateManagedWidget(langcode("CADPUD004"),
2833                       xmLabelWidgetClass,
2834                       cad_form,
2835                       XmNtopAttachment,           XmATTACH_FORM,
2836                       XmNtopOffset,               130,
2837                       XmNbottomAttachment,        XmATTACH_NONE,
2838                       XmNleftAttachment,          XmATTACH_FORM,
2839                       XmNleftOffset,              10,
2840                       XmNrightAttachment,         XmATTACH_NONE,
2841                       MY_FOREGROUND_COLOR,
2842                       MY_BACKGROUND_COLOR,
2843                       XmNfontList, fontlist1,
2844                       NULL);
2845     // probability field
2846     cad_probability_data = XtVaCreateManagedWidget("Set_Del_Object name_data",
2847                            xmTextFieldWidgetClass,
2848                            cad_form,
2849                            XmNeditable,                TRUE,
2850                            XmNcursorPositionVisible,   TRUE,
2851                            XmNsensitive,               TRUE,
2852                            XmNshadowThickness,         1,
2853                            XmNcolumns,                 5,
2854                            XmNmaxLength,               5,
2855                            XmNtopAttachment,           XmATTACH_FORM,
2856                            XmNtopOffset,               130,
2857                            XmNbottomAttachment,        XmATTACH_NONE,
2858                            XmNleftAttachment,          XmATTACH_WIDGET,
2859                            XmNleftWidget,              cad_probability,
2860                            XmNrightAttachment,         XmATTACH_NONE,
2861                            XmNbackground,              colors[0x0f],
2862                            XmNfontList, fontlist1,
2863                            NULL);
2864     // Boundary Line Type
2865     cad_line_style = XtVaCreateManagedWidget("Line Type:",
2866                      xmLabelWidgetClass,
2867                      cad_form,
2868                      XmNtopAttachment,           XmATTACH_WIDGET,
2869                      XmNtopWidget,               cad_probability_data,
2870                      XmNtopOffset,               5,
2871                      XmNbottomAttachment,        XmATTACH_NONE,
2872                      XmNleftAttachment,          XmATTACH_FORM,
2873                      XmNleftOffset,              10,
2874                      XmNrightAttachment,         XmATTACH_NONE,
2875                      MY_FOREGROUND_COLOR,
2876                      MY_BACKGROUND_COLOR,
2877                      XmNfontList, fontlist1,
2878                      NULL);
2879 
2880     // lesstif as of 0.95 in 2008 doesn't fully support combo boxes
2881     //
2882     // Need to replace combo boxes with a pull down menu when lesstif is used.
2883     // See xpdf's  XPDFViewer.cc/XPDFViewer.h for an example.
2884     //cb_items = (XmString *) XtMalloc ( sizeof (XmString) * 4 );
2885     // Solid
2886     cb_items[0] = XmStringCreateLtoR( langcode("CADPUD012"), XmFONTLIST_DEFAULT_TAG);
2887     // Dashed
2888     cb_items[1] = XmStringCreateLtoR( langcode("CADPUD013"), XmFONTLIST_DEFAULT_TAG);
2889     // Double Dash
2890     cb_items[2] = XmStringCreateLtoR( langcode("CADPUD014"), XmFONTLIST_DEFAULT_TAG);
2891 
2892     clsd_widget = cad_line_style_data;
2893 
2894 #ifdef USE_COMBO_BOX
2895     // Combo box to pick line style
2896     cad_line_style_data = XtVaCreateManagedWidget("select line style",
2897                           xmComboBoxWidgetClass,
2898                           cad_form,
2899                           XmNtopAttachment,           XmATTACH_WIDGET,
2900                           XmNtopWidget,               cad_probability_data,
2901                           XmNtopOffset,               5,
2902                           XmNbottomAttachment,        XmATTACH_NONE,
2903                           XmNleftAttachment,          XmATTACH_WIDGET,
2904                           XmNleftWidget,              cad_line_style,
2905                           XmNleftOffset,              10,
2906                           XmNrightAttachment,         XmATTACH_NONE,
2907                           XmNnavigationType,          XmTAB_GROUP,
2908                           XmNcomboBoxType,            XmDROP_DOWN_LIST,
2909                           XmNpositionMode,            XmONE_BASED,
2910                           XmNvisibleItemCount,        3,
2911                           MY_FOREGROUND_COLOR,
2912                           MY_BACKGROUND_COLOR,
2913                           XmNfontList, fontlist1,
2914                           NULL);
2915     XmComboBoxAddItem(cad_line_style_data,cb_items[0],1,1);
2916     XmComboBoxAddItem(cad_line_style_data,cb_items[1],2,1);
2917     XmComboBoxAddItem(cad_line_style_data,cb_items[2],3,1);
2918 
2919     clsd_widget = cad_line_style_data;
2920 #else
2921     // menu replacement for combo box when using lesstif
2922     x = 0;
2923     XtSetArg(args[x], XmNmarginWidth, 0);
2924     ++x;
2925     XtSetArg(args[x], XmNmarginHeight, 0);
2926     ++x;
2927     XtSetArg(args[x], XmNfontList, fontlist1);
2928     ++x;
2929     clsd_menuPane = XmCreatePulldownMenu(cad_form,"sddd_menuPane", args, x);
2930     //sddd_menu is zero based, constants for database types are one based.
2931     //sddd_value is set to match constants in callback.
2932     for (i=0; i<3; i++)
2933     {
2934       x = 0;
2935       XtSetArg(args[x], XmNlabelString, cb_items[i]);
2936       x++;
2937       XtSetArg(args[x], XmNuserData, (XtPointer)i);
2938       x++;
2939       XtSetArg(args[x], XmNfontList, fontlist1);
2940       ++x;
2941       sprintf(buf,"button%d",i);
2942       clsd_button = XmCreatePushButton(clsd_menuPane, buf, args, x);
2943       XtManageChild(clsd_button);
2944       XtAddCallback(clsd_button, XmNactivateCallback, clsd_menuCallback, Set_CAD_object_parameters_dialog);
2945       clsd_buttons[i] = clsd_button;
2946     }
2947     x = 0;
2948     XtSetArg(args[x], XmNleftAttachment, XmATTACH_WIDGET);
2949     ++x;
2950     XtSetArg(args[x], XmNleftWidget, cad_line_style);
2951     ++x;
2952     XtSetArg(args[x], XmNtopAttachment, XmATTACH_WIDGET);
2953     ++x;
2954     XtSetArg(args[x], XmNtopWidget, cad_probability_data);
2955     ++x;
2956     XtSetArg(args[x], XmNmarginWidth, 0);
2957     ++x;
2958     XtSetArg(args[x], XmNmarginHeight, 0);
2959     ++x;
2960     XtSetArg(args[x], XmNtopOffset, 5);
2961     ++x;
2962     XtSetArg(args[x], XmNleftOffset, 10);
2963     ++x;
2964     XtSetArg(args[x], XmNsubMenuId, clsd_menuPane);
2965     ++x;
2966     XtSetArg(args[x], XmNfontList, fontlist1);
2967     ++x;
2968     clsd_menu = XmCreateOptionMenu(cad_form, "sddd_Menu", args, x);
2969     XtManageChild(clsd_menu);
2970     clsd_value = 2;   // set a default value (line on off dash)
2971     clsd_widget = clsd_menu;
2972 #endif  // USE_COMBO_BOX
2973     // free up space from combo box strings
2974     for (i=0; i<3; i++)
2975     {
2976       XmStringFree(cb_items[i]);
2977     }
2978 
2979 
2980     // "OK"
2981     button_done = XtVaCreateManagedWidget(langcode("CADPUD005"),
2982                                           xmPushButtonGadgetClass,
2983                                           cad_form,
2984                                           XmNtopAttachment,     XmATTACH_WIDGET,
2985                                           XmNtopWidget,         clsd_widget,
2986                                           XmNtopOffset,         5,
2987                                           XmNbottomAttachment,  XmATTACH_FORM,
2988                                           XmNbottomOffset,      5,
2989                                           XmNleftAttachment,    XmATTACH_POSITION,
2990                                           XmNleftPosition,      0,
2991                                           XmNrightAttachment,   XmATTACH_POSITION,
2992                                           XmNrightPosition,     1,
2993                                           XmNnavigationType,    XmTAB_GROUP,
2994                                           MY_FOREGROUND_COLOR,
2995                                           MY_BACKGROUND_COLOR,
2996                                           XmNfontList, fontlist1,
2997                                           NULL);
2998 
2999     // "Cancel"
3000     button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"),
3001                                             xmPushButtonGadgetClass,
3002                                             cad_form,
3003                                             XmNtopAttachment,     XmATTACH_WIDGET,
3004                                             XmNtopWidget,         clsd_widget,
3005                                             XmNtopOffset,         5,
3006                                             XmNbottomAttachment,  XmATTACH_FORM,
3007                                             XmNbottomOffset,      5,
3008                                             XmNleftAttachment,    XmATTACH_POSITION,
3009                                             XmNleftPosition,      1,
3010                                             XmNrightAttachment,   XmATTACH_POSITION,
3011                                             XmNrightPosition,     2,
3012                                             XmNnavigationType,    XmTAB_GROUP,
3013                                             MY_FOREGROUND_COLOR,
3014                                             MY_BACKGROUND_COLOR,
3015                                             XmNfontList, fontlist1,
3016                                             NULL);
3017 
3018 
3019     // callback depends on whether this is a new or old object
3020     //XtAddCallback(button_done, XmNactivateCallback, Set_CAD_object_parameters, Set_CAD_object_parameters_dialog);
3021 
3022     if (CAD_object!=NULL)
3023     {
3024       XtAddCallback(button_done, XmNactivateCallback, Set_CAD_object_parameters, (XtPointer *)CAD_object);
3025     }
3026     else
3027     {
3028       // called to get information for a newly created cad object
3029       // pass pointer to the head of the list, which contains
3030       // the most recently created cad object.
3031       XtAddCallback(button_done, XmNactivateCallback, Set_CAD_object_parameters, CAD_list_head);
3032     }
3033 
3034     XtAddCallback(button_cancel, XmNactivateCallback, close_object_params_dialog, NULL);
3035 
3036     pos_dialog(cad_dialog);
3037     XmInternAtom(XtDisplay(cad_dialog),"WM_DELETE_WINDOW", FALSE);
3038 
3039     XtManageChild(cad_form);
3040     XtManageChild(cad_pane);
3041 
3042     XtPopup(cad_dialog,XtGrabNone);
3043   } // end if ! caddialog
3044 
3045   if (CAD_object!=NULL)
3046   {
3047     XmString tempSelection;
3048 
3049     // given an existing object, fill form with its information
3050     XmTextFieldSetString(cad_label_data,CAD_object->label);
3051     XmTextFieldSetString(cad_comment_data,CAD_object->comment);
3052     xastir_snprintf(probability_string,
3053                     sizeof(probability_string),
3054                     "%01.2f",
3055                     CAD_object_get_raw_probability(CAD_object,1));
3056     XmTextFieldSetString(cad_probability_data,probability_string);
3057 
3058     switch(CAD_object->line_type)
3059     {
3060 
3061       case 1: // Solid
3062 #ifndef USE_COMBO_BOX
3063         i = 0;
3064 #endif // !USE_COMBO_BOX
3065         tempSelection = XmStringCreateLtoR( langcode("CADPUD012"),
3066                                             XmFONTLIST_DEFAULT_TAG);
3067         break;
3068 
3069       case 2: // Dashed
3070 #ifndef USE_COMBO_BOX
3071         i = 1;
3072 #endif // !USE_COMBO_BOX
3073         tempSelection = XmStringCreateLtoR( langcode("CADPUD013"),
3074                                             XmFONTLIST_DEFAULT_TAG);
3075         break;
3076 
3077       case 3: // Double Dash
3078 #ifndef USE_COMBO_BOX
3079         i = 2;
3080 #endif // !USE_COMBO_BOX
3081         tempSelection = XmStringCreateLtoR( langcode("CADPUD014"),
3082                                             XmFONTLIST_DEFAULT_TAG);
3083         break;
3084 
3085       default:
3086 #ifndef USE_COMBO_BOX
3087         i = 1;
3088 #endif // !USE_COMBO_BOX
3089         tempSelection = XmStringCreateLtoR( langcode("CADPUD013"),
3090                                             XmFONTLIST_DEFAULT_TAG);
3091         break;
3092     }
3093 #ifdef USE_COMBO_BOX
3094     XmComboBoxSelectItem(cad_line_style_data, tempSelection);
3095 #else
3096     clsd_value = i+1;
3097     //clsd_menu is zero based, line types are one based.
3098     //clsd_value matches line types (1-3).
3099     XtVaSetValues(clsd_menu, XmNmenuHistory, clsd_buttons[i], NULL);
3100 #endif // USE_COMBO_BOX
3101     XmStringFree(tempSelection);
3102   }
3103 }
3104 
3105 
3106 
3107 
3108 
3109 static Cursor cs_CAD = (Cursor)NULL;
3110 
free_cs_CAD(void)3111 void free_cs_CAD(void)
3112 {
3113   XFreeCursor(XtDisplay(da), cs_CAD);
3114   cs_CAD = (Cursor)NULL;
3115 }
3116 
3117 // This is the callback for the Draw togglebutton
3118 //
Draw_CAD_Objects_mode(Widget UNUSED (widget),XtPointer UNUSED (clientData),XtPointer callData)3119 void Draw_CAD_Objects_mode( Widget UNUSED(widget),
3120                             XtPointer UNUSED(clientData),
3121                             XtPointer callData)
3122 {
3123 
3124   XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData;
3125 
3126 
3127   if(state->set)
3128   {
3129     draw_CAD_objects_flag = 1;
3130 
3131     // Create the "pencil" cursor so we know what mode we're in.
3132     //
3133     if(!cs_CAD)
3134     {
3135       cs_CAD=XCreateFontCursor(XtDisplay(da),XC_pencil);
3136       atexit(free_cs_CAD);
3137     }
3138 
3139     // enable the close polygon button on an open CAD menu
3140     if (CAD_close_polygon_menu_item)
3141     {
3142       XtSetSensitive(CAD_close_polygon_menu_item,TRUE);
3143     }
3144 
3145     (void)XDefineCursor(XtDisplay(da),XtWindow(da),cs_CAD);
3146     (void)XFlush(XtDisplay(da));
3147 
3148     draw_CAD_objects_flag = 1;
3149     polygon_last_x = -1;    // Invalid position
3150     polygon_last_y = -1;    // Invalid position
3151   }
3152   else
3153   {
3154     draw_CAD_objects_flag = 0;
3155     polygon_last_x = -1;    // Invalid position
3156     polygon_last_y = -1;    // Invalid position
3157 
3158     Save_CAD_Objects_to_file();
3159 
3160     // Remove the special "pencil" cursor.
3161     (void)XUndefineCursor(XtDisplay(da),XtWindow(da));
3162     (void)XFlush(XtDisplay(da));
3163 
3164     // disable the close polygon button on an open CAD menu.
3165     if (CAD_close_polygon_menu_item)
3166     {
3167       XtSetSensitive(CAD_close_polygon_menu_item,FALSE);
3168     }
3169   }
3170 }
3171 
3172 
3173 
3174 
3175 
3176 // Called when we complete a new CAD object.  Save the object to
3177 // disk so that we can recover in the case of a crash or power
3178 // failure.  Save any old file to a backup file.  Perhaps write them
3179 // to numbered backup files so that we keep several on-hand?
3180 //
Save_CAD_Objects_to_file(void)3181 void Save_CAD_Objects_to_file(void)
3182 {
3183   FILE *f;
3184   char *file;
3185   CADRow *object_ptr = CAD_list_head;
3186   char temp_file_path[MAX_VALUE];
3187 
3188   fprintf(stderr,"Saving CAD objects to file\n");
3189 
3190   // Save in ~/.xastir/config/CAD_object.log
3191   file = get_user_base_dir("config/CAD_object.log", temp_file_path, sizeof(temp_file_path));
3192   f = fopen(file,"w+");
3193 
3194   if (f == NULL)
3195   {
3196     fprintf(stderr,
3197             "Couldn't open config/CAD_object.log file for writing!\n");
3198     return;
3199   }
3200 
3201   while (object_ptr != NULL)
3202   {
3203     VerticeRow *vertice = object_ptr->start;
3204 
3205     // Write out the main object info:
3206     fprintf(f,"\nCAD_Object\n");
3207     fprintf(f,"creation_time:   %lu\n",(unsigned long)object_ptr->creation_time);
3208     fprintf(f,"line_color:      %d\n",object_ptr->line_color);
3209     fprintf(f,"line_type:       %d\n",object_ptr->line_type);
3210     fprintf(f,"line_width:      %d\n",object_ptr->line_width);
3211     fprintf(f,"computed_area:   %f\n",object_ptr->computed_area);
3212     fprintf(f,"raw_probability: %f\n",CAD_object_get_raw_probability(object_ptr,TRUE));
3213     fprintf(f,"label_latitude:  %lu\n",object_ptr->label_latitude);
3214     fprintf(f,"label_longitude: %lu\n",object_ptr->label_longitude);
3215     fprintf(f,"label: %s\n",object_ptr->label);
3216     if (strlen(object_ptr->comment)>1)
3217     {
3218       fprintf(f,"comment: %s\n",object_ptr->comment);
3219     }
3220     else
3221     {
3222       fprintf(f,"comment: NULL\n");
3223     }
3224 
3225     // Iterate through the vertices:
3226     while (vertice != NULL)
3227     {
3228 
3229       fprintf(f,"Vertice: %lu %lu\n",
3230               vertice->latitude,
3231               vertice->longitude);
3232 
3233       vertice = vertice->next;
3234     }
3235     object_ptr = object_ptr->next;
3236   }
3237   (void)fclose(f);
3238 }
3239 
3240 
3241 
3242 
3243 
3244 // Called by main() when we start Xastir.  Restores CAD objects
3245 // created in earlier Xastir sessions.
3246 //
Restore_CAD_Objects_from_file(void)3247 void Restore_CAD_Objects_from_file(void)
3248 {
3249   FILE *f;
3250   char *file;
3251   char line[MAX_FILENAME];
3252   char temp_file_path[MAX_VALUE];
3253 #ifdef CAD_DEBUG
3254   fprintf(stderr,"Restoring CAD objects from file\n");
3255 #endif
3256 
3257   // Restore from ~/.xastir/config/CAD_object.log
3258   file = get_user_base_dir("config/CAD_object.log", temp_file_path, sizeof(temp_file_path));
3259   f = fopen(file,"r");
3260 
3261   if (f == NULL)
3262   {
3263 #ifdef CAD_DEBUG
3264     fprintf(stderr,
3265             "Couldn't open config/CAD_object.log file for reading!\n");
3266 #endif
3267     return;
3268   }
3269 
3270   while (!feof (f))
3271   {
3272     (void)get_line(f, line, MAX_FILENAME);
3273     if (strncasecmp(line,"CAD_Object",10) == 0)
3274     {
3275       // Found a new CAD Object declaration!
3276 
3277       //fprintf(stderr,"Found CAD_Object\n");
3278 
3279       // Malloc a new object, add it to the linked list, start
3280       // filling in the fields.
3281       //
3282       // This gives us a default object with one vertice.  We
3283       // can replace all of the fields in it as we parse them.
3284       CAD_object_allocate(0l, 0l);
3285 
3286       // Remove the one vertice from the newly allocated
3287       // object so that we don't end up with one too many
3288       // vertices when all done.
3289       CAD_vertice_delete_all(CAD_list_head->start);
3290       CAD_list_head->start = NULL;
3291 
3292     }
3293     else if (strncasecmp(line,"creation_time:",14) == 0)
3294     {
3295       //fprintf(stderr,"Found creation_time:\n");
3296       unsigned long temp_time;
3297       if (1 != sscanf(line+15, "%lu",&temp_time))
3298       {
3299         fprintf(stderr,"Restore_CAD_Objects_from_file:sscanf parsing error [creation_time]\n");
3300       }
3301       CAD_list_head->creation_time=(time_t)temp_time;
3302     }
3303     else if (strncasecmp(line,"line_color:",11) == 0)
3304     {
3305       //fprintf(stderr,"Found line_color:\n");
3306       if (1 != sscanf(line+12,"%d",
3307                       &CAD_list_head->line_color))
3308       {
3309         fprintf(stderr,"Restore_CAD_Objects_from_file:sscanf parsing error [line_color]\n");
3310       }
3311     }
3312     else if (strncasecmp(line,"line_type:",10) == 0)
3313     {
3314       //fprintf(stderr,"Found line_type:\n");
3315       if (1 != sscanf(line+11,"%d",
3316                       &CAD_list_head->line_type))
3317       {
3318         fprintf(stderr,"Restore_CAD_Objects_from_file:sscanf parsing error [line_type]\n");
3319       }
3320     }
3321     else if (strncasecmp(line,"line_width:",11) == 0)
3322     {
3323       //fprintf(stderr,"Found line_width:\n");
3324       if (1 != sscanf(line+12,"%d",
3325                       &CAD_list_head->line_width))
3326       {
3327         fprintf(stderr,"Restore_CAD_Objects_from_file:sscanf parsing error [line_width]\n");
3328       }
3329     }
3330     else if (strncasecmp(line,"computed_area:",14) == 0)
3331     {
3332       //fprintf(stderr,"Found computed_area:\n");
3333       if (1 != sscanf(line+15,"%f",
3334                       &CAD_list_head->computed_area))
3335       {
3336         fprintf(stderr,"Restore_CAD_Objects_from_file:sscanf parsing error [computed_area]\n");
3337       }
3338     }
3339     else if (strncasecmp(line,"raw_probability:",16) == 0)
3340     {
3341       //fprintf(stderr,"Found raw_probability:\n");
3342       if (1 != sscanf(line+17,"%f",
3343                       &CAD_list_head->raw_probability))
3344       {
3345         fprintf(stderr,"Restore_CAD_Objects_from_file:sscanf parsing error [raw_probability]\n");
3346       }
3347       else
3348       {
3349         // External storage is as percent, need to make sure that this
3350         // fits the expected internal storage format.
3351         // Thus take given value and store using method that knows
3352         // how to handle percents
3353         CAD_object_set_raw_probability(CAD_list_head,CAD_list_head->raw_probability,TRUE);
3354       }
3355     }
3356     else if (strncasecmp(line,"label_latitude:",15) == 0)
3357     {
3358       //fprintf(stderr,"Found label_latitude:\n");
3359       if (1 != sscanf(line+16,"%lu",
3360                       (unsigned long *)&CAD_list_head->label_latitude))
3361       {
3362         fprintf(stderr,"Restore_CAD_Objects_from_file:sscanf parsing error [label_latitude]\n");
3363       }
3364     }
3365     else if (strncasecmp(line,"label_longitude:",16) == 0)
3366     {
3367       //fprintf(stderr,"Found label_longitude:\n");
3368       if (1 != sscanf(line+17,"%lu",
3369                       (unsigned long *)&CAD_list_head->label_longitude))
3370       {
3371         fprintf(stderr,"Restore_CAD_Objects_from_file:sscanf parsing error [label_longitude]\n");
3372       }
3373     }
3374     else if (strncasecmp(line,"label:",6) == 0)
3375     {
3376       //fprintf(stderr,"Found label:\n");
3377       xastir_snprintf(CAD_list_head->label,
3378                       sizeof(CAD_list_head->label),
3379                       "%s",
3380                       line+7);
3381     }
3382     else if (strncasecmp(line,"comment:",8) == 0)
3383     {
3384       //fprintf(stderr,"Found comment:\n");
3385       xastir_snprintf(CAD_list_head->comment,
3386                       sizeof(CAD_list_head->comment),
3387                       "%s",
3388                       line+9);
3389 
3390       if (strcmp(CAD_list_head->comment,"NULL")==0)
3391       {
3392         xastir_snprintf(CAD_list_head->comment,
3393                         sizeof(CAD_list_head->comment),
3394                         "%c",
3395                         '\0'
3396                        );
3397       }
3398     }
3399     else if (strncasecmp(line,"Vertice:",8) == 0)
3400     {
3401       long latitude, longitude;
3402 
3403       //fprintf(stderr,"Found Vertice:\n");
3404       if (2 != sscanf(line+9,"%lu %lu",
3405                       (unsigned long *)&latitude,
3406                       (unsigned long *)&longitude))
3407       {
3408         fprintf(stderr,"Restore_CAD_Objects_from_file:sscanf parsing error [vertex]\n");
3409       }
3410       CAD_vertice_allocate(latitude,longitude);
3411     }
3412     else
3413     {
3414       // Else not recognized, do nothing with it!
3415       //fprintf(stderr,"Found unrecognized line\n");
3416     }
3417   }
3418   (void)fclose(f);
3419   // Reload symbols/tracks/CAD objects to draw the loaded objects
3420   redraw_symbols(da);
3421 }
3422 
3423 
3424 
3425 
3426 
3427 // popdown and destroy the cad_erase_dialog.
3428 //
Draw_CAD_Objects_erase_dialog_close(Widget UNUSED (w),XtPointer UNUSED (clientData),XtPointer UNUSED (callData))3429 void Draw_CAD_Objects_erase_dialog_close ( Widget UNUSED(w),
3430     XtPointer UNUSED(clientData),
3431     XtPointer UNUSED(callData) )
3432 {
3433 
3434   if (cad_erase_dialog!=NULL)
3435   {
3436     // close cad_erase_dialog
3437     XtPopdown(cad_erase_dialog);
3438     XtDestroyWidget(cad_erase_dialog);
3439     cad_erase_dialog = (Widget)NULL;
3440   }
3441 
3442 }
3443 
3444 
3445 
3446 
3447 
3448 // Call back for delete selected button on
3449 // Draw_CAD_Objects_erase_dialog.  Iterates through the list of
3450 // selected CAD objects and deletes them.
3451 //
Draw_CAD_Objects_erase_selected(Widget w,XtPointer clientData,XtPointer callData)3452 void Draw_CAD_Objects_erase_selected ( Widget w,
3453                                        XtPointer clientData,
3454                                        XtPointer callData)
3455 {
3456   int itemCount;       // number of items in list of CAD objects.
3457   XmString *listItems; // names of CAD objects on list
3458   char *cadName;       // the text name of a CAD object
3459   Position x;          // position on list
3460   char *selectedName;  // the text name of a selected CAD object
3461   CADRow *object_ptr = CAD_list_head;  // pointer to the linked list of CAD objects
3462   int done = 0;        // has a cad object with a name matching the current selection been found
3463 
3464   // For more than a few objects this loop/save/redraw will need to move
3465   // off to a separate thread.
3466 
3467   XtVaGetValues(list_of_existing_CAD_objects,
3468                 XmNitemCount,&itemCount,
3469                 XmNitems,&listItems,
3470                 NULL);
3471   // iterate through list and delete each first object with a name matching
3472   // those that are selected on the list.
3473   //
3474   // *** Note: If names are not unique the results may not be what the user expects.
3475   // The first match to a selection will be deleted, not necessarily the selection.
3476   //
3477   for (x=1; x<=itemCount; x++)
3478   {
3479 
3480     if (done)
3481     {
3482       break;
3483     }
3484 
3485     if (XmListPosSelected(list_of_existing_CAD_objects,x))
3486     {
3487       int no_label = 0;
3488 
3489       XmStringGetLtoR(listItems[(x-1)],XmFONTLIST_DEFAULT_TAG,&selectedName);
3490 
3491       // Check for our own definition of no label for the CAD
3492       // objects, which is "<Empty Label>"
3493       if (strcmp(selectedName,"<Empty Label>") == 0)
3494       {
3495         no_label++;
3496       }
3497 
3498       object_ptr = CAD_list_head;
3499       done = 0;
3500 
3501       while (object_ptr != NULL && done == 0)
3502       {
3503 
3504         cadName = object_ptr->label;
3505 
3506         if (strcmp(cadName,selectedName)==0
3507             || ( (cadName == NULL || cadName[0] == '\0') && no_label) )
3508         {
3509           // delete CAD object matching the selected name
3510           CAD_object_delete(object_ptr);
3511           done = 1;
3512         }
3513         else
3514         {
3515           object_ptr = object_ptr->next;
3516         }
3517       }
3518     }
3519   }
3520 
3521   Draw_CAD_Objects_erase_dialog_close(w,clientData,callData);
3522 
3523   // Save the altered list to file.
3524   Save_CAD_Objects_to_file();
3525   // Reload symbols/tracks/CAD objects
3526   redraw_symbols(da);
3527 
3528   // Here we update the edit cad objects dialog by getting rid of it and
3529   // then re-establishing it if it is active when we start.  This will
3530   // usually make the dialog move, but it's better than having it be
3531   // out-of-date.
3532   //
3533   if (cad_list_dialog!=NULL)
3534   {
3535     // Update the Edit CAD Objects list
3536     Draw_CAD_Objects_list_dialog_close(w, clientData, callData);
3537     Draw_CAD_Objects_list_dialog(w, clientData, callData);
3538   }
3539 }
3540 
3541 
3542 
3543 
3544 
3545 // Callback for delete CAD objects menu option.  Dialog to allow
3546 // users to delete all CAD objects or select individual CAD objects
3547 // to delete.
3548 //
Draw_CAD_Objects_erase_dialog(Widget UNUSED (w),XtPointer UNUSED (clientData),XtPointer UNUSED (callData))3549 void Draw_CAD_Objects_erase_dialog( Widget UNUSED(w),
3550                                     XtPointer UNUSED(clientData),
3551                                     XtPointer UNUSED(callData) )
3552 {
3553 
3554   Widget cad_erase_pane, cad_erase_form, cad_erase_label,
3555          button_delete_all, button_delete_selected, button_cancel;
3556   Arg al[100];       /* Arg List */
3557   unsigned int ac;   /* Arg Count */
3558   CADRow *object_ptr = CAD_list_head;
3559   int counter = 1;
3560   XmString cb_item;
3561 
3562   if (cad_erase_dialog)
3563   {
3564     (void)XRaiseWindow(XtDisplay(cad_erase_dialog), XtWindow(cad_erase_dialog));
3565   }
3566   else
3567   {
3568 
3569     // Delete CAD Objects
3570     cad_erase_dialog = XtVaCreatePopupShell("Delete CAD Objects",
3571                                             xmDialogShellWidgetClass,
3572                                             appshell,
3573                                             XmNdeleteResponse,          XmDESTROY,
3574                                             XmNdefaultPosition,         FALSE,
3575                                             XmNfontList, fontlist1,
3576                                             NULL);
3577 
3578     cad_erase_pane = XtVaCreateWidget("CAD erase Object pane",
3579                                       xmPanedWindowWidgetClass,
3580                                       cad_erase_dialog,
3581                                       MY_FOREGROUND_COLOR,
3582                                       MY_BACKGROUND_COLOR,
3583                                       NULL);
3584 
3585     cad_erase_form =  XtVaCreateWidget("Cad erase Object form",
3586                                        xmFormWidgetClass,
3587                                        cad_erase_pane,
3588                                        XmNfractionBase,            3,
3589                                        XmNautoUnmanage,            FALSE,
3590                                        XmNshadowThickness,         1,
3591                                        MY_FOREGROUND_COLOR,
3592                                        MY_BACKGROUND_COLOR,
3593                                        NULL);
3594 
3595     // heading: Delete CAD Objects
3596     cad_erase_label = XtVaCreateManagedWidget(langcode("CADPUD009"),
3597                       xmLabelWidgetClass,
3598                       cad_erase_form,
3599                       XmNtopAttachment,           XmATTACH_FORM,
3600                       XmNtopOffset,               10,
3601                       XmNbottomAttachment,        XmATTACH_NONE,
3602                       XmNleftAttachment,          XmATTACH_FORM,
3603                       XmNleftOffset,              10,
3604                       XmNrightAttachment,         XmATTACH_NONE,
3605                       MY_FOREGROUND_COLOR,
3606                       MY_BACKGROUND_COLOR,
3607                       XmNfontList, fontlist1,
3608                       NULL);
3609 
3610     // *** need to handle the special case of no CAD objects ? ***
3611 
3612     // scrolled pick list to allow selection of current objects
3613     /*set args for list */
3614     ac=0;
3615     XtSetArg(al[ac], XmNvisibleItemCount, 11);
3616     ac++;
3617     XtSetArg(al[ac], XmNtraversalOn, TRUE);
3618     ac++;
3619     XtSetArg(al[ac], XmNshadowThickness, 3);
3620     ac++;
3621     XtSetArg(al[ac], XmNselectionPolicy, XmEXTENDED_SELECT);
3622     ac++;
3623     XtSetArg(al[ac], XmNscrollBarPlacement, XmBOTTOM_RIGHT);
3624     ac++;
3625     XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET);
3626     ac++;
3627     XtSetArg(al[ac], XmNtopWidget, cad_erase_label);
3628     ac++;
3629     XtSetArg(al[ac], XmNtopOffset, 5);
3630     ac++;
3631     XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE);
3632     ac++;
3633     XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM);
3634     ac++;
3635     XtSetArg(al[ac], XmNrightOffset, 5);
3636     ac++;
3637     XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM);
3638     ac++;
3639     XtSetArg(al[ac], XmNleftOffset, 5);
3640     ac++;
3641     XtSetArg(al[ac], XmNforeground, MY_FG_COLOR);
3642     ac++;
3643     //XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++;
3644     XtSetArg(al[ac], XmNbackground, colors[0x0f]);
3645     ac++;
3646     XtSetArg(al[ac], XmNfontList, fontlist1);
3647     ac++;
3648 
3649     list_of_existing_CAD_objects = XmCreateScrolledList(cad_erase_form,
3650                                    "CAD objects for deletion scrolled list",
3651                                    al,
3652                                    ac);
3653     // make sure list is empty
3654     XmListDeleteAllItems(list_of_existing_CAD_objects);
3655 
3656     // iterate through list of objects to populate scrolled list
3657     while (object_ptr != NULL)
3658     {
3659 
3660       //  If no label, use the string "<Empty Label>" instead
3661       if (object_ptr->label[0] == '\0')
3662       {
3663         cb_item = XmStringCreateLtoR("<Empty Label>", XmFONTLIST_DEFAULT_TAG);
3664       }
3665       else
3666       {
3667         cb_item = XmStringCreateLtoR(object_ptr->label, XmFONTLIST_DEFAULT_TAG);
3668       }
3669 
3670 
3671       XmListAddItem(list_of_existing_CAD_objects,
3672                     cb_item,
3673                     counter);
3674       counter++;
3675       XmStringFree(cb_item);
3676       object_ptr = object_ptr->next;
3677     }
3678 
3679     // "Delete All"
3680     button_delete_all = XtVaCreateManagedWidget(langcode("CADPUD010"),
3681                         xmPushButtonGadgetClass,
3682                         cad_erase_form,
3683                         XmNtopAttachment,     XmATTACH_WIDGET,
3684                         XmNtopWidget,         list_of_existing_CAD_objects,
3685                         XmNtopOffset,         5,
3686                         XmNbottomAttachment,  XmATTACH_FORM,
3687                         XmNbottomOffset,      5,
3688                         XmNleftAttachment,    XmATTACH_FORM,
3689                         XmNleftOffset,        5,
3690                         XmNnavigationType,    XmTAB_GROUP,
3691                         MY_FOREGROUND_COLOR,
3692                         MY_BACKGROUND_COLOR,
3693                         XmNfontList, fontlist1,
3694                         NULL);
3695     XtAddCallback(button_delete_all, XmNactivateCallback, Draw_CAD_Objects_erase, Draw_CAD_Objects_erase_dialog);
3696 
3697     // "Delete Selected"
3698     button_delete_selected = XtVaCreateManagedWidget(langcode("CADPUD011"),
3699                              xmPushButtonGadgetClass,
3700                              cad_erase_form,
3701                              XmNtopAttachment,     XmATTACH_WIDGET,
3702                              XmNtopWidget,         list_of_existing_CAD_objects,
3703                              XmNtopOffset,         5,
3704                              XmNbottomAttachment,  XmATTACH_FORM,
3705                              XmNbottomOffset,      5,
3706                              XmNleftAttachment,    XmATTACH_WIDGET,
3707                              XmNleftWidget,        button_delete_all,
3708                              XmNleftOffset,        10,
3709                              XmNnavigationType,    XmTAB_GROUP,
3710                              MY_FOREGROUND_COLOR,
3711                              MY_BACKGROUND_COLOR,
3712                              XmNfontList, fontlist1,
3713                              NULL);
3714     XtAddCallback(button_delete_selected, XmNactivateCallback, Draw_CAD_Objects_erase_selected, Draw_CAD_Objects_erase_dialog);
3715 
3716     // "Cancel"
3717     button_cancel = XtVaCreateManagedWidget(langcode("CADPUD008"),
3718                                             xmPushButtonGadgetClass,
3719                                             cad_erase_form,
3720                                             XmNtopAttachment,     XmATTACH_WIDGET,
3721                                             XmNtopWidget,         list_of_existing_CAD_objects,
3722                                             XmNtopOffset,         5,
3723                                             XmNbottomAttachment,  XmATTACH_FORM,
3724                                             XmNbottomOffset,      5,
3725                                             XmNleftAttachment,    XmATTACH_WIDGET,
3726                                             XmNleftWidget,        button_delete_selected,
3727                                             XmNleftOffset,        10,
3728                                             XmNnavigationType,    XmTAB_GROUP,
3729                                             MY_FOREGROUND_COLOR,
3730                                             MY_BACKGROUND_COLOR,
3731                                             XmNfontList, fontlist1,
3732                                             NULL);
3733     XtAddCallback(button_cancel, XmNactivateCallback, Draw_CAD_Objects_erase_dialog_close, Draw_CAD_Objects_erase_dialog);
3734     pos_dialog(cad_erase_dialog);
3735     XmInternAtom(XtDisplay(cad_erase_dialog),"WM_DELETE_WINDOW", FALSE);
3736 
3737     XtManageChild(cad_erase_form);
3738     XtManageChild(list_of_existing_CAD_objects);
3739     XtManageChild(cad_erase_pane);
3740 
3741     XtPopup(cad_erase_dialog,XtGrabNone);
3742   }
3743 }
3744 
3745 
3746 
3747 
3748 
3749 // popdown and destroy the cad_list_dialog
3750 //
Draw_CAD_Objects_list_dialog_close(Widget UNUSED (w),XtPointer UNUSED (clientData),XtPointer UNUSED (callData))3751 void Draw_CAD_Objects_list_dialog_close ( Widget UNUSED(w),
3752     XtPointer UNUSED(clientData),
3753     XtPointer UNUSED(callData) )
3754 {
3755 
3756   if (cad_list_dialog!=NULL)
3757   {
3758     // close cad_list_dialog
3759     XtPopdown(cad_list_dialog);
3760     XtDestroyWidget(cad_list_dialog);
3761     cad_list_dialog = (Widget)NULL;
3762   }
3763 
3764 }
3765 
3766 
3767 
3768 
3769 
3770 // Show details for selected CAD object.  Callback for the show/edit
3771 // details button on the Draw_CAD_Objects_list dialog.
3772 //
Show_selected_CAD_object_details(Widget UNUSED (w),XtPointer UNUSED (clientData),XtPointer UNUSED (callData))3773 void Show_selected_CAD_object_details ( Widget UNUSED(w),
3774                                         XtPointer UNUSED(clientData),
3775                                         XtPointer UNUSED(callData) )
3776 {
3777 
3778   static int sizeof_area_description = 200;
3779   int itemCount;       // number of items in list of CAD objects.
3780   XmString *listItems; // names of CAD objects on list
3781   char *cadName;       // the text name of a CAD object
3782   Position x;          // position on list
3783   char *selectedName;  // the text name of a selected CAD object
3784   CADRow *object_ptr = CAD_list_head;  // pointer to the linked list of CAD objects
3785   int done = 0;        // has a cad object with a name matching the current selection been found
3786   double area;
3787   char area_description[sizeof_area_description];
3788   xastir_snprintf(area_description, sizeof_area_description, "Area");
3789 
3790   if (cad_list_dialog!=NULL)
3791   {
3792     // get the selected object
3793     XtVaGetValues(list_of_existing_CAD_objects_edit,
3794                   XmNitemCount,&itemCount,
3795                   XmNitems,&listItems,
3796                   NULL);
3797     // iterate through list and find each object with a name
3798     // matching one selected on the list.
3799     //
3800     // *** Note: If names are not unique the results may not be what the user expects.
3801     // The first match to a selection will be used, not necessarily the selection.
3802     //
3803     for (x=1; x<=itemCount; x++)
3804     {
3805       if (XmListPosSelected(list_of_existing_CAD_objects_edit,x))
3806       {
3807         int no_label = 0;
3808 
3809         XmStringGetLtoR(listItems[(x-1)],XmFONTLIST_DEFAULT_TAG,&selectedName);
3810 
3811         // Check for our own definition of no label for the CAD
3812         // objects, which is "<Empty Label>"
3813         if (strcmp(selectedName,"<Empty Label>") == 0)
3814         {
3815           no_label++;
3816         }
3817 
3818         object_ptr = CAD_list_head;
3819         done = 0;
3820 
3821         while (object_ptr != NULL && done == 0)
3822         {
3823 
3824           cadName = object_ptr->label;
3825 
3826           if (strcmp(cadName,selectedName)==0
3827               || ( (cadName == NULL || cadName[0] == '\0') && no_label) )
3828           {
3829 
3830             // get the area for the CAD object matching the selected name
3831             // and format it as a localized string.
3832             area = object_ptr->computed_area;
3833             Format_area_for_output(&area, area_description,sizeof_area_description);
3834             // open the CAD object details dialog for the matching CAD object
3835             Set_CAD_object_parameters_dialog(area_description,object_ptr);
3836             done = 1;
3837           }
3838           else
3839           {
3840             object_ptr = object_ptr->next;
3841           }
3842         }
3843       }
3844     }
3845 
3846     // leave the list dialog open
3847   }
3848 }
3849 
3850 
3851 
3852 
3853 
3854 // Callback for edit CAD objects menu option.  Dialog to allow users
3855 // to select individual CAD objects in order to edit their metadata.
3856 //
Draw_CAD_Objects_list_dialog(Widget UNUSED (w),XtPointer UNUSED (clientData),XtPointer UNUSED (callData))3857 void Draw_CAD_Objects_list_dialog( Widget UNUSED(w),
3858                                    XtPointer UNUSED(clientData),
3859                                    XtPointer UNUSED(callData) )
3860 {
3861 
3862   Widget cad_list_pane, cad_list_form, cad_list_label,
3863          button_list_selected, button_close;
3864   Arg al[100];       /* Arg List */
3865   unsigned int ac;   /* Arg Count */
3866   CADRow *object_ptr = CAD_list_head;
3867   int counter = 1;
3868   XmString cb_item;
3869 
3870   if (cad_list_dialog)
3871   {
3872     (void)XRaiseWindow(XtDisplay(cad_list_dialog), XtWindow(cad_list_dialog));
3873   }
3874   else
3875   {
3876 
3877     // List CAD Objects
3878     cad_list_dialog = XtVaCreatePopupShell("List CAD Objects",
3879                                            xmDialogShellWidgetClass,
3880                                            appshell,
3881                                            XmNdeleteResponse,          XmDESTROY,
3882                                            XmNdefaultPosition,         FALSE,
3883                                            XmNfontList, fontlist1,
3884                                            NULL);
3885 
3886     cad_list_pane = XtVaCreateWidget("CAD list Object pane",
3887                                      xmPanedWindowWidgetClass,
3888                                      cad_list_dialog,
3889                                      MY_FOREGROUND_COLOR,
3890                                      MY_BACKGROUND_COLOR,
3891                                      XmNfontList, fontlist1,
3892                                      NULL);
3893 
3894     cad_list_form =  XtVaCreateWidget("Cad list Object form",
3895                                       xmFormWidgetClass,
3896                                       cad_list_pane,
3897                                       XmNfractionBase,            3,
3898                                       XmNautoUnmanage,            FALSE,
3899                                       XmNshadowThickness,         1,
3900                                       MY_FOREGROUND_COLOR,
3901                                       MY_BACKGROUND_COLOR,
3902                                       XmNfontList, fontlist1,
3903                                       NULL);
3904 
3905     // heading: CAD Objects
3906     cad_list_label = XtVaCreateManagedWidget(langcode("CADPUD006"),
3907                      xmLabelWidgetClass,
3908                      cad_list_form,
3909                      XmNtopAttachment,           XmATTACH_FORM,
3910                      XmNtopOffset,               10,
3911                      XmNbottomAttachment,        XmATTACH_NONE,
3912                      XmNleftAttachment,          XmATTACH_FORM,
3913                      XmNleftOffset,              10,
3914                      XmNrightAttachment,         XmATTACH_NONE,
3915                      MY_FOREGROUND_COLOR,
3916                      MY_BACKGROUND_COLOR,
3917                      XmNfontList, fontlist1,
3918                      NULL);
3919 
3920     // *** need to handle the special case of no CAD objects ? ***
3921 
3922     // scrolled pick list to allow selection of current objects
3923     /*set args for list */
3924     ac=0;
3925     XtSetArg(al[ac], XmNvisibleItemCount, 11);
3926     ac++;
3927     XtSetArg(al[ac], XmNtraversalOn, TRUE);
3928     ac++;
3929     XtSetArg(al[ac], XmNshadowThickness, 3);
3930     ac++;
3931     XtSetArg(al[ac], XmNselectionPolicy, XmSINGLE_SELECT);
3932     ac++;
3933     XtSetArg(al[ac], XmNscrollBarPlacement, XmBOTTOM_RIGHT);
3934     ac++;
3935     XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET);
3936     ac++;
3937     XtSetArg(al[ac], XmNtopWidget, cad_list_label);
3938     ac++;
3939     XtSetArg(al[ac], XmNtopOffset, 5);
3940     ac++;
3941     XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE);
3942     ac++;
3943     XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM);
3944     ac++;
3945     XtSetArg(al[ac], XmNrightOffset, 5);
3946     ac++;
3947     XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM);
3948     ac++;
3949     XtSetArg(al[ac], XmNleftOffset, 5);
3950     ac++;
3951     XtSetArg(al[ac], XmNforeground, MY_FG_COLOR);
3952     ac++;
3953     //XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++;
3954     XtSetArg(al[ac], XmNbackground, colors[0x0f]);
3955     ac++;
3956     XtSetArg(al[ac], XmNfontList, fontlist1);
3957     ac++;
3958 
3959     list_of_existing_CAD_objects_edit = XmCreateScrolledList(cad_list_form,
3960                                         "CAD objects for deletion scrolled list",
3961                                         al,
3962                                         ac);
3963     // make sure list is empty
3964     XmListDeleteAllItems(list_of_existing_CAD_objects_edit);
3965 
3966     // iterate through list of objects to populate scrolled list
3967     while (object_ptr != NULL)
3968     {
3969 
3970       //  If no label, use the string "<Empty Label>" instead
3971       if (object_ptr->label[0] == '\0')
3972       {
3973         cb_item = XmStringCreateLtoR("<Empty Label>", XmFONTLIST_DEFAULT_TAG);
3974       }
3975       else
3976       {
3977         cb_item = XmStringCreateLtoR(object_ptr->label, XmFONTLIST_DEFAULT_TAG);
3978       }
3979 
3980       XmListAddItem(list_of_existing_CAD_objects_edit,
3981                     cb_item,
3982                     counter);
3983       counter++;
3984       XmStringFree(cb_item);
3985       object_ptr = object_ptr->next;
3986     }
3987 
3988     // "Show/edit details"
3989     button_list_selected = XtVaCreateManagedWidget(langcode("CADPUD007"),
3990                            xmPushButtonGadgetClass,
3991                            cad_list_form,
3992                            XmNtopAttachment,     XmATTACH_WIDGET,
3993                            XmNtopWidget,         list_of_existing_CAD_objects_edit,
3994                            XmNtopOffset,         5,
3995                            XmNbottomAttachment,  XmATTACH_FORM,
3996                            XmNbottomOffset,      5,
3997                            XmNleftAttachment,    XmATTACH_FORM,
3998                            XmNleftOffset,        10,
3999                            XmNnavigationType,    XmTAB_GROUP,
4000                            MY_FOREGROUND_COLOR,
4001                            MY_BACKGROUND_COLOR,
4002                            XmNfontList, fontlist1,
4003                            NULL);
4004     XtAddCallback(button_list_selected, XmNactivateCallback, Show_selected_CAD_object_details, Draw_CAD_Objects_list_dialog);
4005 
4006     // "Close"
4007     button_close = XtVaCreateManagedWidget(langcode("UNIOP00003"),
4008                                            xmPushButtonGadgetClass,
4009                                            cad_list_form,
4010                                            XmNtopAttachment,     XmATTACH_WIDGET,
4011                                            XmNtopWidget,         list_of_existing_CAD_objects_edit,
4012                                            XmNtopOffset,         5,
4013                                            XmNbottomAttachment,  XmATTACH_FORM,
4014                                            XmNbottomOffset,      5,
4015                                            XmNleftAttachment,    XmATTACH_WIDGET,
4016                                            XmNleftWidget,        button_list_selected,
4017                                            XmNleftOffset,        10,
4018                                            XmNnavigationType,    XmTAB_GROUP,
4019                                            MY_FOREGROUND_COLOR,
4020                                            MY_BACKGROUND_COLOR,
4021                                            XmNfontList, fontlist1,
4022                                            NULL);
4023     XtAddCallback(button_close, XmNactivateCallback, Draw_CAD_Objects_list_dialog_close, Draw_CAD_Objects_erase_dialog);
4024     pos_dialog(cad_list_dialog);
4025     XmInternAtom(XtDisplay(cad_list_dialog),"WM_DELETE_WINDOW", FALSE);
4026 
4027     XtManageChild(cad_list_form);
4028     XtManageChild(list_of_existing_CAD_objects_edit);
4029     XtManageChild(cad_list_pane);
4030 
4031     XtPopup(cad_list_dialog,XtGrabNone);
4032   }
4033 }
4034 
4035 
4036 
4037 
4038 
4039 // Free the object and vertice lists then do a screen update.
4040 // callback from delete all button on cad_erase_dialog.
4041 //
Draw_CAD_Objects_erase(Widget w,XtPointer clientData,XtPointer callData)4042 void Draw_CAD_Objects_erase( Widget w,
4043                              XtPointer clientData,
4044                              XtPointer callData)
4045 {
4046 
4047   // if we were called from the cad_erase_dialog, make sure it is closed properly
4048   if (cad_erase_dialog)
4049   {
4050     Draw_CAD_Objects_erase_dialog_close(w,clientData,callData);
4051   }
4052 
4053   CAD_object_delete_all();
4054   polygon_last_x = -1;    // Invalid position
4055   polygon_last_y = -1;    // Invalid position
4056 
4057   // Save the empty list out to file
4058   Save_CAD_Objects_to_file();
4059 
4060   // Reload symbols/tracks/CAD objects
4061   redraw_symbols(da);
4062 }
4063 
4064 
4065 
4066 
4067 
4068 // Formats an area as a string in english (square miles) or metric units
4069 // (square kilometers). Switches to square feet or square meters if the
4070 // area is less than 0.1 of the units.
4071 //
4072 // Parameters:
4073 //     area: an area in square kilometers.
4074 //     area_description: area reformatted as a localized text string.
4075 //     sizeof_area_description: array length of area_description.
4076 //
Format_area_for_output(double * area_km2,char * area_description,int sizeof_area_description)4077 void Format_area_for_output(double *area_km2, char *area_description, int sizeof_area_description)
4078 {
4079   double area;
4080   // Format it for output and dump it out.  We're using square terms, so
4081   // apply the conversion factor twice to convert from square kilometers
4082   // to the units of interest. The result here is squared meters or
4083   // squared feet.
4084 //fprintf(stderr,"Square km: %f\n", *area_km2);
4085 
4086   area = *area_km2 * 1000.0 * 1000.0 * cvt_m2len * cvt_m2len;
4087 
4088   // We could be measuring a very small or a very large object.
4089   // In the case of very small, convert it to square feet or
4090   // square meters.
4091 
4092   if (english_units)   // Square feet
4093   {
4094 //fprintf(stderr,"Square feet: %f\n", area);
4095 
4096     if (area < 2787840.0)   // Switch at 0.5 miles squared
4097     {
4098       // Smaller area: Output in feet squared
4099       xastir_snprintf(area_description,
4100                       sizeof_area_description,
4101                       "A:%0.2f %s %s",
4102                       area,
4103                       langcode("POPUPMA052"),     // sq
4104                       langcode("POPUPMA053") );   // ft
4105       //popup_message_always(langcode("POPUPMA020"),area_description);
4106     }
4107     else
4108     {
4109       // Larger area: Output in miles squared
4110       area = area / 27878400.0;
4111       xastir_snprintf(area_description,
4112                       sizeof_area_description,
4113                       "A:%0.2f %s %s",
4114                       area,
4115                       langcode("POPUPMA052"),     // sq
4116                       langcode("POPUPMA055") );   // mi
4117       //popup_message_always(langcode("POPUPMA020"),area_description);
4118     }
4119   }
4120   else    // Square meters
4121   {
4122 //fprintf(stderr,"Square meters: %f\n", area);
4123 
4124     if (area < 100000.0)   // Switch at 0.1 km squared
4125     {
4126       // Smaller area: Output in meters squared
4127       xastir_snprintf(area_description,
4128                       sizeof_area_description,
4129                       "A:%0.2f %s %s",
4130                       area,
4131                       langcode("POPUPMA052"),     // sq
4132                       langcode("POPUPMA054") );   // meters
4133       //popup_message_always(langcode("POPUPMA020"),area_description);
4134     }
4135     else
4136     {
4137       // Larger ara: Output in kilometers squared
4138       area = area / 1000000.0;
4139       xastir_snprintf(area_description,
4140                       sizeof_area_description,
4141                       "A:%0.2f %s %s",
4142                       area,
4143                       langcode("POPUPMA052"),     // sq
4144                       langcode("UNIOP00005") );   // km
4145       //popup_message_always(langcode("POPUPMA020"),area_description);
4146     }
4147   }
4148 }
4149 
4150 
4151 
4152 
4153 
4154 // Add an ending vertice that is the same as the starting vertice.
4155 // Best not to use the screen coordinates we captured first, as the
4156 // user may have zoomed or panned since then.  Better to copy the
4157 // first vertice that we recorded in our linked list.
4158 //
4159 // Compute the area of the closed polygon.  Write it out to STDERR,
4160 // the computed_area field in the Object, and to a dialog that pops
4161 // up on the screen.
4162 //
Draw_CAD_Objects_close_polygon(Widget UNUSED (widget),XtPointer UNUSED (clientData),XtPointer UNUSED (callData))4163 void Draw_CAD_Objects_close_polygon( Widget UNUSED(widget),
4164                                      XtPointer UNUSED(clientData),
4165                                      XtPointer UNUSED(callData) )
4166 {
4167   static int sizeof_area_description = 200;
4168   VerticeRow *tmp;
4169   double area;
4170   int n;
4171   //char temp_course[20];
4172   char area_description[sizeof_area_description];
4173   xastir_snprintf(area_description, sizeof_area_description, "Area");
4174 
4175   // Check whether we're currently working on a polygon.  If not,
4176   // get out of here.
4177   if (polygon_last_x == -1 || polygon_last_y == -1)
4178   {
4179 
4180     // Tell the code that we're starting a new polygon by wiping
4181     // out the first position.
4182     polygon_last_x = -1;    // Invalid position
4183     polygon_last_y = -1;    // Invalid position
4184 
4185     return;
4186   }
4187 
4188   // Find the last vertice in the linked list.  That will be the
4189   // first vertice we recorded for the object.
4190 
4191   // Check for at least three vertices.  We don't need to check
4192   // that the first/last point are equal:  We force it below by
4193   // copying the first vertice to the last.
4194   //
4195   n = 0;
4196   if (CAD_list_head != NULL)
4197   {
4198 
4199     // Walk the linked list.  Stop at the last record.
4200     tmp = CAD_list_head->start;
4201     if (tmp != NULL)
4202     {
4203       n++;
4204       while (tmp->next != NULL)
4205       {
4206         tmp = tmp->next;
4207         n++;
4208       }
4209       if (n > 2)
4210       {
4211         // We have more than a point or a line, therefore
4212         // can copy the first point to the last, closing the
4213         // polygon.
4214         CAD_vertice_allocate(tmp->latitude, tmp->longitude);
4215       }
4216     }
4217   }
4218   // Reload symbols/tracks/CAD objects and redraw the polygon
4219   redraw_symbols(da);
4220 
4221 #ifdef CAD_DEBUG
4222   fprintf(stderr,"Points in closed polygon: n = %d\n",n);
4223 #endif
4224 
4225   if (n < 3)
4226   {
4227     // Not enough points to compute an area.
4228 
4229     // Tell the code that we're starting a new polygon by wiping
4230     // out the first position.
4231     polygon_last_x = -1;    // Invalid position
4232     polygon_last_y = -1;    // Invalid position
4233 
4234     return;
4235   }
4236   area =  CAD_object_compute_area(CAD_list_head);
4237 
4238   // Save it in the object.  Convert nautical square miles to
4239   // square kilometers because that's what "Format_area_for_output"
4240   // requires.
4241   area = area * 3.429903999977917; // Now in km squared
4242 //fprintf(stderr,"SQUARE KM: %f\n", area);
4243   CAD_list_head->computed_area = area;
4244 
4245   Format_area_for_output(&area, area_description, sizeof_area_description);
4246 
4247 #ifdef CAD_DEBUG
4248   // Also write the area to stderr
4249   fprintf(stderr,"New CAD object %s\n",area_description);
4250 #endif
4251 
4252   // Tell the code that we're starting a new polygon by wiping out
4253   // the first position.
4254   polygon_last_x = -1;    // Invalid position
4255   polygon_last_y = -1;    // Invalid position
4256 
4257   CAD_object_set_label_at_centroid(CAD_list_head);
4258   // CAD object vertices are ready, needs associated data
4259   // obtain label, comment, and probability for this polygon
4260   // from user through a dialog.
4261   Set_CAD_object_parameters_dialog(area_description,NULL);
4262 }
4263 
4264 
4265 
4266 
4267 
4268 // Function called by UpdateTime when doing screen refresh.  Draws
4269 // all CAD objects onto the screen again.
4270 //
Draw_All_CAD_Objects(Widget w)4271 void Draw_All_CAD_Objects(Widget w)
4272 {
4273   CADRow *object_ptr = CAD_list_head;
4274   long x_long, y_lat;
4275   long x_offset, y_offset;
4276   float probability;
4277   char probability_string[8];
4278   VerticeRow *vertice;
4279   double area;
4280   int actual_line_type = LineOnOffDash;
4281   static int sizeof_area_description = 50; // define here as local static to limit size of display on map
4282   // independent of size as shown on form
4283   char area_description[sizeof_area_description];
4284   char dash[2];
4285 
4286   // Start at CAD_list_head, iterate through entire linked list,
4287   // drawing as we go.  Respect the line
4288   // width/line_color/line_type variables for each object.
4289 
4290 //fprintf(stderr,"Drawing CAD objects\n");
4291   if (CAD_draw_objects==TRUE)
4292   {
4293     while (object_ptr != NULL)
4294     {
4295       probability = CAD_object_get_raw_probability(object_ptr,1);
4296       xastir_snprintf(probability_string,
4297                       sizeof(probability_string),
4298                       "%01.1f%%",
4299                       probability);
4300 
4301       // find point at which to draw label and other descriptive text
4302       x_long = object_ptr->label_longitude;
4303       y_lat = object_ptr->label_latitude;
4304 #ifdef CAD_DEBUG
4305       fprintf(stderr,"Drawing object %s\n", (object_ptr->label) ? object_ptr->label : "NULL" );
4306 #endif
4307       //fprintf(stderr,"Lat: %d\n", y_lat);
4308       //fprintf(stderr,"Long: %d\n", x_long);
4309 //            if ((x_long+10>=0) && (x_long-10<=129600000l)) {      // 360 deg
4310 
4311 //                if ((y_lat+10>=0) && (y_lat-10<=64800000l)) {     // 180 deg
4312 
4313       if ((x_long>NW_corner_longitude) && (x_long<SE_corner_longitude))
4314       {
4315 
4316         if ((y_lat>NW_corner_latitude) && (y_lat<SE_corner_latitude))
4317         {
4318 
4319           // ok to draw label and assocated data, point is on screen
4320           x_offset=((x_long-NW_corner_longitude)/scale_x)-(10);
4321           y_offset=((y_lat -NW_corner_latitude) /scale_y)-(10);
4322           // ****** ?? use -10 or point ??
4323           x_offset=((x_long-NW_corner_longitude)/scale_x);
4324           y_offset=((y_lat -NW_corner_latitude) /scale_y);
4325 
4326           if (((int)strlen(object_ptr->label)>0) & (CAD_show_label==TRUE))
4327           {
4328             // Draw Label
4329             // 0x08 is background color
4330             // 0x40 is foreground color (yellow)
4331             draw_nice_string(w,pixmap_final,letter_style,x_offset,y_offset,object_ptr->label,0x08,0x40,strlen(object_ptr->label));
4332 
4333             x_offset=x_offset+12;
4334             y_offset=y_offset+15;
4335           }
4336 
4337           if (CAD_show_raw_probability==TRUE)
4338           {
4339             // draw probability
4340             draw_nice_string(w,pixmap_final,letter_style,x_offset,y_offset,probability_string,0x08,0x40,strlen(probability_string));
4341             y_offset=y_offset+15;
4342           }
4343 
4344           if ((CAD_show_comment==TRUE) & ((int)strlen(object_ptr->comment)>0))
4345           {
4346             // draw comment
4347             draw_nice_string(w,pixmap_final,letter_style,x_offset,y_offset,object_ptr->comment,0x08,0x40,strlen(object_ptr->comment));
4348             y_offset=y_offset+15;
4349           }
4350 
4351 
4352           if (CAD_show_area==TRUE)
4353           {
4354             area = object_ptr->computed_area;
4355             Format_area_for_output(&area, area_description, sizeof_area_description);
4356             draw_nice_string(w,pixmap_final,letter_style,x_offset,y_offset,area_description,0x08,0x40,strlen(area_description));
4357             y_offset=y_offset+15;
4358           }
4359 
4360         }
4361       }
4362 //                }
4363 //            }
4364 
4365       // Iterate through the vertices and draw the lines
4366       vertice = object_ptr->start;
4367 
4368       switch (object_ptr->line_type)
4369       {
4370 
4371         case 1:
4372           actual_line_type = LineSolid;
4373           break;
4374 
4375         case 2:
4376           actual_line_type = LineOnOffDash;
4377           dash[0] = dash[1]  = 8;
4378           break;
4379 
4380         case 3:
4381           actual_line_type = LineDoubleDash;
4382           dash[0] = dash[1]  = 16;
4383           break;
4384 
4385         default:
4386           actual_line_type = LineOnOffDash;
4387           dash[0] = dash[1]  = 8;
4388           break;
4389       }
4390 
4391       // Set up line color/width/type here
4392       (void)XSetLineAttributes (XtDisplay (da),
4393                                 gc_tint,
4394                                 object_ptr->line_width,
4395                                 actual_line_type,
4396                                 CapButt,
4397                                 JoinMiter);
4398 
4399       if (object_ptr->line_type  != 1)
4400       {
4401         (void)XSetDashes (XtDisplay (da),
4402                           gc_tint,
4403                           0,       // dash offset
4404                           dash,    // dash list[]
4405                           2);      // elements in dash lista
4406       }
4407 
4408       (void)XSetForeground (XtDisplay (da),
4409                             gc_tint,
4410                             object_ptr->line_color);
4411 
4412       (void)XSetFunction (XtDisplay (da),
4413                           gc_tint,
4414                           GXxor);
4415 
4416       while (vertice != NULL)
4417       {
4418         if (vertice->next != NULL)
4419         {
4420           // Use the draw_vector function from maps.c
4421           draw_vector(w,
4422                       vertice->longitude,
4423                       vertice->latitude,
4424                       vertice->next->longitude,
4425                       vertice->next->latitude,
4426                       gc_tint,
4427                       pixmap_final,
4428                       0);
4429         }
4430         vertice = vertice->next;
4431       }
4432       object_ptr = object_ptr->next;
4433     }
4434   }
4435 }
4436 
4437 
4438 
4439 /////////////////////////////////////////   Object Dialog   //////////////////////////////////////////
4440 
4441 
4442 
4443 /*
4444  *  Destroy Object Dialog Popup Window
4445  */
Object_destroy_shell(Widget widget,XtPointer clientData,XtPointer callData)4446 void Object_destroy_shell( Widget widget, XtPointer clientData, XtPointer callData)
4447 {
4448   Widget shell = (Widget) clientData;
4449   XtPopdown(shell);
4450   (void)XFreePixmap(XtDisplay(appshell),Ob_icon0);
4451   (void)XFreePixmap(XtDisplay(appshell),Ob_icon);
4452   XtDestroyWidget(shell);
4453   object_dialog = (Widget)NULL;
4454 
4455   // Take down the symbol selection dialog as well (if it's up)
4456   if (select_symbol_dialog)
4457   {
4458     Select_symbol_destroy_shell( widget, select_symbol_dialog, callData);
4459   }
4460 
4461   // NULL out the dialog field in the global struct used for
4462   // Coordinate Calculator.  Prevents segfaults if the calculator is
4463   // still up and trying to write to us.
4464   coordinate_calc_array.calling_dialog = NULL;
4465 }
4466 
4467 
4468 
4469 
4470 
4471 // Snag the latest DR'ed position for an object/item and create the
4472 // types of strings that we need for Setup_object_data() and
4473 // Setup_item_data() for APRS and Base-91 compressed formats.
4474 //
fetch_current_DR_strings(DataRow * p_station,char * lat_str,char * lon_str,char * ext_lat_str,char * ext_lon_str)4475 void fetch_current_DR_strings(DataRow *p_station, char *lat_str,
4476                               char *lon_str, char *ext_lat_str, char *ext_lon_str)
4477 {
4478 
4479   long x_long, y_lat;
4480 
4481 
4482   // Fetch the latest position for a DR'ed object.  Returns the
4483   // values in two longs, x_long and y_lat.
4484   compute_current_DR_position(p_station, &x_long, &y_lat);
4485 
4486   // Normal precision for APRS format
4487   convert_lat_l2s(y_lat,
4488                   lat_str,
4489                   MAX_LAT,
4490                   CONVERT_LP_NOSP);
4491 
4492   convert_lon_l2s(x_long,
4493                   lon_str,
4494                   MAX_LONG,
4495                   CONVERT_LP_NOSP);
4496 
4497   // Extended precision for Base-91 compressed format
4498   convert_lat_l2s(y_lat,
4499                   ext_lat_str,
4500                   MAX_LAT,
4501                   CONVERT_HP_NOSP);
4502 
4503   convert_lon_l2s(x_long,
4504                   ext_lon_str,
4505                   MAX_LONG,
4506                   CONVERT_HP_NOSP);
4507 }
4508 
4509 
4510 
4511 
4512 
4513 // Convert this eventually to populate a DataRow struct, then call
4514 // data.c:Create_object_item_tx_string().  Right now we have a lot
4515 // of code duplication between Setup_object_data, Setup_item_data,
4516 // and Create_object_item_tx_string.
4517 //
4518 // Make sure to look at the "transmit_compressed_objects_items" variable
4519 // to decide whether to send a compressed packet.
4520 /*
4521  *  Setup APRS Information Field for Objects
4522  */
Setup_object_data(char * line,int line_length,DataRow * p_station)4523 int Setup_object_data(char *line, int line_length, DataRow *p_station)
4524 {
4525   char lat_str[MAX_LAT];
4526   char lon_str[MAX_LONG];
4527   char ext_lat_str[20];   // Extended precision for base91 compression
4528   char ext_lon_str[20];   // Extended precision for base91 compression
4529   char comment[43+1];                 // max 43 characters of comment
4530   char time[7+1];
4531   struct tm *day_time;
4532   time_t sec;
4533   char complete_area_color[3];
4534   int complete_area_type;
4535   int lat_offset, lon_offset;
4536   char complete_corridor[6];
4537   char altitude[10];
4538   char speed_course[8];
4539   int speed;
4540   int course;
4541   int temp;
4542   long temp2;
4543   float temp3;
4544   char signpost[6];
4545   char prob_min[20+1];
4546   char prob_max[20+1];
4547   int bearing;
4548   char *temp_ptr;
4549   char *temp_ptr2;
4550   int DR = 0; // Dead-reckoning flag
4551   int comment_field_used = 0;   // Amount of comment field used up
4552 
4553 
4554   //fprintf(stderr,"Setup_object_data\n");
4555 
4556   // If speed for the original object was non-zero, then we need
4557   // to snag the updated DR'ed position for the object.  Snag the
4558   // current DR position and build the strings we need // for
4559   // position transmit.
4560   //
4561   if (p_station != NULL)
4562   {
4563 
4564     speed = atoi(p_station->speed);
4565 
4566     if (speed > 0 && !doing_move_operation)
4567     {
4568 
4569       fetch_current_DR_strings(p_station,
4570                                lat_str,
4571                                lon_str,
4572                                ext_lat_str,
4573                                ext_lon_str);
4574       DR++;   // Set the dead-reckoning flag
4575     }
4576 
4577     // Keep the time current for our own objects.
4578     p_station->sec_heard = sec_now();
4579     move_station_time(p_station,NULL);
4580   }
4581 
4582   temp_ptr = XmTextFieldGetString(object_name_data);
4583   xastir_snprintf(line,
4584                   line_length,
4585                   "%s",
4586                   temp_ptr);
4587   XtFree(temp_ptr);
4588 
4589   (void)remove_trailing_spaces(line);
4590   //(void)to_upper(line);      Not per spec.  Don't use this.
4591   if (!valid_object(line))
4592   {
4593     return(0);
4594   }
4595 
4596   // Copy object name into "last_object"
4597   xastir_snprintf(last_object,
4598                   sizeof(last_object),
4599                   "%s",
4600                   line);
4601 
4602 
4603   if (!DR)    // We're not doing dead-reckoning, so proceed
4604   {
4605 
4606     temp_ptr = XmTextFieldGetString(object_lat_data_ns);
4607     if((char)toupper((int)temp_ptr[0]) == 'S')
4608     {
4609       line[0] = 'S';
4610     }
4611     else
4612     {
4613       line[0] = 'N';
4614     }
4615     XtFree(temp_ptr);
4616 
4617     // Check latitude for out-of-bounds
4618     temp_ptr = XmTextFieldGetString(object_lat_data_deg);
4619     temp = atoi(temp_ptr);
4620     XtFree(temp_ptr);
4621 
4622     if ( (temp > 90) || (temp < 0) )
4623     {
4624       return(0);
4625     }
4626 
4627     temp_ptr = XmTextFieldGetString(object_lat_data_min);
4628     temp3 = atof(temp_ptr);
4629     XtFree(temp_ptr);
4630 
4631     if ( (temp3 >= 60.0) || (temp3 < 0.0) )
4632     {
4633       return(0);
4634     }
4635     if ( (temp == 90) && (temp3 != 0.0) )
4636     {
4637       return(0);
4638     }
4639 
4640     temp_ptr = XmTextFieldGetString(object_lat_data_deg);
4641     temp_ptr2 = XmTextFieldGetString(object_lat_data_min);
4642     xastir_snprintf(lat_str, sizeof(lat_str), "%02d%05.2f%c",
4643                     atoi(temp_ptr),
4644 // An attempt was made to round here, adding 0.001 to the minutes
4645 // value.  Problems arise if it goes above 59 minutes as the degrees
4646 // value would need to bump up also.  This then gets into problems
4647 // at 90.0 degrees.  The correct method would be to convert it to
4648 // decimal at a higher precision and then convert it back to DD
4649 // MM.MM format.
4650 //            atof(temp_ptr2) + 0.001,
4651                     atof(temp_ptr2),
4652                     line[0]);
4653     XtFree(temp_ptr);
4654     XtFree(temp_ptr2);
4655 
4656     temp_ptr = XmTextFieldGetString(object_lat_data_deg);
4657     temp_ptr2 = XmTextFieldGetString(object_lat_data_min);
4658     xastir_snprintf(ext_lat_str, sizeof(ext_lat_str), "%02d%05.3f%c",
4659                     atoi(temp_ptr),
4660 // An attempt was made to round here, adding 0.0001 to the minutes
4661 // value.  Problems arise if it goes above 59 minutes as the degrees
4662 // value would need to bump up also.  This then gets into problems
4663 // at 90.0 degrees.  The correct method would be to convert it to
4664 // decimal at a higher precision and then convert it back to DD
4665 // MM.MM format.
4666 //            atof(temp_ptr2) + 0.0001,
4667                     atof(temp_ptr2),
4668                     line[0]);
4669     XtFree(temp_ptr);
4670     XtFree(temp_ptr2);
4671 
4672     temp_ptr = XmTextFieldGetString(object_lon_data_ew);
4673     xastir_snprintf(line,
4674                     line_length,
4675                     "%s",
4676                     temp_ptr);
4677     XtFree(temp_ptr);
4678 
4679     if((char)toupper((int)line[0]) == 'E')
4680     {
4681       line[0] = 'E';
4682     }
4683     else
4684     {
4685       line[0] = 'W';
4686     }
4687 
4688     // Check longitude for out-of-bounds
4689     temp_ptr = XmTextFieldGetString(object_lon_data_deg);
4690     temp = atoi(temp_ptr);
4691     XtFree(temp_ptr);
4692 
4693     if ( (temp > 180) || (temp < 0) )
4694     {
4695       return(0);
4696     }
4697 
4698     temp_ptr = XmTextFieldGetString(object_lon_data_min);
4699     temp3 = atof(temp_ptr);
4700     XtFree(temp_ptr);
4701 
4702     if ( (temp3 >= 60.0) || (temp3 < 0.0) )
4703     {
4704       return(0);
4705     }
4706 
4707     if ( (temp == 180) && (temp3 != 0.0) )
4708     {
4709       return(0);
4710     }
4711 
4712     temp_ptr = XmTextFieldGetString(object_lon_data_deg);
4713     temp_ptr2 = XmTextFieldGetString(object_lon_data_min);
4714     xastir_snprintf(lon_str, sizeof(lon_str), "%03d%05.2f%c",
4715                     atoi(temp_ptr),
4716 // An attempt was made to round here, adding 0.001 to the minutes
4717 // value.  Problems arise if it goes above 59 minutes as the degrees
4718 // value would need to bump up also.  This then gets into problems
4719 // at 90.0 degrees.  The correct method would be to convert it to
4720 // decimal at a higher precision and then convert it back to DD
4721 // MM.MM format.
4722 //            atof(temp_ptr2) + 0.001,
4723                     atof(temp_ptr2),
4724                     line[0]);
4725     XtFree(temp_ptr);
4726     XtFree(temp_ptr2);
4727 
4728     temp_ptr = XmTextFieldGetString(object_lon_data_deg);
4729     temp_ptr2 = XmTextFieldGetString(object_lon_data_min);
4730     xastir_snprintf(ext_lon_str, sizeof(ext_lon_str), "%03d%05.3f%c",
4731                     atoi(temp_ptr),
4732 // An attempt was made to round here, adding 0.0001 to the minutes
4733 // value.  Problems arise if it goes above 59 minutes as the degrees
4734 // value would need to bump up also.  This then gets into problems
4735 // at 90.0 degrees.  The correct method would be to convert it to
4736 // decimal at a higher precision and then convert it back to DD
4737 // MM.MM format.
4738 //            atof(temp_ptr2) + 0.0001,
4739                     atof(temp_ptr2),
4740                     line[0]);
4741     XtFree(temp_ptr);
4742     XtFree(temp_ptr2);
4743   }
4744 
4745 
4746   temp_ptr = XmTextFieldGetString(object_group_data);
4747   xastir_snprintf(line,
4748                   line_length,
4749                   "%s",
4750                   temp_ptr);
4751   XtFree(temp_ptr);
4752 
4753   last_obj_grp = line[0];
4754   if(isalpha((int)last_obj_grp))
4755   {
4756     last_obj_grp = toupper((int)line[0]);  // todo: toupper in dialog
4757   }
4758 
4759   // Check for overlay character
4760   if (last_obj_grp != '/' && last_obj_grp != '\\')
4761   {
4762     // Found an overlay character.  Check that it's within the
4763     // proper range
4764     if ( (last_obj_grp >= '0' && last_obj_grp <= '9')
4765          || (last_obj_grp >= 'A' && last_obj_grp <= 'Z') )
4766     {
4767       last_obj_overlay = last_obj_grp;
4768       last_obj_grp = '\\';
4769     }
4770     else
4771     {
4772       last_obj_overlay = '\0';
4773     }
4774   }
4775   else
4776   {
4777     last_obj_overlay = '\0';
4778   }
4779 
4780   temp_ptr = XmTextFieldGetString(object_symbol_data);
4781   xastir_snprintf(line,
4782                   line_length,
4783                   "%s",
4784                   temp_ptr);
4785   XtFree(temp_ptr);
4786 
4787   last_obj_sym = line[0];
4788 
4789   temp_ptr = XmTextFieldGetString(object_comment_data);
4790   xastir_snprintf(comment,
4791                   sizeof(comment),
4792                   "%s",
4793                   temp_ptr);
4794   XtFree(temp_ptr);
4795 
4796   (void)remove_trailing_spaces(comment);
4797   //fprintf(stderr,"Comment Field was: %s\n",comment);
4798 
4799   sec = sec_now();
4800   day_time = gmtime(&sec);
4801   xastir_snprintf(time, sizeof(time), "%02d%02d%02dz", day_time->tm_mday, day_time->tm_hour,
4802                   day_time->tm_min);
4803 
4804   // Handle Generic Options
4805 
4806   // Speed/Course Fields
4807   temp_ptr = XmTextFieldGetString(ob_course_data);
4808   xastir_snprintf(line, line_length, "%s", temp_ptr);
4809   XtFree(temp_ptr);
4810 
4811   xastir_snprintf(speed_course, sizeof(speed_course), "%s", ".../");
4812   course = 0;
4813   if (strlen(line) != 0)      // Course was entered
4814   {
4815     // Need to check for 1 to three digits only, and 001-360 degrees)
4816     temp = atoi(line);
4817     if ( (temp >= 1) && (temp <= 360) )
4818     {
4819       xastir_snprintf(speed_course, sizeof(speed_course), "%03d/", temp);
4820       course = temp;
4821     }
4822     else if (temp == 0)       // Spec says 001 to 360 degrees...
4823     {
4824       xastir_snprintf(speed_course, sizeof(speed_course), "%s", "360/");
4825     }
4826   }
4827   temp_ptr = XmTextFieldGetString(ob_speed_data);
4828   xastir_snprintf(line, line_length, "%s", temp_ptr);
4829   XtFree(temp_ptr);
4830 
4831   speed = 0;
4832   if (strlen(line) != 0)   // Speed was entered (we only handle knots currently)
4833   {
4834     // Need to check for 1 to three digits, no alpha characters
4835     temp = atoi(line);
4836     if ( (temp >= 0) && (temp <= 999) )
4837     {
4838       xastir_snprintf(line, line_length, "%03d", temp);
4839       strncat(speed_course,
4840               line,
4841               sizeof(speed_course) - 1 - strlen(speed_course));
4842       speed = temp;
4843     }
4844     else
4845     {
4846       strncat(speed_course,
4847               "...",
4848               sizeof(speed_course) - 1 - strlen(speed_course));
4849     }
4850   }
4851   else    // No speed entered, blank it out
4852   {
4853     strncat(speed_course,
4854             "...",
4855             sizeof(speed_course) - 1 - strlen(speed_course));
4856   }
4857   if ( (speed_course[0] == '.') && (speed_course[4] == '.') )
4858   {
4859     speed_course[0] = '\0'; // No speed or course entered, so blank it
4860   }
4861   if (Area_object_enabled)
4862   {
4863     speed_course[0] = '\0'; // Course/Speed not allowed if Area Object
4864   }
4865 
4866   // Altitude Field
4867   temp_ptr = XmTextFieldGetString(ob_altitude_data);
4868   xastir_snprintf(line, line_length, "%s", temp_ptr);
4869   XtFree(temp_ptr);
4870 
4871   //fprintf(stderr,"Altitude entered: %s\n", line);
4872   altitude[0] = '\0'; // Start with empty string
4873   if (strlen(line) != 0)     // Altitude was entered (we only handle feet currently)
4874   {
4875     // Need to check for all digits, and 1 to 6 digits
4876     if (isdigit((int)line[0]))
4877     {
4878       temp2 = atoi(line);
4879       if ( (temp2 >= 0) && (temp2 <= 999999) )
4880       {
4881         char temp_alt[20];
4882         xastir_snprintf(temp_alt, sizeof(temp_alt), "/A=%06ld", temp2);
4883         memcpy(altitude, temp_alt, sizeof(altitude));
4884         altitude[sizeof(altitude)-1] = '\0';  // Terminate string
4885         //fprintf(stderr,"Altitude string: %s\n",altitude);
4886       }
4887     }
4888   }
4889 
4890   // Handle Specific Options
4891 
4892   // Area Objects
4893   if (Area_object_enabled)
4894   {
4895     //fprintf(stderr,"Area_bright: %d\n", Area_bright);
4896     //fprintf(stderr,"Area_filled: %d\n", Area_filled);
4897     if (Area_bright)    // Bright color
4898     {
4899       xastir_snprintf(complete_area_color, sizeof(complete_area_color), "%2s", Area_color);
4900     }
4901     else                  // Dim color
4902     {
4903       xastir_snprintf(complete_area_color, sizeof(complete_area_color), "%02.0f",
4904                       (float)(atoi(&Area_color[1]) + 8) );
4905 
4906       if ( (Area_color[1] == '0') || (Area_color[1] == '1') )
4907       {
4908         complete_area_color[0] = '/';
4909       }
4910     }
4911     if ( (Area_filled) && (Area_type != 1) && (Area_type != 6) )
4912     {
4913       complete_area_type = Area_type + 5;
4914     }
4915     else      // Can't fill in a line
4916     {
4917       complete_area_type = Area_type;
4918     }
4919     temp_ptr = XmTextFieldGetString(ob_lat_offset_data);
4920     xastir_snprintf(line, line_length, "%s", temp_ptr);
4921     XtFree(temp_ptr);
4922 
4923     lat_offset = sqrt(atof(line));
4924     if (lat_offset > 99)
4925     {
4926       lat_offset = 99;
4927     }
4928     //fprintf(stderr,"Line: %s\tlat_offset: %d\n", line, lat_offset);
4929 
4930     temp_ptr = XmTextFieldGetString(ob_lon_offset_data);
4931     xastir_snprintf(line, line_length, "%s", temp_ptr);
4932     XtFree(temp_ptr);
4933 
4934     lon_offset = sqrt(atof(line));
4935     if (lon_offset > 99)
4936     {
4937       lon_offset = 99;
4938     }
4939     //fprintf(stderr,"Line: %s\tlon_offset: %d\n", line, lon_offset);
4940 
4941     //fprintf(stderr,"Corridor Field: %s\n", XmTextFieldGetString(ob_corridor_data) );
4942     // Corridor
4943     complete_corridor[0] = '\0';
4944     if ( (Area_type == 1) || (Area_type == 6) )
4945     {
4946 
4947       temp_ptr = XmTextFieldGetString(ob_corridor_data);
4948       xastir_snprintf(line, line_length, "%s", temp_ptr);
4949       XtFree(temp_ptr);
4950 
4951       if (strlen(line) != 0)      // We have a line and some corridor data
4952       {
4953         // Need to check for 1 to three digits only
4954         temp = atoi(line);
4955         if ( (temp > 0) && (temp <= 999) )
4956         {
4957           xastir_snprintf(complete_corridor, sizeof(complete_corridor), "{%d}", temp);
4958           //fprintf(stderr,"%s\n",complete_corridor);
4959         }
4960       }
4961     }
4962 
4963     //fprintf(stderr,"Complete_corridor: %s\n", complete_corridor);
4964 
4965     if (transmit_compressed_objects_items)
4966     {
4967       char temp_overlay = last_obj_overlay;
4968 
4969 
4970 // Need to compute "csT" at some point and add it to the object.
4971 // Until we do that we'll have no course/speed/altitude.  Looks like
4972 // we can have course/speed or altitude, but not both.  Must have to
4973 // add the "/A=000123" stuff to the end if we want both.
4974 //
4975 // If we have course and/or speed, use course/speed csT bytes.  If
4976 // no course/speed but we have altitude, use altitude csT bytes.  We
4977 // can cheat right now and just always use course/speed, adding
4978 // altitude with the altitude extension.  Not as efficient, but it
4979 // gets the job done.
4980 //
4981 // Later we should change compress_posit() to accept an altitude
4982 // parameter, and have it decide which csT set of bytes to add, and
4983 // whether to add altitude as an uncompressed extension if
4984 // necessary.
4985 
4986 
4987       // Need to handle the conversion of numeric overlay
4988       // chars to "a-j" here.
4989       if (last_obj_overlay >= '0' && last_obj_overlay <= '9')
4990       {
4991         temp_overlay = last_obj_overlay + 'a';
4992       }
4993 
4994       xastir_snprintf(line, line_length, ";%-9s*%s%s%1d%02d%2s%02d%s%s%s",
4995                       last_object,
4996                       time,
4997                       compress_posit(ext_lat_str,
4998                                      (temp_overlay) ? temp_overlay : last_obj_grp,
4999                                      ext_lon_str,
5000                                      last_obj_sym,
5001                                      course,
5002                                      speed,  // In knots
5003                                      ""),    // PHG, must be blank in this case
5004                       complete_area_type, // In comment field
5005                       lat_offset,         // In comment field
5006                       complete_area_color,// In comment field
5007                       lon_offset,         // In comment field
5008                       speed_course,       // In comment field
5009                       complete_corridor,  // In comment field
5010                       altitude);          // In comment field
5011 
5012       comment_field_used = strlen(line) - 31;
5013 
5014     }
5015     else
5016     {
5017 
5018       xastir_snprintf(line, line_length, ";%-9s*%s%s%c%s%c%1d%02d%2s%02d%s%s%s",
5019                       last_object,
5020                       time,
5021                       lat_str,
5022                       last_obj_grp,
5023                       lon_str,
5024                       last_obj_sym,
5025                       complete_area_type, // In comment field
5026                       lat_offset,         // In comment field
5027                       complete_area_color,// In comment field
5028                       lon_offset,         // In comment field
5029                       speed_course,       // In comment field
5030                       complete_corridor,  // In comment field
5031                       altitude);          // In comment field
5032 
5033       comment_field_used = strlen(line) - 37;
5034     }
5035 
5036     //fprintf(stderr,"String is: %s\n", line);
5037 
5038   }
5039   else if (Signpost_object_enabled)
5040   {
5041     temp_ptr = XmTextFieldGetString(signpost_data);
5042     xastir_snprintf(line, line_length, "%s", temp_ptr);
5043     XtFree(temp_ptr);
5044 
5045     //fprintf(stderr,"Signpost entered: %s\n", line);
5046     if (strlen(line) != 0)     // Signpost data was entered
5047     {
5048       // Need to check for between one and three characters
5049       temp = strlen(line);
5050       if ( (temp >= 0) && (temp <= 3) )
5051       {
5052         xastir_snprintf(signpost, sizeof(signpost), "{%s}", line);
5053       }
5054       else
5055       {
5056         signpost[0] = '\0';
5057       }
5058     }
5059     else      // No signpost data entered, blank it out
5060     {
5061       signpost[0] = '\0';
5062     }
5063 
5064 
5065     if (transmit_compressed_objects_items)
5066     {
5067       char temp_overlay = last_obj_overlay;
5068 
5069 
5070 // Need to compute "csT" at some point and add it to the object.
5071 // Until we do that we'll have no course/speed/altitude.  Looks like
5072 // we can have course/speed or altitude, but not both.  Must have to
5073 // add the "/A=000123" stuff to the end if we want both.
5074 //
5075 // If we have course and/or speed, use course/speed csT bytes.  If
5076 // no course/speed but we have altitude, use altitude csT bytes.  We
5077 // can cheat right now and just always use course/speed, adding
5078 // altitude with the altitude extension.  Not as efficient, but it
5079 // gets the job done.
5080 //
5081 // Later we should change compress_posit() to accept an altitude
5082 // parameter, and have it decide which csT set of bytes to add, and
5083 // whether to add altitude as an uncompressed extension if
5084 // necessary.
5085 
5086 
5087       // Need to handle the conversion of numeric overlay
5088       // chars to "a-j" here.
5089       if (last_obj_overlay >= '0' && last_obj_overlay <= '9')
5090       {
5091         temp_overlay = last_obj_overlay + 'a';
5092       }
5093 
5094       xastir_snprintf(line, line_length, ";%-9s*%s%s%s%s",
5095                       last_object,
5096                       time,
5097                       compress_posit(ext_lat_str,
5098                                      (temp_overlay) ? temp_overlay : last_obj_grp,
5099                                      ext_lon_str,
5100                                      last_obj_sym,
5101                                      course,
5102                                      speed,  // In knots
5103                                      ""),    // PHG, must be blank in this case
5104                       altitude,
5105                       signpost);
5106 
5107       comment_field_used = strlen(line) - 31;
5108 
5109     }
5110     else
5111     {
5112 
5113       xastir_snprintf(line, line_length, ";%-9s*%s%s%c%s%c%s%s%s",
5114                       last_object,
5115                       time,
5116                       lat_str,
5117                       last_obj_grp,
5118                       lon_str,
5119                       last_obj_sym,
5120                       speed_course,
5121                       altitude,
5122                       signpost);
5123 
5124       comment_field_used = strlen(line) - 37;
5125     }
5126 
5127   }
5128   else if (DF_object_enabled)       // A DF'ing object of some type
5129   {
5130     if (Omni_antenna_enabled)
5131     {
5132 
5133       if (transmit_compressed_objects_items)
5134       {
5135         char temp_overlay = last_obj_overlay;
5136 
5137 
5138 // Need to compute "csT" at some point and add it to the object.
5139 // Until we do that we'll have no course/speed/altitude.  Looks like
5140 // we can have course/speed or altitude, but not both.  Must have to
5141 // add the "/A=000123" stuff to the end if we want both.
5142 //
5143 // If we have course and/or speed, use course/speed csT bytes.  If
5144 // no course/speed but we have altitude, use altitude csT bytes.  We
5145 // can cheat right now and just always use course/speed, adding
5146 // altitude with the altitude extension.  Not as efficient, but it
5147 // gets the job done.
5148 //
5149 // Later we should change compress_posit() to accept an altitude
5150 // parameter, and have it decide which csT set of bytes to add, and
5151 // whether to add altitude as an uncompressed extension if
5152 // necessary.
5153 
5154 
5155         // Need to handle the conversion of numeric overlay
5156         // chars to "a-j" here.
5157         if (last_obj_overlay >= '0' && last_obj_overlay <= '9')
5158         {
5159           temp_overlay = last_obj_overlay + 'a';
5160         }
5161 
5162         xastir_snprintf(line, line_length, ";%-9s*%s%sDFS%s/%s%s",
5163                         last_object,
5164                         time,
5165                         compress_posit(ext_lat_str,
5166                                        (temp_overlay) ? temp_overlay : last_obj_grp,
5167                                        ext_lon_str,
5168                                        last_obj_sym,
5169                                        course,
5170                                        speed,  // In knots
5171                                        ""),    // PHG, must be blank in this case
5172                         object_shgd,
5173                         speed_course,
5174                         altitude);
5175 
5176         comment_field_used = strlen(line) - 31;
5177 
5178       }
5179       else
5180       {
5181 
5182         xastir_snprintf(line, line_length, ";%-9s*%s%s%c%s%cDFS%s/%s%s",
5183                         last_object,
5184                         time,
5185                         lat_str,
5186                         last_obj_grp,
5187                         lon_str,
5188                         last_obj_sym,
5189                         object_shgd,
5190                         speed_course,
5191                         altitude);
5192 
5193         comment_field_used = strlen(line) - 37;
5194       }
5195 
5196     }
5197     else      // Beam Heading DFS object
5198     {
5199       if (strlen(speed_course) != 7)
5200         xastir_snprintf(speed_course,
5201                         sizeof(speed_course),
5202                         "000/000");
5203 
5204       temp_ptr = XmTextFieldGetString(ob_bearing_data);
5205       bearing = atoi(temp_ptr);
5206       XtFree(temp_ptr);
5207 
5208       if ( (bearing < 1) || (bearing > 360) )
5209       {
5210         bearing = 360;
5211       }
5212 
5213       if (transmit_compressed_objects_items)
5214       {
5215         char temp_overlay = last_obj_overlay;
5216 
5217 
5218 // Need to compute "csT" at some point and add it to the object.
5219 // Until we do that we'll have no course/speed/altitude.  Looks like
5220 // we can have course/speed or altitude, but not both.  Must have to
5221 // add the "/A=000123" stuff to the end if we want both.
5222 //
5223 // If we have course and/or speed, use course/speed csT bytes.  If
5224 // no course/speed but we have altitude, use altitude csT bytes.  We
5225 // can cheat right now and just always use course/speed, adding
5226 // altitude with the altitude extension.  Not as efficient, but it
5227 // gets the job done.
5228 //
5229 // Later we should change compress_posit() to accept an altitude
5230 // parameter, and have it decide which csT set of bytes to add, and
5231 // whether to add altitude as an uncompressed extension if
5232 // necessary.
5233 
5234 
5235         // Need to handle the conversion of numeric overlay
5236         // chars to "a-j" here.
5237         if (last_obj_overlay >= '0' && last_obj_overlay <= '9')
5238         {
5239           temp_overlay = last_obj_overlay + 'a';
5240         }
5241 
5242         xastir_snprintf(line, line_length, ";%-9s*%s%s/%03i/%s%s",
5243                         last_object,
5244                         time,
5245                         compress_posit(ext_lat_str,
5246                                        (temp_overlay) ? temp_overlay : last_obj_grp,
5247                                        ext_lon_str,
5248                                        last_obj_sym,
5249                                        course,
5250                                        speed,  // In knots
5251                                        ""),    // PHG, must be blank in this case
5252                         bearing,
5253                         object_NRQ,
5254                         altitude);
5255 
5256         comment_field_used = strlen(line) - 31;
5257 
5258       }
5259       else
5260       {
5261 
5262 
5263         xastir_snprintf(line, line_length, ";%-9s*%s%s%c%s%c%s/%03i/%s%s",
5264                         last_object,
5265                         time,
5266                         lat_str,
5267                         last_obj_grp,
5268                         lon_str,
5269                         last_obj_sym,
5270                         speed_course,
5271                         bearing,
5272                         object_NRQ,
5273                         altitude);
5274 
5275         comment_field_used = strlen(line) - 37;
5276       }
5277 
5278     }
5279   }
5280   else      // Else it's a normal object
5281   {
5282 
5283     prob_min[0] = '\0';
5284     prob_max[0] = '\0';
5285 
5286     if (Probability_circles_enabled)
5287     {
5288 
5289       temp_ptr = XmTextFieldGetString(probability_data_min);
5290       xastir_snprintf(line, line_length, "%s", temp_ptr);
5291       XtFree(temp_ptr);
5292 
5293       //fprintf(stderr,"Probability min circle entered: %s\n", line);
5294       if (strlen(line) != 0)     // Probability circle data was entered
5295       {
5296         xastir_snprintf(prob_min, sizeof(prob_min), "Pmin%s,", line);
5297       }
5298 
5299       temp_ptr = XmTextFieldGetString(probability_data_max);
5300       xastir_snprintf(line, line_length, "%s", temp_ptr);
5301       XtFree(temp_ptr);
5302 
5303       //fprintf(stderr,"Probability max circle entered: %s\n", line);
5304       if (strlen(line) != 0)     // Probability circle data was entered
5305       {
5306         xastir_snprintf(prob_max, sizeof(prob_max), "Pmax%s,", line);
5307       }
5308     }
5309 
5310     if (transmit_compressed_objects_items)
5311     {
5312       char temp_overlay = last_obj_overlay;
5313 
5314 
5315 // Need to compute "csT" at some point and add it to the object.
5316 // Until we do that we'll have no course/speed/altitude.  Looks like
5317 // we can have course/speed or altitude, but not both.  Must have to
5318 // add the "/A=000123" stuff to the end if we want both.
5319 //
5320 // If we have course and/or speed, use course/speed csT bytes.  If
5321 // no course/speed but we have altitude, use altitude csT bytes.  We
5322 // can cheat right now and just always use course/speed, adding
5323 // altitude with the altitude extension.  Not as efficient, but it
5324 // gets the job done.
5325 //
5326 // Later we should change compress_posit() to accept an altitude
5327 // parameter, and have it decide which csT set of bytes to add, and
5328 // whether to add altitude as an uncompressed extension if
5329 // necessary.
5330 
5331 
5332       // Need to handle the conversion of numeric overlay
5333       // chars to "a-j" here.
5334       if (last_obj_overlay >= '0' && last_obj_overlay <= '9')
5335       {
5336         temp_overlay = last_obj_overlay + 'a';
5337       }
5338 
5339       xastir_snprintf(line,
5340                       line_length,
5341                       ";%-9s*%s%s%s%s%s",
5342                       last_object,
5343                       time,
5344                       compress_posit(ext_lat_str,
5345                                      (temp_overlay) ? temp_overlay : last_obj_grp,
5346                                      ext_lon_str,
5347                                      last_obj_sym,
5348                                      course,
5349                                      speed,  // In knots
5350                                      ""),    // PHG, must be blank in this case
5351                       altitude,
5352                       prob_min,
5353                       prob_max);
5354 
5355       comment_field_used = strlen(line) - 31;
5356 
5357     }
5358     else
5359     {
5360       xastir_snprintf(line,
5361                       line_length,
5362                       ";%-9s*%s%s%c%s%c%s%s%s%s",
5363                       last_object,
5364                       time,
5365                       lat_str,
5366                       last_obj_overlay ? last_obj_overlay : last_obj_grp,
5367                       lon_str,
5368                       last_obj_sym,
5369                       speed_course,
5370                       altitude,
5371                       prob_min,
5372                       prob_max);
5373 
5374       comment_field_used = strlen(line) - 37;
5375 
5376     }
5377   }
5378 
5379 
5380   // We need to tack the comment on the end, but need to make
5381   // sure we don't go over the maximum length for an object.  The
5382   // maximum comment field is 43 chars.  "comment_field_used"
5383   // tells us how many chars of that field we've used up already
5384   // with other parameters before adding the comment chars to the
5385   // end.
5386   //
5387   //fprintf(stderr,"Comment: %s\n",comment);
5388   if (strlen(comment) != 0)
5389   {
5390 
5391     if (comment[0] == '}')
5392     {
5393       // May be a multipoint polygon string at the start of
5394       // the comment field.  Add a space before this special
5395       // character as multipoints have to start with " }" to
5396       // be valid.
5397       line[strlen(line) + 1] = '\0';
5398       line[strlen(line)] = ' ';
5399 
5400       comment_field_used++;
5401     }
5402 
5403     temp = 0;
5404 //        while ( (strlen(line) < 80) && (temp < (int)strlen(comment)) ) {
5405     while ((comment_field_used < 43) && (temp < (int)strlen(comment)) )
5406     {
5407       //fprintf(stderr,"temp: %d->%d\t%c\n", temp, strlen(line), comment[temp]);
5408       line[strlen(line) + 1] = '\0';
5409       line[strlen(line)] = comment[temp++];
5410       comment_field_used++;
5411     }
5412   }
5413   //fprintf(stderr,"line: %s\n",line);
5414 
5415 // NOTE:  Compressed mode will be shorter still.  Account
5416 // for that when compressed mode is implemented for objects.
5417 
5418   return(1);
5419 }
5420 
5421 
5422 
5423 
5424 
5425 // Convert this eventually to populate a DataRow struct, then call
5426 // data.c:Create_object_item_tx_string().  Right now we have a lot
5427 // of code duplication between Setup_object_data, Setup_item_data,
5428 // and Create_object_item_tx_string.
5429 //
5430 // Make sure to look at the "transmit_compressed_objects_items" variable
5431 // to decide whether to send a compressed packet.
5432 /*
5433  *  Setup APRS Information Field for Items
5434  */
Setup_item_data(char * line,int line_length,DataRow * p_station)5435 int Setup_item_data(char *line, int line_length, DataRow *p_station)
5436 {
5437   char lat_str[MAX_LAT];
5438   char lon_str[MAX_LONG];
5439   char ext_lat_str[20];   // Extended precision for base91 compression
5440   char ext_lon_str[20];   // Extended precision for base91 compression
5441   char comment[43+1];                 // max 43 characters of comment
5442   char complete_area_color[3];
5443   int complete_area_type;
5444   int lat_offset, lon_offset;
5445   char complete_corridor[6];
5446   char altitude[10];
5447   char speed_course[8];
5448   int speed;
5449   int course;
5450   int temp;
5451   long temp2;
5452   float temp3;
5453   char tempstr[MAX_CALLSIGN+1];
5454   char signpost[6];
5455   char prob_min[20+1];
5456   char prob_max[20+1];
5457   int bearing;
5458   char *temp_ptr;
5459   char *temp_ptr2;
5460   int DR = 0; // Dead-reckoning flag
5461   int comment_field_used = 0;   // Amount of comment field used up
5462 
5463 
5464   // If speed for the original object was non-zero, then we need
5465   // to snag the updated DR'ed position for the object.  Snag the
5466   // current DR position and build the strings we need // for
5467   // position transmit.
5468   //
5469   if (p_station != NULL)
5470   {
5471 
5472     speed = atoi(p_station->speed);
5473 
5474     if (speed > 0 && !doing_move_operation)
5475     {
5476 
5477       fetch_current_DR_strings(p_station,
5478                                lat_str,
5479                                lon_str,
5480                                ext_lat_str,
5481                                ext_lon_str);
5482       DR++;   // Set the dead-reckoning flag
5483     }
5484 
5485     // Keep the time current for our own items.
5486     p_station->sec_heard = sec_now();
5487     move_station_time(p_station,NULL);
5488   }
5489 
5490   temp_ptr = XmTextFieldGetString(object_name_data);
5491   xastir_snprintf(line, line_length, "%s", temp_ptr);
5492   XtFree(temp_ptr);
5493 
5494   (void)remove_trailing_spaces(line);
5495   //(void)to_upper(line);     Not per spec.  Don't use this.
5496 
5497   xastir_snprintf(tempstr,
5498                   sizeof(tempstr),
5499                   "%s",
5500                   line);
5501 
5502   if (strlen(line) == 1)  // Add two spaces (to make 3 minimum chars)
5503   {
5504     xastir_snprintf(line, line_length, "%s  ", tempstr);
5505   }
5506 
5507   else if (strlen(line) == 2) // Add one space (to make 3 minimum chars)
5508   {
5509     xastir_snprintf(line, line_length, "%s ", tempstr);
5510   }
5511 
5512   if (!valid_item(line))
5513   {
5514     return(0);
5515   }
5516 
5517   xastir_snprintf(last_object,
5518                   sizeof(last_object),
5519                   "%s",
5520                   line);
5521 
5522 
5523   if (!DR)    // We're not doing dead-reckoning, so proceed
5524   {
5525 
5526     temp_ptr = XmTextFieldGetString(object_lat_data_ns);
5527     if((char)toupper((int)temp_ptr[0]) == 'S')
5528     {
5529       line[0] = 'S';
5530     }
5531     else
5532     {
5533       line[0] = 'N';
5534     }
5535     XtFree(temp_ptr);
5536 
5537     // Check latitude for out-of-bounds
5538     temp_ptr = XmTextFieldGetString(object_lat_data_deg);
5539     temp = atoi(temp_ptr);
5540     XtFree(temp_ptr);
5541 
5542     if ( (temp > 90) || (temp < 0) )
5543     {
5544       return(0);
5545     }
5546 
5547     temp_ptr = XmTextFieldGetString(object_lat_data_min);
5548     temp3 = atof(temp_ptr);
5549     XtFree(temp_ptr);
5550 
5551     if ( (temp3 >= 60.0) || (temp3 < 0.0) )
5552     {
5553       return(0);
5554     }
5555 
5556     if ( (temp == 90) && (temp3 != 0.0) )
5557     {
5558       return(0);
5559     }
5560 
5561     temp_ptr = XmTextFieldGetString(object_lat_data_deg);
5562     temp_ptr2 = XmTextFieldGetString(object_lat_data_min);
5563     xastir_snprintf(lat_str, sizeof(lat_str), "%02d%05.2f%c",
5564                     atoi(temp_ptr),
5565 // An attempt was made to round here, adding 0.001 to the minutes
5566 // value.  Problems arise if it goes above 59 minutes as the degrees
5567 // value would need to bump up also.  This then gets into problems
5568 // at 90.0 degrees.  The correct method would be to convert it to
5569 // decimal at a higher precision and then convert it back to DD
5570 // MM.MM format.
5571 //                atof(temp_ptr2) + 0.001,
5572                     atof(temp_ptr2),
5573                     line[0]);
5574     XtFree(temp_ptr);
5575     XtFree(temp_ptr2);
5576 
5577     temp_ptr = XmTextFieldGetString(object_lat_data_deg);
5578     temp_ptr2 = XmTextFieldGetString(object_lat_data_min);
5579     xastir_snprintf(ext_lat_str, sizeof(ext_lat_str), "%02d%05.3f%c",
5580                     atoi(temp_ptr),
5581 // An attempt was made to round here, adding 0.0001 to the minutes
5582 // value.  Problems arise if it goes above 59 minutes as the degrees
5583 // value would need to bump up also.  This then gets into problems
5584 // at 90.0 degrees.  The correct method would be to convert it to
5585 // decimal at a higher precision and then convert it back to DD
5586 // MM.MM format.
5587 //                atof(temp_ptr2) + 0.0001,
5588                     atof(temp_ptr2),
5589                     line[0]);
5590     XtFree(temp_ptr);
5591     XtFree(temp_ptr2);
5592 
5593     temp_ptr = XmTextFieldGetString(object_lon_data_ew);
5594     if((char)toupper((int)temp_ptr[0]) == 'E')
5595     {
5596       line[0] = 'E';
5597     }
5598     else
5599     {
5600       line[0] = 'W';
5601     }
5602     XtFree(temp_ptr);
5603 
5604     // Check longitude for out-of-bounds
5605     temp_ptr = XmTextFieldGetString(object_lon_data_deg);
5606     temp = atoi(temp_ptr);
5607     XtFree(temp_ptr);
5608 
5609     if ( (temp > 180) || (temp < 0) )
5610     {
5611       return(0);
5612     }
5613 
5614     temp_ptr = XmTextFieldGetString(object_lon_data_min);
5615     temp3 = atof(temp_ptr);
5616     XtFree(temp_ptr);
5617 
5618     if ( (temp3 >= 60.0) || (temp3 < 0.0) )
5619     {
5620       return(0);
5621     }
5622 
5623     if ( (temp == 180) && (temp3 != 0.0) )
5624     {
5625       return(0);
5626     }
5627 
5628     temp_ptr = XmTextFieldGetString(object_lon_data_deg);
5629     temp_ptr2 = XmTextFieldGetString(object_lon_data_min);
5630     xastir_snprintf(lon_str, sizeof(lon_str), "%03d%05.2f%c",
5631                     atoi(temp_ptr),
5632 // An attempt was made to round here, adding 0.001 to the minutes
5633 // value.  Problems arise if it goes above 59 minutes as the degrees
5634 // value would need to bump up also.  This then gets into problems
5635 // at 90.0 degrees.  The correct method would be to convert it to
5636 // decimal at a higher precision and then convert it back to DD
5637 // MM.MM format.
5638 //                atof(temp_ptr2) + 0.001,
5639                     atof(temp_ptr2),
5640                     line[0]);
5641     XtFree(temp_ptr);
5642     XtFree(temp_ptr2);
5643 
5644     temp_ptr = XmTextFieldGetString(object_lon_data_deg);
5645     temp_ptr2 = XmTextFieldGetString(object_lon_data_min);
5646     xastir_snprintf(ext_lon_str, sizeof(ext_lon_str), "%03d%05.3f%c",
5647                     atoi(temp_ptr),
5648 // An attempt was made to round here, adding 0.0001 to the minutes
5649 // value.  Problems arise if it goes above 59 minutes as the degrees
5650 // value would need to bump up also.  This then gets into problems
5651 // at 90.0 degrees.  The correct method would be to convert it to
5652 // decimal at a higher precision and then convert it back to DD
5653 // MM.MM format.
5654 //                atof(temp_ptr2) + 0.0001,
5655                     atof(temp_ptr2),
5656                     line[0]);
5657     XtFree(temp_ptr);
5658     XtFree(temp_ptr2);
5659   }
5660 
5661 
5662   temp_ptr = XmTextFieldGetString(object_group_data);
5663   last_obj_grp = temp_ptr[0];
5664   if(isalpha((int)last_obj_grp))
5665   {
5666     last_obj_grp = toupper((int)temp_ptr[0]);  // todo: toupper in dialog
5667   }
5668   XtFree(temp_ptr);
5669 
5670   // Check for overlay character
5671   if (last_obj_grp != '/' && last_obj_grp != '\\')
5672   {
5673     // Found an overlay character.  Check that it's within the
5674     // proper range
5675     if ( (last_obj_grp >= '0' && last_obj_grp <= '9')
5676          || (last_obj_grp >= 'A' && last_obj_grp <= 'Z') )
5677     {
5678       last_obj_overlay = last_obj_grp;
5679       last_obj_grp = '\\';
5680     }
5681     else
5682     {
5683       last_obj_overlay = '\0';
5684     }
5685   }
5686   else
5687   {
5688     last_obj_overlay = '\0';
5689   }
5690 
5691   temp_ptr = XmTextFieldGetString(object_symbol_data);
5692   last_obj_sym = temp_ptr[0];
5693   XtFree(temp_ptr);
5694 
5695   temp_ptr = XmTextFieldGetString(object_comment_data);
5696   xastir_snprintf(comment,
5697                   sizeof(comment),
5698                   "%s",
5699                   temp_ptr);
5700   XtFree(temp_ptr);
5701 
5702   (void)remove_trailing_spaces(comment);
5703 
5704   // Handle Generic Options
5705 
5706   // Speed/Course Fields
5707   temp_ptr = XmTextFieldGetString(ob_course_data);
5708   xastir_snprintf(line, line_length, "%s", temp_ptr);
5709   XtFree(temp_ptr);
5710 
5711   sprintf(speed_course,".../");   // Start with invalid-data string
5712   course = 0;
5713   if (strlen(line) != 0)      // Course was entered
5714   {
5715     // Need to check for 1 to three digits only, and 001-360 degrees)
5716     temp = atoi(line);
5717     if ( (temp >= 1) && (temp <= 360) )
5718     {
5719       xastir_snprintf(speed_course, sizeof(speed_course), "%03d/", temp);
5720       course = temp;
5721     }
5722     else if (temp == 0)       // Spec says 001 to 360 degrees...
5723     {
5724       sprintf(speed_course, "360/");
5725     }
5726   }
5727   temp_ptr = XmTextFieldGetString(ob_speed_data);
5728   xastir_snprintf(line, line_length, "%s", temp_ptr);
5729   XtFree(temp_ptr);
5730 
5731   speed = 0;
5732   if (strlen(line) != 0)   // Speed was entered (we only handle knots currently)
5733   {
5734     // Need to check for 1 to three digits, no alpha characters
5735     temp = atoi(line);
5736     if ( (temp >= 0) && (temp <= 999) )
5737     {
5738       xastir_snprintf(line, line_length, "%03d", temp);
5739       strncat(speed_course,
5740               line,
5741               sizeof(speed_course) - 1 - strlen(speed_course));
5742       speed = temp;
5743     }
5744     else
5745     {
5746       strncat(speed_course,
5747               "...",
5748               sizeof(speed_course) - 1 - strlen(speed_course));
5749     }
5750   }
5751   else      // No speed entered, blank it out
5752   {
5753     strncat(speed_course,
5754             "...",
5755             sizeof(speed_course) - 1 - strlen(speed_course));
5756   }
5757   if ( (speed_course[0] == '.') && (speed_course[4] == '.') )
5758   {
5759     speed_course[0] = '\0'; // No speed or course entered, so blank it
5760   }
5761 
5762   if (Area_object_enabled)
5763   {
5764     speed_course[0] = '\0'; // Course/Speed not allowed if Area Object
5765   }
5766 
5767   // Altitude Field
5768   temp_ptr = XmTextFieldGetString(ob_altitude_data);
5769   xastir_snprintf(line, line_length, "%s", temp_ptr);
5770   XtFree(temp_ptr);
5771 
5772   //fprintf(stderr,"Altitude entered: %s\n", line);
5773   altitude[0] = '\0'; // Start with empty string
5774   if (strlen(line) != 0)     // Altitude was entered (we only handle feet currently)
5775   {
5776     // Need to check for all digits, and 1 to 6 digits
5777     if (isdigit((int)line[0]))
5778     {
5779       temp2 = atoi(line);
5780       if ((temp2 >= 0) && (temp2 <= 999999))
5781       {
5782         char temp_alt[20];
5783         xastir_snprintf(temp_alt, sizeof(temp_alt), "/A=%06ld",temp2);
5784         memcpy(altitude, temp_alt, sizeof(altitude));
5785         altitude[sizeof(altitude)-1] = '\0';  // Terminate string
5786       }
5787     }
5788   }
5789 
5790   // Handle Specific Options
5791 
5792   // Area Items
5793   if (Area_object_enabled)
5794   {
5795     if (Area_bright)    // Bright color
5796     {
5797       xastir_snprintf(complete_area_color, sizeof(complete_area_color), "%2s",
5798                       Area_color);
5799     }
5800     else                  // Dim color
5801     {
5802       xastir_snprintf(complete_area_color, sizeof(complete_area_color), "%02.0f",
5803                       (float)(atoi(&Area_color[1]) + 8) );
5804       if ((Area_color[1] == '0') || (Area_color[1] == '1'))
5805       {
5806         complete_area_color[0] = '/';
5807       }
5808     }
5809     if ( (Area_filled) && (Area_type != 1) && (Area_type != 6) )
5810     {
5811       complete_area_type = Area_type + 5;
5812     }
5813     else      // Can't fill in a line
5814     {
5815       complete_area_type = Area_type;
5816     }
5817     temp_ptr = XmTextFieldGetString(ob_lat_offset_data);
5818     xastir_snprintf(line, line_length, "%s", temp_ptr);
5819     XtFree(temp_ptr);
5820 
5821     lat_offset = sqrt(atof(line));
5822     if (lat_offset > 99)
5823     {
5824       lat_offset = 99;
5825     }
5826     //fprintf(stderr,"Line: %s\tlat_offset: %d\n", line, lat_offset);
5827     temp_ptr = XmTextFieldGetString(ob_lon_offset_data);
5828     xastir_snprintf(line, line_length, "%s", temp_ptr);
5829     XtFree(temp_ptr);
5830 
5831     lon_offset = sqrt(atof(line));
5832     if (lon_offset > 99)
5833     {
5834       lon_offset = 99;
5835     }
5836     //fprintf(stderr,"Line: %s\tlon_offset: %d\n", line, lon_offset);
5837 
5838     // Corridor
5839     complete_corridor[0] = '\0';
5840     if ( (Area_type == 1) || (Area_type == 6) )
5841     {
5842 
5843       temp_ptr = XmTextFieldGetString(ob_corridor_data);
5844       xastir_snprintf(line, line_length, "%s", temp_ptr);
5845       XtFree(temp_ptr);
5846 
5847       if (strlen(line) != 0)      // We have a line and some corridor data
5848       {
5849         // Need to check for 1 to three digits only
5850         temp = atoi(line);
5851         if ( (temp > 0) && (temp <= 999) )
5852         {
5853           xastir_snprintf(complete_corridor, sizeof(complete_corridor), "{%d}", temp);
5854           //fprintf(stderr,"%s\n",complete_corridor);
5855         }
5856       }
5857     }
5858 
5859     if (transmit_compressed_objects_items)
5860     {
5861       char temp_overlay = last_obj_overlay;
5862 
5863 
5864 // Need to compute "csT" at some point and add it to the object.
5865 // Until we do that we'll have no course/speed/altitude.  Looks like
5866 // we can have course/speed or altitude, but not both.  Must have to
5867 // add the "/A=000123" stuff to the end if we want both.
5868 //
5869 // If we have course and/or speed, use course/speed csT bytes.  If
5870 // no course/speed but we have altitude, use altitude csT bytes.  We
5871 // can cheat right now and just always use course/speed, adding
5872 // altitude with the altitude extension.  Not as efficient, but it
5873 // gets the job done.
5874 //
5875 // Later we should change compress_posit() to accept an altitude
5876 // parameter, and have it decide which csT set of bytes to add, and
5877 // whether to add altitude as an uncompressed extension if
5878 // necessary.
5879 
5880 
5881       // Need to handle the conversion of numeric overlay
5882       // chars to "a-j" here.
5883       if (last_obj_overlay >= '0' && last_obj_overlay <= '9')
5884       {
5885         temp_overlay = last_obj_overlay + 'a';
5886       }
5887 
5888       xastir_snprintf(line, line_length, ")%s!%s%1d%02d%2s%02d%s%s%s",
5889                       last_object,
5890                       compress_posit(ext_lat_str,
5891                                      (temp_overlay) ? temp_overlay : last_obj_grp,
5892                                      ext_lon_str,
5893                                      last_obj_sym,
5894                                      course,
5895                                      speed,  // In knots
5896                                      ""),    // PHG, must be blank in this case
5897                       complete_area_type,
5898                       lat_offset,
5899                       complete_area_color,
5900                       lon_offset,
5901                       speed_course,
5902                       complete_corridor,
5903                       altitude);
5904 
5905       comment_field_used = strlen(line) - 15 - strlen(last_object);
5906 
5907     }
5908     else
5909     {
5910 
5911       xastir_snprintf(line, line_length, ")%s!%s%c%s%c%1d%02d%2s%02d%s%s%s",
5912                       last_object,
5913                       lat_str,
5914                       last_obj_grp,
5915                       lon_str,
5916                       last_obj_sym,
5917                       complete_area_type,
5918                       lat_offset,
5919                       complete_area_color,
5920                       lon_offset,
5921                       speed_course,
5922                       complete_corridor,
5923                       altitude);
5924 
5925       comment_field_used = strlen(line) - 21 - strlen(last_object);
5926     }
5927 
5928   }
5929   else if (Signpost_object_enabled)
5930   {
5931     temp_ptr = XmTextFieldGetString(signpost_data);
5932     xastir_snprintf(line, line_length, "%s", temp_ptr);
5933     XtFree(temp_ptr);
5934 
5935     //fprintf(stderr,"Signpost entered: %s\n", line);
5936     if (strlen(line) != 0)     // Signpost data was entered
5937     {
5938       // Need to check for between one and three characters
5939       temp = strlen(line);
5940       if ( (temp >= 0) && (temp <= 3) )
5941       {
5942         xastir_snprintf(signpost, sizeof(signpost), "{%s}", line);
5943       }
5944       else
5945       {
5946         signpost[0] = '\0';
5947       }
5948     }
5949     else      // No signpost data entered, blank it out
5950     {
5951       signpost[0] = '\0';
5952     }
5953 
5954     if (transmit_compressed_objects_items)
5955     {
5956       char temp_overlay = last_obj_overlay;
5957 
5958 
5959 // Need to compute "csT" at some point and add it to the object.
5960 // Until we do that we'll have no course/speed/altitude.  Looks like
5961 // we can have course/speed or altitude, but not both.  Must have to
5962 // add the "/A=000123" stuff to the end if we want both.
5963 //
5964 // If we have course and/or speed, use course/speed csT bytes.  If
5965 // no course/speed but we have altitude, use altitude csT bytes.  We
5966 // can cheat right now and just always use course/speed, adding
5967 // altitude with the altitude extension.  Not as efficient, but it
5968 // gets the job done.
5969 //
5970 // Later we should change compress_posit() to accept an altitude
5971 // parameter, and have it decide which csT set of bytes to add, and
5972 // whether to add altitude as an uncompressed extension if
5973 // necessary.
5974 
5975 
5976       // Need to handle the conversion of numeric overlay
5977       // chars to "a-j" here.
5978       if (last_obj_overlay >= '0' && last_obj_overlay <= '9')
5979       {
5980         temp_overlay = last_obj_overlay + 'a';
5981       }
5982 
5983       xastir_snprintf(line, line_length, ")%s!%s%s%s",
5984                       last_object,
5985                       compress_posit(ext_lat_str,
5986                                      (temp_overlay) ? temp_overlay : last_obj_grp,
5987                                      ext_lon_str,
5988                                      last_obj_sym,
5989                                      course,
5990                                      speed,  // In knots
5991                                      ""),    // PHG, must be blank in this case
5992                       altitude,
5993                       signpost);
5994 
5995       comment_field_used = strlen(line) - 15 - strlen(last_object);
5996 
5997     }
5998     else
5999     {
6000 
6001       xastir_snprintf(line, line_length, ")%s!%s%c%s%c%s%s%s",
6002                       last_object,
6003                       lat_str,
6004                       last_obj_grp,
6005                       lon_str,
6006                       last_obj_sym,
6007                       speed_course,
6008                       altitude,
6009                       signpost);
6010 
6011       comment_field_used = strlen(line) - 21 - strlen(last_object);
6012     }
6013 
6014   }
6015   else if (DF_object_enabled)       // A DF'ing item of some type
6016   {
6017     if (Omni_antenna_enabled)
6018     {
6019 
6020       if (transmit_compressed_objects_items)
6021       {
6022         char temp_overlay = last_obj_overlay;
6023 
6024 
6025 // Need to compute "csT" at some point and add it to the object.
6026 // Until we do that we'll have no course/speed/altitude.  Looks like
6027 // we can have course/speed or altitude, but not both.  Must have to
6028 // add the "/A=000123" stuff to the end if we want both.
6029 //
6030 // If we have course and/or speed, use course/speed csT bytes.  If
6031 // no course/speed but we have altitude, use altitude csT bytes.  We
6032 // can cheat right now and just always use course/speed, adding
6033 // altitude with the altitude extension.  Not as efficient, but it
6034 // gets the job done.
6035 //
6036 // Later we should change compress_posit() to accept an altitude
6037 // parameter, and have it decide which csT set of bytes to add, and
6038 // whether to add altitude as an uncompressed extension if
6039 // necessary.
6040 
6041 
6042         // Need to handle the conversion of numeric overlay
6043         // chars to "a-j" here.
6044         if (last_obj_overlay >= '0' && last_obj_overlay <= '9')
6045         {
6046           temp_overlay = last_obj_overlay + 'a';
6047         }
6048 
6049         xastir_snprintf(line, line_length, ")%s!%sDFS%s/%s%s",
6050                         last_object,
6051                         compress_posit(ext_lat_str,
6052                                        (temp_overlay) ? temp_overlay : last_obj_grp,
6053                                        ext_lon_str,
6054                                        last_obj_sym,
6055                                        course,
6056                                        speed,  // In knots
6057                                        ""),    // PHG, must be blank in this case
6058                         object_shgd,
6059                         speed_course,
6060                         altitude);
6061 
6062         comment_field_used = strlen(line) - 15 - strlen(last_object);
6063 
6064       }
6065       else
6066       {
6067 
6068         xastir_snprintf(line, line_length, ")%s!%s%c%s%cDFS%s/%s%s",
6069                         last_object,
6070                         lat_str,
6071                         last_obj_grp,
6072                         lon_str,
6073                         last_obj_sym,
6074                         object_shgd,
6075                         speed_course,
6076                         altitude);
6077 
6078         comment_field_used = strlen(line) - 21 - strlen(last_object);
6079 
6080       }
6081 
6082     }
6083     else      // Beam Heading DFS item
6084     {
6085       if (strlen(speed_course) != 7)
6086         xastir_snprintf(speed_course,
6087                         sizeof(speed_course),
6088                         "000/000");
6089 
6090       temp_ptr = XmTextFieldGetString(ob_bearing_data);
6091       bearing = atoi(temp_ptr);
6092       XtFree(temp_ptr);
6093 
6094       if ( (bearing < 1) || (bearing > 360) )
6095       {
6096         bearing = 360;
6097       }
6098 
6099       if (transmit_compressed_objects_items)
6100       {
6101         char temp_overlay = last_obj_overlay;
6102 
6103 
6104 // Need to compute "csT" at some point and add it to the object.
6105 // Until we do that we'll have no course/speed/altitude.  Looks like
6106 // we can have course/speed or altitude, but not both.  Must have to
6107 // add the "/A=000123" stuff to the end if we want both.
6108 //
6109 // If we have course and/or speed, use course/speed csT bytes.  If
6110 // no course/speed but we have altitude, use altitude csT bytes.  We
6111 // can cheat right now and just always use course/speed, adding
6112 // altitude with the altitude extension.  Not as efficient, but it
6113 // gets the job done.
6114 //
6115 // Later we should change compress_posit() to accept an altitude
6116 // parameter, and have it decide which csT set of bytes to add, and
6117 // whether to add altitude as an uncompressed extension if
6118 // necessary.
6119 
6120 
6121         // Need to handle the conversion of numeric overlay
6122         // chars to "a-j" here.
6123         if (last_obj_overlay >= '0' && last_obj_overlay <= '9')
6124         {
6125           temp_overlay = last_obj_overlay + 'a';
6126         }
6127 
6128         xastir_snprintf(line, line_length, ")%s!%s/%03i/%s%s",
6129                         last_object,
6130                         compress_posit(ext_lat_str,
6131                                        (temp_overlay) ? temp_overlay : last_obj_grp,
6132                                        ext_lon_str,
6133                                        last_obj_sym,
6134                                        course,
6135                                        speed,  // In knots
6136                                        ""),    // PHG, must be blank in this case
6137                         bearing,
6138                         object_NRQ,
6139                         altitude);
6140 
6141         comment_field_used = strlen(line) - 15 - strlen(last_object);
6142 
6143       }
6144       else
6145       {
6146 
6147         xastir_snprintf(line, line_length, ")%s!%s%c%s%c%s/%03i/%s%s",
6148                         last_object,
6149                         lat_str,
6150                         last_obj_grp,
6151                         lon_str,
6152                         last_obj_sym,
6153                         speed_course,
6154                         bearing,
6155                         object_NRQ,
6156                         altitude);
6157 
6158         comment_field_used = strlen(line) - 21 - strlen(last_object);
6159       }
6160 
6161     }
6162   }
6163   else      // Else it's a normal item
6164   {
6165 
6166     prob_min[0] = '\0';
6167     prob_max[0] = '\0';
6168 
6169     if (Probability_circles_enabled)
6170     {
6171 
6172       temp_ptr = XmTextFieldGetString(probability_data_min);
6173       xastir_snprintf(line, line_length, "%s", temp_ptr);
6174       XtFree(temp_ptr);
6175 
6176       //fprintf(stderr,"Probability min circle entered: %s\n",
6177       //line);
6178       if (strlen(line) != 0)     // Probability circle data was entered
6179       {
6180         xastir_snprintf(prob_min, sizeof(prob_min), "Pmin%s,", line);
6181       }
6182 
6183       temp_ptr = XmTextFieldGetString(probability_data_max);
6184       xastir_snprintf(line, line_length, "%s", temp_ptr);
6185       XtFree(temp_ptr);
6186 
6187       //fprintf(stderr,"Probability max circle entered: %s\n",
6188       //line);
6189       if (strlen(line) != 0)     // Probability circle data was entered
6190       {
6191         xastir_snprintf(prob_max, sizeof(prob_max), "Pmax%s,", line);
6192       }
6193     }
6194 
6195 
6196     if (transmit_compressed_objects_items)
6197     {
6198       char temp_overlay = last_obj_overlay;
6199 
6200 
6201 // Need to compute "csT" at some point and add it to the object.
6202 // Until we do that we'll have no course/speed/altitude.  Looks like
6203 // we can have course/speed or altitude, but not both.  Must have to
6204 // add the "/A=000123" stuff to the end if we want both.
6205 //
6206 // If we have course and/or speed, use course/speed csT bytes.  If
6207 // no course/speed but we have altitude, use altitude csT bytes.  We
6208 // can cheat right now and just always use course/speed, adding
6209 // altitude with the altitude extension.  Not as efficient, but it
6210 // gets the job done.
6211 //
6212 // Later we should change compress_posit() to accept an altitude
6213 // parameter, and have it decide which csT set of bytes to add, and
6214 // whether to add altitude as an uncompressed extension if
6215 // necessary.
6216 
6217 
6218       // Need to handle the conversion of numeric overlay
6219       // chars to "a-j" here.
6220       if (last_obj_overlay >= '0' && last_obj_overlay <= '9')
6221       {
6222         temp_overlay = last_obj_overlay + 'a';
6223       }
6224 
6225       xastir_snprintf(line,
6226                       line_length,
6227                       ")%s!%s%s%s%s",
6228                       last_object,
6229                       compress_posit(ext_lat_str,
6230                                      (temp_overlay) ? temp_overlay : last_obj_grp,
6231                                      ext_lon_str,
6232                                      last_obj_sym,
6233                                      course,
6234                                      speed,  // In knots
6235                                      ""),    // PHG, must be blank in this case
6236                       altitude,
6237                       prob_min,
6238                       prob_max);
6239 
6240       comment_field_used = strlen(line) - 15 - strlen(last_object);
6241 
6242     }
6243     else
6244     {
6245       xastir_snprintf(line,
6246                       line_length,
6247                       ")%s!%s%c%s%c%s%s%s%s",
6248                       last_object,
6249                       lat_str,
6250                       last_obj_overlay ? last_obj_overlay : last_obj_grp,
6251                       lon_str,
6252                       last_obj_sym,
6253                       speed_course,
6254                       altitude,
6255                       prob_min,
6256                       prob_max);
6257 
6258       comment_field_used = strlen(line) - 21 - strlen(last_object);
6259 
6260     }
6261   }
6262 
6263 
6264   // We need to tack the comment on the end, but need to make
6265   // sure we don't go over the maximum length for an item.
6266   //fprintf(stderr,"Comment: %s\n",comment);
6267   if (strlen(comment) != 0)
6268   {
6269 
6270     if (comment[0] == '}')
6271     {
6272       // May be a multipoint polygon string at the start of
6273       // the comment field.  Add a space before this special
6274       // character as multipoints have to start with " }" to
6275       // be valid.
6276       line[strlen(line) + 1] = '\0';
6277       line[strlen(line)] = ' ';
6278       comment_field_used++;
6279     }
6280 
6281     temp = 0;
6282 //        while ( (strlen(line) < (64 + strlen(last_object))) && (temp < (int)strlen(comment)) ) {
6283     while ( (comment_field_used < 43) && (temp < (int)strlen(comment)) )
6284     {
6285       //fprintf(stderr,"temp: %d->%d\t%c\n", temp, strlen(line), comment[temp]);
6286       line[strlen(line) + 1] = '\0';
6287       line[strlen(line)] = comment[temp++];
6288       comment_field_used++;
6289     }
6290   }
6291   //fprintf(stderr,"line: %s\n",line);
6292 
6293 // NOTE:  Compressed mode will be shorter still.  Account
6294 // for that when compressed mode is implemented for items.
6295 
6296   return(1);
6297 }
6298 
6299 
6300 
6301 
6302 
6303 
6304 /*
6305  *  Set an Object
6306  */
Object_change_data_set(Widget widget,XtPointer clientData,XtPointer UNUSED (callData))6307 void Object_change_data_set(Widget widget, XtPointer clientData, XtPointer UNUSED(callData) )
6308 {
6309   char line[43+1+40];                 // ???
6310   DataRow *p_station = global_parameter1;
6311 
6312   //fprintf(stderr,"Object_change_data_set\n");
6313 
6314   // p_station will be NULL if the object is new.
6315   if (Setup_object_data(line, sizeof(line), p_station))
6316   {
6317 
6318     // Update this object in our save file
6319     log_object_item(line,0,last_object);
6320 
6321     // Set up the timer properly for the decaying algorithm
6322     if (p_station != NULL)
6323     {
6324       p_station->transmit_time_increment = OBJECT_CHECK_RATE;
6325       p_station->last_transmit_time = sec_now();
6326 
6327       // Keep the time current for our own objects.
6328       p_station->sec_heard = sec_now();
6329       move_station_time(p_station,NULL);
6330 
6331 //            p_station->last_modified_time = sec_now(); // For dead-reckoning
6332 //fprintf(stderr,"Object_change_data_set(): Setting transmit increment to %d\n", OBJECT_CHECK_RATE);
6333     }
6334 
6335     if (object_tx_disable || transmit_disable)
6336     {
6337       output_my_data(line,-1,0,1,0,NULL);  // Local loopback only, not igating
6338     }
6339     else
6340     {
6341       output_my_data(line,-1,0,0,0,NULL);  // Transmit/loopback object data, not igating
6342     }
6343 
6344     sched_yield();                  // Wait for transmitted data to get processed
6345     Object_destroy_shell(widget,clientData,NULL);
6346     // Getting a segfault here on a Move operation, so just
6347     // comment it out.  A redraw will occur shortly anyway.
6348     //redraw_symbols(da);
6349     (void)XCopyArea(XtDisplay(da),
6350                     pixmap_final,
6351                     XtWindow(da),
6352                     gc,
6353                     0,
6354                     0,
6355                     (unsigned int)screen_width,
6356                     (unsigned int)screen_height,
6357                     0,
6358                     0);
6359   }
6360   else
6361   {
6362     // error message
6363     popup_message_always(langcode("POPEM00022"),langcode("POPEM00027"));
6364   }
6365 }
6366 
6367 
6368 
6369 
6370 
6371 /*
6372  *  Set an Item
6373  */
Item_change_data_set(Widget widget,XtPointer clientData,XtPointer UNUSED (callData))6374 void Item_change_data_set(Widget widget, XtPointer clientData, XtPointer UNUSED(callData) )
6375 {
6376   char line[43+1+40];                 // ???
6377   DataRow *p_station = global_parameter1;
6378 
6379 
6380   if (Setup_item_data(line,sizeof(line), p_station))
6381   {
6382 
6383     // Update this item in our save file
6384     log_object_item(line,0,last_object);
6385 
6386     // Set up the timer properly for the decaying algorithm
6387     if (p_station != NULL)
6388     {
6389       p_station->transmit_time_increment = OBJECT_CHECK_RATE;
6390       p_station->last_transmit_time = sec_now();
6391 
6392       // Keep the time current for our own items.
6393       p_station->sec_heard = sec_now();
6394       move_station_time(p_station,NULL);
6395 
6396 //            p_station->last_modified_time = sec_now(); // For dead-reckoning
6397 //fprintf(stderr,"Item_change_data_set(): Setting transmit increment to %d\n", OBJECT_CHECK_RATE);
6398     }
6399 
6400     if (object_tx_disable || transmit_disable)
6401     {
6402       output_my_data(line,-1,0,1,0,NULL);  // Local loopback only, not igating
6403     }
6404     else
6405     {
6406       output_my_data(line,-1,0,0,0,NULL);  // Transmit/loopback item data, not igating
6407     }
6408 
6409     sched_yield();                  // Wait for transmitted data to get processed
6410     Object_destroy_shell(widget,clientData,NULL);
6411     // Getting a segfault here on a Move operation, so just
6412     // comment it out.  A redraw will occur shortly anyway.
6413     //redraw_symbols(da);
6414     (void)XCopyArea(XtDisplay(da),
6415                     pixmap_final,
6416                     XtWindow(da),
6417                     gc,
6418                     0,
6419                     0,
6420                     (unsigned int)screen_width,
6421                     (unsigned int)screen_height,
6422                     0,
6423                     0);
6424   }
6425   else
6426   {
6427     // error message
6428     popup_message_always(langcode("POPEM00022"),langcode("POPEM00027"));
6429   }
6430 }
6431 
6432 
6433 
6434 
6435 
6436 // Check the name of a new Object.  If it already exists in our
6437 // database, warn the user.  Confirmation dialog to continue?
6438 //
Object_confirm_data_set(Widget widget,XtPointer clientData,XtPointer callData)6439 void Object_confirm_data_set(Widget widget, XtPointer clientData, XtPointer callData)
6440 {
6441   char *temp_ptr;
6442   char line[MAX_CALLSIGN+1];
6443   DataRow *p_station;
6444 
6445 
6446   temp_ptr = XmTextFieldGetString(object_name_data);
6447   xastir_snprintf(line,
6448                   sizeof(line),
6449                   "%s",
6450                   temp_ptr);
6451   XtFree(temp_ptr);
6452 
6453   (void)remove_leading_spaces(line);
6454   (void)remove_trailing_spaces(line);
6455 
6456   //fprintf(stderr,"Object name:%s\n", line);
6457 
6458   // We have the name now.  Check it against our database of
6459   // stations/objects/items.  Do an exact match.
6460   //
6461   if (search_station_name(&p_station,line,1)
6462       && (p_station->flag & ST_ACTIVE))
6463   {
6464     // Found a live object with that name.  Don't allow Object
6465     // creation.  Bring up a warning message instead.
6466     popup_message_always(langcode("POPEM00035"), langcode("POPEM00038"));
6467   }
6468   else
6469   {
6470 
6471     // Not found.  Allow the Object to be created.
6472     Object_change_data_set(widget, clientData, callData);
6473   }
6474 }
6475 
6476 
6477 
6478 
6479 
6480 // Check the name of a new Item.  If it already exists in our
6481 // database, warn the user.  Confirmation dialog to continue?
6482 //
Item_confirm_data_set(Widget widget,XtPointer clientData,XtPointer callData)6483 void Item_confirm_data_set(Widget widget, XtPointer clientData, XtPointer callData)
6484 {
6485   char *temp_ptr;
6486   char line[MAX_CALLSIGN+1];
6487   DataRow *p_station;
6488 
6489 
6490   temp_ptr = XmTextFieldGetString(object_name_data);
6491   xastir_snprintf(line,
6492                   sizeof(line),
6493                   "%s",
6494                   temp_ptr);
6495   XtFree(temp_ptr);
6496 
6497   (void)remove_leading_spaces(line);
6498   (void)remove_trailing_spaces(line);
6499 
6500   //fprintf(stderr,"Item name:%s\n", line);
6501 
6502   // We have the name now.  Check it against our database of
6503   // stations/objects/items.  Do an exact match.
6504   //
6505   if (search_station_name(&p_station,line,1)
6506       && (p_station->flag & ST_ACTIVE))
6507   {
6508     // Found a live object with that name.  Don't allow Object
6509     // creation.  Bring up a warning message instead.
6510     popup_message_always(langcode("POPEM00035"), langcode("POPEM00038"));
6511   }
6512   else
6513   {
6514 
6515     // Not found.  Allow the Item to be created.
6516     Item_change_data_set(widget, clientData, callData);
6517   }
6518 }
6519 
6520 
6521 
6522 
6523 
6524 /*
6525  *  Delete an Object
6526  */
Object_change_data_del(Widget widget,XtPointer clientData,XtPointer UNUSED (callData))6527 void Object_change_data_del(Widget widget, XtPointer clientData, XtPointer UNUSED(callData) )
6528 {
6529   char line[43+1+40];                 // ???
6530   DataRow *p_station = global_parameter1;
6531 
6532 
6533   if (Setup_object_data(line, sizeof(line), p_station))
6534   {
6535 
6536     line[10] = '_';                         // mark as deleted object
6537 
6538     // Update this object in our save file, then comment all
6539     // instances out in the file.
6540     log_object_item(line,1,last_object);
6541 
6542     // Set up the timer properly for the decaying algorithm
6543     if (p_station != NULL)
6544     {
6545       p_station->transmit_time_increment = OBJECT_CHECK_RATE;
6546       p_station->last_transmit_time = sec_now();
6547 //            p_station->last_modified_time = sec_now(); // For dead-reckoning
6548 //fprintf(stderr,"Object_change_data_del(): Setting transmit increment to %d\n", OBJECT_CHECK_RATE);
6549     }
6550 
6551     if (object_tx_disable || transmit_disable)
6552     {
6553       output_my_data(line,-1,0,1,0,NULL);  // Local loopback only, not igating
6554     }
6555     else
6556     {
6557       output_my_data(line,-1,0,0,0,NULL);  // Transmit object data, not igating
6558     }
6559 
6560     Object_destroy_shell(widget,clientData,NULL);
6561   }
6562 }
6563 
6564 
6565 
6566 
6567 
6568 /*
6569  *  Delete an Item
6570  */
Item_change_data_del(Widget widget,XtPointer clientData,XtPointer UNUSED (callData))6571 void Item_change_data_del(Widget widget, XtPointer clientData, XtPointer UNUSED(callData) )
6572 {
6573   char line[43+1+40];                 // ???
6574   int i, done;
6575   DataRow *p_station = global_parameter1;
6576 
6577 
6578   if (Setup_item_data(line,sizeof(line), p_station))
6579   {
6580 
6581     done = 0;
6582     i = 0;
6583     while ( (!done) && (i < 11) )
6584     {
6585       if (line[i] == '!')
6586       {
6587         line[i] = '_';          // mark as deleted object
6588         done++;                 // Exit from loop
6589       }
6590       i++;
6591     }
6592 
6593     // Update this item in our save file, then comment all
6594     // instances out in the file.
6595     log_object_item(line,1,last_object);
6596 
6597     // Set up the timer properly for the decaying algorithm
6598     if (p_station != NULL)
6599     {
6600       p_station->transmit_time_increment = OBJECT_CHECK_RATE;
6601       p_station->last_transmit_time = sec_now();
6602 //            p_station->last_modified_time = sec_now(); // For dead-reckoning
6603 //fprintf(stderr,"Item_change_data_del(): Setting transmit increment to %d\n", OBJECT_CHECK_RATE);
6604     }
6605 
6606     if (object_tx_disable || transmit_disable)
6607     {
6608       output_my_data(line,-1,0,1,0,NULL);  // Local loopback only, not igating
6609     }
6610     else
6611     {
6612       output_my_data(line,-1,0,0,0,NULL);  // Transmit item data, not igating
6613     }
6614 
6615     Object_destroy_shell(widget,clientData,NULL);
6616   }
6617 }
6618 
6619 
6620 
6621 
6622 
6623 /*
6624  *  Select a symbol graphically
6625  */
Ob_change_symbol(Widget widget,XtPointer clientData,XtPointer callData)6626 void Ob_change_symbol(Widget widget, XtPointer clientData, XtPointer callData)
6627 {
6628   //fprintf(stderr,"Trying to change a symbol\n");
6629   symbol_change_requested_from = 2;   // Tell Select_symbol who to return the data to
6630   Select_symbol(widget, clientData, callData);
6631 }
6632 
6633 
6634 
6635 
6636 
6637 /*
6638  *  Update symbol picture for changed symbol or table
6639  */
updateObjectPictureCallback(Widget UNUSED (w),XtPointer UNUSED (clientData),XtPointer UNUSED (callData))6640 void updateObjectPictureCallback(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) )
6641 {
6642   char table, overlay;
6643   char symb, group;
6644   char *temp_ptr;
6645 
6646 
6647   XtVaSetValues(object_icon, XmNlabelPixmap, Ob_icon0, NULL);         // clear old icon
6648   XtManageChild(object_icon);
6649 
6650   temp_ptr = XmTextFieldGetString(object_group_data);
6651   group = temp_ptr[0];
6652   XtFree(temp_ptr);
6653 
6654   temp_ptr = XmTextFieldGetString(object_symbol_data);
6655   symb  = temp_ptr[0];
6656   XtFree(temp_ptr);
6657 
6658   if (group == '/' || group == '\\')
6659   {
6660     // No overlay character
6661     table   = group;
6662     overlay = ' ';
6663   }
6664   else
6665   {
6666     // Found overlay character.  Check that it's a valid
6667     // overlay.
6668     if ( (group >= '0' && group <= '9')
6669          || (group >= 'A' && group <= 'Z') )
6670     {
6671       // Valid overlay character
6672       table   = '\\';
6673       overlay = group;
6674     }
6675     else
6676     {
6677       // Bad overlay character
6678       table = '\\';
6679       overlay = ' ';
6680     }
6681   }
6682   symbol(object_icon,0,table,symb,overlay,Ob_icon,0,0,0,' ');         // create icon
6683 
6684   XtVaSetValues(object_icon,XmNlabelPixmap,Ob_icon,NULL);             // draw new icon
6685   XtManageChild(object_icon);
6686 }
6687 
6688 
6689 
6690 
6691 
6692 // Handler for "Signpost" toggle button
Signpost_object_toggle(Widget widget,XtPointer UNUSED (clientData),XtPointer callData)6693 void Signpost_object_toggle( Widget widget, XtPointer UNUSED(clientData), XtPointer callData)
6694 {
6695   XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData;
6696   char temp_data[40];
6697   char comment[43+1];     // max 43 characters of comment
6698   char signpost_name[10];
6699   char *temp_ptr;
6700 
6701 
6702   // Save name and comment fields temporarily
6703   temp_ptr = XmTextFieldGetString(object_name_data);
6704   xastir_snprintf(signpost_name,
6705                   sizeof(signpost_name),
6706                   "%s",
6707                   temp_ptr);
6708   XtFree(temp_ptr);
6709 
6710   (void)remove_trailing_spaces(signpost_name);
6711 
6712   temp_ptr = XmTextFieldGetString(object_comment_data);
6713   xastir_snprintf(comment,
6714                   sizeof(comment),
6715                   "%s",
6716                   temp_ptr);
6717   XtFree(temp_ptr);
6718 
6719   (void)remove_trailing_spaces(comment);
6720 
6721 
6722   if(state->set)
6723   {
6724     Signpost_object_enabled = 1;
6725     Area_object_enabled = 0;
6726     DF_object_enabled = 0;
6727     Map_View_object_enabled = 0;
6728     Probability_circles_enabled = 0;
6729 
6730     //fprintf(stderr,"Signpost Objects are ENABLED\n");
6731 
6732     // Call Set_Del_Object again, causing it to redraw with the new options.
6733     //Set_Del_Object( widget, clientData, callData );
6734     Set_Del_Object( widget, global_parameter1, global_parameter2 );
6735 
6736     XmToggleButtonSetState(area_toggle, FALSE, FALSE);
6737     XmToggleButtonSetState(df_bearing_toggle, FALSE, FALSE);
6738     XmToggleButtonSetState(map_view_toggle, FALSE, FALSE);
6739     XmToggleButtonSetState(probabilities_toggle, FALSE, FALSE);
6740 
6741     temp_data[0] = '\\';
6742     temp_data[1] = '\0';
6743     XmTextFieldSetString(object_group_data,temp_data);
6744 
6745     temp_data[0] = 'm';
6746     temp_data[1] = '\0';
6747     XmTextFieldSetString(object_symbol_data,temp_data);
6748 
6749     XtSetSensitive(ob_frame,FALSE);
6750 
6751     // update symbol picture
6752     (void)updateObjectPictureCallback((Widget)NULL,(XtPointer)NULL,(XtPointer)NULL);
6753   }
6754   else
6755   {
6756     Signpost_object_enabled = 0;
6757 
6758     //fprintf(stderr,"Signpost Objects are DISABLED\n");
6759 
6760     // Call Set_Del_Object again, causing it to redraw with the new options.
6761     //Set_Del_Object( widget, clientData, callData );
6762     Set_Del_Object( widget, global_parameter1, global_parameter2 );
6763 
6764 
6765     temp_data[0] = '/';
6766     temp_data[1] = '\0';
6767     XmTextFieldSetString(object_group_data,temp_data);
6768 
6769     temp_data[0] = '/';
6770     temp_data[1] = '\0';
6771     XmTextFieldSetString(object_symbol_data,temp_data);
6772 
6773     XtSetSensitive(ob_frame,TRUE);
6774 
6775     // update symbol picture
6776     (void)updateObjectPictureCallback((Widget)NULL,(XtPointer)NULL,(XtPointer)NULL);
6777   }
6778 
6779   // Restore name and comment fields
6780   XmTextFieldSetString(object_name_data,signpost_name);
6781   XmTextFieldSetString(object_comment_data,comment);
6782 }
6783 
6784 
6785 
6786 
6787 
6788 // Handler for "Probability Circles" toggle button
Probability_circle_toggle(Widget widget,XtPointer UNUSED (clientData),XtPointer callData)6789 void Probability_circle_toggle( Widget widget, XtPointer UNUSED(clientData), XtPointer callData)
6790 {
6791   XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData;
6792   char temp_data[40];
6793   char comment[43+1];     // max 43 characters of comment
6794   char signpost_name[10];
6795   char *temp_ptr;
6796 
6797 
6798   // Save name and comment fields temporarily
6799   temp_ptr = XmTextFieldGetString(object_name_data);
6800   xastir_snprintf(signpost_name,
6801                   sizeof(signpost_name),
6802                   "%s",
6803                   temp_ptr);
6804   XtFree(temp_ptr);
6805 
6806   (void)remove_trailing_spaces(signpost_name);
6807 
6808   temp_ptr = XmTextFieldGetString(object_comment_data);
6809   xastir_snprintf(comment,
6810                   sizeof(comment),
6811                   "%s",
6812                   temp_ptr);
6813   XtFree(temp_ptr);
6814 
6815   (void)remove_trailing_spaces(comment);
6816 
6817 
6818   if(state->set)
6819   {
6820     Signpost_object_enabled = 0;
6821     Area_object_enabled = 0;
6822     DF_object_enabled = 0;
6823     Map_View_object_enabled = 0;
6824     Probability_circles_enabled = 1;
6825 
6826     //fprintf(stderr,"Probability Circles are ENABLED\n");
6827 
6828     // Call Set_Del_Object again, causing it to redraw with the new options.
6829     //Set_Del_Object( widget, clientData, callData );
6830     Set_Del_Object( widget, global_parameter1, global_parameter2 );
6831 
6832     XmToggleButtonSetState(area_toggle, FALSE, FALSE);
6833     XmToggleButtonSetState(df_bearing_toggle, FALSE, FALSE);
6834     XmToggleButtonSetState(map_view_toggle, FALSE, FALSE);
6835     XmToggleButtonSetState(signpost_toggle, FALSE, FALSE);
6836 
6837     // Set to hiker symbol by default, but can be changed by
6838     // user to something else.
6839     temp_data[0] = '/';
6840     temp_data[1] = '\0';
6841     XmTextFieldSetString(object_group_data,temp_data);
6842 
6843     temp_data[0] = '[';
6844     temp_data[1] = '\0';
6845     XmTextFieldSetString(object_symbol_data,temp_data);
6846 
6847     // update symbol picture
6848     (void)updateObjectPictureCallback((Widget)NULL,(XtPointer)NULL,(XtPointer)NULL);
6849   }
6850   else
6851   {
6852     Probability_circles_enabled = 0;
6853 
6854     //fprintf(stderr,"Signpost Objects are DISABLED\n");
6855 
6856     // Call Set_Del_Object again, causing it to redraw with the new options.
6857     //Set_Del_Object( widget, clientData, callData );
6858     Set_Del_Object( widget, global_parameter1, global_parameter2 );
6859 
6860 
6861     temp_data[0] = '/';
6862     temp_data[1] = '\0';
6863     XmTextFieldSetString(object_group_data,temp_data);
6864 
6865     temp_data[0] = '/';
6866     temp_data[1] = '\0';
6867     XmTextFieldSetString(object_symbol_data,temp_data);
6868 
6869     XtSetSensitive(ob_frame,TRUE);
6870 
6871     // update symbol picture
6872     (void)updateObjectPictureCallback((Widget)NULL,(XtPointer)NULL,(XtPointer)NULL);
6873   }
6874 
6875   // Restore name and comment fields
6876   XmTextFieldSetString(object_name_data,signpost_name);
6877   XmTextFieldSetString(object_comment_data,comment);
6878 }
6879 
6880 
6881 
6882 
6883 
6884 // Handler for "Enable Area Type" toggle button
Area_object_toggle(Widget widget,XtPointer UNUSED (clientData),XtPointer callData)6885 void  Area_object_toggle( Widget widget, XtPointer UNUSED(clientData), XtPointer callData)
6886 {
6887   XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData;
6888   char temp_data[40];
6889   char comment[43+1];     // max 43 characters of comment
6890   char signpost_name[10];
6891   char *temp_ptr;
6892 
6893 
6894   // Save name and comment fields temporarily
6895   temp_ptr = XmTextFieldGetString(object_name_data);
6896   xastir_snprintf(signpost_name,
6897                   sizeof(signpost_name),
6898                   "%s",
6899                   temp_ptr);
6900   XtFree(temp_ptr);
6901 
6902   (void)remove_trailing_spaces(signpost_name);
6903 
6904   temp_ptr = XmTextFieldGetString(object_comment_data);
6905   xastir_snprintf(comment,
6906                   sizeof(comment),
6907                   "%s",
6908                   temp_ptr);
6909   XtFree(temp_ptr);
6910 
6911   (void)remove_trailing_spaces(comment);
6912 
6913 
6914   if(state->set)
6915   {
6916     Area_object_enabled = 1;
6917     Signpost_object_enabled = 0;
6918     DF_object_enabled = 0;
6919     Map_View_object_enabled = 0;
6920     Probability_circles_enabled = 0;
6921 
6922     //fprintf(stderr,"Area Objects are ENABLED\n");
6923 
6924     // Call Set_Del_Object again, causing it to redraw with the new options.
6925     //Set_Del_Object( widget, clientData, callData );
6926     Set_Del_Object( widget, global_parameter1, global_parameter2 );
6927 
6928 
6929     XmToggleButtonSetState(signpost_toggle, FALSE, FALSE);
6930     XmToggleButtonSetState(df_bearing_toggle, FALSE, FALSE);
6931     XmToggleButtonSetState(map_view_toggle, FALSE, FALSE);
6932     XmToggleButtonSetState(probabilities_toggle, FALSE, FALSE);
6933 
6934     XtSetSensitive(ob_speed,FALSE);
6935     XtSetSensitive(ob_speed_data,FALSE);
6936     XtSetSensitive(ob_course,FALSE);
6937     XtSetSensitive(ob_course_data,FALSE);
6938 
6939     temp_data[0] = '\\';
6940     temp_data[1] = '\0';
6941     XmTextFieldSetString(object_group_data,temp_data);
6942 
6943     temp_data[0] = 'l';
6944     temp_data[1] = '\0';
6945     XmTextFieldSetString(object_symbol_data,temp_data);
6946 
6947     XtSetSensitive(ob_frame,FALSE);
6948 
6949     // update symbol picture
6950     (void)updateObjectPictureCallback((Widget)NULL,(XtPointer)NULL,(XtPointer)NULL);
6951   }
6952   else
6953   {
6954     Area_object_enabled = 0;
6955 
6956     //fprintf(stderr,"Area Objects are DISABLED\n");
6957 
6958     // Call Set_Del_Object again, causing it to redraw with the new options.
6959     //Set_Del_Object( widget, clientData, callData );
6960     Set_Del_Object( widget, global_parameter1, global_parameter2 );
6961 
6962 
6963     XtSetSensitive(ob_speed,TRUE);
6964     XtSetSensitive(ob_speed_data,TRUE);
6965     XtSetSensitive(ob_course,TRUE);
6966     XtSetSensitive(ob_course_data,TRUE);
6967 
6968     temp_data[0] = '/';
6969     temp_data[1] = '\0';
6970     XmTextFieldSetString(object_group_data,temp_data);
6971 
6972     temp_data[0] = '/';
6973     temp_data[1] = '\0';
6974     XmTextFieldSetString(object_symbol_data,temp_data);
6975 
6976     XtSetSensitive(ob_frame,TRUE);
6977 
6978     // update symbol picture
6979     (void)updateObjectPictureCallback((Widget)NULL,(XtPointer)NULL,(XtPointer)NULL);
6980   }
6981 
6982   // Restore name and comment fields
6983   XmTextFieldSetString(object_name_data,signpost_name);
6984   XmTextFieldSetString(object_comment_data,comment);
6985 }
6986 
6987 
6988 
6989 
6990 
6991 // Handler for "DF Bearing Object" toggle button
DF_bearing_object_toggle(Widget widget,XtPointer UNUSED (clientData),XtPointer callData)6992 void  DF_bearing_object_toggle( Widget widget, XtPointer UNUSED(clientData), XtPointer callData)
6993 {
6994   XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData;
6995   char temp_data[40];
6996   char comment[43+1];     // max 43 characters of comment
6997   char signpost_name[10];
6998   char *temp_ptr;
6999 
7000 
7001   // Save name and comment fields temporarily
7002   temp_ptr = XmTextFieldGetString(object_name_data);
7003   xastir_snprintf(signpost_name,
7004                   sizeof(signpost_name),
7005                   "%s",
7006                   temp_ptr);
7007   XtFree(temp_ptr);
7008 
7009   (void)remove_trailing_spaces(signpost_name);
7010 
7011   temp_ptr = XmTextFieldGetString(object_comment_data);
7012   xastir_snprintf(comment,
7013                   sizeof(comment),
7014                   "%s",
7015                   temp_ptr);
7016   XtFree(temp_ptr);
7017   (void)remove_trailing_spaces(comment);
7018 
7019 
7020   if(state->set)
7021   {
7022     Area_object_enabled = 0;
7023     Signpost_object_enabled = 0;
7024     DF_object_enabled = 1;
7025     Map_View_object_enabled = 0;
7026     Probability_circles_enabled = 0;
7027 
7028     //fprintf(stderr,"DF Objects are ENABLED\n");
7029 
7030     // Call Set_Del_Object again, causing it to redraw with the new options.
7031     //Set_Del_Object( widget, clientData, callData );
7032     Set_Del_Object( widget, global_parameter1, global_parameter2 );
7033 
7034 
7035     XmToggleButtonSetState(signpost_toggle, FALSE, FALSE);
7036     XmToggleButtonSetState(area_toggle, FALSE, FALSE);
7037     XmToggleButtonSetState(map_view_toggle, FALSE, FALSE);
7038     XmToggleButtonSetState(probabilities_toggle, FALSE, FALSE);
7039 
7040     XtSetSensitive(ob_speed,TRUE);
7041     XtSetSensitive(ob_speed_data,TRUE);
7042     XtSetSensitive(ob_course,TRUE);
7043     XtSetSensitive(ob_course_data,TRUE);
7044     XtSetSensitive(frameomni,FALSE);
7045     XtSetSensitive(framebeam,FALSE);
7046     Omni_antenna_enabled = 0;
7047     Beam_antenna_enabled = 0;
7048 
7049     temp_data[0] = '/';
7050     temp_data[1] = '\0';
7051     XmTextFieldSetString(object_group_data,temp_data);
7052 
7053     temp_data[0] = '\\';
7054     temp_data[1] = '\0';
7055     XmTextFieldSetString(object_symbol_data,temp_data);
7056 
7057     XtSetSensitive(ob_frame,FALSE);
7058 
7059     // update symbol picture
7060     (void)updateObjectPictureCallback((Widget)NULL,(XtPointer)NULL,(XtPointer)NULL);
7061   }
7062   else
7063   {
7064     DF_object_enabled = 0;
7065 
7066     //fprintf(stderr,"DF Objects are DISABLED\n");
7067 
7068     // Call Set_Del_Object again, causing it to redraw with the new options.
7069     //Set_Del_Object( widget, clientData, callData );
7070     Set_Del_Object( widget, global_parameter1, global_parameter2 );
7071 
7072 
7073     temp_data[0] = '/';
7074     temp_data[1] = '\0';
7075     XmTextFieldSetString(object_group_data,temp_data);
7076 
7077     temp_data[0] = '/';
7078     temp_data[1] = '\0';
7079     XmTextFieldSetString(object_symbol_data,temp_data);
7080 
7081     XtSetSensitive(ob_frame,TRUE);
7082 
7083     // update symbol picture
7084     (void)updateObjectPictureCallback((Widget)NULL,(XtPointer)NULL,(XtPointer)NULL);
7085   }
7086 
7087   // Restore name and comment fields
7088   XmTextFieldSetString(object_name_data,signpost_name);
7089   XmTextFieldSetString(object_comment_data,comment);
7090 }
7091 
7092 
7093 
7094 
7095 
7096 // Handler for "Map View Object" toggle button
Map_View_object_toggle(Widget widget,XtPointer UNUSED (clientData),XtPointer callData)7097 void  Map_View_object_toggle( Widget widget, XtPointer UNUSED(clientData), XtPointer callData)
7098 {
7099   XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData;
7100   char temp_data[40];
7101   char comment[43+1];     // max 43 characters of comment
7102   char signpost_name[10];
7103   char *temp_ptr;
7104 
7105 
7106   // Save name and comment fields temporarily
7107   temp_ptr = XmTextFieldGetString(object_name_data);
7108   xastir_snprintf(signpost_name,
7109                   sizeof(signpost_name),
7110                   "%s",
7111                   temp_ptr);
7112   XtFree(temp_ptr);
7113 
7114   (void)remove_trailing_spaces(signpost_name);
7115 
7116   temp_ptr = XmTextFieldGetString(object_comment_data);
7117   xastir_snprintf(comment,
7118                   sizeof(comment),
7119                   "%s",
7120                   temp_ptr);
7121   XtFree(temp_ptr);
7122   (void)remove_trailing_spaces(comment);
7123 
7124 
7125   if(state->set)
7126   {
7127     // Make a bunch of the fields insensitive that we don't use
7128     // here.
7129 
7130     Area_object_enabled = 0;
7131     Signpost_object_enabled = 0;
7132     DF_object_enabled = 0;
7133     Map_View_object_enabled = 1;
7134     Probability_circles_enabled = 0;
7135 
7136     //fprintf(stderr,"Map View Objects are ENABLED\n");
7137 
7138 
7139 // Make a bunch of the fields insensitive that we don't use here?
7140 
7141 
7142     // Call Set_Del_Object again, causing it to redraw with the new options.
7143     //Set_Del_Object( widget, clientData, callData );
7144     Set_Del_Object( widget, global_parameter1, global_parameter2 );
7145 
7146     XmToggleButtonSetState(signpost_toggle, FALSE, FALSE);
7147     XmToggleButtonSetState(area_toggle, FALSE, FALSE);
7148     XmToggleButtonSetState(df_bearing_toggle, FALSE, FALSE);
7149     XmToggleButtonSetState(probabilities_toggle, FALSE, FALSE);
7150 
7151     temp_data[0] = '/';
7152     temp_data[1] = '\0';
7153     XmTextFieldSetString(object_group_data,temp_data);
7154 
7155     temp_data[0] = 'E'; // Eyeball symbol
7156     temp_data[1] = '\0';
7157     XmTextFieldSetString(object_symbol_data,temp_data);
7158 
7159     XtSetSensitive(ob_frame,FALSE);
7160     XtSetSensitive(ob_option_frame,FALSE);
7161 
7162     // update symbol picture
7163     (void)updateObjectPictureCallback((Widget)NULL,(XtPointer)NULL,(XtPointer)NULL);
7164   }
7165   else
7166   {
7167     Map_View_object_enabled = 0;
7168 
7169     //fprintf(stderr,"Map View Objects are DISABLED\n");
7170 
7171     // Call Set_Del_Object again, causing it to redraw with the new options.
7172     //Set_Del_Object( widget, clientData, callData );
7173     Set_Del_Object( widget, global_parameter1, global_parameter2 );
7174 
7175 
7176     temp_data[0] = '/';
7177     temp_data[1] = '\0';
7178     XmTextFieldSetString(object_group_data,temp_data);
7179 
7180     temp_data[0] = '/';
7181     temp_data[1] = '\0';
7182     XmTextFieldSetString(object_symbol_data,temp_data);
7183 
7184     XtSetSensitive(ob_frame,TRUE);
7185     XtSetSensitive(ob_option_frame,TRUE);
7186 
7187     // update symbol picture
7188     (void)updateObjectPictureCallback((Widget)NULL,(XtPointer)NULL,(XtPointer)NULL);
7189   }
7190 
7191   // Restore name and comment fields
7192   XmTextFieldSetString(object_name_data,signpost_name);
7193 
7194   // Don't want to restore the comment if it is a Map View object,
7195   // as Set_Del_Object() changes that field in that case.
7196   if (!Map_View_object_enabled)
7197   {
7198     XmTextFieldSetString(object_comment_data,comment);
7199   }
7200 }
7201 
7202 
7203 
7204 
7205 
7206 /* Area object type radio buttons */
Area_type_toggle(Widget UNUSED (widget),XtPointer clientData,XtPointer callData)7207 void Area_type_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData)
7208 {
7209   char *which = (char *)clientData;
7210   XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData;
7211 
7212   if(state->set)
7213   {
7214     Area_type = atoi(which);    // Set to shape desired
7215     if ( (Area_type == 1) || (Area_type == 6) )     // If either line type
7216     {
7217       //fprintf(stderr,"Line type: %d\n", Area_type);
7218       XtSetSensitive(ob_corridor,TRUE);
7219       XtSetSensitive(ob_corridor_data,TRUE);
7220       XtSetSensitive(ob_corridor_miles,TRUE);
7221       XtSetSensitive(open_filled_toggle,FALSE);
7222     }
7223     else    // Not line type
7224     {
7225       //fprintf(stderr,"Not line type: %d\n", Area_type);
7226       XtSetSensitive(ob_corridor,FALSE);
7227       XtSetSensitive(ob_corridor_data,FALSE);
7228       XtSetSensitive(ob_corridor_miles,FALSE);
7229       XtSetSensitive(open_filled_toggle,TRUE);
7230     }
7231   }
7232   else
7233   {
7234     Area_type = 0;  // Open circle
7235     //fprintf(stderr,"Type zero\n");
7236   }
7237   //fprintf(stderr,"Area type: %d\n", Area_type);
7238 }
7239 
7240 
7241 
7242 
7243 
7244 /* Area object color radio buttons */
Area_color_toggle(Widget UNUSED (widget),XtPointer clientData,XtPointer callData)7245 void Area_color_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData)
7246 {
7247   char *which = (char *)clientData;
7248   XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData;
7249 
7250   if(state->set)
7251   {
7252     Area_color[0] = which[0];   // Set to color desired.
7253     Area_color[1] = which[1];
7254     Area_color[2] = '\0';
7255   }
7256   else
7257   {
7258     Area_color[0] = '/';
7259     Area_color[1] = '0';    // Black
7260     Area_color[2] = '\0';
7261   }
7262   //fprintf(stderr,"Area color: %s\n", Area_color);
7263 }
7264 
7265 
7266 
7267 
7268 
7269 /* Area bright color enable button */
Area_bright_dim_toggle(Widget UNUSED (widget),XtPointer clientData,XtPointer callData)7270 void Area_bright_dim_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData)
7271 {
7272   char *which = (char *)clientData;
7273   XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData;
7274 
7275   if(state->set)
7276   {
7277     Area_bright = atoi(which);
7278     //fprintf(stderr,"Bright colors are ENABLED: %d\n", Area_bright);
7279   }
7280   else
7281   {
7282     Area_bright = 0;
7283     //fprintf(stderr,"Bright colors are DISABLED: %d\n", Area_bright);
7284   }
7285 }
7286 
7287 
7288 
7289 
7290 
7291 /* Area filled enable button */
Area_open_filled_toggle(Widget UNUSED (widget),XtPointer clientData,XtPointer callData)7292 void Area_open_filled_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData)
7293 {
7294   char *which = (char *)clientData;
7295   XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData;
7296 
7297   if(state->set)
7298   {
7299     Area_filled = atoi(which);
7300     //fprintf(stderr,"Filled shapes ENABLED: %d\n", Area_filled);
7301   }
7302   else
7303   {
7304     Area_filled = 0;
7305     //fprintf(stderr,"Filled shapes DISABLED: %d\n", Area_filled);
7306   }
7307 }
7308 
7309 
7310 
7311 
7312 
7313 // Handler for "Omni Antenna" toggle button
Omni_antenna_toggle(Widget UNUSED (widget),XtPointer UNUSED (clientData),XtPointer callData)7314 void  Omni_antenna_toggle( Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer callData)
7315 {
7316   XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData;
7317 
7318   if(state->set)
7319   {
7320     //fprintf(stderr,"Omni Antenna ENABLED\n");
7321     XmToggleButtonSetState(beam_antenna_toggle, FALSE, FALSE);
7322     XtSetSensitive(frameomni,TRUE);
7323     XtSetSensitive(framebeam,FALSE);
7324     Omni_antenna_enabled = 1;
7325     Beam_antenna_enabled = 0;
7326   }
7327   else
7328   {
7329     //fprintf(stderr,"Omni Antenna DISABLED\n");
7330     XtSetSensitive(frameomni,FALSE);
7331     Omni_antenna_enabled = 0;
7332   }
7333 }
7334 
7335 
7336 
7337 
7338 
7339 // Handler for "Beam Antenna" toggle button
Beam_antenna_toggle(Widget UNUSED (widget),XtPointer UNUSED (clientData),XtPointer callData)7340 void  Beam_antenna_toggle( Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer callData)
7341 {
7342   XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData;
7343 
7344   if(state->set)
7345   {
7346     //fprintf(stderr,"Beam Antenna ENABLED\n");
7347     XmToggleButtonSetState(omni_antenna_toggle, FALSE, FALSE);
7348     XtSetSensitive(frameomni,FALSE);
7349     XtSetSensitive(framebeam,TRUE);
7350     Omni_antenna_enabled = 0;
7351     Beam_antenna_enabled = 1;
7352   }
7353   else
7354   {
7355     //fprintf(stderr,"Beam Antenna DISABLED\n");
7356     XtSetSensitive(framebeam,FALSE);
7357     Beam_antenna_enabled = 0;
7358   }
7359 }
7360 
7361 
7362 
7363 
7364 
7365 /* Object signal radio buttons */
Ob_signal_toggle(Widget UNUSED (widget),XtPointer clientData,XtPointer callData)7366 void Ob_signal_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData)
7367 {
7368   char *which = (char *)clientData;
7369   XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData;
7370 
7371   if(state->set)
7372   {
7373     object_shgd[0] = which[0];  // Set to signal quality heard
7374   }
7375   else
7376   {
7377     object_shgd[0] = '0';       // 0 (Signal not heard)
7378   }
7379   object_shgd[4] = '\0';
7380 
7381   //fprintf(stderr,"SHGD: %s\n",object_shgd);
7382 }
7383 
7384 
7385 
7386 
7387 
7388 /* Object height radio buttons */
Ob_height_toggle(Widget UNUSED (widget),XtPointer clientData,XtPointer callData)7389 void Ob_height_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData)
7390 {
7391   char *which = (char *)clientData;
7392   XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData;
7393 
7394   if(state->set)
7395   {
7396     object_shgd[1] = which[0];  // Set to height desired
7397   }
7398   else
7399   {
7400     object_shgd[1] = '0';       // 0 (10ft HAAT)
7401   }
7402   object_shgd[4] = '\0';
7403 
7404   //fprintf(stderr,"SHGD: %s\n",object_shgd);
7405 }
7406 
7407 
7408 
7409 
7410 
7411 /* Object gain radio buttons */
Ob_gain_toggle(Widget UNUSED (widget),XtPointer clientData,XtPointer callData)7412 void Ob_gain_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData)
7413 {
7414   char *which = (char *)clientData;
7415   XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData;
7416 
7417   if(state->set)
7418   {
7419     object_shgd[2] = which[0];  // Set to antenna gain desired
7420   }
7421   else
7422   {
7423     object_shgd[2] = '0';       // 0dB gain
7424   }
7425   object_shgd[4] = '\0';
7426 
7427   //fprintf(stderr,"SHGD: %s\n",object_shgd);
7428 }
7429 
7430 
7431 
7432 
7433 
7434 /* Object directivity radio buttons */
Ob_directivity_toggle(Widget UNUSED (widget),XtPointer clientData,XtPointer callData)7435 void Ob_directivity_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData)
7436 {
7437   char *which = (char *)clientData;
7438   XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData;
7439 
7440   if(state->set)
7441   {
7442     object_shgd[3] = which[0];  // Set to antenna pattern desired
7443   }
7444   else
7445   {
7446     object_shgd[3] = '0';       // Omni-directional pattern
7447   }
7448   object_shgd[4] = '\0';
7449 
7450   //fprintf(stderr,"SHGD: %s\n",object_shgd);
7451 }
7452 
7453 
7454 
7455 
7456 
7457 /* Object beamwidth radio buttons */
Ob_width_toggle(Widget UNUSED (widget),XtPointer clientData,XtPointer callData)7458 void Ob_width_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData)
7459 {
7460   char *which = (char *)clientData;
7461   XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData;
7462 
7463   if(state->set)
7464   {
7465     object_NRQ[2] = which[0];  // Set to antenna beamwidth desired
7466   }
7467   else
7468   {
7469     object_NRQ[2] = '0';       // Beamwidth = "Useless"
7470   }
7471   object_NRQ[3] = '\0';
7472 
7473   //fprintf(stderr,"NRQ: %s\n", object_NRQ);
7474 }
7475 
7476 
7477 
7478 
7479 
7480 /* populate predefined object (SAR) struct */
Populate_predefined_objects(predefinedObject * predefinedObjects)7481 void Populate_predefined_objects(predefinedObject *predefinedObjects)
7482 {
7483   // The number of objects you are defining below must be
7484   // exactly equal to number_of_predefined_objects
7485   // and less than MAX_NUMBER_OF_PREDEFINED_OBJECTS.
7486   // using counter j for this seems inelegant **
7487 
7488   // A set of predefined SAR objects are hardcoded and used by default
7489   // other sets of predefined objects (SAR in km, public service event,
7490   // and user defined objects) can be loaded from a file.
7491   //
7492   // Detailed instructions for the format of the files can be found in
7493   // the two example files provided: predefined_SAR.sys and
7494   // predefined_EVENT.sys
7495   char predefined_object_definition_file[263];
7496   int read_file_ok = 0;
7497   int line_max_length = 255;
7498   int object_read_ok = 0;
7499   char line[line_max_length];
7500   char *value;
7501   char *variable;
7502   FILE *fp_file;
7503   int j = 0;
7504   char error_correct_location[300];
7505   char predef_obj_path[MAX_VALUE];
7506 #ifdef OBJECT_DEF_FILE_USER_BASE
7507   char temp_file_path[MAX_VALUE];
7508 #endif
7509 
7510 
7511   xastir_snprintf(line,sizeof(line),"%s","\0");
7512   xastir_snprintf(predefined_object_definition_file,sizeof(predefined_object_definition_file),"config/%s",predefined_object_definition_filename);
7513 
7514   get_user_base_dir(predefined_object_definition_file, predef_obj_path,
7515                     sizeof(predef_obj_path));
7516 
7517   number_of_predefined_objects = 0;
7518 
7519   if (predefined_menu_from_file == 1 )
7520   {
7521     // Check to see if a file containing predefined object definitions
7522     // exists, if it does, open it and try to read the definitions
7523     // if this fails, use the hardcoded SAR default instead.
7524 //        fprintf(stderr,"Checking for predefined objects menu file\n");
7525 #ifdef OBJECT_DEF_FILE_USER_BASE
7526     if (filethere(predef_obj_path))
7527     {
7528       fp_file = fopen(predef_obj_path,"r");
7529 #else   // OBJECT_DEF_FILE_USER_BASE
7530     if (filethere(get_data_base_dir(predefined_object_definition_file)))
7531     {
7532       fp_file = fopen(get_data_base_dir(predefined_object_definition_file),"r");
7533 #endif  // OBJECT_DEF_FILE_USER_BASE
7534 
7535       xastir_snprintf(error_correct_location,
7536                       sizeof(error_correct_location),
7537                       "Loading from %s/%s \n",
7538 #ifdef OBJECT_DEF_FILE_USER_BASE
7539                       get_user_base_dir("config", temp_file_path, sizeof(temp_file_path)),
7540 #else   // OBJECT_DEF_FILE_USER_BASE
7541                       get_data_base_dir("config"),
7542 #endif  // OBJECT_DEF_FILE_USER_BASE
7543                       predefined_object_definition_file);
7544       fprintf(stderr, "%s", error_correct_location);
7545       while (!feof(fp_file))
7546       {
7547         // read lines to end of file
7548         (void)get_line(fp_file, line, line_max_length);
7549         // ignore blank lines and lines starting with #
7550         if ((strncmp("#",line,1)!=0) && (strlen(line) > 2))
7551         {
7552           // if line starts "NAME" begin an object
7553           // next five lines should be PAGE, SYMBOL, DATA, MENU, HIDDENCHILD
7554           // NAME, PAGE, SYMBOL, MENU, and HIDDENCHILD are required.
7555           // HIDDENCHILD must come last (it is being used to identify the
7556           // end of one object).
7557           // split line into variable/value pairs on tab
7558           // See predefined_SAR.sys and predefined_event.sys for more details.
7559           variable = strtok((char *)&line,"\t");
7560           if (strcmp("NAME",variable)==0)
7561           {
7562             value = strtok(NULL,"\t\r\n");
7563             if (value != NULL)
7564             {
7565               xastir_snprintf(predefinedObjects[j].call,sizeof(predefinedObjects[j].call), "%s", value);
7566               // by default, set data to an empty string, allowing DATA to be ommitted
7567               xastir_snprintf(predefinedObjects[j].data,sizeof(predefinedObjects[j].data),"%c",'\0');
7568               object_read_ok ++;
7569             }
7570           }
7571           if (strcmp("PAGE",variable)==0)
7572           {
7573             value = strtok(NULL,"\t\r\n");
7574             if (value != NULL)
7575             {
7576               xastir_snprintf(predefinedObjects[j].page,sizeof(predefinedObjects[j].page), "%s", value);
7577               object_read_ok ++;
7578             }
7579           }
7580           if (strcmp("SYMBOL",variable)==0)
7581           {
7582             value = strtok(NULL,"\t\r\n");
7583             if (value != NULL)
7584             {
7585               xastir_snprintf(predefinedObjects[j].symbol,sizeof(predefinedObjects[j].symbol), "%s", value);
7586               object_read_ok ++;
7587             }
7588           }
7589           if (strcmp("DATA",variable)==0)
7590           {
7591             value = strtok(NULL,"\t\r\n");
7592             if (value == NULL || strcmp(value,"NULL")==0)
7593             {
7594               xastir_snprintf(predefinedObjects[j].data,sizeof(predefinedObjects[j].data),"%c",'\0');
7595             }
7596             else
7597             {
7598               xastir_snprintf(predefinedObjects[j].data,sizeof(predefinedObjects[j].data), "%s", value);
7599             }
7600           }
7601           if (strcmp("MENU",variable)==0)
7602           {
7603             value = strtok(NULL,"\t\r\n");
7604             if (value != NULL)
7605             {
7606               xastir_snprintf(predefinedObjects[j].menu_call,sizeof(predefinedObjects[j].menu_call), "%s", value);
7607               object_read_ok ++;
7608             }
7609           }
7610           if (strcmp("HIDDENCHILD",variable)==0)
7611           {
7612             value = strtok(NULL,"\t\r\n");
7613             if (strcmp(value,"YES")==0)
7614             {
7615               predefinedObjects[j].show_on_menu = 0;
7616               predefinedObjects[j].index_of_child = j - 1;
7617               predefinedObjects[j].index = j;
7618             }
7619             else
7620             {
7621               predefinedObjects[j].show_on_menu = 1;
7622               predefinedObjects[j].index_of_child = -1;
7623               predefinedObjects[j].index = j;
7624             }
7625             if (object_read_ok == 4)
7626             {
7627               // All elements for an object were read correctly.
7628               // Begin filling next element in array.
7629               j++;
7630               // Read of at least one object was successful,
7631               // don't display default hardcoded menu items.
7632               read_file_ok = 1;
7633               // Reset value counter for next object.
7634               object_read_ok = 0;
7635             }
7636             else
7637             {
7638               // Something was missing or HIDDENCHILD was out of order.
7639               // Don't increment array (overwrite a partly filled entry).
7640               fprintf(stderr,"Error in reading predefined object menu file:\nAn object is not correctly defined.\n");
7641             }
7642           }
7643         }
7644       } // end while !feof()
7645       fclose(fp_file);
7646       if (read_file_ok==0)
7647       {
7648         fprintf(stderr,"Error in reading predefined objects menu file:\nNo valid objects found.\n");
7649       }
7650     }
7651     else
7652     {
7653 
7654       fprintf(stderr,"Error: Predefined objects menu file not found.\n");
7655 
7656       xastir_snprintf(error_correct_location,
7657                       sizeof(error_correct_location),
7658                       "File should be in %s\n",
7659 #ifdef OBJECT_DEF_FILE_USER_BASE
7660                       get_user_base_dir("config", temp_file_path, sizeof(temp_file_path)));
7661 #else   // OBJECT_DEF_FILE_USER_BASE
7662                       get_data_base_dir("config"));
7663 #endif  // OBJECT_DEF_FILE_USER_BASE
7664       fprintf(stderr, "%s", error_correct_location);
7665     }
7666   }
7667 
7668   if (read_file_ok==0)
7669   {
7670     // file read failed or was not requested, display default SAR menu
7671 
7672     // command post
7673     xastir_snprintf(predefinedObjects[j].call,sizeof(predefinedObjects[j].call),"ICP");
7674     xastir_snprintf(predefinedObjects[j].page,sizeof(predefinedObjects[j].page),"/");
7675     xastir_snprintf(predefinedObjects[j].symbol,sizeof(predefinedObjects[j].symbol),"c");
7676     xastir_snprintf(predefinedObjects[j].data,sizeof(predefinedObjects[j].data),"%c",'\0');
7677     xastir_snprintf(predefinedObjects[j].menu_call,sizeof(predefinedObjects[j].menu_call),"ICP: Command Post");
7678     predefinedObjects[j].show_on_menu = 1;
7679     predefinedObjects[j].index_of_child = -1;
7680     predefinedObjects[j].index = j;
7681     j++;
7682 
7683     // Staging area
7684     xastir_snprintf(predefinedObjects[j].call,sizeof(predefinedObjects[j].call),"Staging");
7685     xastir_snprintf(predefinedObjects[j].page,sizeof(predefinedObjects[j].page),"S");
7686     xastir_snprintf(predefinedObjects[j].symbol,sizeof(predefinedObjects[j].symbol),"0");
7687     xastir_snprintf(predefinedObjects[j].data,sizeof(predefinedObjects[j].data),"%c",'\0');
7688     xastir_snprintf(predefinedObjects[j].menu_call,sizeof(predefinedObjects[j].menu_call),"Staging");
7689     predefinedObjects[j].show_on_menu = 1;
7690     predefinedObjects[j].index_of_child = -1;
7691     predefinedObjects[j].index = j;
7692     j++;
7693 
7694     // Initial Planning Point
7695     // set up to draw as two objects with different probability circles
7696     xastir_snprintf(predefinedObjects[j].call,sizeof(predefinedObjects[j].call),"IPP_");
7697     xastir_snprintf(predefinedObjects[j].page,sizeof(predefinedObjects[j].page),"/");
7698     xastir_snprintf(predefinedObjects[j].symbol,sizeof(predefinedObjects[j].symbol),"/");
7699     xastir_snprintf(predefinedObjects[j].data,sizeof(predefinedObjects[j].data)," Pmin0.75,Pmax1.0");
7700     xastir_snprintf(predefinedObjects[j].menu_call,sizeof(predefinedObjects[j].menu_call),"[not shown]");
7701     // show on menu = 0 will hide this entry on menu
7702     predefinedObjects[j].show_on_menu = 0;
7703     predefinedObjects[j].index_of_child = -1;
7704     predefinedObjects[j].index = j;
7705     j++;
7706     xastir_snprintf(predefinedObjects[j].call,sizeof(predefinedObjects[j].call),"IPP");
7707     xastir_snprintf(predefinedObjects[j].page,sizeof(predefinedObjects[j].page),"/");
7708     xastir_snprintf(predefinedObjects[j].symbol,sizeof(predefinedObjects[j].symbol),"/");
7709     xastir_snprintf(predefinedObjects[j].data,sizeof(predefinedObjects[j].data)," Pmin0.25,Pmax0.5");
7710     xastir_snprintf(predefinedObjects[j].menu_call,sizeof(predefinedObjects[j].menu_call),"IPP: InitialPlanningPoint");
7711     predefinedObjects[j].show_on_menu = 1;
7712     // index of child j - 1 will add additional callback to IPP_
7713     predefinedObjects[j].index_of_child = j - 1;
7714     predefinedObjects[j].index = j;
7715     j++;
7716 
7717     // Point last seen
7718     xastir_snprintf(predefinedObjects[j].call,sizeof(predefinedObjects[j].call),"PLS");
7719     xastir_snprintf(predefinedObjects[j].page,sizeof(predefinedObjects[j].page),"/");
7720     xastir_snprintf(predefinedObjects[j].symbol,sizeof(predefinedObjects[j].symbol),"/");
7721     xastir_snprintf(predefinedObjects[j].data,sizeof(predefinedObjects[j].data),"%c",'\0');
7722     xastir_snprintf(predefinedObjects[j].menu_call,sizeof(predefinedObjects[j].menu_call),"PLS: Point Last Seen");
7723     predefinedObjects[j].show_on_menu = 1;
7724     predefinedObjects[j].index_of_child = -1;
7725     predefinedObjects[j].index = j;
7726     j++;
7727 
7728 
7729     // Last known point
7730     xastir_snprintf(predefinedObjects[j].call,sizeof(predefinedObjects[j].call),"LKP");
7731     xastir_snprintf(predefinedObjects[j].page,sizeof(predefinedObjects[j].page),"/");
7732     xastir_snprintf(predefinedObjects[j].symbol,sizeof(predefinedObjects[j].symbol),".");
7733     xastir_snprintf(predefinedObjects[j].data,sizeof(predefinedObjects[j].data),"%c",'\0');
7734     xastir_snprintf(predefinedObjects[j].menu_call,sizeof(predefinedObjects[j].menu_call),"LKP: Last Known Point");
7735     predefinedObjects[j].show_on_menu = 1;
7736     predefinedObjects[j].index_of_child = -1;
7737     predefinedObjects[j].index = j;
7738     j++;
7739 
7740     // Base
7741     xastir_snprintf(predefinedObjects[j].call,sizeof(predefinedObjects[j].call),"Base");
7742     xastir_snprintf(predefinedObjects[j].page,sizeof(predefinedObjects[j].page),"B");
7743     xastir_snprintf(predefinedObjects[j].symbol,sizeof(predefinedObjects[j].symbol),"0");
7744     xastir_snprintf(predefinedObjects[j].data,sizeof(predefinedObjects[j].data),"%c",'\0');
7745     xastir_snprintf(predefinedObjects[j].menu_call,sizeof(predefinedObjects[j].menu_call),"Base");
7746     predefinedObjects[j].show_on_menu = 1;
7747     predefinedObjects[j].index_of_child = -1;
7748     predefinedObjects[j].index = j;
7749     j++;
7750 
7751     // Helibase (helicopter support base)
7752     xastir_snprintf(predefinedObjects[j].call,sizeof(predefinedObjects[j].call),"Helibase");
7753     xastir_snprintf(predefinedObjects[j].page,sizeof(predefinedObjects[j].page),"H");
7754     xastir_snprintf(predefinedObjects[j].symbol,sizeof(predefinedObjects[j].symbol),"0");
7755     xastir_snprintf(predefinedObjects[j].data,sizeof(predefinedObjects[j].data),"%c",'\0');
7756     xastir_snprintf(predefinedObjects[j].menu_call,sizeof(predefinedObjects[j].menu_call),"Helibase");
7757     predefinedObjects[j].show_on_menu = 1;
7758     predefinedObjects[j].index_of_child = -1;
7759     predefinedObjects[j].index = j;
7760     j++;
7761 
7762     // Helispot  (helicopter landing spot)
7763     // Heli- will be created as Heli-1, Heli-2, Heli-3, etc.
7764     // terminal - on a call is a magic character. see Create_SAR+Object.
7765     xastir_snprintf(predefinedObjects[j].call,sizeof(predefinedObjects[j].call),"Heli-");
7766     xastir_snprintf(predefinedObjects[j].page,sizeof(predefinedObjects[j].page),"/");
7767     xastir_snprintf(predefinedObjects[j].symbol,sizeof(predefinedObjects[j].symbol),"/");
7768     xastir_snprintf(predefinedObjects[j].data,sizeof(predefinedObjects[j].data),"%c",'\0');
7769     xastir_snprintf(predefinedObjects[j].menu_call,sizeof(predefinedObjects[j].menu_call),"Heli-n: Helispot");
7770     predefinedObjects[j].show_on_menu = 1;
7771     predefinedObjects[j].index_of_child = -1;
7772     predefinedObjects[j].index = j;
7773     j++;
7774 
7775     // Camp
7776     xastir_snprintf(predefinedObjects[j].call,sizeof(predefinedObjects[j].call),"Camp");
7777     xastir_snprintf(predefinedObjects[j].page,sizeof(predefinedObjects[j].page),"C");
7778     xastir_snprintf(predefinedObjects[j].symbol,sizeof(predefinedObjects[j].symbol),"0");
7779     xastir_snprintf(predefinedObjects[j].data,sizeof(predefinedObjects[j].data),"%c",'\0');
7780     xastir_snprintf(predefinedObjects[j].menu_call,sizeof(predefinedObjects[j].menu_call),"Camp");
7781     predefinedObjects[j].show_on_menu = 1;
7782     predefinedObjects[j].index_of_child = -1;
7783     predefinedObjects[j].index = j;
7784     j++;
7785 
7786   }
7787 
7788   // Could read additional entries from a file here.
7789   // The total number of entries should be left fairly small
7790   // to prevent the menu from becoming too large and unweildy.
7791 
7792   number_of_predefined_objects = j;
7793   if (number_of_predefined_objects>MAX_NUMBER_OF_PREDEFINED_OBJECTS)
7794   {
7795     // need beter handling of this - we will allready have run
7796     // past the end of the array if we have reached here.
7797     number_of_predefined_objects=MAX_NUMBER_OF_PREDEFINED_OBJECTS;
7798   }
7799 }
7800 
7801 
7802 
7803 
7804 
7805 /* Create a predefined SAR/Public Event object
7806    Create an object of the specified type at the current mouse position
7807    without a dialog.
7808    Current undesirable behavior: If an object of the same name exists,
7809    takes control of that object and moves it to the current mouse position.
7810 
7811    clientData is pointer to an integer representing the index of a
7812    predefined object in the predefinedObjects array
7813    */
7814 void Create_SAR_Object(Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(calldata) )
7815 {
7816   Dimension width, height;
7817   char call[MAX_CALLSIGN+1];
7818   long x_lat,x_lon;
7819   char origin[MAX_CALLSIGN+1];  // mycall
7820   char data[MAX_LINE_SIZE];
7821   char page[2];
7822   // reserve space for probability circle as well as symbol /Pmin0.25,Pmax0.5,
7823   char symbol_plus[PREDEFINED_OBJECT_DATA_LENGTH];
7824   char symbol[2];
7825   char c_lon[10];
7826   char c_lat[10];
7827   char time[7];
7828   intptr_t i;
7829   DataRow *p_station;
7830   int done = 0;
7831   int iterations_left = 1000; // Max iterations of while loop below
7832   int extra_num = 1;
7833   char orig_call[MAX_CALLSIGN+1];
7834 
7835 
7836   // set some defaults in case of a non-matched value
7837   xastir_snprintf(page,sizeof(page),"/");
7838   xastir_snprintf(symbol,sizeof(symbol),"/");
7839   xastir_snprintf(call, sizeof(call), "Marker");
7840 
7841   //for (i=0;i<number_of_predefined_objects;i++) {
7842   //   if (strcmp((char *)clientData,predefinedObjects[i].call)==0) {
7843   i = (intptr_t)clientData;
7844   if (i > -1)
7845   {
7846     if (i <= number_of_predefined_objects)
7847     {
7848       xastir_snprintf(page,sizeof(page), "%s", predefinedObjects[i].page);
7849       xastir_snprintf(symbol,sizeof(symbol), "%s", predefinedObjects[i].symbol);
7850       xastir_snprintf(call, sizeof(call), "%s", predefinedObjects[i].call);
7851       xastir_snprintf(symbol_plus, sizeof(symbol_plus), "%s%s",symbol,predefinedObjects[i].data);
7852     }
7853   }
7854 
7855   // Get mouse position.
7856   XtVaGetValues(da,XmNwidth, &width,XmNheight, &height, NULL);
7857   x_lon = center_longitude - ((width *scale_x)/2) + (menu_x*scale_x);
7858   x_lat = center_latitude  - ((height*scale_y)/2) + (menu_y*scale_y);
7859   if(debug_level & 1)
7860     fprintf(stderr, "Creating symbol %s %s at: %lu %lu with calldata: [%li]\n",
7861             page,
7862             symbol,
7863             x_lat,
7864             x_lon,
7865             (intptr_t)clientData);
7866 
7867   // CONVERT_LP_NOSP      = DDMM.MMN
7868   convert_lat_l2s(x_lat, (char *)c_lat, sizeof(c_lat), CONVERT_LP_NOSP);
7869   convert_lon_l2s(x_lon, (char *)c_lon, sizeof(c_lon), CONVERT_LP_NOSP);
7870 
7871 
7872   // Save "call" away in "orig_call" so that we can use it again
7873   // and again as we try to come up with a unique name for the
7874   // object.
7875   //
7876   xastir_snprintf(orig_call,
7877                   sizeof(orig_call),
7878                   "%s",
7879                   call);
7880 
7881   // '-' is a magic character.
7882   //
7883   // If the last character in call is a "-", the symbol is expected
7884   // to be a numeric series starting with call-1, so change call to
7885   // call-1.  This lets us describe Heli- and create Heli-1, Heli-2
7886   // and similar series.  Storing call to orig_call before appending
7887   // the number should allow the sequence to increment normally.
7888   if ((int)'-'==(int)*(call+(strlen(call)-1)))
7889   {
7890     // make sure that we don't write past the end of call
7891     if (strlen(call)<MAX_CALLSIGN)
7892     {
7893       strncat(call,"1",sizeof(call)-strlen(call)-1);
7894     }
7895   }
7896   // Check object names against our station database until we find
7897   // a unique name or a killed object name we can use.
7898   //
7899   while (!done && iterations_left)
7900   {
7901     char num_string[10];
7902 
7903     // Create object as owned by own station, or take control of
7904     // object if it has another owner.  Taking control of a
7905     // received object is probably not a desirable behavior.
7906 
7907     if (!search_station_name(&p_station,call,1))
7908     {
7909       //
7910       // No match found with the original name, so the name
7911       // for our object is ok to use.  Get out of the while
7912       // loop and create the object.
7913       //
7914       done++;
7915       continue;   // Next loop iteration (Exit the while loop)
7916     }
7917 
7918 
7919     // If we get to here, a station with this name exists.  We
7920     // have a pointer to it with p_station.
7921     //
7922     // If object or item and killed, use the old name to create
7923     // a new object.
7924     //
7925     // If not killed or not object/item, pick a new name by
7926     // adding digits onto the end of the old name until we don't
7927     // have a name collision or we find an old object or item by
7928     // that name that has been killed.
7929 
7930 
7931     // Check whether object or item.  If so, check whether killed.
7932     if ((p_station->flag & (ST_OBJECT | ST_ITEM)) != 0)   // It's an object or item
7933     {
7934 
7935       // Check whether object/item has been killed already
7936       if ((p_station->flag & ST_ACTIVE) != ST_ACTIVE)
7937       {
7938         //
7939         // The object or item has been killed.  Ok to use
7940         // this object name.  Get out of the while loop and
7941         // create the object.
7942         //
7943         done++;
7944         continue;   // Next loop iteration (Exit the while loop)
7945       }
7946     }
7947 
7948 
7949 // If we get to this point we have an object name that matches
7950 // another in our database.  We must come up with a new name.  We
7951 // add digits to the end of the original name until we get one that
7952 // works for us.
7953 
7954 
7955 
7956     /*
7957             // If my_callsign (Exact match includes SSID)
7958     //        if (is_my_call(p_station->origin,1)) {
7959             if (is_my_object_item(p_station)) {
7960 
7961                 // The previous object with the same name is owned by
7962                 // me.
7963                 //   a) MOVE the EXISTING object (default), perhaps with the option
7964                 //      to clear the track.  Clearing the track would only take
7965                 //      effect on our local map screen, not on everyone else's.
7966                 //   b) RENAME the NEW object, perhaps tacking a number
7967                 //   onto the end until we get to an unused name.
7968                 //   c) CANCEL request
7969 
7970 
7971     fprintf(stderr, "Object with same name exists, owned by me\n");
7972 
7973     // Pop up a new dialog with the various options on it.  Save our
7974     // state here so that we can create the object in the callbacks for
7975     // the next dialog.
7976     //
7977     // Code goes here...
7978 
7979 
7980             else {
7981                 // The previous object with the same name is NOT owned
7982                 // by me.
7983                 //   a) ADOPT the existing object and MOVE it (a very
7984                 //      poor idea).
7985                 //      Same track-clearing as option 1a.
7986                 //   b) RENAME the NEW object (default), perhaps tacking
7987                 //   a number onto the end until we get to an unused
7988                 //   name.
7989                 //   c) CANCEL request
7990 
7991 
7992     fprintf(stderr, "Object with same name exists, owned by %s\n", p_station->origin);
7993 
7994     // Pop up a new dialog with the various options on it.  Save our
7995     // state here so that we can create the object in the callbacks for
7996     // the next dialog.
7997     //
7998     // Code goes here...
7999 
8000 
8001             }
8002     */
8003 
8004 
8005     extra_num++;
8006 
8007     // Append extra_num to the object name (starts at "2"), try
8008     // again to see if it is unique.
8009     //
8010     // Note: Converting to float only to use width specifiers
8011     // properly and quiet a compiler warning.
8012     xastir_snprintf(num_string, sizeof(num_string), "%2.0f", (float)extra_num);
8013     strcpy(call, orig_call);
8014     call[sizeof(call)-1] = '\0';  // Terminate string
8015     strcat(call, num_string);
8016     call[sizeof(call)-1] = '\0';  // Terminate string
8017 // ****** Bug ********
8018 // need to check length of call - if it has gone over 9 characters only
8019 // the first 9 will be treated as unique, thus FirstAid11 will become FirstAid1
8020 // and become new position for existing FirstAid1.
8021 // MAX_CALLSIGN is the constraining global.
8022 // In that case, need to fail gracefully and throw an error message.
8023     iterations_left--;
8024 
8025   }   // End of while loop
8026 
8027 
8028   if (iterations_left == 0)
8029   {
8030 // Pop up a message stating that we couldn't find an empty name in
8031 // 1000 iterations.  Call popup_message_always()
8032 
8033     fprintf(stderr, "No more iterations left\n");
8034 
8035   }
8036 
8037 
8038   xastir_snprintf(origin,
8039                   sizeof(origin),
8040                   "%s", my_callsign);
8041   xastir_snprintf(time, sizeof(time), "%02d%02d%02d",
8042                   get_hours(),
8043                   get_minutes(),
8044                   get_seconds() );
8045   // Prepare APRS data string using latitude and longitude from mouse click location
8046   // and page, symbol, and any additional data from the prepared object.
8047   xastir_snprintf(data,
8048                   sizeof(data),
8049                   ";%-9s*%sh%s%s%s%s",
8050                   call,
8051                   time,
8052                   c_lat,
8053                   page,
8054                   c_lon,
8055                   symbol_plus);
8056 
8057 //fprintf(stderr,"Packet:%s\n", data);
8058 
8059   log_object_item(data,0,last_object);
8060 
8061 // *********** New objects not being displayed on map untill restart
8062 
8063 
8064   if (object_tx_disable || transmit_disable)
8065   {
8066     output_my_data(data,-1,0,1,0,NULL);  // Local loopback only, not igating
8067   }
8068   else
8069   {
8070     output_my_data(data,-1,0,0,0,NULL);  // Transmit/loopback object data, not igating
8071   }
8072 }
8073 
8074 
8075 
8076 
8077 
8078 // Fill in fields from an existing object/item or create the proper
8079 // transmit string for a new object/item from these fields.
8080 /*
8081  *  Setup Object/Item Dialog
8082  *  clientData = pointer to object struct, if it's a modify or a move operation,
8083  *  else it's NULL.
8084  *  If calldata = 2, then we're doing a move object operation.  We want in that
8085  *  case to fill in the new values for lat/long and make them take effect.
8086  *  If calldata = 1, then we've dropped through Station_info/Station_data
8087  *  on the way to Modify->Object.
8088  *  Need to put the tests for the different types of objects
8089  *  at the top of this function, then the dialog will build properly for
8090  *  the type of object initially.
8091  */
8092 void Set_Del_Object( Widget w, XtPointer clientData, XtPointer calldata)
8093 {
8094   Dimension width, height;
8095   long lat,lon;
8096   char lat_str[MAX_LAT];
8097   char lon_str[MAX_LONG];
8098   static Widget ob_pane, ob_scrollwindow, ob_form,
8099          ob_name,ob_latlon_frame,ob_latlon_form,
8100          ob_lat, ob_lat_deg, ob_lat_min,
8101          ob_lon, ob_lon_deg, ob_lon_min, ob_lon_ew,
8102          ob_form1,
8103          signpost_form,
8104          signpost_label,
8105          probability_frame,probability_form,
8106          probability_label_min, probability_label_max,
8107          ob_option_form,
8108          area_form,
8109          bright_dim_toggle,
8110          shape_box,toption1,toption2,toption3,toption4,toption5,
8111          color_box,coption1,coption2,coption3,coption4,coption5,coption6,coption7,coption8,
8112          formomni,
8113          signal_box,soption0,soption1,soption2,soption3,soption4,soption5,soption6,soption7,soption8,soption9,
8114          height_box,hoption0,hoption1,hoption2,hoption3,hoption4,hoption5,hoption6,hoption7,hoption8,hoption9,
8115          gain_box,goption0,goption1,goption2,goption3,goption4,goption5,goption6,goption7,goption8,goption9,
8116          directivity_box,doption0,doption1,doption2,doption3,doption4,doption5,doption6,doption7,doption8,
8117          formbeam,
8118          width_box,woption0,woption1,woption2,woption3,woption4,woption5,woption6,woption7,woption8,woption9,
8119          ob_bearing,
8120          ob_lat_offset,ob_lon_offset,
8121          ob_sep, ob_button_set,ob_button_del,ob_button_cancel,it_button_set,
8122          ob_button_symbol,
8123          compute_button;
8124   char temp_data[40];
8125   Atom delw;
8126   DataRow *p_station = (DataRow *)clientData;
8127   Arg al[50];         /* Arg List */
8128   unsigned int ac;    /* Arg Count */
8129   long x,y;
8130 
8131 
8132   /*
8133       if (p_station != NULL)
8134           fprintf(stderr,"Have a pointer to an object.  ");
8135       else
8136           fprintf(stderr,"No pointer, new object?       ");
8137       if (calldata != NULL) {
8138           if (strcmp(calldata,"2") == 0)
8139               fprintf(stderr,"Set_Del_Object: calldata: 2.  Move object.\n");
8140           else if (strcmp(calldata,"1") == 0)
8141               fprintf(stderr,"Set_Del_Object: calldata: 1.  Modify object.\n");
8142           else if (strcmp(calldata,"0") == 0)
8143               fprintf(stderr,"Set_Del_Object: calldata: 0.  New object.\n");
8144           else
8145               fprintf(stderr,"Set_Del_Object: calldata: invalid.  New object.\n");
8146       }
8147   */
8148 
8149   // Save the data so that other routines can access it.  Some of the
8150   // callbacks can only handle one parameter, and we need two.
8151   if (p_station != NULL)
8152   {
8153     global_parameter1 = clientData;
8154   }
8155   else
8156   {
8157     global_parameter1 = NULL;
8158   }
8159   global_parameter2 = calldata;
8160 
8161 
8162 
8163   // This function can be invoked from the mouse menus or by being called
8164   // directly by other routines.  We look at the p_station pointer to decide
8165   // how we were called.
8166   //
8167   if (p_station != NULL)    // We were called from the Modify_object()
8168   {
8169     // or Move() functions
8170     //fprintf(stderr,"Got a pointer!\n");
8171     lon = p_station->coord_lon;     // Fill in values from the original object
8172     lat = p_station->coord_lat;
8173   }
8174   else
8175   {
8176     // We were called from the "Create New Object" mouse menu or
8177     // by the "Move" option get default position for object, the
8178     // position we have clicked at.  For the special case of a
8179     // Map View object, we instead want the screen center for
8180     // this new object.
8181     //
8182     if (Map_View_object_enabled)
8183     {
8184       // Get center of screen
8185       lon = center_longitude;
8186       lat = center_latitude;
8187     }
8188     else
8189     {
8190       // Get mouse position
8191       XtVaGetValues(da,XmNwidth, &width,XmNheight, &height, NULL);
8192       lon = center_longitude - ((width *scale_x)/2) + (menu_x*scale_x);
8193       lat = center_latitude  - ((height*scale_y)/2) + (menu_y*scale_y);
8194     }
8195   }
8196 
8197 
8198   // If the object dialog is up, we need to kill it and draw a new
8199   // one so that we have the correct values filled in.
8200   if (object_dialog)
8201   {
8202     Object_destroy_shell( w, object_dialog, NULL);
8203   }
8204 
8205 
8206   // Check for the three "Special" types of objects we deal with and set
8207   // the global variables for them here.  This will result in the correct
8208   // type of dialog being drawn for each type of object.
8209 // Question:  What about for Modify->Object where we're trying to change
8210 // the type of the object?
8211 
8212   if (p_station != NULL)
8213   {
8214     /*
8215             if (calldata != NULL) {
8216                 if (strcmp(calldata,"2") == 0)
8217                     fprintf(stderr,"Set_Del_Object: calldata: 2.  Move object.\n");
8218                 else if (strcmp(calldata,"1") == 0)
8219                     fprintf(stderr,"Set_Del_Object: calldata: 1.  Modify object.\n");
8220                 else if (strcmp(calldata,"0") == 0)
8221                     fprintf(stderr,"Set_Del_Object: calldata: 0.  New object.\n");
8222                 else
8223                     fprintf(stderr,"Set_Del_Object: calldata: invalid.  New object.\n");
8224             }
8225     */
8226 
8227     // Check to see whether we should even be here at all!
8228     if ( !(p_station->flag & ST_OBJECT)
8229          && !(p_station->flag & ST_ITEM))    // Not an object or item
8230     {
8231       //fprintf(stderr,"flag: %i\n", (int)p_station->flag);
8232       popup_message_always(langcode("POPEM00022"),
8233                            langcode("POPEM00043") ); // "Not an Object/Item!"
8234       return;
8235     }
8236 
8237     // Set to known defaults first
8238     Area_object_enabled = 0;
8239     Signpost_object_enabled = 0;
8240     DF_object_enabled = 0;
8241     Map_View_object_enabled = 0;
8242     Probability_circles_enabled = 0;
8243 
8244     if (p_station->aprs_symbol.area_object.type != AREA_NONE)   // Found an area object
8245     {
8246       Area_object_enabled = 1;
8247     }
8248     else if ( (p_station->aprs_symbol.aprs_symbol == 'm') // Found a signpost object
8249               && (p_station->aprs_symbol.aprs_type == '\\') )
8250     {
8251       Signpost_object_enabled = 1;
8252     }
8253     else if ( (p_station->aprs_symbol.aprs_symbol == '\\') // Found a DF object
8254               && (p_station->aprs_symbol.aprs_type == '/')
8255               && ((strlen(p_station->signal_gain) == 7) // That has data associated with it
8256                   || (strlen(p_station->bearing) == 3)
8257                   || (strlen(p_station->NRQ) == 3) ) )
8258     {
8259       DF_object_enabled = 1;
8260     }
8261     else if ( (p_station->aprs_symbol.aprs_symbol == 'E') // Found a Map View object
8262               && (p_station->aprs_symbol.aprs_type == '/')
8263               && (strstr(p_station->power_gain,"RNG") != 0) )   // Has a range value
8264     {
8265 
8266       //fprintf(stderr,"Found a range\n");
8267       Map_View_object_enabled = 1;
8268     }
8269 
8270     else if (p_station->probability_min[0] != '\0'      // Found some data
8271              || p_station->probability_max[0] != '\0')   // Found some data
8272     {
8273       Probability_circles_enabled = 1;
8274     }
8275   }
8276 
8277   //fprintf(stderr,"Area:Signpost:DF  %i:%i:%i\n",Area_object_enabled,Signpost_object_enabled,DF_object_enabled);
8278 
8279 // Ok.  The stage is now set to draw the proper type of dialog for the
8280 // type of object we're interested in currently.
8281 
8282 
8283   if(object_dialog)           // it is already open
8284   {
8285     (void)XRaiseWindow(XtDisplay(object_dialog), XtWindow(object_dialog));
8286   }
8287   else                        // create new popup window
8288   {
8289     object_dialog = XtVaCreatePopupShell(langcode("POPUPOB001"),
8290                                          xmDialogShellWidgetClass,   appshell,
8291                                          XmNdeleteResponse,          XmDESTROY,
8292                                          XmNdefaultPosition,         FALSE,
8293                                          XmNfontList, fontlist1,
8294                                          NULL);
8295 
8296     ob_pane = XtVaCreateWidget("Set_Del_Object pane",
8297                                xmPanedWindowWidgetClass,
8298                                object_dialog,
8299                                MY_FOREGROUND_COLOR,
8300                                MY_BACKGROUND_COLOR,
8301                                XmNfontList, fontlist1,
8302                                NULL);
8303 
8304     ob_scrollwindow = XtVaCreateManagedWidget("scrollwindow",
8305                                               xmScrolledWindowWidgetClass,
8306                                               ob_pane,
8307                                               XmNscrollingPolicy, XmAUTOMATIC,
8308                                               NULL);
8309 
8310     ob_form =  XtVaCreateWidget("Set_Del_Object ob_form",
8311                                 xmFormWidgetClass,
8312                                 ob_scrollwindow,
8313                                 XmNfractionBase,            3,
8314                                 XmNautoUnmanage,            FALSE,
8315                                 XmNshadowThickness,         1,
8316                                 MY_FOREGROUND_COLOR,
8317                                 MY_BACKGROUND_COLOR,
8318                                 XmNfontList, fontlist1,
8319                                 NULL);
8320 
8321     // "Name"
8322     ob_name = XtVaCreateManagedWidget(langcode("POPUPOB002"),
8323                                       xmLabelWidgetClass,
8324                                       ob_form,
8325                                       XmNtopAttachment,           XmATTACH_FORM,
8326                                       XmNtopOffset,               10,
8327                                       XmNbottomAttachment,        XmATTACH_NONE,
8328                                       XmNleftAttachment,          XmATTACH_FORM,
8329                                       XmNleftOffset,              10,
8330                                       XmNrightAttachment,         XmATTACH_NONE,
8331                                       MY_FOREGROUND_COLOR,
8332                                       MY_BACKGROUND_COLOR,
8333                                       XmNfontList, fontlist1,
8334                                       NULL);
8335     // object name
8336     object_name_data = XtVaCreateManagedWidget("Set_Del_Object name_data",
8337                        xmTextFieldWidgetClass,
8338                        ob_form,
8339                        XmNeditable,                TRUE,
8340                        XmNcursorPositionVisible,   TRUE,
8341                        XmNsensitive,               TRUE,
8342                        XmNshadowThickness,         1,
8343                        XmNcolumns,                 9,
8344                        XmNmaxLength,               9,
8345                        XmNtopAttachment,           XmATTACH_FORM,
8346                        XmNtopOffset,               5,
8347                        XmNbottomAttachment,        XmATTACH_NONE,
8348                        XmNleftAttachment,          XmATTACH_WIDGET,
8349                        XmNleftWidget,              ob_name,
8350                        XmNrightAttachment,         XmATTACH_NONE,
8351                        XmNbackground,              colors[0x0f],
8352                        XmNfontList, fontlist1,
8353                        NULL);
8354 
8355 
8356 //----- Frame for table / symbol
8357     ob_frame = XtVaCreateManagedWidget("Set_Del_Object ob_frame",
8358                                        xmFrameWidgetClass,
8359                                        ob_form,
8360                                        XmNtopAttachment,           XmATTACH_WIDGET,
8361                                        XmNtopWidget,               object_name_data,
8362                                        XmNtopOffset,               10,
8363                                        XmNbottomAttachment,        XmATTACH_NONE,
8364                                        XmNleftAttachment,          XmATTACH_FORM,
8365                                        XmNleftOffset,              10,
8366                                        XmNrightAttachment,         XmATTACH_NONE,
8367                                        MY_FOREGROUND_COLOR,
8368                                        MY_BACKGROUND_COLOR,
8369                                        XmNfontList, fontlist1,
8370                                        NULL);
8371     // "Station Symbol"
8372     // ob_ts
8373     (void)XtVaCreateManagedWidget(langcode("WPUPCFS009"),
8374                                   xmLabelWidgetClass,
8375                                   ob_frame,
8376                                   XmNchildType,               XmFRAME_TITLE_CHILD,
8377                                   MY_FOREGROUND_COLOR,
8378                                   MY_BACKGROUND_COLOR,
8379                                   XmNfontList, fontlist1,
8380                                   NULL);
8381 
8382     ob_form1 =  XtVaCreateWidget("Set_Del_Object form1",
8383                                  xmFormWidgetClass,
8384                                  ob_frame,
8385                                  XmNfractionBase,            5,
8386                                  MY_FOREGROUND_COLOR,
8387                                  MY_BACKGROUND_COLOR,
8388                                  XmNfontList, fontlist1,
8389                                  NULL);
8390 
8391     // "Group/overlay"
8392     ob_group = XtVaCreateManagedWidget(langcode("WPUPCFS010"),
8393                                        xmLabelWidgetClass,
8394                                        ob_form1,
8395                                        XmNtopAttachment,           XmATTACH_FORM,
8396                                        XmNtopOffset,               8,
8397                                        XmNbottomAttachment,        XmATTACH_FORM,
8398                                        XmNbottomOffset,            10,
8399                                        XmNleftAttachment,          XmATTACH_FORM,
8400                                        XmNleftOffset,              10,
8401                                        XmNrightAttachment,         XmATTACH_NONE,
8402                                        MY_FOREGROUND_COLOR,
8403                                        MY_BACKGROUND_COLOR,
8404                                        XmNfontList, fontlist1,
8405                                        NULL);
8406     // table
8407     object_group_data = XtVaCreateManagedWidget("Set_Del_Object group",
8408                         xmTextFieldWidgetClass,
8409                         ob_form1,
8410                         XmNeditable,                TRUE,
8411                         XmNcursorPositionVisible,   FALSE,
8412                         XmNsensitive,               TRUE,
8413                         XmNshadowThickness,         1,
8414                         XmNcolumns,                 1,
8415                         XmNmaxLength,               1,
8416                         XmNtopOffset,               3,
8417                         XmNbackground,              colors[0x0f],
8418                         XmNleftAttachment,          XmATTACH_WIDGET,
8419                         XmNleftWidget,              ob_group,
8420                         XmNleftOffset,              5,
8421                         XmNtopAttachment,           XmATTACH_FORM,
8422                         XmNbottomAttachment,        XmATTACH_NONE,
8423                         XmNrightAttachment,         XmATTACH_NONE,
8424                         XmNfontList, fontlist1,
8425                         NULL);
8426 
8427     // "Symbol"
8428     ob_symbol = XtVaCreateManagedWidget(langcode("WPUPCFS011"),
8429                                         xmLabelWidgetClass,
8430                                         ob_form1,
8431                                         XmNtopAttachment,           XmATTACH_FORM,
8432                                         XmNtopOffset,               8,
8433                                         XmNbottomAttachment,        XmATTACH_NONE,
8434                                         XmNleftAttachment,          XmATTACH_WIDGET,
8435                                         XmNleftWidget,              object_group_data,
8436                                         XmNleftOffset,              20,
8437                                         XmNrightAttachment,         XmATTACH_NONE,
8438                                         MY_FOREGROUND_COLOR,
8439                                         MY_BACKGROUND_COLOR,
8440                                         XmNfontList, fontlist1,
8441                                         NULL);
8442     // symbol
8443     object_symbol_data = XtVaCreateManagedWidget("Set_Del_Object symbol",
8444                          xmTextFieldWidgetClass,
8445                          ob_form1,
8446                          XmNeditable,                TRUE,
8447                          XmNcursorPositionVisible,   FALSE,
8448                          XmNsensitive,               TRUE,
8449                          XmNshadowThickness,         1,
8450                          XmNcolumns,                 1,
8451                          XmNmaxLength,               1,
8452                          XmNtopOffset,               3,
8453                          XmNbackground,              colors[0x0f],
8454                          XmNleftAttachment,          XmATTACH_WIDGET,
8455                          XmNleftWidget,              ob_symbol,
8456                          XmNleftOffset,              5,
8457                          XmNtopAttachment,           XmATTACH_FORM,
8458                          XmNbottomAttachment,        XmATTACH_NONE,
8459                          XmNrightAttachment,         XmATTACH_NONE,
8460                          XmNfontList, fontlist1,
8461                          NULL);
8462 
8463     // icon
8464     Ob_icon0 = XCreatePixmap(XtDisplay(appshell),
8465                              RootWindowOfScreen(XtScreen(appshell)),
8466                              20,
8467                              20,
8468                              DefaultDepthOfScreen(XtScreen(appshell)));
8469     Ob_icon  = XCreatePixmap(XtDisplay(appshell),
8470                              RootWindowOfScreen(XtScreen(appshell)),
8471                              20,
8472                              20,
8473                              DefaultDepthOfScreen(XtScreen(appshell)));
8474     object_icon = XtVaCreateManagedWidget("Set_Del_Object icon",
8475                                           xmLabelWidgetClass,
8476                                           ob_form1,
8477                                           XmNlabelType,               XmPIXMAP,
8478                                           XmNlabelPixmap,             Ob_icon,
8479                                           XmNleftAttachment,          XmATTACH_WIDGET,
8480                                           XmNleftWidget,              object_symbol_data,
8481                                           XmNleftOffset,              15,
8482                                           XmNtopAttachment,           XmATTACH_FORM,
8483                                           XmNtopOffset,               8,
8484                                           XmNbottomAttachment,        XmATTACH_NONE,
8485                                           XmNrightAttachment,         XmATTACH_NONE,
8486                                           MY_FOREGROUND_COLOR,
8487                                           MY_BACKGROUND_COLOR,
8488                                           XmNfontList, fontlist1,
8489                                           NULL);
8490 
8491     ob_button_symbol = XtVaCreateManagedWidget(langcode("WPUPCFS028"),
8492                        xmPushButtonGadgetClass,
8493                        ob_form1,
8494                        XmNtopAttachment,           XmATTACH_FORM,
8495                        XmNtopOffset,               2,
8496                        XmNbottomAttachment,        XmATTACH_NONE,
8497                        XmNleftAttachment,          XmATTACH_WIDGET,
8498                        XmNleftWidget,              object_icon,
8499                        XmNleftOffset,              5,
8500                        XmNrightAttachment,         XmATTACH_FORM,
8501                        XmNrightOffset,             5,
8502                        XmNnavigationType,          XmTAB_GROUP,
8503                        MY_FOREGROUND_COLOR,
8504                        MY_BACKGROUND_COLOR,
8505                        XmNfontList, fontlist1,
8506                        NULL);
8507     XtAddCallback(ob_button_symbol, XmNactivateCallback, Ob_change_symbol, object_dialog);
8508 
8509 //----- Frame for Lat/Long
8510     ob_latlon_frame = XtVaCreateManagedWidget("Set_Del_Object ob_latlon_frame",
8511                       xmFrameWidgetClass,
8512                       ob_form,
8513                       XmNtopAttachment,           XmATTACH_FORM,
8514                       XmNtopOffset,               10,
8515                       XmNbottomAttachment,        XmATTACH_NONE,
8516                       XmNleftAttachment,          XmATTACH_WIDGET,
8517                       XmNleftWidget,              ob_frame,
8518                       XmNleftOffset,              10,
8519                       XmNrightAttachment,         XmATTACH_FORM,
8520                       XmNrightOffset,             10,
8521                       MY_FOREGROUND_COLOR,
8522                       MY_BACKGROUND_COLOR,
8523                       NULL);
8524 
8525     // "Location"
8526     //ob_latlon_ts
8527     (void)XtVaCreateManagedWidget(langcode("POPUPOB028"),
8528                                   xmLabelWidgetClass,
8529                                   ob_latlon_frame,
8530                                   XmNchildType,               XmFRAME_TITLE_CHILD,
8531                                   MY_FOREGROUND_COLOR,
8532                                   MY_BACKGROUND_COLOR,
8533                                   XmNfontList, fontlist1,
8534                                   NULL);
8535 
8536     ob_latlon_form =  XtVaCreateWidget("Set_Del_Object ob_latlon_form",
8537                                        xmFormWidgetClass,
8538                                        ob_latlon_frame,
8539                                        XmNfractionBase,            5,
8540                                        MY_FOREGROUND_COLOR,
8541                                        MY_BACKGROUND_COLOR,
8542                                        XmNfontList, fontlist1,
8543                                        NULL);
8544 
8545     // "LAT"
8546     ob_lat = XtVaCreateManagedWidget(langcode("WPUPCFS003"),
8547                                      xmLabelWidgetClass,
8548                                      ob_latlon_form,
8549                                      XmNtopAttachment,           XmATTACH_FORM,
8550                                      XmNtopOffset,               10,
8551                                      XmNbottomAttachment,        XmATTACH_NONE,
8552                                      XmNleftAttachment,          XmATTACH_FORM,
8553                                      XmNleftOffset,              15,
8554                                      XmNrightAttachment,         XmATTACH_NONE,
8555                                      MY_FOREGROUND_COLOR,
8556                                      MY_BACKGROUND_COLOR,
8557                                      XmNfontList, fontlist1,
8558                                      NULL);
8559     // lat deg
8560     object_lat_data_deg = XtVaCreateManagedWidget("Set_Del_Object lat_deg",
8561                           xmTextFieldWidgetClass,
8562                           ob_latlon_form,
8563                           XmNeditable,                TRUE,
8564                           XmNcursorPositionVisible,   TRUE,
8565                           XmNsensitive,               TRUE,
8566                           XmNshadowThickness,         1,
8567                           XmNcolumns,                 3,
8568                           XmNmaxLength,               2,
8569                           XmNtopOffset,               5,
8570                           XmNtopAttachment,           XmATTACH_FORM,
8571                           XmNbottomAttachment,        XmATTACH_NONE,
8572                           XmNleftAttachment,          XmATTACH_WIDGET,
8573                           XmNleftWidget,              ob_lat,
8574                           XmNrightAttachment,         XmATTACH_NONE,
8575                           XmNbackground,              colors[0x0f],
8576                           XmNfontList, fontlist1,
8577                           NULL);
8578     // "deg"
8579     ob_lat_deg = XtVaCreateManagedWidget(langcode("WPUPCFS004"),
8580                                          xmLabelWidgetClass,
8581                                          ob_latlon_form,
8582                                          XmNtopAttachment,           XmATTACH_FORM,
8583                                          XmNtopOffset,               10,
8584                                          XmNbottomAttachment,        XmATTACH_NONE,
8585                                          XmNleftAttachment,          XmATTACH_WIDGET,
8586                                          XmNleftWidget,              object_lat_data_deg,
8587                                          XmNrightAttachment,         XmATTACH_NONE,
8588                                          MY_FOREGROUND_COLOR,
8589                                          MY_BACKGROUND_COLOR,
8590                                          XmNfontList, fontlist1,
8591                                          NULL);
8592     // lat min
8593     object_lat_data_min = XtVaCreateManagedWidget("Set_Del_Object lat_min",
8594                           xmTextFieldWidgetClass,
8595                           ob_latlon_form,
8596                           XmNeditable,                TRUE,
8597                           XmNcursorPositionVisible,   TRUE,
8598                           XmNsensitive,               TRUE,
8599                           XmNshadowThickness,         1,
8600                           XmNcolumns,                 6,
8601                           XmNmaxLength,               6,
8602                           XmNtopOffset,               5,
8603                           XmNleftAttachment,          XmATTACH_WIDGET,
8604                           XmNleftWidget,              ob_lat_deg,
8605                           XmNleftOffset,              10,
8606                           XmNtopAttachment,           XmATTACH_FORM,
8607                           XmNbottomAttachment,        XmATTACH_NONE,
8608                           XmNrightAttachment,         XmATTACH_NONE,
8609                           XmNbackground,              colors[0x0f],
8610                           XmNfontList, fontlist1,
8611                           NULL);
8612     // "min"
8613     ob_lat_min = XtVaCreateManagedWidget(langcode("WPUPCFS005"),
8614                                          xmLabelWidgetClass,
8615                                          ob_latlon_form,
8616                                          XmNtopAttachment,           XmATTACH_FORM,
8617                                          XmNtopOffset,               10,
8618                                          XmNbottomAttachment,        XmATTACH_NONE,
8619                                          XmNleftAttachment,          XmATTACH_WIDGET,
8620                                          XmNleftWidget,              object_lat_data_min,
8621                                          XmNrightAttachment,         XmATTACH_NONE,
8622                                          MY_FOREGROUND_COLOR,
8623                                          MY_BACKGROUND_COLOR,
8624                                          XmNfontList, fontlist1,
8625                                          NULL);
8626     // N/S
8627     object_lat_data_ns = XtVaCreateManagedWidget("Set_Del_Object lat_ns",
8628                          xmTextFieldWidgetClass,
8629                          ob_latlon_form,
8630                          XmNeditable,                TRUE,
8631                          XmNcursorPositionVisible,   FALSE,
8632                          XmNsensitive,               TRUE,
8633                          XmNshadowThickness,         1,
8634                          XmNcolumns,                 1,
8635                          XmNmaxLength,               1,
8636                          XmNtopOffset,               5,
8637                          XmNleftAttachment,          XmATTACH_WIDGET,
8638                          XmNleftWidget,              ob_lat_min,
8639                          XmNleftOffset,              10,
8640                          XmNtopAttachment,           XmATTACH_FORM,
8641                          XmNbottomAttachment,        XmATTACH_NONE,
8642                          XmNrightAttachment,         XmATTACH_NONE,
8643                          XmNbackground,              colors[0x0f],
8644                          XmNfontList, fontlist1,
8645                          NULL);
8646     // "(N/S)"
8647     // ob_lat_ns
8648     (void)XtVaCreateManagedWidget(langcode("WPUPCFS006"),
8649                                   xmLabelWidgetClass,
8650                                   ob_latlon_form,
8651                                   XmNtopAttachment,           XmATTACH_FORM,
8652                                   XmNtopOffset,               10,
8653                                   XmNbottomAttachment,        XmATTACH_NONE,
8654                                   XmNleftAttachment,          XmATTACH_WIDGET,
8655                                   XmNleftWidget,              object_lat_data_ns,
8656                                   XmNrightAttachment,         XmATTACH_NONE,
8657                                   MY_FOREGROUND_COLOR,
8658                                   MY_BACKGROUND_COLOR,
8659                                   XmNfontList, fontlist1,
8660                                   NULL);
8661 
8662     // "LONG"
8663     ob_lon = XtVaCreateManagedWidget(langcode("WPUPCFS007"),
8664                                      xmLabelWidgetClass,
8665                                      ob_latlon_form,
8666                                      XmNtopAttachment,           XmATTACH_WIDGET,
8667                                      XmNtopWidget,               ob_lat,
8668                                      XmNtopOffset,               20,
8669                                      XmNbottomAttachment,        XmATTACH_NONE,
8670                                      XmNleftAttachment,          XmATTACH_FORM,
8671                                      XmNleftOffset,              10,
8672                                      XmNrightAttachment,         XmATTACH_NONE,
8673                                      MY_FOREGROUND_COLOR,
8674                                      MY_BACKGROUND_COLOR,
8675                                      XmNfontList, fontlist1,
8676                                      NULL);
8677     // long
8678     object_lon_data_deg = XtVaCreateManagedWidget("Set_Del_Object long_deg",
8679                           xmTextFieldWidgetClass,
8680                           ob_latlon_form,
8681                           XmNeditable,                TRUE,
8682                           XmNcursorPositionVisible,   TRUE,
8683                           XmNsensitive,               TRUE,
8684                           XmNshadowThickness,         1,
8685                           XmNcolumns,                 3,
8686                           XmNmaxLength,               3,
8687                           XmNtopOffset,               14,
8688                           XmNtopAttachment,           XmATTACH_WIDGET,
8689                           XmNtopWidget,               ob_lat,
8690                           XmNbottomAttachment,        XmATTACH_NONE,
8691                           XmNleftAttachment,          XmATTACH_WIDGET,
8692                           XmNleftWidget,              ob_lon,
8693                           XmNrightAttachment,         XmATTACH_NONE,
8694                           XmNbackground,              colors[0x0f],
8695                           XmNfontList, fontlist1,
8696                           NULL);
8697     // "deg"
8698     ob_lon_deg = XtVaCreateManagedWidget(langcode("WPUPCFS004"),
8699                                          xmLabelWidgetClass,
8700                                          ob_latlon_form,
8701                                          XmNtopAttachment,           XmATTACH_WIDGET,
8702                                          XmNtopWidget,               ob_lat,
8703                                          XmNtopOffset,               20,
8704                                          XmNbottomAttachment,        XmATTACH_NONE,
8705                                          XmNleftAttachment,          XmATTACH_WIDGET,
8706                                          XmNleftWidget,              object_lon_data_deg,
8707                                          XmNrightAttachment,         XmATTACH_NONE,
8708                                          MY_FOREGROUND_COLOR,
8709                                          MY_BACKGROUND_COLOR,
8710                                          XmNfontList, fontlist1,
8711                                          NULL);
8712     // min
8713     object_lon_data_min = XtVaCreateManagedWidget("Set_Del_Object long_min",
8714                           xmTextFieldWidgetClass,
8715                           ob_latlon_form,
8716                           XmNeditable,                TRUE,
8717                           XmNcursorPositionVisible,   TRUE,
8718                           XmNsensitive,               TRUE,
8719                           XmNshadowThickness,         1,
8720                           XmNcolumns,                 6,
8721                           XmNmaxLength,               6,
8722                           XmNtopOffset,               14,
8723                           XmNleftAttachment,          XmATTACH_WIDGET,
8724                           XmNleftWidget,              ob_lon_deg,
8725                           XmNleftOffset,              10,
8726                           XmNtopAttachment,           XmATTACH_WIDGET,
8727                           XmNtopWidget,               ob_lat,
8728                           XmNbottomAttachment,        XmATTACH_NONE,
8729                           XmNrightAttachment,         XmATTACH_NONE,
8730                           XmNbackground,              colors[0x0f],
8731                           XmNfontList, fontlist1,
8732                           NULL);
8733     // "min"
8734     ob_lon_min = XtVaCreateManagedWidget(langcode("WPUPCFS005"),
8735                                          xmLabelWidgetClass,
8736                                          ob_latlon_form,
8737                                          XmNtopAttachment,           XmATTACH_WIDGET,
8738                                          XmNtopWidget,               ob_lat,
8739                                          XmNtopOffset,               20,
8740                                          XmNbottomAttachment,        XmATTACH_NONE,
8741                                          XmNleftAttachment,          XmATTACH_WIDGET,
8742                                          XmNleftWidget,              object_lon_data_min,
8743                                          XmNrightAttachment,         XmATTACH_NONE,
8744                                          MY_FOREGROUND_COLOR,
8745                                          MY_BACKGROUND_COLOR,
8746                                          XmNfontList, fontlist1,
8747                                          NULL);
8748     // E/W
8749     object_lon_data_ew = XtVaCreateManagedWidget("Set_Del_Object long_ew",
8750                          xmTextFieldWidgetClass,
8751                          ob_latlon_form,
8752                          XmNeditable,                TRUE,
8753                          XmNcursorPositionVisible,   FALSE,
8754                          XmNsensitive,               TRUE,
8755                          XmNshadowThickness,         1,
8756                          XmNcolumns,                 1,
8757                          XmNmaxLength,               1,
8758                          XmNtopOffset,               14,
8759                          XmNleftAttachment,          XmATTACH_WIDGET,
8760                          XmNleftWidget,              ob_lon_min,
8761                          XmNleftOffset,              10,
8762                          XmNtopAttachment,           XmATTACH_WIDGET,
8763                          XmNtopWidget,               ob_lat,
8764                          XmNbottomAttachment,        XmATTACH_NONE,
8765                          XmNrightAttachment,         XmATTACH_NONE,
8766                          XmNbackground,              colors[0x0f],
8767                          XmNfontList, fontlist1,
8768                          NULL);
8769     // "(E/W)"
8770     ob_lon_ew = XtVaCreateManagedWidget(langcode("WPUPCFS008"),
8771                                         xmLabelWidgetClass,
8772                                         ob_latlon_form,
8773                                         XmNtopAttachment,           XmATTACH_WIDGET,
8774                                         XmNtopWidget,               ob_lat,
8775                                         XmNtopOffset,               20,
8776                                         XmNbottomAttachment,        XmATTACH_NONE,
8777                                         XmNleftAttachment,          XmATTACH_WIDGET,
8778                                         XmNleftWidget,              object_lon_data_ew,
8779                                         XmNrightAttachment,         XmATTACH_NONE,
8780                                         MY_FOREGROUND_COLOR,
8781                                         MY_BACKGROUND_COLOR,
8782                                         XmNfontList, fontlist1,
8783                                         NULL);
8784 
8785     compute_button = XtVaCreateManagedWidget(langcode("COORD002"),
8786                      xmPushButtonGadgetClass,
8787                      ob_latlon_form,
8788                      XmNtopAttachment,           XmATTACH_WIDGET,
8789                      XmNtopWidget,               ob_lat,
8790                      XmNtopOffset,               20,
8791                      XmNbottomAttachment,        XmATTACH_NONE,
8792                      XmNleftAttachment,          XmATTACH_WIDGET,
8793                      XmNleftWidget,              ob_lon_ew,
8794                      XmNleftOffset,              10,
8795                      XmNrightAttachment,         XmATTACH_NONE,
8796                      XmNnavigationType,          XmTAB_GROUP,
8797                      MY_FOREGROUND_COLOR,
8798                      MY_BACKGROUND_COLOR,
8799                      XmNfontList, fontlist1,
8800                      NULL);
8801 
8802     // Fill in the pointers to our input textfields so that the coordinate
8803     // calculator can fiddle with them.
8804     coordinate_calc_array.calling_dialog = object_dialog;
8805     coordinate_calc_array.input_lat_deg = object_lat_data_deg;
8806     coordinate_calc_array.input_lat_min = object_lat_data_min;
8807     coordinate_calc_array.input_lat_dir = object_lat_data_ns;
8808     coordinate_calc_array.input_lon_deg = object_lon_data_deg;
8809     coordinate_calc_array.input_lon_min = object_lon_data_min;
8810     coordinate_calc_array.input_lon_dir = object_lon_data_ew;
8811 //        XtAddCallback(compute_button, XmNactivateCallback, Coordinate_calc, ob_latlon_form);
8812 //        XtAddCallback(compute_button, XmNactivateCallback, Coordinate_calc, "Set_Del_Object");
8813     XtAddCallback(compute_button, XmNactivateCallback, Coordinate_calc, langcode("POPUPOB001"));
8814 
8815 //----- Frame for generic options
8816     ob_option_frame = XtVaCreateManagedWidget("Set_Del_Object ob_option_frame",
8817                       xmFrameWidgetClass,
8818                       ob_form,
8819                       XmNtopAttachment,           XmATTACH_WIDGET,
8820                       XmNtopWidget,               ob_frame,
8821                       XmNtopOffset,               10,
8822                       XmNbottomAttachment,        XmATTACH_NONE,
8823                       XmNleftAttachment,          XmATTACH_FORM,
8824                       XmNleftOffset,              10,
8825                       XmNrightAttachment,         XmATTACH_NONE,
8826                       XmNrightOffset,             10,
8827                       MY_FOREGROUND_COLOR,
8828                       MY_BACKGROUND_COLOR,
8829                       XmNfontList, fontlist1,
8830                       NULL);
8831     // "Generic Options"
8832     // ob_option_ts
8833     (void)XtVaCreateManagedWidget(langcode("POPUPOB027"),
8834                                   xmLabelWidgetClass,
8835                                   ob_option_frame,
8836                                   XmNchildType,               XmFRAME_TITLE_CHILD,
8837                                   MY_FOREGROUND_COLOR,
8838                                   MY_BACKGROUND_COLOR,
8839                                   XmNfontList, fontlist1,
8840                                   NULL);
8841 
8842     ob_option_form =  XtVaCreateWidget("Set_Del_Object ob_option_form",
8843                                        xmFormWidgetClass,
8844                                        ob_option_frame,
8845                                        XmNfractionBase,            5,
8846                                        MY_FOREGROUND_COLOR,
8847                                        MY_BACKGROUND_COLOR,
8848                                        XmNfontList, fontlist1,
8849                                        NULL);
8850 
8851     // "Speed"
8852     ob_speed = XtVaCreateManagedWidget(langcode("POPUPOB036"),
8853                                        xmLabelWidgetClass,
8854                                        ob_option_form,
8855                                        XmNtopAttachment,           XmATTACH_FORM,
8856                                        XmNtopOffset,               8,
8857                                        XmNbottomAttachment,        XmATTACH_FORM,
8858                                        XmNbottomOffset,            10,
8859                                        XmNleftAttachment,          XmATTACH_FORM,
8860                                        XmNleftOffset,              5,
8861                                        XmNrightAttachment,         XmATTACH_NONE,
8862                                        MY_FOREGROUND_COLOR,
8863                                        MY_BACKGROUND_COLOR,
8864                                        XmNfontList, fontlist1,
8865                                        NULL);
8866 
8867     ob_speed_data = XtVaCreateManagedWidget("Set_Del_Object ob_speed_data",
8868                                             xmTextFieldWidgetClass,
8869                                             ob_option_form,
8870                                             XmNeditable,                TRUE,
8871                                             XmNcursorPositionVisible,   TRUE,
8872                                             XmNsensitive,               TRUE,
8873                                             XmNshadowThickness,         1,
8874                                             XmNcolumns,                 3,
8875                                             XmNmaxLength,               3,
8876                                             XmNtopOffset,               3,
8877                                             XmNbackground,              colors[0x0f],
8878                                             XmNleftAttachment,          XmATTACH_WIDGET,
8879                                             XmNleftWidget,              ob_speed,
8880                                             XmNtopAttachment,           XmATTACH_FORM,
8881                                             XmNbottomAttachment,        XmATTACH_FORM,
8882                                             XmNrightAttachment,         XmATTACH_NONE,
8883                                             XmNfontList, fontlist1,
8884                                             NULL);
8885 
8886     // "Course"
8887     ob_course = XtVaCreateManagedWidget(langcode("POPUPOB037"),
8888                                         xmLabelWidgetClass,
8889                                         ob_option_form,
8890                                         XmNtopAttachment,           XmATTACH_FORM,
8891                                         XmNtopOffset,               8,
8892                                         XmNbottomAttachment,        XmATTACH_FORM,
8893                                         XmNbottomOffset,            10,
8894                                         XmNleftAttachment,          XmATTACH_WIDGET,
8895                                         XmNleftWidget,              ob_speed_data,
8896                                         XmNleftOffset,              10,
8897                                         XmNrightAttachment,         XmATTACH_NONE,
8898                                         MY_FOREGROUND_COLOR,
8899                                         MY_BACKGROUND_COLOR,
8900                                         XmNfontList, fontlist1,
8901                                         NULL);
8902 
8903     ob_course_data = XtVaCreateManagedWidget("Set_Del_Object ob_course_data",
8904                      xmTextFieldWidgetClass,
8905                      ob_option_form,
8906                      XmNeditable,                TRUE,
8907                      XmNcursorPositionVisible,   TRUE,
8908                      XmNsensitive,               TRUE,
8909                      XmNshadowThickness,         1,
8910                      XmNcolumns,                 3,
8911                      XmNmaxLength,               3,
8912                      XmNtopOffset,               3,
8913                      XmNbackground,              colors[0x0f],
8914                      XmNleftAttachment,          XmATTACH_WIDGET,
8915                      XmNleftWidget,              ob_course,
8916                      XmNtopAttachment,           XmATTACH_FORM,
8917                      XmNbottomAttachment,        XmATTACH_FORM,
8918                      XmNrightAttachment,         XmATTACH_NONE,
8919                      XmNfontList, fontlist1,
8920                      NULL);
8921 
8922     // "Altitude"
8923     ob_altitude = XtVaCreateManagedWidget(langcode("POPUPOB035"),
8924                                           xmLabelWidgetClass,
8925                                           ob_option_form,
8926                                           XmNtopAttachment,           XmATTACH_FORM,
8927                                           XmNtopOffset,               8,
8928                                           XmNbottomAttachment,        XmATTACH_FORM,
8929                                           XmNbottomOffset,            10,
8930                                           XmNleftAttachment,          XmATTACH_WIDGET,
8931                                           XmNleftWidget,              ob_course_data,
8932                                           XmNleftOffset,              10,
8933                                           XmNrightAttachment,         XmATTACH_NONE,
8934                                           MY_FOREGROUND_COLOR,
8935                                           MY_BACKGROUND_COLOR,
8936                                           XmNfontList, fontlist1,
8937                                           NULL);
8938 
8939     ob_altitude_data = XtVaCreateManagedWidget("Set_Del_Object ob_altitude_data",
8940                        xmTextFieldWidgetClass,
8941                        ob_option_form,
8942                        XmNeditable,                TRUE,
8943                        XmNcursorPositionVisible,   TRUE,
8944                        XmNsensitive,               TRUE,
8945                        XmNshadowThickness,         1,
8946                        XmNcolumns,                 6,
8947                        XmNmaxLength,               6,
8948                        XmNtopOffset,               3,
8949                        XmNbackground,              colors[0x0f],
8950                        XmNleftAttachment,          XmATTACH_WIDGET,
8951                        XmNleftWidget,              ob_altitude,
8952                        XmNtopAttachment,           XmATTACH_FORM,
8953                        XmNbottomAttachment,        XmATTACH_FORM,
8954                        XmNrightAttachment,         XmATTACH_NONE,
8955                        XmNfontList, fontlist1,
8956                        NULL);
8957 
8958 
8959 //----- Comment Field
8960     // "Comment:"
8961     ob_comment = XtVaCreateManagedWidget(langcode("WPUPCFS017"),
8962                                          xmLabelWidgetClass,
8963                                          ob_form,
8964                                          XmNtopAttachment,           XmATTACH_WIDGET,
8965                                          XmNtopWidget,               ob_option_frame,
8966                                          XmNtopOffset,               10,
8967                                          XmNbottomAttachment,        XmATTACH_NONE,
8968                                          XmNleftAttachment,          XmATTACH_FORM,
8969                                          XmNleftOffset,              10,
8970                                          XmNrightAttachment,         XmATTACH_NONE,
8971                                          MY_FOREGROUND_COLOR,
8972                                          MY_BACKGROUND_COLOR,
8973                                          XmNfontList, fontlist1,
8974                                          NULL);
8975 
8976     object_comment_data = XtVaCreateManagedWidget("Set_Del_Object comment",
8977                           xmTextFieldWidgetClass,
8978                           ob_form,
8979                           XmNeditable,                TRUE,
8980                           XmNcursorPositionVisible,   TRUE,
8981                           XmNsensitive,               TRUE,
8982                           XmNshadowThickness,         1,
8983                           XmNcolumns,                 37,     // max 43 without Data Extension
8984                           XmNmaxLength,               43,
8985                           XmNtopOffset,               6,
8986                           XmNbackground,              colors[0x0f],
8987                           XmNleftAttachment,          XmATTACH_WIDGET,
8988                           XmNleftWidget,              ob_comment,
8989                           XmNleftOffset,              5,
8990                           XmNtopAttachment,           XmATTACH_WIDGET,
8991                           XmNtopWidget,               ob_option_frame,
8992                           XmNbottomAttachment,        XmATTACH_NONE,
8993                           XmNrightAttachment,         XmATTACH_NONE,
8994                           XmNfontList, fontlist1,
8995                           NULL);
8996 
8997 
8998     // "Probability Circles"
8999     probabilities_toggle = XtVaCreateManagedWidget(langcode("POPUPOB047"),
9000                            xmToggleButtonGadgetClass,
9001                            ob_form,
9002                            XmNtopAttachment,           XmATTACH_WIDGET,
9003                            XmNtopWidget,               ob_latlon_frame,
9004                            XmNtopOffset,               2,
9005                            XmNbottomAttachment,        XmATTACH_NONE,
9006                            XmNbottomOffset,            0,
9007                            XmNleftAttachment,          XmATTACH_WIDGET,
9008                            XmNleftWidget,              ob_option_frame,
9009                            XmNleftOffset,              10,
9010                            XmNrightAttachment,         XmATTACH_NONE,
9011                            MY_FOREGROUND_COLOR,
9012                            MY_BACKGROUND_COLOR,
9013                            XmNfontList, fontlist1,
9014                            NULL);
9015     XtAddCallback(probabilities_toggle,XmNvalueChangedCallback,Probability_circle_toggle,(XtPointer)p_station);
9016 
9017 
9018     // "Signpost Enable"
9019     signpost_toggle = XtVaCreateManagedWidget(langcode("POPUPOB029"),
9020                       xmToggleButtonGadgetClass,
9021                       ob_form,
9022                       XmNtopAttachment,           XmATTACH_WIDGET,
9023                       XmNtopWidget,               probabilities_toggle,
9024                       XmNtopOffset,               0,
9025                       XmNbottomAttachment,        XmATTACH_NONE,
9026                       XmNbottomOffset,            0,
9027                       XmNleftAttachment,          XmATTACH_WIDGET,
9028                       XmNleftWidget,              ob_option_frame,
9029                       XmNleftOffset,              10,
9030                       XmNrightAttachment,         XmATTACH_NONE,
9031                       MY_FOREGROUND_COLOR,
9032                       MY_BACKGROUND_COLOR,
9033                       XmNfontList, fontlist1,
9034                       NULL);
9035     XtAddCallback(signpost_toggle,XmNvalueChangedCallback,Signpost_object_toggle,(XtPointer)p_station);
9036 
9037 
9038     // "Area Enable"
9039     area_toggle = XtVaCreateManagedWidget(langcode("POPUPOB008"),
9040                                           xmToggleButtonGadgetClass,
9041                                           ob_form,
9042                                           XmNtopAttachment,           XmATTACH_WIDGET,
9043                                           XmNtopWidget,               signpost_toggle,
9044                                           XmNtopOffset,               0,
9045                                           XmNbottomAttachment,        XmATTACH_NONE,
9046                                           XmNbottomOffset,            0,
9047                                           XmNleftAttachment,          XmATTACH_WIDGET,
9048                                           XmNleftWidget,              ob_option_frame,
9049                                           XmNleftOffset,              10,
9050                                           XmNrightAttachment,         XmATTACH_NONE,
9051                                           MY_FOREGROUND_COLOR,
9052                                           MY_BACKGROUND_COLOR,
9053                                           XmNfontList, fontlist1,
9054                                           NULL);
9055     XtAddCallback(area_toggle,XmNvalueChangedCallback,Area_object_toggle,(XtPointer)p_station);
9056 
9057 
9058 
9059     // "Area Enable"
9060     df_bearing_toggle = XtVaCreateManagedWidget(langcode("POPUPOB038"),
9061                         xmToggleButtonGadgetClass,
9062                         ob_form,
9063                         XmNtopAttachment,           XmATTACH_WIDGET,
9064                         XmNtopWidget,               area_toggle,
9065                         XmNtopOffset,               0,
9066                         XmNbottomAttachment,        XmATTACH_NONE,
9067                         XmNbottomOffset,            0,
9068                         XmNleftAttachment,          XmATTACH_WIDGET,
9069                         XmNleftWidget,              ob_option_frame,
9070                         XmNleftOffset,              10,
9071                         XmNrightAttachment,         XmATTACH_NONE,
9072                         MY_FOREGROUND_COLOR,
9073                         MY_BACKGROUND_COLOR,
9074                         XmNfontList, fontlist1,
9075                         NULL);
9076     XtAddCallback(df_bearing_toggle,XmNvalueChangedCallback,DF_bearing_object_toggle,(XtPointer)p_station);
9077 
9078 
9079 
9080     // "Map View Object"
9081     map_view_toggle = XtVaCreateManagedWidget(langcode("POPUPOB048"),
9082                       xmToggleButtonGadgetClass,
9083                       ob_form,
9084                       XmNtopAttachment,           XmATTACH_WIDGET,
9085                       XmNtopWidget,               df_bearing_toggle,
9086                       XmNtopOffset,               0,
9087                       XmNbottomAttachment,        XmATTACH_NONE,
9088                       XmNbottomOffset,            0,
9089                       XmNleftAttachment,          XmATTACH_WIDGET,
9090                       XmNleftWidget,              ob_option_frame,
9091                       XmNleftOffset,              10,
9092                       XmNrightAttachment,         XmATTACH_NONE,
9093                       MY_FOREGROUND_COLOR,
9094                       MY_BACKGROUND_COLOR,
9095                       XmNfontList, fontlist1,
9096                       NULL);
9097     XtAddCallback(map_view_toggle,XmNvalueChangedCallback,Map_View_object_toggle,(XtPointer)p_station);
9098 
9099 
9100 
9101 //----- Frame for Probability Circles info
9102     if (Probability_circles_enabled)
9103     {
9104 
9105       //fprintf(stderr,"Drawing probability circle data\n");
9106 
9107       probability_frame = XtVaCreateManagedWidget("Set_Del_Object probability_frame",
9108                           xmFrameWidgetClass,
9109                           ob_form,
9110                           XmNtopAttachment,           XmATTACH_WIDGET,
9111                           XmNtopWidget,               map_view_toggle,
9112                           XmNtopOffset,               0,
9113                           XmNbottomAttachment,        XmATTACH_NONE,
9114                           XmNleftAttachment,          XmATTACH_FORM,
9115                           XmNleftOffset,              10,
9116                           XmNrightAttachment,         XmATTACH_FORM,
9117                           XmNrightOffset,             10,
9118                           MY_FOREGROUND_COLOR,
9119                           MY_BACKGROUND_COLOR,
9120                           XmNfontList, fontlist1,
9121                           NULL);
9122 
9123       // "Probability Circles"
9124       // probability_ts
9125       (void)XtVaCreateManagedWidget(langcode("POPUPOB047"),
9126                                     xmLabelWidgetClass,
9127                                     probability_frame,
9128                                     XmNchildType,               XmFRAME_TITLE_CHILD,
9129                                     MY_FOREGROUND_COLOR,
9130                                     MY_BACKGROUND_COLOR,
9131                                     XmNfontList, fontlist1,
9132                                     NULL);
9133 
9134       probability_form =  XtVaCreateWidget("Set_Del_Object probability_form",
9135                                            xmFormWidgetClass,
9136                                            probability_frame,
9137                                            XmNfractionBase,            5,
9138                                            XmNautoUnmanage,            FALSE,
9139                                            MY_FOREGROUND_COLOR,
9140                                            MY_BACKGROUND_COLOR,
9141                                            XmNfontList, fontlist1,
9142                                            NULL);
9143 
9144       // "Min (mi):"
9145       probability_label_min = XtVaCreateManagedWidget(langcode("POPUPOB049"),
9146                               xmLabelWidgetClass,
9147                               probability_form,
9148                               XmNtopAttachment,           XmATTACH_FORM,
9149                               XmNtopOffset,               8,
9150                               XmNbottomAttachment,        XmATTACH_NONE,
9151                               XmNleftAttachment,          XmATTACH_FORM,
9152                               XmNleftOffset,              10,
9153                               XmNrightAttachment,         XmATTACH_NONE,
9154                               MY_FOREGROUND_COLOR,
9155                               MY_BACKGROUND_COLOR,
9156                               XmNfontList, fontlist1,
9157                               NULL);
9158 
9159       probability_data_min = XtVaCreateManagedWidget("Set_Del_Object probability_data_min",
9160                              xmTextFieldWidgetClass,
9161                              probability_form,
9162                              XmNeditable,                TRUE,
9163                              XmNcursorPositionVisible,   TRUE,
9164                              XmNsensitive,               TRUE,
9165                              XmNshadowThickness,         1,
9166                              XmNcolumns,                 10,
9167                              XmNmaxLength,               10,
9168                              XmNtopOffset,               3,
9169                              XmNbackground,              colors[0x0f],
9170                              XmNleftAttachment,          XmATTACH_WIDGET,
9171                              XmNleftWidget,              probability_label_min,
9172                              XmNtopAttachment,           XmATTACH_FORM,
9173                              XmNbottomAttachment,        XmATTACH_NONE,
9174                              XmNrightAttachment,         XmATTACH_NONE,
9175                              XmNfontList, fontlist1,
9176                              NULL);
9177 
9178       // "Max (mi):"
9179       probability_label_max = XtVaCreateManagedWidget(langcode("POPUPOB050"),
9180                               xmLabelWidgetClass,
9181                               probability_form,
9182                               XmNtopAttachment,           XmATTACH_WIDGET,
9183                               XmNtopWidget,               probability_label_min,
9184                               XmNtopOffset,               8,
9185                               XmNbottomAttachment,        XmATTACH_NONE,
9186                               XmNbottomOffset,            10,
9187                               XmNleftAttachment,          XmATTACH_FORM,
9188                               XmNleftOffset,              10,
9189                               XmNrightAttachment,         XmATTACH_NONE,
9190                               MY_FOREGROUND_COLOR,
9191                               MY_BACKGROUND_COLOR,
9192                               XmNfontList, fontlist1,
9193                               NULL);
9194 
9195       probability_data_max = XtVaCreateManagedWidget("Set_Del_Object probability_data_max",
9196                              xmTextFieldWidgetClass,
9197                              probability_form,
9198                              XmNeditable,                TRUE,
9199                              XmNcursorPositionVisible,   TRUE,
9200                              XmNsensitive,               TRUE,
9201                              XmNshadowThickness,         1,
9202                              XmNcolumns,                 10,
9203                              XmNmaxLength,               10,
9204                              XmNtopOffset,               3,
9205                              XmNbackground,              colors[0x0f],
9206                              XmNleftAttachment,          XmATTACH_WIDGET,
9207                              XmNleftWidget,              probability_label_max,
9208                              XmNtopAttachment,           XmATTACH_WIDGET,
9209                              XmNtopWidget,               probability_label_min,
9210                              XmNbottomAttachment,        XmATTACH_NONE,
9211                              XmNrightAttachment,         XmATTACH_NONE,
9212                              XmNfontList, fontlist1,
9213                              NULL);
9214 
9215 
9216 
9217       ob_sep = XtVaCreateManagedWidget("Set_Del_Object ob_sep",
9218                                        xmSeparatorGadgetClass,
9219                                        ob_form,
9220                                        XmNorientation,             XmHORIZONTAL,
9221                                        XmNtopAttachment,           XmATTACH_WIDGET,
9222                                        XmNtopWidget,               probability_frame,
9223                                        XmNtopOffset,               14,
9224                                        XmNbottomAttachment,        XmATTACH_NONE,
9225                                        XmNleftAttachment,          XmATTACH_FORM,
9226                                        XmNrightAttachment,         XmATTACH_FORM,
9227                                        MY_FOREGROUND_COLOR,
9228                                        MY_BACKGROUND_COLOR,
9229                                        XmNfontList, fontlist1,
9230                                        NULL);
9231     }
9232 
9233 
9234 
9235 //----- Frame for signpost info
9236     else if (Signpost_object_enabled)
9237     {
9238 
9239       //fprintf(stderr,"Drawing signpost data\n");
9240 
9241       signpost_frame = XtVaCreateManagedWidget("Set_Del_Object signpost_frame",
9242                        xmFrameWidgetClass,
9243                        ob_form,
9244                        XmNtopAttachment,           XmATTACH_WIDGET,
9245                        XmNtopWidget,               map_view_toggle,
9246                        XmNtopOffset,               0,
9247                        XmNbottomAttachment,        XmATTACH_NONE,
9248                        XmNleftAttachment,          XmATTACH_FORM,
9249                        XmNleftOffset,              10,
9250                        XmNrightAttachment,         XmATTACH_FORM,
9251                        XmNrightOffset,             10,
9252                        MY_FOREGROUND_COLOR,
9253                        MY_BACKGROUND_COLOR,
9254                        NULL);
9255 
9256       // "Signpost"
9257       // signpost_ts
9258       (void)XtVaCreateManagedWidget(langcode("POPUPOB031"),
9259                                     xmLabelWidgetClass,
9260                                     signpost_frame,
9261                                     XmNchildType,               XmFRAME_TITLE_CHILD,
9262                                     MY_FOREGROUND_COLOR,
9263                                     MY_BACKGROUND_COLOR,
9264                                     XmNfontList, fontlist1,
9265                                     NULL);
9266 
9267       signpost_form =  XtVaCreateWidget("Set_Del_Object signpost_form",
9268                                         xmFormWidgetClass,
9269                                         signpost_frame,
9270                                         XmNfractionBase,            5,
9271                                         XmNautoUnmanage,            FALSE,
9272                                         MY_FOREGROUND_COLOR,
9273                                         MY_BACKGROUND_COLOR,
9274                                         XmNfontList, fontlist1,
9275                                         NULL);
9276 
9277       // "Signpost Data"
9278       signpost_label = XtVaCreateManagedWidget(langcode("POPUPOB030"),
9279                        xmLabelWidgetClass,
9280                        signpost_form,
9281                        XmNtopAttachment,           XmATTACH_FORM,
9282                        XmNtopOffset,               8,
9283                        XmNbottomAttachment,        XmATTACH_FORM,
9284                        XmNbottomOffset,            10,
9285                        XmNleftAttachment,          XmATTACH_FORM,
9286                        XmNleftOffset,              10,
9287                        XmNrightAttachment,         XmATTACH_NONE,
9288                        MY_FOREGROUND_COLOR,
9289                        MY_BACKGROUND_COLOR,
9290                        XmNfontList, fontlist1,
9291                        NULL);
9292 
9293       signpost_data = XtVaCreateManagedWidget("Set_Del_Object signpost_data",
9294                                               xmTextFieldWidgetClass,
9295                                               signpost_form,
9296                                               XmNeditable,                TRUE,
9297                                               XmNcursorPositionVisible,   TRUE,
9298                                               XmNsensitive,               TRUE,
9299                                               XmNshadowThickness,         1,
9300                                               XmNcolumns,                 3,
9301                                               XmNmaxLength,               3,
9302                                               XmNtopOffset,               3,
9303                                               XmNbackground,              colors[0x0f],
9304                                               XmNleftAttachment,          XmATTACH_WIDGET,
9305                                               XmNleftWidget,              signpost_label,
9306                                               XmNtopAttachment,           XmATTACH_FORM,
9307                                               XmNbottomAttachment,        XmATTACH_FORM,
9308                                               XmNrightAttachment,         XmATTACH_NONE,
9309                                               XmNfontList, fontlist1,
9310                                               NULL);
9311 
9312       ob_sep = XtVaCreateManagedWidget("Set_Del_Object ob_sep",
9313                                        xmSeparatorGadgetClass,
9314                                        ob_form,
9315                                        XmNorientation,             XmHORIZONTAL,
9316                                        XmNtopAttachment,           XmATTACH_WIDGET,
9317                                        XmNtopWidget,               signpost_frame,
9318                                        XmNtopOffset,               14,
9319                                        XmNbottomAttachment,        XmATTACH_NONE,
9320                                        XmNleftAttachment,          XmATTACH_FORM,
9321                                        XmNrightAttachment,         XmATTACH_FORM,
9322                                        MY_FOREGROUND_COLOR,
9323                                        MY_BACKGROUND_COLOR,
9324                                        XmNfontList, fontlist1,
9325                                        NULL);
9326     }
9327 
9328 
9329 
9330 //----- Frame for area info
9331     else if (Area_object_enabled)
9332     {
9333 
9334       //fprintf(stderr,"Drawing Area data\n");
9335 
9336       area_frame = XtVaCreateManagedWidget("Set_Del_Object area_frame",
9337                                            xmFrameWidgetClass,
9338                                            ob_form,
9339                                            XmNtopAttachment,           XmATTACH_WIDGET,
9340                                            XmNtopWidget,               map_view_toggle,
9341                                            XmNtopOffset,               0,
9342                                            XmNbottomAttachment,        XmATTACH_NONE,
9343                                            XmNleftAttachment,          XmATTACH_FORM,
9344                                            XmNleftOffset,              10,
9345                                            XmNrightAttachment,         XmATTACH_FORM,
9346                                            XmNrightOffset,             10,
9347                                            MY_FOREGROUND_COLOR,
9348                                            MY_BACKGROUND_COLOR,
9349                                            NULL);
9350 
9351       // "Area Options"
9352       // area_ts
9353       (void)XtVaCreateManagedWidget(langcode("POPUPOB007"),
9354                                     xmLabelWidgetClass,
9355                                     area_frame,
9356                                     XmNchildType,               XmFRAME_TITLE_CHILD,
9357                                     MY_FOREGROUND_COLOR,
9358                                     MY_BACKGROUND_COLOR,
9359                                     XmNfontList, fontlist1,
9360                                     NULL);
9361 
9362       area_form =  XtVaCreateWidget("Set_Del_Object area_form",
9363                                     xmFormWidgetClass,
9364                                     area_frame,
9365                                     XmNfractionBase,            5,
9366                                     XmNautoUnmanage,            FALSE,
9367                                     MY_FOREGROUND_COLOR,
9368                                     MY_BACKGROUND_COLOR,
9369                                     NULL);
9370 
9371       // "Bright Color Enable"
9372       bright_dim_toggle = XtVaCreateManagedWidget(langcode("POPUPOB009"),
9373                           xmToggleButtonGadgetClass,
9374                           area_form,
9375                           XmNtopAttachment,           XmATTACH_FORM,
9376                           XmNtopOffset,               8,
9377                           XmNbottomAttachment,        XmATTACH_NONE,
9378                           XmNleftAttachment,          XmATTACH_FORM,
9379                           XmNleftOffset,              10,
9380                           XmNrightAttachment,         XmATTACH_NONE,
9381                           XmNset,                     FALSE,   // Select default to be OFF
9382                           MY_FOREGROUND_COLOR,
9383                           MY_BACKGROUND_COLOR,
9384                           XmNfontList, fontlist1,
9385                           NULL);
9386       XtAddCallback(bright_dim_toggle,XmNvalueChangedCallback,Area_bright_dim_toggle,"1");
9387       Area_bright = 0;    // Set to default each time dialog is created
9388 
9389       // "Color-Fill Enable"
9390       open_filled_toggle = XtVaCreateManagedWidget(langcode("POPUPOB010"),
9391                            xmToggleButtonGadgetClass,
9392                            area_form,
9393                            XmNtopAttachment,           XmATTACH_FORM,
9394                            XmNtopOffset,               8,
9395                            XmNbottomAttachment,        XmATTACH_NONE,
9396                            XmNleftAttachment,          XmATTACH_WIDGET,
9397                            XmNleftWidget,              bright_dim_toggle,
9398                            XmNleftOffset,              10,
9399                            XmNrightAttachment,         XmATTACH_NONE,
9400                            XmNset,                     FALSE,   // Select default to be OFF
9401                            MY_FOREGROUND_COLOR,
9402                            MY_BACKGROUND_COLOR,
9403                            XmNfontList, fontlist1,
9404                            NULL);
9405       XtAddCallback(open_filled_toggle,XmNvalueChangedCallback,Area_open_filled_toggle,"1");
9406       Area_filled = 0;    // Set to default each time dialog is created
9407 
9408 
9409 // Shape of object
9410       ac = 0;
9411       XtSetArg(al[ac], XmNforeground, MY_FG_COLOR);
9412       ac++;
9413       XtSetArg(al[ac], XmNbackground, MY_BG_COLOR);
9414       ac++;
9415 
9416       shape_box = XmCreateRadioBox(area_form,
9417                                    "Set_Del_Object Shape Options box",
9418                                    al,
9419                                    ac);
9420 
9421       XtVaSetValues(shape_box,
9422                     XmNpacking, XmPACK_TIGHT,
9423                     XmNorientation, XmHORIZONTAL,
9424                     XmNtopAttachment,XmATTACH_WIDGET,
9425                     XmNtopWidget,  bright_dim_toggle,
9426                     XmNbottomAttachment,XmATTACH_NONE,
9427                     XmNleftAttachment, XmATTACH_FORM,
9428                     XmNleftOffset, 5,
9429                     XmNrightAttachment,XmATTACH_FORM,
9430                     XmNrightOffset, 5,
9431                     XmNnumColumns,1,
9432                     NULL);
9433 
9434 
9435       // "Circle"
9436       toption1 = XtVaCreateManagedWidget(langcode("POPUPOB011"),
9437                                          xmToggleButtonGadgetClass,
9438                                          shape_box,
9439                                          MY_FOREGROUND_COLOR,
9440                                          MY_BACKGROUND_COLOR,
9441                                          XmNfontList, fontlist1,
9442                                          NULL);
9443       XtAddCallback(toption1,XmNvalueChangedCallback,Area_type_toggle,"0");
9444 
9445       // "Line-Right '/'"
9446       toption2 = XtVaCreateManagedWidget(langcode("POPUPOB013"),
9447                                          xmToggleButtonGadgetClass,
9448                                          shape_box,
9449                                          MY_FOREGROUND_COLOR,
9450                                          MY_BACKGROUND_COLOR,
9451                                          XmNfontList, fontlist1,
9452                                          NULL);
9453       XtAddCallback(toption2,XmNvalueChangedCallback,Area_type_toggle,"1");
9454 
9455       // "Line-Left '\'
9456       toption3 = XtVaCreateManagedWidget(langcode("POPUPOB012"),
9457                                          xmToggleButtonGadgetClass,
9458                                          shape_box,
9459                                          MY_FOREGROUND_COLOR,
9460                                          MY_BACKGROUND_COLOR,
9461                                          XmNfontList, fontlist1,
9462                                          NULL);
9463       XtAddCallback(toption3,XmNvalueChangedCallback,Area_type_toggle,"6");
9464 
9465       // "Triangle"
9466       toption4 = XtVaCreateManagedWidget(langcode("POPUPOB014"),
9467                                          xmToggleButtonGadgetClass,
9468                                          shape_box,
9469                                          MY_FOREGROUND_COLOR,
9470                                          MY_BACKGROUND_COLOR,
9471                                          XmNfontList, fontlist1,
9472                                          NULL);
9473       XtAddCallback(toption4,XmNvalueChangedCallback,Area_type_toggle,"3");
9474 
9475       // "Rectangle"
9476       toption5 = XtVaCreateManagedWidget(langcode("POPUPOB015"),
9477                                          xmToggleButtonGadgetClass,
9478                                          shape_box,
9479                                          MY_FOREGROUND_COLOR,
9480                                          MY_BACKGROUND_COLOR,
9481                                          XmNfontList, fontlist1,
9482                                          NULL);
9483       XtAddCallback(toption5,XmNvalueChangedCallback,Area_type_toggle,"4");
9484 
9485 
9486 // Color of object
9487       color_box = XmCreateRadioBox(area_form,
9488                                    "Set_Del_Object Color Options box",
9489                                    al,
9490                                    ac);
9491 
9492       XtVaSetValues(color_box,
9493                     XmNpacking, XmPACK_TIGHT,
9494                     XmNorientation, XmHORIZONTAL,
9495                     XmNtopAttachment,XmATTACH_WIDGET,
9496                     XmNtopWidget, shape_box,
9497                     XmNbottomAttachment,XmATTACH_NONE,
9498                     XmNleftAttachment, XmATTACH_FORM,
9499                     XmNleftOffset, 5,
9500                     XmNrightAttachment,XmATTACH_FORM,
9501                     XmNrightOffset, 5,
9502                     NULL);
9503 
9504 
9505       XtVaSetValues(color_box,
9506                     XmNnumColumns,4,
9507                     NULL);
9508 
9509       // "Black"
9510       coption1 = XtVaCreateManagedWidget(langcode("POPUPOB016"),
9511                                          xmToggleButtonGadgetClass,
9512                                          color_box,
9513                                          MY_FOREGROUND_COLOR,
9514                                          MY_BACKGROUND_COLOR,
9515                                          XmNfontList, fontlist1,
9516                                          NULL);
9517       XtAddCallback(coption1,XmNvalueChangedCallback,Area_color_toggle,"/0");
9518 
9519       // "Blue"
9520       coption2 = XtVaCreateManagedWidget(langcode("POPUPOB017"),
9521                                          xmToggleButtonGadgetClass,
9522                                          color_box,
9523                                          MY_FOREGROUND_COLOR,
9524                                          MY_BACKGROUND_COLOR,
9525                                          XmNfontList, fontlist1,
9526                                          NULL);
9527       XtAddCallback(coption2,XmNvalueChangedCallback,Area_color_toggle,"/1");
9528 
9529       // "Green"
9530       coption3 = XtVaCreateManagedWidget(langcode("POPUPOB018"),
9531                                          xmToggleButtonGadgetClass,
9532                                          color_box,
9533                                          MY_FOREGROUND_COLOR,
9534                                          MY_BACKGROUND_COLOR,
9535                                          XmNfontList, fontlist1,
9536                                          NULL);
9537       XtAddCallback(coption3,XmNvalueChangedCallback,Area_color_toggle,"/2");
9538 
9539       // "Cyan"
9540       coption4 = XtVaCreateManagedWidget(langcode("POPUPOB019"),
9541                                          xmToggleButtonGadgetClass,
9542                                          color_box,
9543                                          MY_FOREGROUND_COLOR,
9544                                          MY_BACKGROUND_COLOR,
9545                                          XmNfontList, fontlist1,
9546                                          NULL);
9547       XtAddCallback(coption4,XmNvalueChangedCallback,Area_color_toggle,"/3");
9548 
9549       // "Red"
9550       coption5 = XtVaCreateManagedWidget(langcode("POPUPOB020"),
9551                                          xmToggleButtonGadgetClass,
9552                                          color_box,
9553                                          MY_FOREGROUND_COLOR,
9554                                          MY_BACKGROUND_COLOR,
9555                                          XmNfontList, fontlist1,
9556                                          NULL);
9557       XtAddCallback(coption5,XmNvalueChangedCallback,Area_color_toggle,"/4");
9558 
9559       // "Violet"
9560       coption6 = XtVaCreateManagedWidget(langcode("POPUPOB021"),
9561                                          xmToggleButtonGadgetClass,
9562                                          color_box,
9563                                          MY_FOREGROUND_COLOR,
9564                                          MY_BACKGROUND_COLOR,
9565                                          XmNfontList, fontlist1,
9566                                          NULL);
9567       XtAddCallback(coption6,XmNvalueChangedCallback,Area_color_toggle,"/5");
9568 
9569       // "Yellow"
9570       coption7 = XtVaCreateManagedWidget(langcode("POPUPOB022"),
9571                                          xmToggleButtonGadgetClass,
9572                                          color_box,
9573                                          MY_FOREGROUND_COLOR,
9574                                          MY_BACKGROUND_COLOR,
9575                                          XmNfontList, fontlist1,
9576                                          NULL);
9577       XtAddCallback(coption7,XmNvalueChangedCallback,Area_color_toggle,"/6");
9578 
9579       // "Grey"
9580       coption8 = XtVaCreateManagedWidget(langcode("POPUPOB023"),
9581                                          xmToggleButtonGadgetClass,
9582                                          color_box,
9583                                          MY_FOREGROUND_COLOR,
9584                                          MY_BACKGROUND_COLOR,
9585                                          XmNfontList, fontlist1,
9586                                          NULL);
9587       XtAddCallback(coption8,XmNvalueChangedCallback,Area_color_toggle,"/7");
9588 
9589 // Latitude offset
9590       // "Offset Up"
9591       ob_lat_offset = XtVaCreateManagedWidget(langcode("POPUPOB024"),
9592                                               xmLabelWidgetClass,
9593                                               area_form,
9594                                               XmNtopAttachment,           XmATTACH_WIDGET,
9595                                               XmNtopWidget,               color_box,
9596                                               XmNtopOffset,               10,
9597                                               XmNbottomAttachment,        XmATTACH_FORM,
9598                                               XmNbottomOffset,            10,
9599                                               XmNleftAttachment,          XmATTACH_FORM,
9600                                               XmNleftOffset,              10,
9601                                               XmNrightAttachment,         XmATTACH_NONE,
9602                                               MY_FOREGROUND_COLOR,
9603                                               MY_BACKGROUND_COLOR,
9604                                               XmNfontList, fontlist1,
9605                                               NULL);
9606 
9607       ob_lat_offset_data = XtVaCreateManagedWidget("Set_Del_Object lat offset",
9608                            xmTextFieldWidgetClass,
9609                            area_form,
9610                            XmNeditable,                TRUE,
9611                            XmNcursorPositionVisible,   TRUE,
9612                            XmNsensitive,               TRUE,
9613                            XmNshadowThickness,         1,
9614                            XmNcolumns,                 4,
9615                            XmNmaxLength,               4,
9616                            XmNtopOffset,               5,
9617                            XmNbackground,              colors[0x0f],
9618                            XmNleftAttachment,          XmATTACH_WIDGET,
9619                            XmNleftWidget,              ob_lat_offset,
9620                            XmNtopAttachment,           XmATTACH_WIDGET,
9621                            XmNtopWidget,               color_box,
9622                            XmNbottomAttachment,        XmATTACH_FORM,
9623                            XmNrightAttachment,         XmATTACH_NONE,
9624                            XmNfontList, fontlist1,
9625                            NULL);
9626 
9627 // Longitude offset
9628       // "Offset Left (except for '/')"
9629       ob_lon_offset = XtVaCreateManagedWidget(langcode("POPUPOB025"),
9630                                               xmLabelWidgetClass,
9631                                               area_form,
9632                                               XmNtopAttachment,           XmATTACH_WIDGET,
9633                                               XmNtopWidget,               color_box,
9634                                               XmNtopOffset,               10,
9635                                               XmNbottomAttachment,        XmATTACH_FORM,
9636                                               XmNbottomOffset,            10,
9637                                               XmNleftAttachment,          XmATTACH_WIDGET,
9638                                               XmNleftWidget,              ob_lat_offset_data,
9639                                               XmNleftOffset,              10,
9640                                               XmNrightAttachment,         XmATTACH_NONE,
9641                                               MY_FOREGROUND_COLOR,
9642                                               MY_BACKGROUND_COLOR,
9643                                               XmNfontList, fontlist1,
9644                                               NULL);
9645 
9646       ob_lon_offset_data = XtVaCreateManagedWidget("Set_Del_Object long offset",
9647                            xmTextFieldWidgetClass,
9648                            area_form,
9649                            XmNeditable,                TRUE,
9650                            XmNcursorPositionVisible,   TRUE,
9651                            XmNsensitive,               TRUE,
9652                            XmNshadowThickness,         1,
9653                            XmNcolumns,                 4,
9654                            XmNmaxLength,               4,
9655                            XmNtopOffset,               5,
9656                            XmNbackground,              colors[0x0f],
9657                            XmNleftAttachment,          XmATTACH_WIDGET,
9658                            XmNleftWidget,              ob_lon_offset,
9659                            XmNtopAttachment,           XmATTACH_WIDGET,
9660                            XmNtopWidget,               color_box,
9661                            XmNbottomAttachment,        XmATTACH_FORM,
9662                            XmNrightAttachment,         XmATTACH_NONE,
9663                            XmNfontList, fontlist1,
9664                            NULL);
9665 
9666       // "Corridor (Lines only)"
9667       ob_corridor = XtVaCreateManagedWidget(langcode("POPUPOB026"),
9668                                             xmLabelWidgetClass,
9669                                             area_form,
9670                                             XmNtopAttachment,           XmATTACH_WIDGET,
9671                                             XmNtopWidget,               color_box,
9672                                             XmNtopOffset,               10,
9673                                             XmNbottomAttachment,        XmATTACH_FORM,
9674                                             XmNbottomOffset,            10,
9675                                             XmNleftAttachment,          XmATTACH_WIDGET,
9676                                             XmNleftWidget,              ob_lon_offset_data,
9677                                             XmNleftOffset,              10,
9678                                             XmNrightAttachment,         XmATTACH_NONE,
9679                                             MY_FOREGROUND_COLOR,
9680                                             MY_BACKGROUND_COLOR,
9681                                             XmNfontList, fontlist1,
9682                                             NULL);
9683 
9684       ob_corridor_data = XtVaCreateManagedWidget("Set_Del_Object lat offset",
9685                          xmTextFieldWidgetClass,
9686                          area_form,
9687                          XmNeditable,                TRUE,
9688                          XmNcursorPositionVisible,   TRUE,
9689                          XmNsensitive,               TRUE,
9690                          XmNshadowThickness,         1,
9691                          XmNcolumns,                 3,
9692                          XmNmaxLength,               3,
9693                          XmNtopOffset,               5,
9694                          XmNbackground,              colors[0x0f],
9695                          XmNleftAttachment,          XmATTACH_WIDGET,
9696                          XmNleftWidget,              ob_corridor,
9697                          XmNtopAttachment,           XmATTACH_WIDGET,
9698                          XmNtopWidget,               color_box,
9699                          XmNbottomAttachment,        XmATTACH_FORM,
9700                          XmNrightAttachment,         XmATTACH_NONE,
9701                          XmNfontList, fontlist1,
9702                          NULL);
9703 
9704       // "Miles"
9705       ob_corridor_miles = XtVaCreateManagedWidget(langcode("UNIOP00004"),
9706                           xmLabelWidgetClass,
9707                           area_form,
9708                           XmNtopAttachment,           XmATTACH_WIDGET,
9709                           XmNtopWidget,               color_box,
9710                           XmNtopOffset,               10,
9711                           XmNbottomAttachment,        XmATTACH_FORM,
9712                           XmNbottomOffset,            10,
9713                           XmNleftAttachment,          XmATTACH_WIDGET,
9714                           XmNleftWidget,              ob_corridor_data,
9715                           XmNrightAttachment,         XmATTACH_NONE,
9716                           MY_FOREGROUND_COLOR,
9717                           MY_BACKGROUND_COLOR,
9718                           XmNfontList, fontlist1,
9719                           NULL);
9720       XtSetSensitive(ob_corridor,FALSE);
9721       XtSetSensitive(ob_corridor_data,FALSE);
9722       XtSetSensitive(ob_corridor_miles,FALSE);
9723 
9724 
9725       ob_sep = XtVaCreateManagedWidget("Set_Del_Object ob_sep",
9726                                        xmSeparatorGadgetClass,
9727                                        ob_form,
9728                                        XmNorientation,             XmHORIZONTAL,
9729                                        XmNtopAttachment,           XmATTACH_WIDGET,
9730                                        XmNtopWidget,               area_frame,
9731                                        XmNtopOffset,               14,
9732                                        XmNbottomAttachment,        XmATTACH_NONE,
9733                                        XmNleftAttachment,          XmATTACH_FORM,
9734                                        XmNrightAttachment,         XmATTACH_FORM,
9735                                        MY_FOREGROUND_COLOR,
9736                                        MY_BACKGROUND_COLOR,
9737                                        XmNfontList, fontlist1,
9738                                        NULL);
9739     }
9740 
9741 
9742 
9743 //----- Frame for DF-omni info
9744     else if (DF_object_enabled)
9745     {
9746 
9747       //fprintf(stderr,"Drawing DF data\n");
9748 
9749       // "Omni Antenna"
9750       omni_antenna_toggle = XtVaCreateManagedWidget(langcode("POPUPOB041"),
9751                             xmToggleButtonGadgetClass,
9752                             ob_form,
9753                             XmNtopAttachment,           XmATTACH_WIDGET,
9754                             XmNtopWidget,               signpost_toggle,
9755                             XmNtopOffset,               0,
9756                             XmNbottomAttachment,        XmATTACH_NONE,
9757                             XmNbottomOffset,            0,
9758                             XmNleftAttachment,          XmATTACH_WIDGET,
9759                             XmNleftWidget,              area_toggle,
9760                             XmNleftOffset,              10,
9761                             XmNrightAttachment,         XmATTACH_NONE,
9762                             MY_FOREGROUND_COLOR,
9763                             MY_BACKGROUND_COLOR,
9764                             XmNfontList, fontlist1,
9765                             NULL);
9766       XtAddCallback(omni_antenna_toggle,XmNvalueChangedCallback,Omni_antenna_toggle,(XtPointer)p_station);
9767 
9768 
9769       // "Beam Antenna"
9770       beam_antenna_toggle = XtVaCreateManagedWidget(langcode("POPUPOB042"),
9771                             xmToggleButtonGadgetClass,
9772                             ob_form,
9773                             XmNtopAttachment,           XmATTACH_WIDGET,
9774                             XmNtopWidget,               omni_antenna_toggle,
9775                             XmNtopOffset,               0,
9776                             XmNbottomAttachment,        XmATTACH_NONE,
9777                             XmNbottomOffset,            0,
9778                             XmNleftAttachment,          XmATTACH_WIDGET,
9779                             XmNleftWidget,              area_toggle,
9780                             XmNleftOffset,              10,
9781                             XmNrightAttachment,         XmATTACH_NONE,
9782                             MY_FOREGROUND_COLOR,
9783                             MY_BACKGROUND_COLOR,
9784                             XmNfontList, fontlist1,
9785                             NULL);
9786       XtAddCallback(beam_antenna_toggle,XmNvalueChangedCallback,Beam_antenna_toggle,(XtPointer)p_station);
9787 
9788 
9789       frameomni = XtVaCreateManagedWidget("Set_Del_Object frameomni",
9790                                           xmFrameWidgetClass,
9791                                           ob_form,
9792                                           XmNtopAttachment,           XmATTACH_WIDGET,
9793                                           XmNtopWidget,               map_view_toggle,
9794                                           XmNtopOffset,               0,
9795                                           XmNbottomAttachment,        XmATTACH_NONE,
9796                                           XmNleftAttachment,          XmATTACH_FORM,
9797                                           XmNleftOffset,              10,
9798                                           XmNrightAttachment,         XmATTACH_FORM,
9799                                           XmNrightOffset,             10,
9800                                           MY_FOREGROUND_COLOR,
9801                                           MY_BACKGROUND_COLOR,
9802                                           NULL);
9803 
9804       // omnilabel
9805       (void)XtVaCreateManagedWidget(langcode("POPUPOB039"),
9806                                     xmLabelWidgetClass,
9807                                     frameomni,
9808                                     XmNchildType,               XmFRAME_TITLE_CHILD,
9809                                     MY_FOREGROUND_COLOR,
9810                                     MY_BACKGROUND_COLOR,
9811                                     XmNfontList, fontlist1,
9812                                     NULL);
9813 
9814       formomni =  XtVaCreateWidget("Set_Del_Object formomni",
9815                                    xmFormWidgetClass,
9816                                    frameomni,
9817                                    XmNfractionBase,            5,
9818                                    MY_FOREGROUND_COLOR,
9819                                    MY_BACKGROUND_COLOR,
9820                                    XmNfontList, fontlist1,
9821                                    NULL);
9822 
9823 
9824       // Power
9825       ac = 0;
9826       XtSetArg(al[ac], XmNforeground, MY_FG_COLOR);
9827       ac++;
9828       XtSetArg(al[ac], XmNbackground, MY_BG_COLOR);
9829       ac++;
9830 
9831       signal_box = XmCreateRadioBox(formomni,
9832                                     "Set_Del_Object Power Radio Box",
9833                                     al,
9834                                     ac);
9835 
9836       XtVaSetValues(signal_box,
9837                     XmNpacking,               XmPACK_TIGHT,
9838                     XmNorientation,           XmHORIZONTAL,
9839                     XmNtopAttachment,         XmATTACH_FORM,
9840                     XmNtopOffset,             5,
9841                     XmNbottomAttachment,      XmATTACH_NONE,
9842                     XmNleftAttachment,        XmATTACH_FORM,
9843                     XmNleftOffset,            5,
9844                     XmNrightAttachment,       XmATTACH_FORM,
9845                     XmNrightOffset,           5,
9846                     XmNnumColumns,            11,
9847                     NULL);
9848 
9849       // No signal detected what-so-ever
9850       soption0 = XtVaCreateManagedWidget("0",
9851                                          xmToggleButtonGadgetClass,
9852                                          signal_box,
9853                                          MY_FOREGROUND_COLOR,
9854                                          MY_BACKGROUND_COLOR,
9855                                          XmNfontList, fontlist1,
9856                                          NULL);
9857       XtAddCallback(soption0,XmNvalueChangedCallback,Ob_signal_toggle,"0");
9858 
9859       // Detectible signal (Maybe)
9860       soption1 = XtVaCreateManagedWidget("1",
9861                                          xmToggleButtonGadgetClass,
9862                                          signal_box,
9863                                          MY_FOREGROUND_COLOR,
9864                                          MY_BACKGROUND_COLOR,
9865                                          XmNfontList, fontlist1,
9866                                          NULL);
9867       XtAddCallback(soption1,XmNvalueChangedCallback,Ob_signal_toggle,"1");
9868 
9869       // Detectible signal (certain but not copyable)
9870       soption2 = XtVaCreateManagedWidget("2",
9871                                          xmToggleButtonGadgetClass,
9872                                          signal_box,
9873                                          MY_FOREGROUND_COLOR,
9874                                          MY_BACKGROUND_COLOR,
9875                                          XmNfontList, fontlist1,
9876                                          NULL);
9877       XtAddCallback(soption2,XmNvalueChangedCallback,Ob_signal_toggle,"2");
9878 
9879       // Weak signal marginally readable
9880       soption3 = XtVaCreateManagedWidget("3",
9881                                          xmToggleButtonGadgetClass,
9882                                          signal_box,
9883                                          MY_FOREGROUND_COLOR,
9884                                          MY_BACKGROUND_COLOR,
9885                                          XmNfontList, fontlist1,
9886                                          NULL);
9887       XtAddCallback(soption3,XmNvalueChangedCallback,Ob_signal_toggle,"3");
9888 
9889       // Noisy but copyable
9890       soption4 = XtVaCreateManagedWidget("4",
9891                                          xmToggleButtonGadgetClass,
9892                                          signal_box,
9893                                          MY_FOREGROUND_COLOR,
9894                                          MY_BACKGROUND_COLOR,
9895                                          XmNfontList, fontlist1,
9896                                          NULL);
9897       XtAddCallback(soption4,XmNvalueChangedCallback,Ob_signal_toggle,"4");
9898 
9899       // Some noise but easy to copy
9900       soption5 = XtVaCreateManagedWidget("5",
9901                                          xmToggleButtonGadgetClass,
9902                                          signal_box,
9903                                          MY_FOREGROUND_COLOR,
9904                                          MY_BACKGROUND_COLOR,
9905                                          XmNfontList, fontlist1,
9906                                          NULL);
9907       XtAddCallback(soption5,XmNvalueChangedCallback,Ob_signal_toggle,"5");
9908 
9909       // Good signal with detectible noise
9910       soption6 = XtVaCreateManagedWidget("6",
9911                                          xmToggleButtonGadgetClass,
9912                                          signal_box,
9913                                          MY_FOREGROUND_COLOR,
9914                                          MY_BACKGROUND_COLOR,
9915                                          XmNfontList, fontlist1,
9916                                          NULL);
9917       XtAddCallback(soption6,XmNvalueChangedCallback,Ob_signal_toggle,"6");
9918 
9919       // Near full-quieting signal
9920       soption7 = XtVaCreateManagedWidget("7",
9921                                          xmToggleButtonGadgetClass,
9922                                          signal_box,
9923                                          MY_FOREGROUND_COLOR,
9924                                          MY_BACKGROUND_COLOR,
9925                                          XmNfontList, fontlist1,
9926                                          NULL);
9927       XtAddCallback(soption7,XmNvalueChangedCallback,Ob_signal_toggle,"7");
9928 
9929       // Dead full-quieting signal, no noise detectible
9930       soption8 = XtVaCreateManagedWidget("8",
9931                                          xmToggleButtonGadgetClass,
9932                                          signal_box,
9933                                          MY_FOREGROUND_COLOR,
9934                                          MY_BACKGROUND_COLOR,
9935                                          XmNfontList, fontlist1,
9936                                          NULL);
9937       XtAddCallback(soption8,XmNvalueChangedCallback,Ob_signal_toggle,"8");
9938 
9939       // Extremely strong signal "pins the meter"
9940       soption9 = XtVaCreateManagedWidget("9",
9941                                          xmToggleButtonGadgetClass,
9942                                          signal_box,
9943                                          MY_FOREGROUND_COLOR,
9944                                          MY_BACKGROUND_COLOR,
9945                                          XmNfontList, fontlist1,
9946                                          NULL);
9947       XtAddCallback(soption9,XmNvalueChangedCallback,Ob_signal_toggle,"9");
9948 
9949 
9950       // Height
9951       height_box = XmCreateRadioBox(formomni,
9952                                     "Set_Del_Object Height Radio Box",
9953                                     al,
9954                                     ac);
9955 
9956       XtVaSetValues(height_box,
9957                     XmNpacking, XmPACK_TIGHT,
9958                     XmNorientation, XmHORIZONTAL,
9959                     XmNtopAttachment,XmATTACH_WIDGET,
9960                     XmNtopWidget,signal_box,
9961                     XmNbottomAttachment,XmATTACH_NONE,
9962                     XmNleftAttachment, XmATTACH_FORM,
9963                     XmNleftOffset, 5,
9964                     XmNrightAttachment,XmATTACH_FORM,
9965                     XmNrightOffset, 5,
9966                     XmNnumColumns,10,
9967                     NULL);
9968 
9969 
9970       // 10 Feet
9971       hoption0 = XtVaCreateManagedWidget(
9972                    (english_units) ? "10ft" : "3m",
9973                    xmToggleButtonGadgetClass,
9974                    height_box,
9975                    MY_FOREGROUND_COLOR,
9976                    MY_BACKGROUND_COLOR,
9977                    XmNfontList, fontlist1,
9978                    NULL);
9979       XtAddCallback(hoption0,XmNvalueChangedCallback,Ob_height_toggle,"0");
9980 
9981       // 20 Feet
9982       hoption1 = XtVaCreateManagedWidget(
9983                    (english_units) ? "20ft" : "6m",
9984                    xmToggleButtonGadgetClass,
9985                    height_box,
9986                    MY_FOREGROUND_COLOR,
9987                    MY_BACKGROUND_COLOR,
9988                    XmNfontList, fontlist1,
9989                    NULL);
9990       XtAddCallback(hoption1,XmNvalueChangedCallback,Ob_height_toggle,"1");
9991 
9992       // 40 Feet
9993       hoption2 = XtVaCreateManagedWidget(
9994                    (english_units) ? "40ft" : "12m",
9995                    xmToggleButtonGadgetClass,
9996                    height_box,
9997                    MY_FOREGROUND_COLOR,
9998                    MY_BACKGROUND_COLOR,
9999                    XmNfontList, fontlist1,
10000                    NULL);
10001       XtAddCallback(hoption2,XmNvalueChangedCallback,Ob_height_toggle,"2");
10002 
10003       // 80 Feet
10004       hoption3 = XtVaCreateManagedWidget(
10005                    (english_units) ? "80ft" : "24m",
10006                    xmToggleButtonGadgetClass,
10007                    height_box,
10008                    MY_FOREGROUND_COLOR,
10009                    MY_BACKGROUND_COLOR,
10010                    XmNfontList, fontlist1,
10011                    NULL);
10012       XtAddCallback(hoption3,XmNvalueChangedCallback,Ob_height_toggle,"3");
10013 
10014       // 160 Feet
10015       hoption4 = XtVaCreateManagedWidget(
10016                    (english_units) ? "160ft" : "49m",
10017                    xmToggleButtonGadgetClass,
10018                    height_box,
10019                    MY_FOREGROUND_COLOR,
10020                    MY_BACKGROUND_COLOR,
10021                    XmNfontList, fontlist1,
10022                    NULL);
10023       XtAddCallback(hoption4,XmNvalueChangedCallback,Ob_height_toggle,"4");
10024 
10025       // 320 Feet
10026       hoption5 = XtVaCreateManagedWidget(
10027                    (english_units) ? "320ft" : "98m",
10028                    xmToggleButtonGadgetClass,
10029                    height_box,
10030                    MY_FOREGROUND_COLOR,
10031                    MY_BACKGROUND_COLOR,
10032                    XmNfontList, fontlist1,
10033                    NULL);
10034       XtAddCallback(hoption5,XmNvalueChangedCallback,Ob_height_toggle,"5");
10035 
10036       // 640 Feet
10037       hoption6 = XtVaCreateManagedWidget(
10038                    (english_units) ? "640ft" : "195m",
10039                    xmToggleButtonGadgetClass,
10040                    height_box,
10041                    MY_FOREGROUND_COLOR,
10042                    MY_BACKGROUND_COLOR,
10043                    XmNfontList, fontlist1,
10044                    NULL);
10045       XtAddCallback(hoption6,XmNvalueChangedCallback,Ob_height_toggle,"6");
10046 
10047       // 1280 Feet
10048       hoption7 = XtVaCreateManagedWidget(
10049                    (english_units) ? "1280ft" : "390m",
10050                    xmToggleButtonGadgetClass,
10051                    height_box,
10052                    MY_FOREGROUND_COLOR,
10053                    MY_BACKGROUND_COLOR,
10054                    XmNfontList, fontlist1,
10055                    NULL);
10056       XtAddCallback(hoption7,XmNvalueChangedCallback,Ob_height_toggle,"7");
10057 
10058       // 2560 Feet
10059       hoption8 = XtVaCreateManagedWidget(
10060                    (english_units) ? "2560ft" : "780m",
10061                    xmToggleButtonGadgetClass,
10062                    height_box,
10063                    MY_FOREGROUND_COLOR,
10064                    MY_BACKGROUND_COLOR,
10065                    XmNfontList, fontlist1,
10066                    NULL);
10067       XtAddCallback(hoption8,XmNvalueChangedCallback,Ob_height_toggle,"8");
10068 
10069       // 5120 Feet
10070       hoption9 = XtVaCreateManagedWidget(
10071                    (english_units) ? "5120ft" : "1561m",
10072                    xmToggleButtonGadgetClass,
10073                    height_box,
10074                    MY_FOREGROUND_COLOR,
10075                    MY_BACKGROUND_COLOR,
10076                    XmNfontList, fontlist1,
10077                    NULL);
10078       XtAddCallback(hoption9,XmNvalueChangedCallback,Ob_height_toggle,"9");
10079 
10080 
10081       // Gain
10082       gain_box = XmCreateRadioBox(formomni,
10083                                   "Set_Del_Object Gain Radio Box",
10084                                   al,
10085                                   ac);
10086 
10087       XtVaSetValues(gain_box,
10088                     XmNpacking, XmPACK_TIGHT,
10089                     XmNorientation, XmHORIZONTAL,
10090                     XmNtopAttachment,XmATTACH_WIDGET,
10091                     XmNtopWidget,height_box,
10092                     XmNbottomAttachment,XmATTACH_NONE,
10093                     XmNleftAttachment, XmATTACH_FORM,
10094                     XmNleftOffset, 5,
10095                     XmNrightAttachment,XmATTACH_FORM,
10096                     XmNrightOffset, 5,
10097                     XmNnumColumns,10,
10098                     NULL);
10099 
10100 
10101       // 0 dB
10102       goption0 = XtVaCreateManagedWidget("0dB",
10103                                          xmToggleButtonGadgetClass,
10104                                          gain_box,
10105                                          MY_FOREGROUND_COLOR,
10106                                          MY_BACKGROUND_COLOR,
10107                                          XmNfontList, fontlist1,
10108                                          NULL);
10109       XtAddCallback(goption0,XmNvalueChangedCallback,Ob_gain_toggle,"0");
10110 
10111       // 1 dB
10112       goption1 = XtVaCreateManagedWidget("1dB",
10113                                          xmToggleButtonGadgetClass,
10114                                          gain_box,
10115                                          MY_FOREGROUND_COLOR,
10116                                          MY_BACKGROUND_COLOR,
10117                                          XmNfontList, fontlist1,
10118                                          NULL);
10119       XtAddCallback(goption1,XmNvalueChangedCallback,Ob_gain_toggle,"1");
10120 
10121       // 2 dB
10122       goption2 = XtVaCreateManagedWidget("2dB",
10123                                          xmToggleButtonGadgetClass,
10124                                          gain_box,
10125                                          MY_FOREGROUND_COLOR,
10126                                          MY_BACKGROUND_COLOR,
10127                                          XmNfontList, fontlist1,
10128                                          NULL);
10129       XtAddCallback(goption2,XmNvalueChangedCallback,Ob_gain_toggle,"2");
10130 
10131       // 3 dB
10132       goption3 = XtVaCreateManagedWidget("3dB",
10133                                          xmToggleButtonGadgetClass,
10134                                          gain_box,
10135                                          MY_FOREGROUND_COLOR,
10136                                          MY_BACKGROUND_COLOR,
10137                                          XmNfontList, fontlist1,
10138                                          NULL);
10139       XtAddCallback(goption3,XmNvalueChangedCallback,Ob_gain_toggle,"3");
10140 
10141       // 4 dB
10142       goption4 = XtVaCreateManagedWidget("4dB",
10143                                          xmToggleButtonGadgetClass,
10144                                          gain_box,
10145                                          MY_FOREGROUND_COLOR,
10146                                          MY_BACKGROUND_COLOR,
10147                                          XmNfontList, fontlist1,
10148                                          NULL);
10149       XtAddCallback(goption4,XmNvalueChangedCallback,Ob_gain_toggle,"4");
10150 
10151       // 5 dB
10152       goption5 = XtVaCreateManagedWidget("5dB",
10153                                          xmToggleButtonGadgetClass,
10154                                          gain_box,
10155                                          MY_FOREGROUND_COLOR,
10156                                          MY_BACKGROUND_COLOR,
10157                                          XmNfontList, fontlist1,
10158                                          NULL);
10159       XtAddCallback(goption5,XmNvalueChangedCallback,Ob_gain_toggle,"5");
10160 
10161       // 6 dB
10162       goption6 = XtVaCreateManagedWidget("6dB",
10163                                          xmToggleButtonGadgetClass,
10164                                          gain_box,
10165                                          MY_FOREGROUND_COLOR,
10166                                          MY_BACKGROUND_COLOR,
10167                                          XmNfontList, fontlist1,
10168                                          NULL);
10169       XtAddCallback(goption6,XmNvalueChangedCallback,Ob_gain_toggle,"6");
10170 
10171       // 7 dB
10172       goption7 = XtVaCreateManagedWidget("7dB",
10173                                          xmToggleButtonGadgetClass,
10174                                          gain_box,
10175                                          MY_FOREGROUND_COLOR,
10176                                          MY_BACKGROUND_COLOR,
10177                                          XmNfontList, fontlist1,
10178                                          NULL);
10179       XtAddCallback(goption7,XmNvalueChangedCallback,Ob_gain_toggle,"7");
10180 
10181       // 8 dB
10182       goption8 = XtVaCreateManagedWidget("8dB",
10183                                          xmToggleButtonGadgetClass,
10184                                          gain_box,
10185                                          MY_FOREGROUND_COLOR,
10186                                          MY_BACKGROUND_COLOR,
10187                                          XmNfontList, fontlist1,
10188                                          NULL);
10189       XtAddCallback(goption8,XmNvalueChangedCallback,Ob_gain_toggle,"8");
10190 
10191       // 9 dB
10192       goption9 = XtVaCreateManagedWidget("9dB",
10193                                          xmToggleButtonGadgetClass,
10194                                          gain_box,
10195                                          MY_FOREGROUND_COLOR,
10196                                          MY_BACKGROUND_COLOR,
10197                                          XmNfontList, fontlist1,
10198                                          NULL);
10199       XtAddCallback(goption9,XmNvalueChangedCallback,Ob_gain_toggle,"9");
10200 
10201 
10202       // Gain
10203       directivity_box = XmCreateRadioBox(formomni,
10204                                          "Set_Del_Object Directivity Radio Box",
10205                                          al,
10206                                          ac);
10207 
10208       XtVaSetValues(directivity_box,
10209                     XmNpacking, XmPACK_TIGHT,
10210                     XmNorientation, XmHORIZONTAL,
10211                     XmNtopAttachment,XmATTACH_WIDGET,
10212                     XmNtopWidget,gain_box,
10213                     XmNbottomAttachment,XmATTACH_NONE,
10214                     XmNleftAttachment, XmATTACH_FORM,
10215                     XmNleftOffset, 5,
10216                     XmNrightAttachment,XmATTACH_FORM,
10217                     XmNrightOffset, 5,
10218                     XmNnumColumns,10,
10219                     NULL);
10220 
10221 
10222       // Omni-directional
10223       doption0 = XtVaCreateManagedWidget(langcode("WPUPCFS016"),
10224                                          xmToggleButtonGadgetClass,
10225                                          directivity_box,
10226                                          MY_FOREGROUND_COLOR,
10227                                          MY_BACKGROUND_COLOR,
10228                                          XmNfontList, fontlist1,
10229                                          NULL);
10230       XtAddCallback(doption0,XmNvalueChangedCallback,Ob_directivity_toggle,"0");
10231 
10232       // 45 NE
10233       doption1 = XtVaCreateManagedWidget("45\xB0",
10234                                          xmToggleButtonGadgetClass,
10235                                          directivity_box,
10236                                          MY_FOREGROUND_COLOR,
10237                                          MY_BACKGROUND_COLOR,
10238                                          XmNfontList, fontlist1,
10239                                          NULL);
10240       XtAddCallback(doption1,XmNvalueChangedCallback,Ob_directivity_toggle,"1");
10241 
10242       // 90 E
10243       doption2 = XtVaCreateManagedWidget("90\xB0",
10244                                          xmToggleButtonGadgetClass,
10245                                          directivity_box,
10246                                          MY_FOREGROUND_COLOR,
10247                                          MY_BACKGROUND_COLOR,
10248                                          XmNfontList, fontlist1,
10249                                          NULL);
10250       XtAddCallback(doption2,XmNvalueChangedCallback,Ob_directivity_toggle,"2");
10251 
10252       // 135 SE
10253       doption3 = XtVaCreateManagedWidget("135\xB0",
10254                                          xmToggleButtonGadgetClass,
10255                                          directivity_box,
10256                                          MY_FOREGROUND_COLOR,
10257                                          MY_BACKGROUND_COLOR,
10258                                          XmNfontList, fontlist1,
10259                                          NULL);
10260       XtAddCallback(doption3,XmNvalueChangedCallback,Ob_directivity_toggle,"3");
10261 
10262       // 180 S
10263       doption4 = XtVaCreateManagedWidget("180\xB0",
10264                                          xmToggleButtonGadgetClass,
10265                                          directivity_box,
10266                                          MY_FOREGROUND_COLOR,
10267                                          MY_BACKGROUND_COLOR,
10268                                          XmNfontList, fontlist1,
10269                                          NULL);
10270       XtAddCallback(doption4,XmNvalueChangedCallback,Ob_directivity_toggle,"4");
10271 
10272       // 225 SW
10273       doption5 = XtVaCreateManagedWidget("225\xB0",
10274                                          xmToggleButtonGadgetClass,
10275                                          directivity_box,
10276                                          MY_FOREGROUND_COLOR,
10277                                          MY_BACKGROUND_COLOR,
10278                                          XmNfontList, fontlist1,
10279                                          NULL);
10280       XtAddCallback(doption5,XmNvalueChangedCallback,Ob_directivity_toggle,"5");
10281 
10282       // 270 W
10283       doption6 = XtVaCreateManagedWidget("270\xB0",
10284                                          xmToggleButtonGadgetClass,
10285                                          directivity_box,
10286                                          MY_FOREGROUND_COLOR,
10287                                          MY_BACKGROUND_COLOR,
10288                                          XmNfontList, fontlist1,
10289                                          NULL);
10290       XtAddCallback(doption6,XmNvalueChangedCallback,Ob_directivity_toggle,"6");
10291 
10292       // 315 NW
10293       doption7 = XtVaCreateManagedWidget("315\xB0",
10294                                          xmToggleButtonGadgetClass,
10295                                          directivity_box,
10296                                          MY_FOREGROUND_COLOR,
10297                                          MY_BACKGROUND_COLOR,
10298                                          XmNfontList, fontlist1,
10299                                          NULL);
10300       XtAddCallback(doption7,XmNvalueChangedCallback,Ob_directivity_toggle,"7");
10301 
10302       // 360 N
10303       doption8 = XtVaCreateManagedWidget("360\xB0",
10304                                          xmToggleButtonGadgetClass,
10305                                          directivity_box,
10306                                          MY_FOREGROUND_COLOR,
10307                                          MY_BACKGROUND_COLOR,
10308                                          XmNfontList, fontlist1,
10309                                          NULL);
10310       XtAddCallback(doption8,XmNvalueChangedCallback,Ob_directivity_toggle,"8");
10311 
10312 
10313 //----- Frame for DF-beam info
10314       framebeam = XtVaCreateManagedWidget("Set_Del_Object framebeam",
10315                                           xmFrameWidgetClass,
10316                                           ob_form,
10317                                           XmNtopAttachment,           XmATTACH_WIDGET,
10318                                           XmNtopWidget,               frameomni,
10319                                           XmNtopOffset,               10,
10320                                           XmNbottomAttachment,        XmATTACH_NONE,
10321                                           XmNleftAttachment,          XmATTACH_FORM,
10322                                           XmNleftOffset,              10,
10323                                           XmNrightAttachment,         XmATTACH_FORM,
10324                                           XmNrightOffset,             10,
10325                                           MY_FOREGROUND_COLOR,
10326                                           MY_BACKGROUND_COLOR,
10327                                           NULL);
10328 
10329       // beamlabel
10330       (void)XtVaCreateManagedWidget(langcode("POPUPOB040"),
10331                                     xmLabelWidgetClass,
10332                                     framebeam,
10333                                     XmNchildType,               XmFRAME_TITLE_CHILD,
10334                                     MY_FOREGROUND_COLOR,
10335                                     MY_BACKGROUND_COLOR,
10336                                     XmNfontList, fontlist1,
10337                                     NULL);
10338 
10339       formbeam =  XtVaCreateWidget("Set_Del_Object formbeam",
10340                                    xmFormWidgetClass,
10341                                    framebeam,
10342                                    XmNfractionBase,            5,
10343                                    MY_FOREGROUND_COLOR,
10344                                    MY_BACKGROUND_COLOR,
10345                                    NULL);
10346 
10347 
10348       // Beam width
10349       ac = 0;
10350       XtSetArg(al[ac], XmNforeground, MY_FG_COLOR);
10351       ac++;
10352       XtSetArg(al[ac], XmNbackground, MY_BG_COLOR);
10353       ac++;
10354 
10355       width_box = XmCreateRadioBox(formbeam,
10356                                    "Set_Del_Object Width Box",
10357                                    al,
10358                                    ac);
10359 
10360       XtVaSetValues(width_box,
10361                     XmNpacking,               XmPACK_TIGHT,
10362                     XmNorientation,           XmHORIZONTAL,
10363                     XmNtopAttachment,         XmATTACH_FORM,
10364                     XmNtopOffset,             5,
10365                     XmNbottomAttachment,      XmATTACH_NONE,
10366                     XmNleftAttachment,        XmATTACH_FORM,
10367                     XmNleftOffset,            5,
10368                     XmNrightAttachment,       XmATTACH_FORM,
10369                     XmNrightOffset,           5,
10370                     XmNnumColumns,            11,
10371                     NULL);
10372 
10373       // Useless
10374       woption0 = XtVaCreateManagedWidget(langcode("POPUPOB043"),
10375                                          xmToggleButtonGadgetClass,
10376                                          width_box,
10377                                          MY_FOREGROUND_COLOR,
10378                                          MY_BACKGROUND_COLOR,
10379                                          XmNfontList, fontlist1,
10380                                          NULL);
10381       XtAddCallback(woption0,XmNvalueChangedCallback,Ob_width_toggle,"0");
10382 
10383       // < 240 Degrees
10384       woption1 = XtVaCreateManagedWidget("<240\xB0",
10385                                          xmToggleButtonGadgetClass,
10386                                          width_box,
10387                                          MY_FOREGROUND_COLOR,
10388                                          MY_BACKGROUND_COLOR,
10389                                          XmNfontList, fontlist1,
10390                                          NULL);
10391       XtAddCallback(woption1,XmNvalueChangedCallback,Ob_width_toggle,"1");
10392 
10393       // < 120 Degrees
10394       woption2 = XtVaCreateManagedWidget("<120\xB0",
10395                                          xmToggleButtonGadgetClass,
10396                                          width_box,
10397                                          MY_FOREGROUND_COLOR,
10398                                          MY_BACKGROUND_COLOR,
10399                                          XmNfontList, fontlist1,
10400                                          NULL);
10401       XtAddCallback(woption2,XmNvalueChangedCallback,Ob_width_toggle,"2");
10402 
10403       // < 64 Degrees
10404       woption3 = XtVaCreateManagedWidget("<64\xB0",
10405                                          xmToggleButtonGadgetClass,
10406                                          width_box,
10407                                          MY_FOREGROUND_COLOR,
10408                                          MY_BACKGROUND_COLOR,
10409                                          XmNfontList, fontlist1,
10410                                          NULL);
10411       XtAddCallback(woption3,XmNvalueChangedCallback,Ob_width_toggle,"3");
10412 
10413       // < 32 Degrees
10414       woption4 = XtVaCreateManagedWidget("<32\xB0",
10415                                          xmToggleButtonGadgetClass,
10416                                          width_box,
10417                                          MY_FOREGROUND_COLOR,
10418                                          MY_BACKGROUND_COLOR,
10419                                          XmNfontList, fontlist1,
10420                                          NULL);
10421       XtAddCallback(woption4,XmNvalueChangedCallback,Ob_width_toggle,"4");
10422 
10423       // < 16 Degrees
10424       woption5 = XtVaCreateManagedWidget("<16\xB0",
10425                                          xmToggleButtonGadgetClass,
10426                                          width_box,
10427                                          MY_FOREGROUND_COLOR,
10428                                          MY_BACKGROUND_COLOR,
10429                                          XmNfontList, fontlist1,
10430                                          NULL);
10431       XtAddCallback(woption5,XmNvalueChangedCallback,Ob_width_toggle,"5");
10432 
10433       // < 8 Degrees
10434       woption6 = XtVaCreateManagedWidget("<8\xB0",
10435                                          xmToggleButtonGadgetClass,
10436                                          width_box,
10437                                          MY_FOREGROUND_COLOR,
10438                                          MY_BACKGROUND_COLOR,
10439                                          XmNfontList, fontlist1,
10440                                          NULL);
10441       XtAddCallback(woption6,XmNvalueChangedCallback,Ob_width_toggle,"6");
10442 
10443       // < 4 Degrees
10444       woption7 = XtVaCreateManagedWidget("<4\xB0",
10445                                          xmToggleButtonGadgetClass,
10446                                          width_box,
10447                                          MY_FOREGROUND_COLOR,
10448                                          MY_BACKGROUND_COLOR,
10449                                          XmNfontList, fontlist1,
10450                                          NULL);
10451       XtAddCallback(woption7,XmNvalueChangedCallback,Ob_width_toggle,"7");
10452 
10453       // < 2 Degrees
10454       woption8 = XtVaCreateManagedWidget("<2\xB0",
10455                                          xmToggleButtonGadgetClass,
10456                                          width_box,
10457                                          MY_FOREGROUND_COLOR,
10458                                          MY_BACKGROUND_COLOR,
10459                                          XmNfontList, fontlist1,
10460                                          NULL);
10461       XtAddCallback(woption8,XmNvalueChangedCallback,Ob_width_toggle,"8");
10462 
10463       // < 1 Degrees
10464       woption9 = XtVaCreateManagedWidget("<1\xB0",
10465                                          xmToggleButtonGadgetClass,
10466                                          width_box,
10467                                          MY_FOREGROUND_COLOR,
10468                                          MY_BACKGROUND_COLOR,
10469                                          XmNfontList, fontlist1,
10470                                          NULL);
10471       XtAddCallback(woption9,XmNvalueChangedCallback,Ob_width_toggle,"9");
10472 
10473 
10474       // "Bearing"
10475       ob_bearing = XtVaCreateManagedWidget(langcode("POPUPOB046"),
10476                                            xmLabelWidgetClass,
10477                                            formbeam,
10478                                            XmNtopAttachment,           XmATTACH_WIDGET,
10479                                            XmNtopWidget,               width_box,
10480                                            XmNtopOffset,               10,
10481                                            XmNbottomAttachment,        XmATTACH_NONE,
10482                                            XmNleftAttachment,          XmATTACH_FORM,
10483                                            XmNleftOffset,              10,
10484                                            XmNrightAttachment,         XmATTACH_NONE,
10485                                            MY_FOREGROUND_COLOR,
10486                                            MY_BACKGROUND_COLOR,
10487                                            XmNfontList, fontlist1,
10488                                            NULL);
10489       // Bearing data
10490       ob_bearing_data = XtVaCreateManagedWidget("Set_Del_Object ob_bearing_data",
10491                         xmTextFieldWidgetClass,
10492                         formbeam,
10493                         XmNeditable,                TRUE,
10494                         XmNcursorPositionVisible,   TRUE,
10495                         XmNsensitive,               TRUE,
10496                         XmNshadowThickness,         1,
10497                         XmNcolumns,                 9,
10498                         XmNmaxLength,               9,
10499                         XmNtopAttachment,           XmATTACH_WIDGET,
10500                         XmNtopWidget,               width_box,
10501                         XmNtopOffset,               5,
10502                         XmNbottomAttachment,        XmATTACH_NONE,
10503                         XmNleftAttachment,          XmATTACH_WIDGET,
10504                         XmNleftWidget,              ob_bearing,
10505                         XmNrightAttachment,         XmATTACH_NONE,
10506                         XmNbackground,              colors[0x0f],
10507                         XmNfontList, fontlist1,
10508                         NULL);
10509 
10510 
10511       XtSetSensitive(frameomni,FALSE);
10512       XtSetSensitive(framebeam,FALSE);
10513       Omni_antenna_enabled = 0;
10514       Beam_antenna_enabled = 0;
10515 
10516 
10517       ob_sep = XtVaCreateManagedWidget("Set_Del_Object ob_sep",
10518                                        xmSeparatorGadgetClass,
10519                                        ob_form,
10520                                        XmNorientation,             XmHORIZONTAL,
10521                                        XmNtopAttachment,           XmATTACH_WIDGET,
10522                                        XmNtopWidget,               framebeam,
10523                                        XmNtopOffset,               14,
10524                                        XmNbottomAttachment,        XmATTACH_NONE,
10525                                        XmNleftAttachment,          XmATTACH_FORM,
10526                                        XmNrightAttachment,         XmATTACH_FORM,
10527                                        MY_FOREGROUND_COLOR,
10528                                        MY_BACKGROUND_COLOR,
10529                                        XmNfontList, fontlist1,
10530                                        NULL);
10531     }
10532 // End of DF-specific widgets
10533 
10534 
10535 
10536 //----- No Special options selected.  We need a widget here for the next widget to attach to.
10537     if (!DF_object_enabled
10538         && !Area_object_enabled
10539         && !Signpost_object_enabled
10540         && !Probability_circles_enabled)
10541     {
10542 
10543       //fprintf(stderr,"No special object types\n");
10544 
10545       ob_sep = XtVaCreateManagedWidget("Set_Del_Object ob_sep",
10546                                        xmSeparatorGadgetClass,
10547                                        ob_form,
10548                                        XmNorientation,             XmHORIZONTAL,
10549                                        XmNtopAttachment,           XmATTACH_WIDGET,
10550                                        XmNtopWidget,               map_view_toggle,
10551                                        XmNtopOffset,               0,
10552                                        XmNbottomAttachment,        XmATTACH_NONE,
10553                                        XmNleftAttachment,          XmATTACH_FORM,
10554                                        XmNrightAttachment,         XmATTACH_FORM,
10555                                        MY_FOREGROUND_COLOR,
10556                                        MY_BACKGROUND_COLOR,
10557                                        XmNfontList, fontlist1,
10558                                        NULL);
10559     }
10560 
10561 
10562 
10563 //----- Buttons
10564     if (p_station != NULL)    // We were called from the Modify_object() or Move function
10565     {
10566 
10567       // Change the buttons/callbacks based on whether we're dealing with an item or an object
10568       if ((p_station->flag & ST_ITEM) != 0)       // Modifying an Item
10569       {
10570         // Here we need Modify Item/Delete Item/Cancel buttons
10571         ob_button_set = XtVaCreateManagedWidget(langcode("POPUPOB034"),
10572                                                 xmPushButtonGadgetClass,
10573                                                 ob_form,
10574                                                 XmNtopAttachment,           XmATTACH_WIDGET,
10575                                                 XmNtopWidget,               ob_sep,
10576                                                 XmNtopOffset,               5,
10577                                                 XmNbottomAttachment,        XmATTACH_FORM,
10578                                                 XmNbottomOffset,            5,
10579                                                 XmNleftAttachment,          XmATTACH_POSITION,
10580                                                 XmNleftPosition,            0,
10581                                                 XmNrightAttachment,         XmATTACH_POSITION,
10582                                                 XmNrightPosition,           1,
10583                                                 XmNnavigationType,          XmTAB_GROUP,
10584                                                 MY_FOREGROUND_COLOR,
10585                                                 MY_BACKGROUND_COLOR,
10586                                                 XmNfontList, fontlist1,
10587                                                 NULL);
10588         XtAddCallback(ob_button_set, XmNactivateCallback, Item_change_data_set, object_dialog);
10589 
10590         // Check whether we own this item
10591         if (strcasecmp(p_station->origin,my_callsign)==0)
10592         {
10593 
10594           // We own this item, set up the "Delete"
10595           // button.
10596           ob_button_del = XtVaCreateManagedWidget(langcode("POPUPOB033"),
10597                                                   xmPushButtonGadgetClass,
10598                                                   ob_form,
10599                                                   XmNtopAttachment,           XmATTACH_WIDGET,
10600                                                   XmNtopWidget,               ob_sep,
10601                                                   XmNtopOffset,               5,
10602                                                   XmNbottomAttachment,        XmATTACH_FORM,
10603                                                   XmNbottomOffset,            5,
10604                                                   XmNleftAttachment,          XmATTACH_POSITION,
10605                                                   XmNleftPosition,            1,
10606                                                   XmNrightAttachment,         XmATTACH_POSITION,
10607                                                   XmNrightPosition,           2,
10608                                                   XmNnavigationType,          XmTAB_GROUP,
10609                                                   MY_FOREGROUND_COLOR,
10610                                                   MY_BACKGROUND_COLOR,
10611                                                   XmNfontList, fontlist1,
10612                                                   NULL);
10613           XtAddCallback(ob_button_del, XmNactivateCallback, Item_change_data_del, object_dialog);
10614         }
10615         else
10616         {
10617 
10618           // Somebody else owns this item, set up the
10619           // "Adopt" button.
10620           ob_button_del = XtVaCreateManagedWidget(langcode("POPUPOB045"),
10621                                                   xmPushButtonGadgetClass,
10622                                                   ob_form,
10623                                                   XmNtopAttachment,           XmATTACH_WIDGET,
10624                                                   XmNtopWidget,               ob_sep,
10625                                                   XmNtopOffset,               5,
10626                                                   XmNbottomAttachment,        XmATTACH_FORM,
10627                                                   XmNbottomOffset,            5,
10628                                                   XmNleftAttachment,          XmATTACH_POSITION,
10629                                                   XmNleftPosition,            1,
10630                                                   XmNrightAttachment,         XmATTACH_POSITION,
10631                                                   XmNrightPosition,           2,
10632                                                   XmNnavigationType,          XmTAB_GROUP,
10633                                                   MY_FOREGROUND_COLOR,
10634                                                   MY_BACKGROUND_COLOR,
10635                                                   XmNfontList, fontlist1,
10636                                                   NULL);
10637           XtAddCallback(ob_button_del, XmNactivateCallback, Item_change_data_set, object_dialog);
10638         }
10639       }
10640       else    // Modifying an Object
10641       {
10642         // Here we need Modify Object/Delete Object/Cancel buttons
10643         ob_button_set = XtVaCreateManagedWidget(langcode("POPUPOB005"),
10644                                                 xmPushButtonGadgetClass,
10645                                                 ob_form,
10646                                                 XmNtopAttachment,           XmATTACH_WIDGET,
10647                                                 XmNtopWidget,               ob_sep,
10648                                                 XmNtopOffset,               5,
10649                                                 XmNbottomAttachment,        XmATTACH_FORM,
10650                                                 XmNbottomOffset,            5,
10651                                                 XmNleftAttachment,          XmATTACH_POSITION,
10652                                                 XmNleftPosition,            0,
10653                                                 XmNrightAttachment,         XmATTACH_POSITION,
10654                                                 XmNrightPosition,           1,
10655                                                 XmNnavigationType,          XmTAB_GROUP,
10656                                                 MY_FOREGROUND_COLOR,
10657                                                 MY_BACKGROUND_COLOR,
10658                                                 XmNfontList, fontlist1,
10659                                                 NULL);
10660         XtAddCallback(ob_button_set, XmNactivateCallback, Object_change_data_set, object_dialog);
10661 
10662         // Check whether we own this Object
10663         if (strcasecmp(p_station->origin,my_callsign)==0)
10664         {
10665 
10666           // We own this object, set up the "Delete"
10667           // button.
10668           ob_button_del = XtVaCreateManagedWidget(langcode("POPUPOB004"),
10669                                                   xmPushButtonGadgetClass,
10670                                                   ob_form,
10671                                                   XmNtopAttachment,           XmATTACH_WIDGET,
10672                                                   XmNtopWidget,               ob_sep,
10673                                                   XmNtopOffset,               5,
10674                                                   XmNbottomAttachment,        XmATTACH_FORM,
10675                                                   XmNbottomOffset,            5,
10676                                                   XmNleftAttachment,          XmATTACH_POSITION,
10677                                                   XmNleftPosition,            1,
10678                                                   XmNrightAttachment,         XmATTACH_POSITION,
10679                                                   XmNrightPosition,           2,
10680                                                   XmNnavigationType,          XmTAB_GROUP,
10681                                                   MY_FOREGROUND_COLOR,
10682                                                   MY_BACKGROUND_COLOR,
10683                                                   XmNfontList, fontlist1,
10684                                                   NULL);
10685           XtAddCallback(ob_button_del, XmNactivateCallback, Object_change_data_del, object_dialog);
10686         }
10687         else
10688         {
10689 
10690           // Somebody else owns this object, set up the
10691           // "Adopt" button.
10692           ob_button_del = XtVaCreateManagedWidget(langcode("POPUPOB044"),
10693                                                   xmPushButtonGadgetClass,
10694                                                   ob_form,
10695                                                   XmNtopAttachment,           XmATTACH_WIDGET,
10696                                                   XmNtopWidget,               ob_sep,
10697                                                   XmNtopOffset,               5,
10698                                                   XmNbottomAttachment,        XmATTACH_FORM,
10699                                                   XmNbottomOffset,            5,
10700                                                   XmNleftAttachment,          XmATTACH_POSITION,
10701                                                   XmNleftPosition,            1,
10702                                                   XmNrightAttachment,         XmATTACH_POSITION,
10703                                                   XmNrightPosition,           2,
10704                                                   XmNnavigationType,          XmTAB_GROUP,
10705                                                   MY_FOREGROUND_COLOR,
10706                                                   MY_BACKGROUND_COLOR,
10707                                                   XmNfontList, fontlist1,
10708                                                   NULL);
10709           XtAddCallback(ob_button_del, XmNactivateCallback, Object_change_data_set, object_dialog);
10710         }
10711       }
10712     }
10713     else    // We were called from Create->Object mouse menu
10714     {
10715       ob_button_set = XtVaCreateManagedWidget(langcode("POPUPOB003"),xmPushButtonGadgetClass, ob_form,
10716                                               XmNtopAttachment,           XmATTACH_WIDGET,
10717                                               XmNtopWidget,               ob_sep,
10718                                               XmNtopOffset,               5,
10719                                               XmNbottomAttachment,        XmATTACH_FORM,
10720                                               XmNbottomOffset,            5,
10721                                               XmNleftAttachment,          XmATTACH_POSITION,
10722                                               XmNleftPosition,            0,
10723                                               XmNrightAttachment,         XmATTACH_POSITION,
10724                                               XmNrightPosition,           1,
10725                                               XmNnavigationType,          XmTAB_GROUP,
10726                                               MY_FOREGROUND_COLOR,
10727                                               MY_BACKGROUND_COLOR,
10728                                               XmNfontList, fontlist1,
10729                                               NULL);
10730 
10731       it_button_set = XtVaCreateManagedWidget(langcode("POPUPOB006"),xmPushButtonGadgetClass, ob_form,
10732                                               XmNtopAttachment,           XmATTACH_WIDGET,
10733                                               XmNtopWidget,               ob_sep,
10734                                               XmNtopOffset,               5,
10735                                               XmNbottomAttachment,        XmATTACH_FORM,
10736                                               XmNbottomOffset,            5,
10737                                               XmNleftAttachment,          XmATTACH_POSITION,
10738                                               XmNleftPosition,            1,
10739                                               XmNrightAttachment,         XmATTACH_POSITION,
10740                                               XmNrightPosition,           2,
10741                                               XmNnavigationType,          XmTAB_GROUP,
10742                                               MY_FOREGROUND_COLOR,
10743                                               MY_BACKGROUND_COLOR,
10744                                               XmNfontList, fontlist1,
10745                                               NULL);
10746 
10747 
10748       // Changed to different callback routines here which
10749       // check the new object/item name against our internal
10750       // database then call
10751       // Object_change_data_set/Item_change_data_set if all
10752       // ok.  If a conflict (object/item already exists), do a
10753       // popup_message() instead or bring up a confirmation
10754       // dialog before creating the object/item.
10755       //
10756       //XtAddCallback(ob_button_set,
10757       //    XmNactivateCallback,
10758       //    Object_change_data_set,
10759       //    object_dialog);
10760       //XtAddCallback(it_button_set,
10761       //    XmNactivateCallback,
10762       //    Item_change_data_set,
10763       //    object_dialog);
10764       XtAddCallback(ob_button_set,
10765                     XmNactivateCallback,
10766                     Object_confirm_data_set,
10767                     object_dialog);
10768       XtAddCallback(it_button_set,
10769                     XmNactivateCallback,
10770                     Item_confirm_data_set,
10771                     object_dialog);
10772     }
10773 
10774     ob_button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"),xmPushButtonGadgetClass, ob_form,
10775                        XmNtopAttachment,           XmATTACH_WIDGET,
10776                        XmNtopWidget,               ob_sep,
10777                        XmNtopOffset,               5,
10778                        XmNbottomAttachment,        XmATTACH_FORM,
10779                        XmNbottomOffset,            5,
10780                        XmNleftAttachment,          XmATTACH_POSITION,
10781                        XmNleftPosition,            2,
10782                        XmNrightAttachment,         XmATTACH_POSITION,
10783                        XmNrightPosition,           3,
10784                        XmNnavigationType,          XmTAB_GROUP,
10785                        MY_FOREGROUND_COLOR,
10786                        MY_BACKGROUND_COLOR,
10787                        XmNfontList, fontlist1,
10788                        NULL);
10789     XtAddCallback(ob_button_cancel, XmNactivateCallback, Object_destroy_shell,   object_dialog);
10790 
10791 
10792     // Set ToggleButtons for the current state.  Don't notify the callback
10793     // functions associated with them or we'll be in an infinite loop.
10794     if (Area_object_enabled)
10795     {
10796       XmToggleButtonSetState(area_toggle, TRUE, FALSE);
10797     }
10798     if (Signpost_object_enabled)
10799     {
10800       XmToggleButtonSetState(signpost_toggle, TRUE, FALSE);
10801     }
10802     if (DF_object_enabled)
10803     {
10804       XmToggleButtonSetState(df_bearing_toggle, TRUE, FALSE);
10805     }
10806     if (Map_View_object_enabled)
10807     {
10808       XmToggleButtonSetState(map_view_toggle, TRUE, FALSE);
10809     }
10810     if (Probability_circles_enabled)
10811     {
10812       XmToggleButtonSetState(probabilities_toggle, TRUE, FALSE);
10813     }
10814 
10815 
10816 // Fill in current data if object already exists
10817     if (p_station != NULL)    // We were called from the Modify_object() or Move functions
10818     {
10819 
10820       // Don't allow changing types if the object is already created.
10821       // Already tried allowing it, and it causes other problems.
10822       XtSetSensitive(area_toggle, FALSE);
10823       XtSetSensitive(signpost_toggle, FALSE);
10824       XtSetSensitive(df_bearing_toggle, FALSE);
10825       XtSetSensitive(map_view_toggle, FALSE);
10826       XtSetSensitive(probabilities_toggle, FALSE);
10827 
10828       XmTextFieldSetString(object_name_data,p_station->call_sign);
10829       // Need to make the above field non-editable 'cuz we're trying to modify
10830       // _parameters_ of the object and the name has to stay the same in order
10831       // to do this.  Change the name and we'll be creating a new object instead
10832       // of modifying an old one.
10833       XtSetSensitive(object_name_data, FALSE);
10834       // Would be nice to change the colors too
10835 
10836       // Check for overlay character
10837       if (p_station->aprs_symbol.special_overlay)
10838       {
10839         // Found an overlay character
10840         temp_data[0] = p_station->aprs_symbol.special_overlay;
10841       }
10842       else    // No overlay character
10843       {
10844         temp_data[0] = p_station->aprs_symbol.aprs_type;
10845       }
10846       temp_data[1] = '\0';
10847       XmTextFieldSetString(object_group_data,temp_data);
10848 
10849       temp_data[0] = p_station->aprs_symbol.aprs_symbol;
10850       temp_data[1] = '\0';
10851       XmTextFieldSetString(object_symbol_data,temp_data);
10852 
10853       // We only check the first possible comment string in
10854       // the record
10855       //if (strlen(p_station->comments) > 0)
10856       if (Map_View_object_enabled)
10857       {
10858 
10859         if ( (p_station->comment_data != NULL)
10860              && (p_station->comment_data->text_ptr != NULL) )
10861         {
10862           char temp[100];
10863 
10864           xastir_snprintf(temp,
10865                           sizeof(temp),
10866                           "%s%s",
10867                           p_station->power_gain,
10868                           p_station->comment_data->text_ptr);
10869           XmTextFieldSetString(object_comment_data,temp);
10870         }
10871         else
10872         {
10873           XmTextFieldSetString(object_comment_data,p_station->power_gain);
10874         }
10875       }
10876 
10877       else if ( (p_station->comment_data != NULL)
10878                 && (p_station->comment_data->text_ptr != NULL) )
10879       {
10880         XmTextFieldSetString(object_comment_data,p_station->comment_data->text_ptr);
10881       }
10882 
10883       else
10884       {
10885         XmTextFieldSetString(object_comment_data,"");
10886       }
10887 
10888 
10889 //            if ( (p_station->aprs_symbol.area_object.type != AREA_NONE) // Found an area object
10890 //                    && Area_object_enabled ) {
10891       if (Area_object_enabled)
10892       {
10893 
10894         XtSetSensitive(ob_frame,FALSE);
10895         XtSetSensitive(area_frame,TRUE);
10896 
10897         switch (p_station->aprs_symbol.area_object.type)
10898         {
10899           case (1):   // Line '/'
10900             XmToggleButtonSetState(toption2, TRUE, TRUE);
10901             XmToggleButtonGadgetSetState(open_filled_toggle, FALSE, TRUE);
10902             if (p_station->aprs_symbol.area_object.corridor_width > 0)
10903               xastir_snprintf(temp_data, sizeof(temp_data), "%d",
10904                               p_station->aprs_symbol.area_object.corridor_width );
10905             else
10906             {
10907               temp_data[0] = '\0';  // Empty string
10908             }
10909 
10910             XmTextFieldSetString( ob_corridor_data, temp_data );
10911             break;
10912           case (6):   // Line '\'
10913             XmToggleButtonGadgetSetState(toption3, TRUE, TRUE);
10914             XmToggleButtonGadgetSetState(open_filled_toggle, FALSE, TRUE);
10915             if (p_station->aprs_symbol.area_object.corridor_width > 0)
10916               xastir_snprintf(temp_data, sizeof(temp_data), "%d",
10917                               p_station->aprs_symbol.area_object.corridor_width );
10918             else
10919             {
10920               temp_data[0] = '\0';  // Empty string
10921             }
10922 
10923             XmTextFieldSetString( ob_corridor_data, temp_data );
10924             break;
10925           case (3):   // Open Triangle
10926             XmToggleButtonGadgetSetState(toption4, TRUE, TRUE);
10927             XmToggleButtonGadgetSetState(open_filled_toggle, FALSE, TRUE);
10928             break;
10929           case (4):   // Open Rectangle
10930             XmToggleButtonGadgetSetState(toption5, TRUE, TRUE);
10931             XmToggleButtonGadgetSetState(open_filled_toggle, FALSE, TRUE);
10932             break;
10933           case (5):   // Filled Circle
10934             XmToggleButtonGadgetSetState(toption1, TRUE, TRUE);
10935             XmToggleButtonGadgetSetState(open_filled_toggle, TRUE, TRUE);
10936             break;
10937           case (8):   // Filled Triangle
10938             XmToggleButtonGadgetSetState(toption4, TRUE, TRUE);
10939             XmToggleButtonGadgetSetState(open_filled_toggle, TRUE, TRUE);
10940             break;
10941           case (9):   // Filled Rectangle
10942             XmToggleButtonGadgetSetState(toption5, TRUE, TRUE);
10943             XmToggleButtonGadgetSetState(open_filled_toggle, TRUE, TRUE);
10944             break;
10945           case (0):   // Open Circle
10946           default:
10947             XmToggleButtonGadgetSetState(toption1, TRUE, TRUE);
10948             XmToggleButtonGadgetSetState(open_filled_toggle, FALSE, TRUE);
10949             break;
10950         }
10951 
10952         switch (p_station->aprs_symbol.area_object.color)
10953         {
10954           case (1):   // Blue Bright
10955             XmToggleButtonGadgetSetState(coption2, TRUE, TRUE);
10956             XmToggleButtonGadgetSetState(bright_dim_toggle, TRUE, TRUE);
10957             break;
10958           case (2):   // Green Bright
10959             XmToggleButtonGadgetSetState(coption3, TRUE, TRUE);
10960             XmToggleButtonGadgetSetState(bright_dim_toggle, TRUE, TRUE);
10961             break;
10962           case (3):   // Cyan Bright
10963             XmToggleButtonGadgetSetState(coption4, TRUE, TRUE);
10964             XmToggleButtonGadgetSetState(bright_dim_toggle, TRUE, TRUE);
10965             break;
10966           case (4):   // Red Bright
10967             XmToggleButtonGadgetSetState(coption5, TRUE, TRUE);
10968             XmToggleButtonGadgetSetState(bright_dim_toggle, TRUE, TRUE);
10969             break;
10970           case (5):   // Violet Bright
10971             XmToggleButtonGadgetSetState(coption6, TRUE, TRUE);
10972             XmToggleButtonGadgetSetState(bright_dim_toggle, TRUE, TRUE);
10973             break;
10974           case (6):   // Yellow Bright
10975             XmToggleButtonGadgetSetState(coption7, TRUE, TRUE);
10976             XmToggleButtonGadgetSetState(bright_dim_toggle, TRUE, TRUE);
10977             break;
10978           case (7):   // Gray Bright
10979             XmToggleButtonGadgetSetState(coption8, TRUE, TRUE);
10980             XmToggleButtonGadgetSetState(bright_dim_toggle, TRUE, TRUE);
10981             break;
10982           case (8):   // Black Dim
10983             XmToggleButtonGadgetSetState(coption1, TRUE, TRUE);
10984             XmToggleButtonGadgetSetState(bright_dim_toggle, FALSE, TRUE);
10985             break;
10986           case (9):   // Blue Dim
10987             XmToggleButtonGadgetSetState(coption2, TRUE, TRUE);
10988             XmToggleButtonGadgetSetState(bright_dim_toggle, FALSE, TRUE);
10989             break;
10990           case (10):  // Green Dim
10991             XmToggleButtonGadgetSetState(coption3, TRUE, TRUE);
10992             XmToggleButtonGadgetSetState(bright_dim_toggle, FALSE, TRUE);
10993             break;
10994           case (11):  // Cyan Dim
10995             XmToggleButtonGadgetSetState(coption4, TRUE, TRUE);
10996             XmToggleButtonGadgetSetState(bright_dim_toggle, FALSE, TRUE);
10997             break;
10998           case (12):  // Red Dim
10999             XmToggleButtonGadgetSetState(coption5, TRUE, TRUE);
11000             XmToggleButtonGadgetSetState(bright_dim_toggle, FALSE, TRUE);
11001             break;
11002           case (13):  // Violet Dim
11003             XmToggleButtonGadgetSetState(coption6, TRUE, TRUE);
11004             XmToggleButtonGadgetSetState(bright_dim_toggle, FALSE, TRUE);
11005             break;
11006           case (14):  // Yellow Dim
11007             XmToggleButtonGadgetSetState(coption7, TRUE, TRUE);
11008             XmToggleButtonGadgetSetState(bright_dim_toggle, FALSE, TRUE);
11009             break;
11010           case (15):  // Gray Dim
11011             XmToggleButtonGadgetSetState(coption8, TRUE, TRUE);
11012             XmToggleButtonGadgetSetState(bright_dim_toggle, FALSE, TRUE);
11013             break;
11014           case (0):   // Black Bright
11015           default:
11016             XmToggleButtonGadgetSetState(coption1, TRUE, TRUE);
11017             XmToggleButtonGadgetSetState(bright_dim_toggle, TRUE, TRUE);
11018             break;
11019         }
11020 
11021         xastir_snprintf(temp_data, sizeof(temp_data), "%d",
11022                         p_station->aprs_symbol.area_object.sqrt_lat_off
11023                         * p_station->aprs_symbol.area_object.sqrt_lat_off );
11024 
11025         XmTextFieldSetString( ob_lat_offset_data, temp_data );
11026 
11027         xastir_snprintf(temp_data, sizeof(temp_data), "%d",
11028                         p_station->aprs_symbol.area_object.sqrt_lon_off
11029                         * p_station->aprs_symbol.area_object.sqrt_lon_off );
11030 
11031         XmTextFieldSetString( ob_lon_offset_data, temp_data );
11032 
11033       }   // Done with filling in Area Objects
11034 
11035       else    // Signpost/Probability/Normal Object
11036       {
11037 
11038         // Handle Generic Options (common to Signpost/Normal Objects)
11039         if (strlen(p_station->speed) != 0)
11040         {
11041           xastir_snprintf(temp_data, sizeof(temp_data), "%d",
11042                           (int)(atof(p_station->speed) + 0.5) );
11043 
11044           XmTextFieldSetString( ob_speed_data, temp_data );
11045         }
11046         else
11047         {
11048           XmTextFieldSetString( ob_speed_data, "" );
11049         }
11050 
11051         if (strlen(p_station->course) != 0)
11052         {
11053           XmTextFieldSetString( ob_course_data, p_station->course);
11054         }
11055         else
11056         {
11057           XmTextFieldSetString( ob_course_data, "" );
11058         }
11059 
11060 //                if ( (p_station->aprs_symbol.aprs_symbol == 'm')   // Found a signpost object
11061 //                        && (p_station->aprs_symbol.aprs_type == '\\')
11062 //                        && Signpost_object_enabled) {
11063         if (Signpost_object_enabled)
11064         {
11065           XtSetSensitive(ob_frame,FALSE);
11066           XtSetSensitive(signpost_frame,TRUE);
11067           XmTextFieldSetString( signpost_data, p_station->signpost);
11068         }   // Done with filling in Signpost Objects
11069 
11070 
11071         if (Probability_circles_enabled)
11072         {
11073           // Fetch the min/max fields from the object data and
11074           // write that data into the input fields.
11075           XmTextFieldSetString( probability_data_min, p_station->probability_min );
11076           XmTextFieldSetString( probability_data_max, p_station->probability_max );
11077         }
11078 
11079 
11080 //                else if ( (p_station->aprs_symbol.aprs_type == '/') // Found a DF object
11081 //                        && (p_station->aprs_symbol.aprs_symbol == '\\' )) {
11082         if (DF_object_enabled)
11083         {
11084           XtSetSensitive(ob_frame,FALSE);
11085           //fprintf(stderr,"Found a DF object\n");
11086 
11087           // Decide if it was an omni-DF object or a beam heading object
11088           if (p_station->NRQ[0] == '\0')      // Must be an omni-DF object
11089           {
11090             //fprintf(stderr,"omni-DF\n");
11091             //fprintf(stderr,"Signal_gain: %s\n", p_station->signal_gain);
11092 
11093             XmToggleButtonSetState(omni_antenna_toggle, TRUE, TRUE);
11094 
11095             // Set the received signal quality toggle
11096             switch (p_station->signal_gain[3])
11097             {
11098               case ('1'):   // 1
11099                 XmToggleButtonGadgetSetState(soption1, TRUE, TRUE);
11100                 break;
11101               case ('2'):   // 2
11102                 XmToggleButtonGadgetSetState(soption2, TRUE, TRUE);
11103                 break;
11104               case ('3'):   // 3
11105                 XmToggleButtonGadgetSetState(soption3, TRUE, TRUE);
11106                 break;
11107               case ('4'):   // 4
11108                 XmToggleButtonGadgetSetState(soption4, TRUE, TRUE);
11109                 break;
11110               case ('5'):   // 5
11111                 XmToggleButtonGadgetSetState(soption5, TRUE, TRUE);
11112                 break;
11113               case ('6'):   // 6
11114                 XmToggleButtonGadgetSetState(soption6, TRUE, TRUE);
11115                 break;
11116               case ('7'):   // 7
11117                 XmToggleButtonGadgetSetState(soption7, TRUE, TRUE);
11118                 break;
11119               case ('8'):   // 8
11120                 XmToggleButtonGadgetSetState(soption8, TRUE, TRUE);
11121                 break;
11122               case ('9'):   // 9
11123                 XmToggleButtonGadgetSetState(soption9, TRUE, TRUE);
11124                 break;
11125               case ('0'):   // 0
11126               default:
11127                 XmToggleButtonGadgetSetState(soption0, TRUE, TRUE);
11128                 break;
11129             }
11130 
11131             // Set the HAAT toggle
11132             switch (p_station->signal_gain[4])
11133             {
11134               case ('1'):   // 20ft
11135                 XmToggleButtonGadgetSetState(hoption1, TRUE, TRUE);
11136                 break;
11137               case ('2'):   // 40ft
11138                 XmToggleButtonGadgetSetState(hoption2, TRUE, TRUE);
11139                 break;
11140               case ('3'):   // 80ft
11141                 XmToggleButtonGadgetSetState(hoption3, TRUE, TRUE);
11142                 break;
11143               case ('4'):   // 160ft
11144                 XmToggleButtonGadgetSetState(hoption4, TRUE, TRUE);
11145                 break;
11146               case ('5'):   // 320ft
11147                 XmToggleButtonGadgetSetState(hoption5, TRUE, TRUE);
11148                 break;
11149               case ('6'):   // 640ft
11150                 XmToggleButtonGadgetSetState(hoption6, TRUE, TRUE);
11151                 break;
11152               case ('7'):   // 1280ft
11153                 XmToggleButtonGadgetSetState(hoption7, TRUE, TRUE);
11154                 break;
11155               case ('8'):   // 2560ft
11156                 XmToggleButtonGadgetSetState(hoption8, TRUE, TRUE);
11157                 break;
11158               case ('9'):   // 5120ft
11159                 XmToggleButtonGadgetSetState(hoption9, TRUE, TRUE);
11160                 break;
11161               case ('0'):   // 10ft
11162               default:
11163                 XmToggleButtonGadgetSetState(hoption0, TRUE, TRUE);
11164                 break;
11165             }
11166 
11167             // Set the antenna gain toggle
11168             switch (p_station->signal_gain[5])
11169             {
11170               case ('1'):   // 1dB
11171                 XmToggleButtonGadgetSetState(goption1, TRUE, TRUE);
11172                 break;
11173               case ('2'):   // 2dB
11174                 XmToggleButtonGadgetSetState(goption2, TRUE, TRUE);
11175                 break;
11176               case ('3'):   // 3dB
11177                 XmToggleButtonGadgetSetState(goption3, TRUE, TRUE);
11178                 break;
11179               case ('4'):   // 4dB
11180                 XmToggleButtonGadgetSetState(goption4, TRUE, TRUE);
11181                 break;
11182               case ('5'):   // 5dB
11183                 XmToggleButtonGadgetSetState(goption5, TRUE, TRUE);
11184                 break;
11185               case ('6'):   // 6dB
11186                 XmToggleButtonGadgetSetState(goption6, TRUE, TRUE);
11187                 break;
11188               case ('7'):   // 7dB
11189                 XmToggleButtonGadgetSetState(goption7, TRUE, TRUE);
11190                 break;
11191               case ('8'):   // 8dB
11192                 XmToggleButtonGadgetSetState(goption8, TRUE, TRUE);
11193                 break;
11194               case ('9'):   // 9dB
11195                 XmToggleButtonGadgetSetState(goption9, TRUE, TRUE);
11196                 break;
11197               case ('0'):   // 0dB
11198               default:
11199                 XmToggleButtonGadgetSetState(goption0, TRUE, TRUE);
11200                 break;
11201             }
11202 
11203             // Set the antenna directivity toggle
11204             switch (p_station->signal_gain[6])
11205             {
11206               case ('1'):   // 45
11207                 XmToggleButtonGadgetSetState(doption1, TRUE, TRUE);
11208                 break;
11209               case ('2'):   // 90
11210                 XmToggleButtonGadgetSetState(doption2, TRUE, TRUE);
11211                 break;
11212               case ('3'):   // 135
11213                 XmToggleButtonGadgetSetState(doption3, TRUE, TRUE);
11214                 break;
11215               case ('4'):   // 180
11216                 XmToggleButtonGadgetSetState(doption4, TRUE, TRUE);
11217                 break;
11218               case ('5'):   // 225
11219                 XmToggleButtonGadgetSetState(doption5, TRUE, TRUE);
11220                 break;
11221               case ('6'):   // 270
11222                 XmToggleButtonGadgetSetState(doption6, TRUE, TRUE);
11223                 break;
11224               case ('7'):   // 315
11225                 XmToggleButtonGadgetSetState(doption7, TRUE, TRUE);
11226                 break;
11227               case ('8'):   // 360
11228                 XmToggleButtonGadgetSetState(doption8, TRUE, TRUE);
11229                 break;
11230               case ('0'):   // Omni
11231               default:
11232                 XmToggleButtonGadgetSetState(doption0, TRUE, TRUE);
11233                 break;
11234             }
11235           }
11236           else    // Must be a beam-heading object
11237           {
11238             //fprintf(stderr,"beam-heading\n");
11239 
11240             XmToggleButtonSetState(beam_antenna_toggle, TRUE, TRUE);
11241 
11242             XmTextFieldSetString(ob_bearing_data, p_station->bearing);
11243 
11244             switch (p_station->NRQ[2])
11245             {
11246               case ('1'):   // 240�
11247                 XmToggleButtonGadgetSetState(woption1, TRUE, TRUE);
11248                 break;
11249               case ('2'):   // 120�
11250                 XmToggleButtonGadgetSetState(woption2, TRUE, TRUE);
11251                 break;
11252               case ('3'):   // 64�
11253                 XmToggleButtonGadgetSetState(woption3, TRUE, TRUE);
11254                 break;
11255               case ('4'):   // 32�
11256                 XmToggleButtonGadgetSetState(woption4, TRUE, TRUE);
11257                 break;
11258               case ('5'):   // 16�
11259                 XmToggleButtonGadgetSetState(woption5, TRUE, TRUE);
11260                 break;
11261               case ('6'):   // 8�
11262                 XmToggleButtonGadgetSetState(woption6, TRUE, TRUE);
11263                 break;
11264               case ('7'):   // 4�
11265                 XmToggleButtonGadgetSetState(woption7, TRUE, TRUE);
11266                 break;
11267               case ('8'):   // 2�
11268                 XmToggleButtonGadgetSetState(woption8, TRUE, TRUE);
11269                 break;
11270               case ('9'):   // 1�
11271                 XmToggleButtonGadgetSetState(woption9, TRUE, TRUE);
11272                 break;
11273               case ('0'):   // Useless
11274               default:
11275                 XmToggleButtonGadgetSetState(woption0, TRUE, TRUE);
11276                 break;
11277             }
11278           }
11279         }
11280         else      // Found a normal object
11281         {
11282           // Nothing needed in this block currently
11283         } // Done with filling in Normal objects
11284 
11285       } // Done with filling in Signpost, DF, or Normal Objects
11286 
11287       // Handle Generic Options (common to all)
11288       // Convert altitude from meters to feet
11289       if (strlen(p_station->altitude) != 0)
11290       {
11291         xastir_snprintf(temp_data, sizeof(temp_data), "%d",
11292                         (int)((atof(p_station->altitude) / 0.3048) + 0.5) );
11293 
11294         XmTextFieldSetString( ob_altitude_data, temp_data );
11295       }
11296       else
11297       {
11298         XmTextFieldSetString( ob_altitude_data, "" );
11299       }
11300     }
11301 
11302 // Else we're creating a new object from scratch:  p_station == NULL
11303     else
11304     {
11305       if (Area_object_enabled)
11306       {
11307         XmToggleButtonGadgetSetState(coption1, TRUE, TRUE);             // Black
11308         XmToggleButtonGadgetSetState(bright_dim_toggle, FALSE, TRUE);   // Dim
11309         XmToggleButtonGadgetSetState(toption1, TRUE, TRUE);             // Circle
11310       }
11311 
11312       XmTextFieldSetString(object_name_data,"");
11313 
11314 
11315       // Set the symbol type based on the global variables
11316       if (Area_object_enabled)
11317       {
11318         temp_data[0] = '\\';
11319         temp_data[1] = '\0';
11320         XmTextFieldSetString(object_group_data,temp_data);
11321 
11322         temp_data[0] = 'l';
11323         temp_data[1] = '\0';
11324         XmTextFieldSetString(object_symbol_data,temp_data);
11325 
11326         XtSetSensitive(ob_frame,FALSE);
11327 
11328 
11329       }
11330       else if (Signpost_object_enabled)
11331       {
11332         temp_data[0] = '\\';
11333         temp_data[1] = '\0';
11334         XmTextFieldSetString(object_group_data,temp_data);
11335 
11336         temp_data[0] = 'm';
11337         temp_data[1] = '\0';
11338         XmTextFieldSetString(object_symbol_data,temp_data);
11339 
11340         XmTextFieldSetString( signpost_data, "" );
11341 
11342         XtSetSensitive(ob_frame,FALSE);
11343 
11344 
11345       }
11346       else if (Probability_circles_enabled)
11347       {
11348         temp_data[0] = '/';
11349         temp_data[1] = '\0';
11350         XmTextFieldSetString(object_group_data,temp_data);
11351 
11352         temp_data[0] = '[';
11353         temp_data[1] = '\0';
11354         XmTextFieldSetString(object_symbol_data,temp_data);
11355 
11356         XmTextFieldSetString( probability_data_min, "" );
11357         XmTextFieldSetString( probability_data_max, "" );
11358 
11359 
11360       }
11361       else if (DF_object_enabled)
11362       {
11363         temp_data[0] = '/';
11364         temp_data[1] = '\0';
11365         XmTextFieldSetString(object_group_data,temp_data);
11366 
11367         temp_data[0] = '\\';
11368         temp_data[1] = '\0';
11369         XmTextFieldSetString(object_symbol_data,temp_data);
11370 
11371         // Defaults Omni-DF
11372         XmToggleButtonGadgetSetState(soption0, TRUE, TRUE); // Nothing heard
11373         XmToggleButtonGadgetSetState(hoption1, TRUE, TRUE); // 20 feet HAAT
11374         XmToggleButtonGadgetSetState(goption3, TRUE, TRUE); // 3dB gain antenna
11375         XmToggleButtonGadgetSetState(doption0, TRUE, TRUE); // No directivity
11376 
11377         // Defaults Beam-DF
11378         XmToggleButtonGadgetSetState(woption5, TRUE, TRUE); // 16 degree beamwidth
11379 
11380         XtSetSensitive(ob_frame,FALSE);
11381 
11382 
11383       }
11384       else if (Map_View_object_enabled)
11385       {
11386         temp_data[0] = '/';
11387         temp_data[1] = '\0';
11388         XmTextFieldSetString(object_group_data,temp_data);
11389 
11390         temp_data[0] = 'E';
11391         temp_data[1] = '\0';
11392         XmTextFieldSetString(object_symbol_data,temp_data);
11393 
11394         XtSetSensitive(ob_frame,FALSE);
11395         XtSetSensitive(ob_option_frame,FALSE);
11396 
11397 
11398       }
11399       else      // Normal object/item
11400       {
11401         temp_data[0] = '/';
11402         temp_data[1] = '\0';
11403         XmTextFieldSetString(object_group_data,temp_data);
11404 
11405         temp_data[0] = '/';
11406         temp_data[1] = '\0';
11407         XmTextFieldSetString(object_symbol_data,temp_data);
11408       }
11409 
11410       // Compute the range for the Map View object and store
11411       // it in the comment field.
11412       if (Map_View_object_enabled)
11413       {
11414         double top_range, left_range, max_range;
11415         char range[10];
11416         Dimension width, height;
11417 
11418 
11419         // Get the display parameters
11420         XtVaGetValues(da,XmNwidth, &width,XmNheight, &height, NULL);
11421 
11422         // Find distance from center to top of screen.
11423         // top_range = distance from center_longitude,
11424         // center_latitude to center_longitude,
11425         // center_latitude-((height*scale_y)/2).
11426         top_range = calc_distance(center_latitude,
11427                                   center_longitude,
11428                                   NW_corner_latitude,
11429                                   center_longitude);
11430 //fprintf(stderr," top_range:%1.0f meters\n", top_range);
11431         // Find distance from center to left of screen.
11432         // left_range = distance from center_longitude,
11433         // center_latitude to
11434         // center_longitude-((width*scale_x)/2),
11435         // center_latitude.
11436         left_range = calc_distance(center_latitude,
11437                                    center_longitude,
11438                                    center_latitude,
11439                                    NW_corner_longitude);
11440 //fprintf(stderr,"left_range:%1.0f meters\n", left_range);
11441 
11442         // Compute greater of the two.  This is our range in
11443         // meters.
11444         if (top_range > left_range)
11445         {
11446           max_range = top_range;
11447         }
11448         else
11449         {
11450           max_range = left_range;
11451         }
11452 
11453         // Convert from meters to miles
11454         max_range = max_range / 1000.0;  // kilometers
11455         max_range = max_range * 0.62137; // miles
11456 
11457         // Restrict it to four digits.
11458         if (max_range > 9999.0)
11459         {
11460           max_range = 9999.0;
11461         }
11462 
11463 //fprintf(stderr,"Range:%04d miles\n", (int)(max_range + 0.5));
11464 
11465         xastir_snprintf(range,
11466                         sizeof(range),
11467                         "RNG%04d",
11468                         (int)(max_range + 0.5)); // Poor man's rounding
11469 
11470         XmTextFieldSetString(object_comment_data, range);
11471       }
11472       else
11473       {
11474         XmTextFieldSetString(object_comment_data,"");
11475       }
11476     }
11477 
11478 
11479 
11480     if (strcmp(calldata,"2") != 0)    // Normal Modify->Object or Create->Object behavior
11481     {
11482       // Fill in original lat/lon values
11483       convert_lat_l2s(lat, lat_str, sizeof(lat_str), CONVERT_HP_NOSP);
11484       substr(temp_data,lat_str,2);
11485       XmTextFieldSetString(object_lat_data_deg,temp_data);
11486       substr(temp_data,lat_str+2,6);
11487       XmTextFieldSetString(object_lat_data_min,temp_data);
11488       substr(temp_data,lat_str+8,1);
11489       XmTextFieldSetString(object_lat_data_ns,temp_data);
11490 
11491       convert_lon_l2s(lon, lon_str, sizeof(lon_str), CONVERT_HP_NOSP);
11492       substr(temp_data,lon_str,3);
11493       XmTextFieldSetString(object_lon_data_deg,temp_data);
11494       substr(temp_data,lon_str+3,6);
11495       XmTextFieldSetString(object_lon_data_min,temp_data);
11496       substr(temp_data,lon_str+9,1);
11497       XmTextFieldSetString(object_lon_data_ew,temp_data);
11498     }
11499 
11500     else    // We're in the middle of moving an object, calldata was "2"
11501     {
11502       // Fill in new lat/long values
11503       //fprintf(stderr,"Here we will fill in the new lat/long values\n");
11504       x = (center_longitude - ((screen_width  * scale_x)/2) + (input_x * scale_x));
11505       y = (center_latitude  - ((screen_height * scale_y)/2) + (input_y * scale_y));
11506       if (x < 0)
11507       {
11508         x = 0l;  // 180�W
11509       }
11510 
11511       if (x > 129600000l)
11512       {
11513         x = 129600000l;  // 180�E
11514       }
11515 
11516       if (y < 0)
11517       {
11518         y = 0l;  //  90�N
11519       }
11520 
11521       if (y > 64800000l)
11522       {
11523         y = 64800000l;  //  90�S
11524       }
11525 
11526       convert_lat_l2s(y, lat_str, sizeof(lat_str), CONVERT_HP_NOSP);
11527       substr(temp_data,lat_str,2);
11528       XmTextFieldSetString(object_lat_data_deg,temp_data);
11529       substr(temp_data,lat_str+2,6);
11530       XmTextFieldSetString(object_lat_data_min,temp_data);
11531       substr(temp_data,lat_str+8,1);
11532       XmTextFieldSetString(object_lat_data_ns,temp_data);
11533 
11534       convert_lon_l2s(x, lon_str, sizeof(lon_str), CONVERT_HP_NOSP);
11535       substr(temp_data,lon_str,3);
11536       XmTextFieldSetString(object_lon_data_deg,temp_data);
11537       substr(temp_data,lon_str+3,6);
11538       XmTextFieldSetString(object_lon_data_min,temp_data);
11539       substr(temp_data,lon_str+9,1);
11540       XmTextFieldSetString(object_lon_data_ew,temp_data);
11541     }
11542 
11543     XtAddCallback(object_group_data, XmNvalueChangedCallback, updateObjectPictureCallback, object_dialog);
11544     XtAddCallback(object_symbol_data, XmNvalueChangedCallback, updateObjectPictureCallback, object_dialog);
11545 
11546     // update symbol picture
11547     (void)updateObjectPictureCallback((Widget)NULL,(XtPointer)NULL,(XtPointer)NULL);
11548 
11549     pos_dialog(object_dialog);
11550 
11551     delw = XmInternAtom(XtDisplay(object_dialog),"WM_DELETE_WINDOW", FALSE);
11552     XmAddWMProtocolCallback(object_dialog, delw, Object_destroy_shell, (XtPointer)object_dialog);
11553 
11554     if (Signpost_object_enabled)
11555     {
11556       XtManageChild(signpost_form);
11557     }
11558     else if (Probability_circles_enabled)
11559     {
11560       XtManageChild(probability_form);
11561     }
11562     else if (Area_object_enabled)
11563     {
11564       XtManageChild(shape_box);
11565       XtManageChild(color_box);
11566       XtManageChild(area_form);
11567     }
11568     else if (DF_object_enabled)
11569     {
11570       XtManageChild(signal_box);
11571       XtManageChild(height_box);
11572       XtManageChild(gain_box);
11573       XtManageChild(directivity_box);
11574       XtManageChild(width_box);
11575       XtManageChild(formomni);
11576       XtManageChild(formbeam);
11577     }
11578 
11579     XtManageChild(ob_latlon_form);
11580     XtManageChild(ob_option_form);
11581     XtManageChild(ob_form1);
11582     XtManageChild(ob_form);
11583     XtManageChild(ob_pane);
11584 
11585     resize_dialog(ob_form, object_dialog);
11586 
11587     XtPopup(object_dialog,XtGrabNone);
11588 
11589     // Move focus to the Cancel button.  This appears to highlight the
11590     // button fine, but we're not able to hit the <Enter> key to
11591     // have that default function happen.  Note:  We _can_ hit the
11592     // <SPACE> key, and that activates the option.
11593 //        XmUpdateDisplay(object_dialog);
11594     XmProcessTraversal(ob_button_cancel, XmTRAVERSE_CURRENT);
11595   }
11596 
11597   // This will cause the move to happen quickly without any button presses.
11598   if (calldata != NULL)   // If we're doing a "move" operation
11599   {
11600     if (strcmp(calldata,"2") == 0)
11601     {
11602       if ((p_station->flag & ST_ITEM) != 0)       // Moving an Item
11603       {
11604 //fprintf(stderr,"Calling Item_change_data_set()\n");
11605         Item_change_data_set(w,object_dialog,object_dialog);    // Move it now!
11606 //fprintf(stderr,"Done with call\n");
11607       }
11608       else                                        // Moving an Object
11609       {
11610 //fprintf(stderr,"Calling Object_change_data_set()\n");
11611         Object_change_data_set(w,object_dialog,object_dialog);  // Move it now!
11612 //fprintf(stderr,"Done with call\n");
11613       }
11614     }
11615   }
11616 
11617 }   // End of Set_Del_Object
11618 
11619 
11620 
11621 
11622 
11623 /*
11624  *  Change data for current object
11625  *  If calldata = 2, we're doing a move object operation.  Pass the
11626  *  value on through to Set_Del_Object.
11627  */
11628 void Modify_object( Widget w, XtPointer clientData, XtPointer calldata)
11629 {
11630   DataRow *p_station = clientData;
11631 
11632   //if (calldata != NULL)
11633   //    fprintf(stderr,"Modify_object:  calldata:  %s\n", (char *)calldata);
11634 
11635   //fprintf(stderr,"Object Name: %s\n", p_station->call_sign);
11636 
11637   // Only move the object if it is our callsign, else force the
11638   // user to adopt the object first, then move it.
11639   //
11640   // Not exact match (this one is useful for testing)
11641 ////    if (!is_my_call(p_station->origin,0)) {
11642 //    if (!is_my_object_item(p_station)) {
11643   //
11644   // Exact match includes SSID (this one is for production code)
11645 //    if (!is_my_call(p_station->origin,1)) {
11646   if (!is_my_object_item(p_station))
11647   {
11648 
11649     // It's not from my callsign
11650     if (strncmp(calldata,"2",1) == 0)
11651     {
11652 
11653       // We're doing a Move Object operation
11654       //fprintf(stderr,"Modify_object:  Object not owned by
11655       //me!\n");
11656       popup_message_always(langcode("POPEM00035"),
11657                            langcode("POPEM00042"));
11658       return;
11659     }
11660   }
11661 
11662   Set_Del_Object( w, p_station, calldata );
11663 }
11664 
11665 
11666 
11667 
11668 
11669 //
11670 // Disown function called by object/item decode routines.
11671 // If an object/item is received that matches something in our
11672 // object.log file, we immediately cease to transmit that object and
11673 // we mark each line containing that object in our log file with a
11674 // hash mark ('#').  This comments out that object so that the next
11675 // time we reboot, we won't start transmitting it again.
11676 
11677 // Note that the length of "line" can be up to MAX_DEVICE_BUFFER,
11678 // which is currently set to 4096.
11679 //
11680 void disown_object_item(char *call_sign, char *new_owner)
11681 {
11682   char file[200];
11683   char file_temp[200];
11684   FILE *f;
11685   FILE *f_temp;
11686   char line[300];
11687   char name[15];
11688   int ret;
11689 
11690 
11691 //fprintf(stderr,"disown_object_item, object: %s, new_owner: %s\n",
11692 //    call_sign,
11693 //    new_owner);
11694 
11695 
11696   // If it's my call in the new_owner field, then I must have just
11697   // deleted the object and am transmitting a killed object for
11698   // it.  If it's not my call, someone else has assumed control of
11699   // the object.
11700   //
11701   // Comment out any references to the object in the log file so
11702   // that we don't start retransmitting it on a restart.
11703 
11704   if (is_my_call(new_owner,1))   // Exact match includes SSID
11705   {
11706     //fprintf(stderr,"Commenting out %s in object.log\n",
11707     //call_sign);
11708   }
11709   else
11710   {
11711     fprintf(stderr,"Disowning '%s': '%s' is taking over control of it.\n",
11712             call_sign, new_owner);
11713   }
11714 
11715   get_user_base_dir("config/object.log", file, sizeof(file));
11716 
11717   get_user_base_dir("config/object-temp.log", file_temp, sizeof(file_temp));
11718 
11719   //fprintf(stderr,"%s\t%s\n",file,file_temp);
11720 
11721   // Our own internal function from util.c
11722   ret = copy_file(file, file_temp);
11723   if (ret)
11724   {
11725     fprintf(stderr,"\n\nCouldn't create temp file %s!\n\n\n",
11726             file_temp);
11727     return;
11728   }
11729 
11730   // Open the temp file and write to the original file, with hash
11731   // marks in front of the appropriate lines.
11732   f_temp=fopen(file_temp,"r");
11733   f=fopen(file,"w");
11734 
11735   if (f == NULL)
11736   {
11737     fprintf(stderr,"Couldn't open %s\n",file);
11738     return;
11739   }
11740   if (f_temp == NULL)
11741   {
11742     fprintf(stderr,"Couldn't open %s\n",file_temp);
11743     return;
11744   }
11745 
11746   // Read lines from the temp file and write them to the standard
11747   // file, modifying them as necessary.
11748   while (fgets(line, 300, f_temp) != NULL)
11749   {
11750 
11751     // Need to check that the length matches for both!  Best way
11752     // is to parse the object/item name out of the string and
11753     // then do a normal string compare between the two.
11754 
11755     if (line[0] == ';')         // Object
11756     {
11757       substr(name,&line[1],9);
11758       name[9] = '\0';
11759       remove_trailing_spaces(name);
11760     }
11761 
11762     else if (line[0] == ')')    // Item
11763     {
11764       int i;
11765 
11766       // 3-9 char name
11767       for (i = 1; i <= 9; i++)
11768       {
11769         if (line[i] == '!' || line[i] == '_')
11770         {
11771           name[i-1] = '\0';
11772           break;
11773         }
11774         name[i-1] = line[i];
11775       }
11776       name[9] = '\0';  // In case we never saw '!' || '_'
11777 
11778       // Don't remove trailing spaces for Items, else we won't
11779       // get a match.
11780     }
11781 
11782     else if (line[1] == ';')    // Commented out Object
11783     {
11784       substr(name,&line[2],10);
11785       name[9] = '\0';
11786       remove_trailing_spaces(name);
11787 
11788     }
11789 
11790     else if (line[1] == ')')    // Commented out Item
11791     {
11792       int i;
11793 
11794       // 3-9 char name
11795       for (i = 2; i <= 10; i++)
11796       {
11797         if (line[i] == '!' || line[i] == '_')
11798         {
11799           name[i-1] = '\0';
11800           break;
11801         }
11802         name[i-1] = line[i];
11803       }
11804       name[9] = '\0';  // In case we never saw '!' || '_'
11805 
11806       // Don't remove trailing spaces for Items, else we won't
11807       // get a match.
11808     }
11809 
11810 
11811     //fprintf(stderr,"'%s'\t'%s'\n", name, call_sign);
11812 
11813     if (valid_object(name))
11814     {
11815 
11816       if ( strcmp(name,call_sign) == 0 )
11817       {
11818         // Match.  Comment it out in the file unless it's
11819         // already commented out.
11820         if (line[0] != '#')
11821         {
11822           fprintf(f,"#%s",line);
11823           //fprintf(stderr,"#%s",line);
11824         }
11825         else
11826         {
11827           fprintf(f,"%s",line);
11828           //fprintf(stderr,"%s",line);
11829         }
11830       }
11831       else
11832       {
11833         // No match.  Copy the line verbatim unless it's
11834         // just a
11835         // blank line.
11836         if (line[0] != '\n')
11837         {
11838           fprintf(f,"%s",line);
11839           //fprintf(stderr,"%s",line);
11840         }
11841       }
11842     }
11843   }
11844   fclose(f);
11845   fclose(f_temp);
11846 }
11847 
11848 
11849 
11850 
11851 
11852 //
11853 // Logging function called by object/item create/modify routines.
11854 // We log each object/item as one line in a file.
11855 //
11856 // We need to check for objects of the same name in the file,
11857 // deleting lines that have the same name, and adding new records to
11858 // the end.  Actually  BAD IDEA!  We want to keep the history of the
11859 // object so that we can trace its movements later.
11860 //
11861 // Note that the length of "line" can be up to MAX_DEVICE_BUFFER,
11862 // which is currently set to 4096.
11863 //
11864 // Change this function so that deleted objects/items get disowned
11865 // instead (commented out in the file so that they're not
11866 // transmitted again after a restart).  See disown_object_item().
11867 //
11868 void log_object_item(char *line, int disable_object, char *object_name)
11869 {
11870   char file[MAX_VALUE];
11871   FILE *f;
11872 
11873   get_user_base_dir("config/object.log", file, sizeof(file));
11874 
11875   f=fopen(file,"a");
11876   if (f!=NULL)
11877   {
11878     fprintf(f,"%s\n",line);
11879     (void)fclose(f);
11880 
11881     if (debug_level & 1)
11882     {
11883       fprintf(stderr,"Saving object/item to file: %s",line);
11884     }
11885 
11886     // Comment out all instances of the object/item in the log
11887     // file.  This will make sure that the object is not
11888     // retransmitted again when Xastir is restarted.
11889     if (disable_object)
11890     {
11891       disown_object_item(object_name, my_callsign);
11892     }
11893 
11894   }
11895   else
11896   {
11897     fprintf(stderr,"Couldn't open file for appending: %s\n", file);
11898   }
11899 }
11900 
11901 
11902 
11903 
11904 
11905 //
11906 // Function to load saved objects and items back into Xastir.  This
11907 // is called on startup.  This implements persistent objects/items
11908 // across Xastir restarts.
11909 //
11910 // Note that the length of "line" can be up to MAX_DEVICE_BUFFER,
11911 // which is currently set to 4096.
11912 //
11913 // This appears to skip the loading of killed objects/items.  We may
11914 // instead want to begin transmitting them again until they time
11915 // out, then mark them with a '#' in the log file at that point.
11916 //
11917 void reload_object_item(void)
11918 {
11919   char file[MAX_VALUE];
11920   FILE *f;
11921   char line[300+1];
11922   char line2[350];
11923   int save_state;
11924 
11925 
11926   get_user_base_dir("config/object.log", file, sizeof(file));
11927 
11928   f=fopen(file,"r");
11929   if (f!=NULL)
11930   {
11931 
11932     // Turn off duplicate point checking (need this in order to
11933     // work with SAR objects).  Save state so that we don't mess
11934     // it up.
11935     save_state = skip_dupe_checking;
11936     skip_dupe_checking++;
11937 
11938     while (fgets(line, 300, f) != NULL)
11939     {
11940 
11941       if (debug_level & 1)
11942       {
11943         fprintf(stderr,"Loading object/item from file: %s",line);
11944       }
11945 
11946       if (line[0] != '#')     // Skip comment lines
11947       {
11948         xastir_snprintf(line2,
11949                         sizeof(line2),
11950                         "%s>%s:%s",
11951                         my_callsign,
11952                         VERSIONFRM,
11953                         line);
11954 
11955         // Decode this packet.  This will put it into our
11956         // station database and cause it to be transmitted
11957         // at
11958         // regular intervals.  Port is set to -1 here.
11959         decode_ax25_line( line2, DATA_VIA_LOCAL, -1, 1);
11960 
11961 // Right about here we could do a lookup for the object/item
11962 // matching the name and change the timing on it.  This could serve
11963 // to spread the transmit timing out a bit so that all objects/items
11964 // are not transmitted together.  Another easier option would be to
11965 // change the routine which chooses when to transmit, having it
11966 // randomize the numbers a bit each time.  I chose the second
11967 // option.
11968 
11969       }
11970     }
11971     (void)fclose(f);
11972 
11973     // Restore the skip_dupe_checking state
11974     skip_dupe_checking = save_state;
11975 
11976     // Update the screen
11977     redraw_symbols(da);
11978     (void)XCopyArea(XtDisplay(da),
11979                     pixmap_final,
11980                     XtWindow(da),
11981                     gc,
11982                     0,
11983                     0,
11984                     screen_width,
11985                     screen_height,
11986                     0,
11987                     0);
11988   }
11989   else
11990   {
11991     if (debug_level & 1)
11992     {
11993       fprintf(stderr,"Couldn't open file for reading: %s\n", file);
11994     }
11995   }
11996 
11997   // Start transmitting these objects in about 30 seconds.
11998   // Prevent transmission of objects until sometime after we're
11999   // done with our initial load.
12000   last_object_check = sec_now() + 30;
12001 }
12002 
12003 
12004