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